Quick Search:

View

Revision:
Expand:  
Changeset: MAIN:ragge:20110327131236

Diff

Diff from 1.128 to:

Annotations

Annotate by Age | Author | Mixed | None
/fisheye/browse/pcc/pcc/cc/cpp/cpp.c

Annotated File View

ragge
1.128
1 /*      $Id: cpp.c,v 1.128 2011/03/27 13:12:36 ragge Exp $      */
ragge
1.1
2
3 /*
ragge
1.109
4  * Copyright (c) 2004,2010 Anders Magnusson (ragge@ludd.luth.se).
ragge
1.1
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27
28 /*
29  * The C preprocessor.
30  * This code originates from the V6 preprocessor with some additions
31  * from V7 cpp, and at last ansi/c99 support.
32  */
pj
1.23
33
ragge
1.74
34 #include "config.h"
pj
1.23
35
gmcgarry
1.81
36 #ifdef HAVE_SYS_WAIT_H
ragge
1.1
37 #include <sys/wait.h>
gmcgarry
1.81
38 #endif
ragge
1.108
39 #include <sys/stat.h>
ragge
1.1
40
41 #include <fcntl.h>
gmcgarry
1.81
42 #ifdef HAVE_UNISTD_H
ragge
1.1
43 #include <unistd.h>
gmcgarry
1.81
44 #endif
ragge
1.1
45 #include <stdio.h>
46 #include <stdarg.h>
47 #include <stdlib.h>
48 #include <string.h>
ragge
1.9
49 #include <time.h>
ragge
1.51
50 #include <ctype.h>
ragge
1.1
51
ragge
1.74
52 #include "compat.h"
ragge
1.1
53 #include "cpp.h"
ragge
1.36
54 #include "y.tab.h"
ragge
1.1
55
ragge
1.126
56 #define SBSIZE  1000000
ragge
1.1
57
58 static usch     sbf[SBSIZE];
59 /* C command */
60
61 int tflag;      /* traditional cpp syntax */
62 #ifdef CPP_DEBUG
63 int dflag;      /* debug printouts */
ragge
1.36
64 #define DPRINT(x) if (dflag) printf x
65 #define DDPRINT(x) if (dflag > 1) printf x
66 #else
67 #define DPRINT(x)
68 #define DDPRINT(x)
ragge
1.1
69 #endif
ragge
1.36
70
ragge
1.51
71 int ofd;
ragge
1.56
72 usch outbuf[CPPBUF];
ragge
1.97
73 int obufpistty;
gmcgarry
1.85
74 int CflagMflagdMflagPflag;
ragge
1.51
75 usch *Mfile;
ragge
1.53
76 struct initar *initar;
ragge
1.117
77 int readmaclastoch;
ragge
1.1
78
ragge
1.10
79 /* include dirs */
80 struct incs {
81         struct incs *next;
ragge
1.39
82         usch *dir;
ragge
1.108
83         dev_t dev;
84         ino_t ino;
ragge
1.20
85 } *incdir[2];
86 #define INCINC 0
87 #define SYSINC 1
ragge
1.10
88
ragge
1.1
89 static struct symtab *filloc;
90 static struct symtab *linloc;
ragge
1.65
91 static struct symtab *pragloc;
ragge
1.10
92 int     trulvl;
93 int     flslvl;
94 int     elflvl;
95 int     elslvl;
96 usch *stringbuf = sbf;
ragge
1.1
97
98 /*
99  * Macro replacement list syntax:
100  * - For object-type macros, replacement strings are stored as-is.
101  * - For function-type macros, macro args are substituted for the
102  *   character WARN followed by the argument number.
ragge
1.12
103  * - The value element points to the end of the string, to simplify
104  *   pushback onto the input queue.
ragge
1.1
105  * 
ragge
1.12
106  * The first character (from the end) in the replacement list is
107  * the number of arguments:
ragge
1.37
108  *   VARG  - ends with ellipsis, next char is argcount without ellips.
ragge
1.1
109  *   OBJCT - object-type macro
110  *   0     - empty parenthesis, foo()
111  *   1->   - number of args.
ragge
1.109
112  *
113  * WARN is used:
114  *      - in stored replacement lists to tell that an argument comes
115  *      - When expanding replacement lists to tell that the list ended.
ragge
1.116
116  *
117  * To ensure that an already expanded identifier won't get expanded
118  * again a EBLOCK char + its number is stored directly before any 
119  * expanded identifier.
ragge
1.1
120  */
121
122 /* args for lookup() */
123 #define FIND    0
124 #define ENTER   1
125
ragge
1.112
126 static int readargs(struct symtab *spconst usch **args);
127 void prline(const usch *s);
128 static void prrep(const usch *s);
ragge
1.116
129 static void exparg(int);
ragge
1.112
130 static void subarg(struct symtab *spconst usch **argsint);
ragge
1.36
131 void define(void);
132 void include(void);
ragge
1.102
133 void include_next(void);
ragge
1.36
134 void line(void);
ragge
1.37
135 void flbuf(void);
136 void usage(void);
ragge
1.116
137 usch *xstrdup(const usch *str);
ragge
1.108
138 static void addidir(char *idirstruct incs **ww);
ragge
1.113
139 void imp(const char *);
ragge
1.112
140 #define IMP(x) if (dflag>1) imp(x)
ragge
1.1
141
142 int
143 main(int argcchar **argv)
144 {
ragge
1.53
145         struct initar *it;
ragge
1.26
146         struct symtab *nl;
147         register int ch;
ragge
1.103
148         const usch *fn1, *fn2;
ragge
1.15
149
ragge
1.94
150 #ifdef TIMING
151         struct timeval t1t2;
152
153         (void)gettimeofday(&t1NULL);
154 #endif
155
gmcgarry
1.85
156         while ((ch = getopt(argcargv"CD:I:MPS:U:d:i:tvV?")) != -1)
ragge
1.1
157                 switch (ch) {
ragge
1.22
158                 case 'C'/* Do not discard comments */
159                         Cflag++;
160                         break;
161
ragge
1.53
162                 case 'i'/* include */
163                 case 'U'/* undef */
164                 case 'D'/* define something */
ragge
1.58
165                         /* XXX should not need malloc() here */
166                         if ((it = malloc(sizeof(struct initar))) == NULL)
167                                 error("couldn't apply -%c %s"choptarg);
ragge
1.53
168                         it->type = ch;
169                         it->str = optarg;
170                         it->next = initar;
171                         initar = it;
ragge
1.7
172                         break;
173
ragge
1.51
174                 case 'M'/* Generate dependencies for make */
175                         Mflag++;
176                         break;
177
gmcgarry
1.85
178                 case 'P'/* Inhibit generation of line numbers */
179                         Pflag++;
180                         break;
181
ragge
1.7
182                 case 'S':
ragge
1.10
183                 case 'I':
ragge
1.108
184                         addidir(optarg, &incdir[ch == 'I' ? INCINC : SYSINC]);
ragge
1.7
185                         break;
186
ragge
1.1
187 #ifdef CPP_DEBUG
ragge
1.64
188                 case 'V':
ragge
1.18
189                         dflag++;
ragge
1.1
190                         break;
191 #endif
ragge
1.64
192                 case 'v':
193                         printf("cpp: %s\n"VERSSTR);
194                         break;
ragge
1.60
195                 case 'd':
196                         if (optarg[0] == 'M') {
197                                 dMflag = 1;
198                                 Mflag = 1;
199                         }
200                         /* ignore others */
201                         break;
202
ragge
1.1
203                 case 't':
204                         tflag = 1;
205                         break;
206
ragge
1.37
207                 case '?':
208                         usage();
ragge
1.1
209                 default:
ragge
1.37
210                         error("bad arg %c\n"ch);
ragge
1.1
211                 }
212         argc -= optind;
213         argv += optind;
214
ragge
1.103
215         filloc = lookup((const usch *)"__FILE__"ENTER);
216         linloc = lookup((const usch *)"__LINE__"ENTER);
ragge
1.114
217         filloc->value = linloc->value = stringbuf;
218         savch(OBJCT);
219
220         /* create a complete macro for pragma */
ragge
1.103
221         pragloc = lookup((const usch *)"_Pragma"ENTER);
ragge
1.114
222         savch(0);
ragge
1.115
223         savstr((const usch *)"_Pragma(");
ragge
1.114
224         savch(0);
225         savch(WARN);
226         savch(')');
227         pragloc->value = stringbuf;
228         savch(1);
ragge
1.15
229
ragge
1.12
230         if (tflag == 0) {
231                 time_t t = time(NULL);
ragge
1.39
232                 usch *n = (usch *)ctime(&t);
ragge
1.12
233
234                 /*
235                  * Manually move in the predefined macros.
236                  */
ragge
1.103
237                 nl = lookup((const usch *)"__TIME__"ENTER);
ragge
1.13
238                 savch(0); savch('"');  n[19] = 0savstr(&n[11]); savch('"');
ragge
1.12
239                 savch(OBJCT);
240                 nl->value = stringbuf-1;
241
ragge
1.103
242                 nl = lookup((const usch *)"__DATE__"ENTER);
ragge
1.13
243                 savch(0); savch('"'); n[24] = n[11] = 0savstr(&n[4]);
244                 savstr(&n[20]); savch('"'); savch(OBJCT);
ragge
1.12
245                 nl->value = stringbuf-1;
246
ragge
1.103
247                 nl = lookup((const usch *)"__STDC__"ENTER);
ragge
1.13
248                 savch(0); savch('1'); savch(OBJCT);
ragge
1.12
249                 nl->value = stringbuf-1;
ragge
1.73
250
ragge
1.103
251                 nl = lookup((const usch *)"__STDC_VERSION__"ENTER);
252                 savch(0); savstr((const usch *)"199901L"); savch(OBJCT);
ragge
1.73
253                 nl->value = stringbuf-1;
ragge
1.12
254         }
ragge
1.1
255
ragge
1.60
256         if (Mflag && !dMflag) {
ragge
1.51
257                 usch *c;
258
259                 if (argc < 1)
260                         error("-M and no infile");
261                 if ((c = (usch *)strrchr(argv[0], '/')) == NULL)
262                         c = (usch *)argv[0];
263                 else
264                         c++;
265                 Mfile = stringbuf;
266                 savstr(c); savch(0);
267                 if ((c = (usch *)strrchr((char *)Mfile'.')) == NULL)
268                         error("-M and no extension: ");
269                 c[1] = 'o';
270                 c[2] = 0;
271         }
272
ragge
1.26
273         if (argc == 2) {
ragge
1.37
274                 if ((ofd = open(argv[1], O_WRONLY|O_CREAT0600)) < 0)
275                         error("Can't creat %s"argv[1]);
ragge
1.26
276         } else
ragge
1.37
277                 ofd = 1/* stdout */
278         istty = isatty(ofd);
ragge
1.26
279
ragge
1.102
280         if (argc && strcmp(argv[0], "-")) {
281                 fn1 = fn2 = (usch *)argv[0];
282         } else {
283                 fn1 = NULL;
ragge
1.103
284                 fn2 = (const usch *)"";
ragge
1.102
285         }
286         if (pushfile(fn1fn20NULL))
ragge
1.26
287                 error("cannot open %s"argv[0]);
288
ragge
1.37
289         flbuf();
290         close(ofd);
ragge
1.94
291 #ifdef TIMING
292         (void)gettimeofday(&t2NULL);
293         t2.tv_sec -= t1.tv_sec;
294         t2.tv_usec -= t1.tv_usec;
295         if (t2.tv_usec < 0) {
296                 t2.tv_usec += 1000000;
297                 t2.tv_sec -= 1;
298         }
299         fprintf(stderr"cpp total time: %ld s %ld us\n",
300              t2.tv_sect2.tv_usec);
301 #endif
ragge
1.37
302         return 0;
ragge
1.26
303 }
304
ragge
1.108
305 static void
306 addidir(char *idirstruct incs **ww)
307 {
308         struct incs *w;
309         struct stat st;
310
311         if (stat(idir, &st) == -1 || S_ISDIR(st.st_mode) == 0)
312                 return/* ignore */
313         if (*ww != NULL) {
314                 for (w = *www->nextw = w->next) {
315                         if (w->dev == st.st_dev && w->ino == st.st_ino)
316                                 return;
317                 }
318                 if (w->dev == st.st_dev && w->ino == st.st_ino)
319                         return;
320                 ww = &w->next;
321         }
322         if ((w = calloc(sizeof(struct incs), 1)) == NULL)
323                 error("couldn't add path %s"idir);
324         w->dir = (usch *)idir;
325         w->dev = st.st_dev;
326         w->ino = st.st_ino;
327         *ww = w;
328 }
329
ragge
1.1
330 void
ragge
1.9
331 line()
332 {
ragge
1.37
333         static usch *lbuf;
334         static int llen;
ragge
1.97
335         usch *p;
ragge
1.9
336         int c;
337
ragge
1.97
338         if ((c = yylex()) != NUMBER)
ragge
1.9
339                 goto bad;
gmcgarry
1.100
340         ifiles->lineno = (int)(yylval.node.nd_val - 1);
ragge
1.9
341
ragge
1.97
342         if ((c = yylex()) == '\n')
ragge
1.37
343                 return;
ragge
1.97
344
345         if (c != STRING)
ragge
1.9
346                 goto bad;
ragge
1.97
347
348         p = (usch *)yytext;
349         if (*p == 'L')
350                 p++;
351         c = strlen((char *)p);
ragge
1.37
352         if (llen < c) {
ragge
1.52
353                 /* XXX may loose heap space */
ragge
1.37
354                 lbuf = stringbuf;
355                 stringbuf += c;
356                 llen = c;
357         }
ragge
1.97
358         p[strlen((char *)p)-1] = 0;
359         if (strlcpy((char *)lbuf, (char *)&p[1], SBSIZE) >= SBSIZE)
ragge
1.63
360                 error("line exceeded buffer size");
361
ragge
1.37
362         ifiles->fname = lbuf;
ragge
1.97
363         if (yylex() == '\n')
364                 return;
ragge
1.9
365
366 bad:    error("bad line directive");
367 }
368
ragge
1.10
369 /*
ragge
1.102
370  * Search for and include next file.
371  * Return 1 on success.
372  */
373 static int
ragge
1.103
374 fsrch(const usch *fnint idxstruct incs *w)
ragge
1.102
375 {
376         int i;
377
378         for (i = idxi < 2i++) {
379                 if (i > idx)
380                         w = incdir[i];
381                 for (; ww = w->next) {
382                         usch *nm = stringbuf;
383
384                         savstr(w->dir); savch('/');
385                         savstr(fn); savch(0);
386                         if (pushfile(nmfniw->next) == 0)
387                                 return 1;
388                         stringbuf = nm;
389                 }
390         }
391         return 0;
392 }
393
394 /*
ragge
1.10
395  * Include a file. Include order:
ragge
1.20
396  * - For <...> files, first search -I directories, then system directories.
397  * - For "..." files, first search "current" dir, then as <...> files.
ragge
1.10
398  */
ragge
1.9
399 void
ragge
1.3
400 include()
401 {
ragge
1.101
402         struct symtab *nl;
ragge
1.10
403         usch *osp;
ragge
1.62
404         usch *fn, *safefn;
ragge
1.102
405         int cit;
ragge
1.3
406
ragge
1.37
407         if (flslvl)
408                 return;
ragge
1.10
409         osp = stringbuf;
ragge
1.97
410
ragge
1.101
411         while ((c = sloscan()) == WSPACE)
412                 ;
413         if (c == IDENT) {
414                 /* sloscan() will not expand idents */
415                 if ((nl = lookup((usch *)yytextFIND)) == NULL)
416                         goto bad;
ragge
1.112
417                 if (kfind(nl))
418                         unpstr(stringbuf);
419                 else
420                         unpstr(nl->namep);
ragge
1.101
421                 stringbuf = osp;
422                 c = yylex();
423         }
424         if (c != STRING && c != '<')
ragge
1.3
425                 goto bad;
426
ragge
1.97
427         if (c == '<') {
ragge
1.10
428                 fn = stringbuf;
ragge
1.97
429                 while ((c = sloscan()) != '>' && c != '\n') {
ragge
1.105
430                         if (c == '\n'/* XXX check - cannot reach */
ragge
1.10
431                                 goto bad;
ragge
1.39
432                         savstr((usch *)yytext);
ragge
1.10
433                 }
434                 savch('\0');
ragge
1.97
435                 while ((c = sloscan()) == WSPACE)
ragge
1.37
436                         ;
437                 if (c != '\n')
438                         goto bad;
ragge
1.20
439                 it = SYSINC;
ragge
1.62
440                 safefn = fn;
ragge
1.3
441         } else {
ragge
1.20
442                 usch *nm = stringbuf;
443
ragge
1.116
444                 yytext[strlen((char *)yytext)-1] = 0;
ragge
1.39
445                 fn = (usch *)&yytext[1];
ragge
1.20
446                 /* first try to open file relative to previous file */
ragge
1.53
447                 /* but only if it is not an absolute path */
448                 if (*fn != '/') {
449                         savstr(ifiles->orgfn);
450                         if ((stringbuf =
451                             (usch *)strrchr((char *)nm'/')) == NULL)
452                                 stringbuf = nm;
453                         else
454                                 stringbuf++;
455                 }
ragge
1.62
456                 safefn = stringbuf;
ragge
1.20
457                 savstr(fn); savch(0);
ragge
1.97
458                 c = yylex();
ragge
1.37
459                 if (c != '\n')
460                         goto bad;
ragge
1.102
461                 if (pushfile(nmsafefn0NULL) == 0)
ragge
1.97
462                         goto okret;
ragge
1.62
463                 /* XXX may loose stringbuf space */
ragge
1.10
464         }
465
ragge
1.102
466         if (fsrch(safefn0incdir[0]))
467                 goto okret;
ragge
1.10
468
ragge
1.62
469         error("cannot find '%s'"safefn);
ragge
1.37
470         /* error() do not return */
ragge
1.3
471
472 bad:    error("bad include");
ragge
1.37
473         /* error() do not return */
ragge
1.97
474 okret:
475         prtline();
ragge
1.37
476 }
477
ragge
1.102
478 void
479 include_next()
480 {
ragge
1.105
481         struct symtab *nl;
482         usch *osp;
483         usch *fn;
484         int c;
485
ragge
1.107
486         if (flslvl)
487                 return;
ragge
1.105
488         osp = stringbuf;
489         while ((c = sloscan()) == WSPACE)
490                 ;
491         if (c == IDENT) {
492                 /* sloscan() will not expand idents */
493                 if ((nl = lookup((usch *)yytextFIND)) == NULL)
494                         goto bad;
ragge
1.112
495                 if (kfind(nl))
496                         unpstr(stringbuf);
497                 else
498                         unpstr(nl->namep);
ragge
1.105
499                 stringbuf = osp;
500                 c = yylex();
501         }
502         if (c != STRING && c != '<')
503                 goto bad;
504
505         fn = stringbuf;
506         if (c == STRING) {
507                 savstr((usch *)&yytext[1]);
508                 stringbuf[-1] = 0;
509         } else { /* < > */
510                 while ((c = sloscan()) != '>') {
511                         if (c == '\n')
512                                 goto bad;
513                         savstr((usch *)yytext);
514                 }
515                 savch('\0');
516         }
517         while ((c = sloscan()) == WSPACE)
518                 ;
519         if (c != '\n')
520                 goto bad;
521
522         if (fsrch(fnifiles->idxifiles->incs) == 0)
523                 error("cannot find '%s'"fn);
524         prtline();
525         return;
526
527 bad:    error("bad include");
528         /* error() do not return */
ragge
1.102
529 }
530
ragge
1.37
531 static int
532 definp(void)
533 {
534         int c;
535
536         do
ragge
1.97
537                 c = sloscan();
ragge
1.37
538         while (c == WSPACE);
539         return c;
ragge
1.3
540 }
541
ragge
1.80
542 void
ragge
1.79
543 getcmnt(void)
544 {
545         int c;
546
547         savstr((usch *)yytext);
ragge
1.104
548         savch(cinput()); /* Lost * */
ragge
1.79
549         for (;;) {
550                 c = cinput();
551                 if (c == '*') {
552                         c = cinput();
553                         if (c == '/') {
ragge
1.103
554                                 savstr((const usch *)"*/");
ragge
1.79
555                                 return;
556                         }
557                         cunput(c);
558                         c = '*';
559                 }
560                 savch(c);
561         }
562 }
563
564 /*
565  * Compare two replacement lists, taking in account comments etc.
566  */
567 static int
ragge
1.103
568 cmprepl(const usch *oconst usch *n)
ragge
1.79
569 {
570         for (; *oo--, n--) {
571                 /* comment skip */
572                 if (*o == '/' && o[-1] == '*') {
573                         while (*o != '*' || o[-1] != '/')
574                                 o--;
575                         o -= 2;
576                 }
577                 if (*n == '/' && n[-1] == '*') {
578                         while (*n != '*' || n[-1] != '/')
579                                 n--;
580                         n -= 2;
581                 }
582                 while (*o == ' ' || *o == '\t')
583                         o--;
584                 while (*n == ' ' || *n == '\t')
585                         n--;
586                 if (*o != *n)
587                         return 1;
588         }
589         return 0;
590 }
591
ragge
1.97
592 static int
593 isell(void)
594 {
595         int ch;
596
597         if ((ch = cinput()) != '.') {
598                 cunput(ch);
599                 return 0;
600         }
601         if ((ch = cinput()) != '.') {
602                 cunput(ch);
603                 cunput('.');
604                 return 0;
605         }
606         return 1;
607 }
608
ragge
1.3
609 void
ragge
1.1
610 define()
611 {
612         struct symtab *np;
ragge
1.112
613         usch *args[MAXARGS+1], *ubuf, *sbeg;
ragge
1.15
614         int ciredef;
ragge
1.1
615         int mkstr = 0narg = -1;
ragge
1.37
616         int ellips = 0;
ragge
1.128
617 #ifdef GCC_COMPAT
ragge
1.86
618         usch *gccvari = NULL;
ragge
1.91
619         int wascon;
ragge
1.86
620 #endif
ragge
1.1
621
ragge
1.37
622         if (flslvl)
623                 return;
ragge
1.97
624         if (sloscan() != WSPACE || sloscan() != IDENT)
ragge
1.37
625                 goto bad;
ragge
1.36
626
ragge
1.51
627         if (isdigit((int)yytext[0]))
628                 goto bad;
629
ragge
1.39
630         np = lookup((usch *)yytextENTER);
ragge
1.15
631         redef = np->value != NULL;
ragge
1.1
632
ragge
1.79
633         readmac = 1;
ragge
1.15
634         sbeg = stringbuf;
ragge
1.97
635         if ((c = sloscan()) == '(') {
ragge
1.1
636                 narg = 0;
637                 /* function-like macros, deal with identifiers */
ragge
1.72
638                 c = definp();
ragge
1.37
639                 for (;;) {
ragge
1.1
640                         if (c == ')')
641                                 break;
ragge
1.97
642                         if (c == '.' && isell()) {
ragge
1.37
643                                 ellips = 1;
644                                 if (definp() != ')')
645                                         goto bad;
646                                 break;
647                         }
648                         if (c == IDENT) {
ragge
1.72
649                                 /* make sure there is no arg of same name */
650                                 for (i = 0i < nargi++)
ragge
1.116
651                                         if (!strcmp((char *) args[i], (char *)yytext))
ragge
1.72
652                                                 error("Duplicate macro "
653                                                   "parameter \"%s\""yytext);
ragge
1.112
654                                 if (narg == MAXARGS)
655                                         error("Too many macro args");
ragge
1.90
656                                 args[narg++] = xstrdup(yytext);
ragge
1.72
657                                 if ((c = definp()) == ',') {
658                                         if ((c = definp()) == ')')
659                                                 goto bad;
ragge
1.37
660                                         continue;
ragge
1.72
661                                 }
ragge
1.128
662 #ifdef GCC_COMPAT
ragge
1.97
663                                 if (c == '.' && isell()) {
ragge
1.86
664                                         if (definp() != ')')
665                                                 goto bad;
666                                         gccvari = args[--narg];
667                                         break;
668                                 }
669 #endif
ragge
1.37
670                                 if (c == ')')
671                                         break;
672                         }
673                         goto bad;
ragge
1.1
674                 }
ragge
1.97
675                 c = sloscan();
ragge
1.36
676         } else if (c == '\n') {
ragge
1.8
677                 /* #define foo */
ragge
1.36
678                 ;
ragge
1.1
679         } else if (c != WSPACE)
ragge
1.37
680                 goto bad;
ragge
1.1
681
ragge
1.31
682         while (c == WSPACE)
ragge
1.97
683                 c = sloscan();
ragge
1.1
684
ragge
1.72
685         /* replacement list cannot start with ## operator */
ragge
1.97
686         if (c == '#') {
687                 if ((c = sloscan()) == '#')
688                         goto bad;
689                 savch('\0');
ragge
1.128
690 #ifdef GCC_COMPAT
ragge
1.97
691                 wascon = 0;
692 #endif
693                 goto in2;
694         }
ragge
1.72
695
ragge
1.1
696         /* parse replacement-list, substituting arguments */
697         savch('\0');
ragge
1.36
698         while (c != '\n') {
ragge
1.128
699 #ifdef GCC_COMPAT
ragge
1.91
700                 wascon = 0;
701 loop:
702 #endif
ragge
1.1
703                 switch (c) {
704                 case WSPACE:
705                         /* remove spaces if it surrounds a ## directive */
ragge
1.2
706                         ubuf = stringbuf;
ragge
1.39
707                         savstr((usch *)yytext);
ragge
1.97
708                         c = sloscan();
709                         if (c == '#') {
710                                 if ((c = sloscan()) != '#')
711                                         goto in2;
ragge
1.2
712                                 stringbuf = ubuf;
ragge
1.1
713                                 savch(CONC);
ragge
1.97
714                                 if ((c = sloscan()) == WSPACE)
715                                         c = sloscan();
ragge
1.128
716 #ifdef GCC_COMPAT
ragge
1.91
717                                 if (c == '\n')
718                                         break;
719                                 wascon = 1;
720                                 goto loop;
721 #endif
ragge
1.1
722                         }
723                         continue;
724
ragge
1.97
725                 case '#':
726                         c = sloscan();
727                         if (c == '#') {
728                                 /* concat op */
729                                 savch(CONC);
730                                 if ((c = sloscan()) == WSPACE)
731                                         c = sloscan();
ragge
1.128
732 #ifdef GCC_COMPAT
ragge
1.97
733                                 if (c == '\n')
734                                         break;
735                                 wascon = 1;
736                                 goto loop;
ragge
1.91
737 #else
ragge
1.97
738                                 continue;
ragge
1.91
739 #endif
ragge
1.97
740                         } 
741 in2:                    if (narg < 0) {
ragge
1.1
742                                 /* no meaning in object-type macro */
743                                 savch('#');
ragge
1.97
744                                 continue;
ragge
1.1
745                         }
746                         /* remove spaces between # and arg */
747                         savch(SNUFF);
ragge
1.97
748                         if (c == WSPACE)
749                                 c = sloscan(); /* whitespace, ignore */
ragge
1.1
750                         mkstr = 1;
ragge
1.116
751                         if (c == IDENT && strcmp((char *)yytext"__VA_ARGS__") == 0)
ragge
1.37
752                                 continue;
ragge
1.1
753
754                         /* FALLTHROUGH */
755                 case IDENT:
ragge
1.116
756                         if (strcmp((char *)yytext"__VA_ARGS__") == 0) {
ragge
1.97
757                                 if (ellips == 0)
758                                         error("unwanted %s"yytext);
ragge
1.128
759 #ifdef GCC_COMPAT
760                                 savch(wascon ? GCCARG : VARG);
761 #else
ragge
1.97
762                                 savch(VARG);
ragge
1.128
763 #endif
764
ragge
1.97
765                                 savch(WARN);
766                                 if (mkstr)
767                                         savch(SNUFF), mkstr = 0;
768                                 break;
769                         }
ragge
1.1
770                         if (narg < 0)
771                                 goto id/* just add it if object */
772                         /* check if its an argument */
773                         for (i = 0i < nargi++)
ragge
1.116
774                                 if (strcmp((char *)yytext, (char *)args[i]) == 0)
ragge
1.1
775                                         break;
776                         if (i == narg) {
ragge
1.128
777 #ifdef GCC_COMPAT
ragge
1.87
778                                 if (gccvari &&
ragge
1.116
779                                     strcmp((char *)yytext, (char *)gccvari) == 0) {
ragge
1.91
780                                         savch(wascon ? GCCARG : VARG);
ragge
1.86
781                                         savch(WARN);
782                                         if (mkstr)
783                                                 savch(SNUFF), mkstr = 0;
784                                         break;
785                                 }
786 #endif
ragge
1.1
787                                 if (mkstr)
788                                         error("not argument");
789                                 goto id;
790                         }
791                         savch(i);
792                         savch(WARN);
793                         if (mkstr)
794                                 savch(SNUFF), mkstr = 0;
795                         break;
796
ragge
1.79
797                 case CMNT/* save comments */
798                         getcmnt();
799                         break;
800
ragge
1.1
801                 default:
ragge
1.39
802 id:                     savstr((usch *)yytext);
ragge
1.1
803                         break;
804                 }
ragge
1.97
805                 c = sloscan();
ragge
1.1
806         }
ragge
1.79
807         readmac = 0;
ragge
1.20
808         /* remove trailing whitespace */
809         while (stringbuf > sbeg) {
810                 if (stringbuf[-1] == ' ' || stringbuf[-1] == '\t')
811                         stringbuf--;
ragge
1.72
812                 /* replacement list cannot end with ## operator */
813                 else if (stringbuf[-1] == CONC)
814                         goto bad;
ragge
1.20
815                 else
816                         break;
817         }
ragge
1.128
818 #ifdef GCC_COMPAT
ragge
1.86
819         if (gccvari) {
820                 savch(narg);
821                 savch(VARG);
822         } else
823 #endif
ragge
1.37
824         if (ellips) {
825                 savch(narg);
826                 savch(VARG);
827         } else
828                 savch(narg < 0 ? OBJCT : narg);
ragge
1.118
829         if (redef && ifiles->idx != SYSINC) {
ragge
1.119
830                 if (cmprepl(np->valuestringbuf-1)) {
831                         sbeg = stringbuf;
832                         np->value = stringbuf-1;
833                         warning("%s redefined\nprevious define: %s:%d",
ragge
1.53
834                             np->namepnp->filenp->line);
ragge
1.119
835                 }
ragge
1.15
836                 stringbuf = sbeg;  /* forget this space */
837         } else
838                 np->value = stringbuf-1;
ragge
1.1
839
840 #ifdef CPP_DEBUG
841         if (dflag) {
ragge
1.103
842                 const usch *w = np->value;
ragge
1.1
843
844                 printf("!define: ");
845                 if (*w == OBJCT)
846                         printf("[object]");
ragge
1.37
847                 else if (*w == VARG)
848                         printf("[VARG%d]", *--w);
ragge
1.1
849                 while (*--w) {
850                         switch (*w) {
851                         case WARNprintf("<%d>", *--w); break;
852                         case CONCprintf("<##>"); break;
853                         case SNUFFprintf("<\">"); break;
854                         defaultputchar(*w); break;
855                         }
856                 }
857                 putchar('\n');
858         }
859 #endif
ragge
1.90
860         for (i = 0i < nargi++)
861                 free(args[i]);
ragge
1.37
862         return;
863
864 bad:    error("bad define");
ragge
1.1
865 }
866
867 void
stefan
1.68
868 xwarning(usch *s)
stefan
1.67
869 {
870         usch *t;
871         usch *sb = stringbuf;
ragge
1.96
872         int dummy;
stefan
1.67
873
874         flbuf();
875         savch(0);
876         if (ifiles != NULL) {
877                 t = sheap("%s:%d: warning: "ifiles->fnameifiles->lineno);
878                 write (2tstrlen((char *)t));
879         }
ragge
1.96
880         dummy = write (2sstrlen((char *)s));
881         dummy = write (2"\n"1);
stefan
1.67
882         stringbuf = sb;
883 }
884
885 void
ragge
1.37
886 xerror(usch *s)
ragge
1.1
887 {
ragge
1.37
888         usch *t;
ragge
1.96
889         int dummy;
ragge
1.1
890
ragge
1.48
891         flbuf();
ragge
1.38
892         savch(0);
ragge
1.37
893         if (ifiles != NULL) {
ragge
1.70
894                 t = sheap("%s:%d: error: "ifiles->fnameifiles->lineno);
ragge
1.96
895                 dummy = write (2tstrlen((char *)t));
ragge
1.37
896         }
ragge
1.96
897         dummy = write (2sstrlen((char *)s));
898         dummy = write (2"\n"1);
ragge
1.37
899         exit(1);
ragge
1.1
900 }
901
ragge
1.124
902 static void
903 sss(void)
904 {
905         savch(EBLOCK);
906         savch(cinput());
907         savch(cinput());
908 }
909
ragge
1.112
910