Quick Search:

View

Revision:
Expand:  
Changeset: MAIN:gmcgarry:20110516235651

Diff

Diff from 1.130 to:

Annotations

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

Annotated File View

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