Quick Search:

View

Revision:
Expand:  
Changeset: MAIN:ragge:20090815082422

Diff

Diff from 1.101 to:

Annotations

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

Annotated File View

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