Quick Search:

View

Revision:
Expand:  
Changeset: MAIN:ragge:20101218113847

Diff

Diff from 1.109 to:

Annotations

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

Annotated File View

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