Quick Search:

View

Revision:
Expand:  
Changeset: MAIN:ragge:20080816152727

Diff

Diff from 1.92 to:

Annotations

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

Annotated File View

ragge
1.92
1 /*      $Id: cpp.c,v 1.92 2008/08/16 15:27:27 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.77
110 int obufpisttyinmac;
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
gmcgarry
1.85
189         while ((ch = getopt(argcargv"CD:I:MPS:U:d:i:tvV?")) != -1)
ragge
1.1
190                 switch (ch) {
ragge
1.22
191                 case 'C'/* Do not discard comments */
192                         Cflag++;
193                         break;
194
ragge
1.53
195                 case 'i'/* include */
196                 case 'U'/* undef */
197                 case 'D'/* define something */
ragge
1.58
198                         /* XXX should not need malloc() here */
199                         if ((it = malloc(sizeof(struct initar))) == NULL)
200                                 error("couldn't apply -%c %s"choptarg);
ragge
1.53
201                         it->type = ch;
202                         it->str = optarg;
203                         it->next = initar;
204                         initar = it;
ragge
1.7
205                         break;
206
ragge
1.51
207                 case 'M'/* Generate dependencies for make */
208                         Mflag++;
209                         break;
210
gmcgarry
1.85
211                 case 'P'/* Inhibit generation of line numbers */
212                         Pflag++;
213                         break;
214
ragge
1.7
215                 case 'S':
ragge
1.10
216                 case 'I':
ragge
1.58
217                         if ((w = calloc(sizeof(struct incs), 1)) == NULL)
218                                 error("couldn't apply -%c %s"choptarg);
ragge
1.39
219                         w->dir = (usch *)optarg;
ragge
1.10
220                         w2 = incdir[ch == 'I' ? INCINC : SYSINC];
221                         if (w2 != NULL) {
222                                 while (w2->next)
223                                         w2 = w2->next;
224                                 w2->next = w;
225                         } else
226                                 incdir[ch == 'I' ? INCINC : SYSINC] = w;
ragge
1.7
227                         break;
228
ragge
1.1
229 #ifdef CPP_DEBUG
ragge
1.64
230                 case 'V':
ragge
1.18
231                         dflag++;
ragge
1.1
232                         break;
233 #endif
ragge
1.64
234                 case 'v':
235                         printf("cpp: %s\n"VERSSTR);
236                         break;
ragge
1.60
237                 case 'd':
238                         if (optarg[0] == 'M') {
239                                 dMflag = 1;
240                                 Mflag = 1;
241                         }
242                         /* ignore others */
243                         break;
244
ragge
1.1
245                 case 't':
246                         tflag = 1;
247                         break;
248
ragge
1.37
249                 case '?':
250                         usage();
ragge
1.1
251                 default:
ragge
1.37
252                         error("bad arg %c\n"ch);
ragge
1.1
253                 }
254         argc -= optind;
255         argv += optind;
256
ragge
1.39
257         filloc = lookup((usch *)"__FILE__"ENTER);
258         linloc = lookup((usch *)"__LINE__"ENTER);
ragge
1.65
259         pragloc = lookup((usch *)"_Pragma"ENTER);
ragge
1.39
260         filloc->value = linloc->value = (usch *)""/* Just something */
ragge
1.65
261         pragloc->value = (usch *)"";
ragge
1.15
262
ragge
1.12
263         if (tflag == 0) {
264                 time_t t = time(NULL);
ragge
1.39
265                 usch *n = (usch *)ctime(&t);
ragge
1.12
266
267                 /*
268                  * Manually move in the predefined macros.
269                  */
ragge
1.39
270                 nl = lookup((usch *)"__TIME__"ENTER);
ragge
1.13
271                 savch(0); savch('"');  n[19] = 0savstr(&n[11]); savch('"');
ragge
1.12
272                 savch(OBJCT);
273                 nl->value = stringbuf-1;
274
ragge
1.39
275                 nl = lookup((usch *)"__DATE__"ENTER);
ragge
1.13
276                 savch(0); savch('"'); n[24] = n[11] = 0savstr(&n[4]);
277                 savstr(&n[20]); savch('"'); savch(OBJCT);
ragge
1.12
278                 nl->value = stringbuf-1;
279
ragge
1.39
280                 nl = lookup((usch *)"__STDC__"ENTER);
ragge
1.13
281                 savch(0); savch('1'); savch(OBJCT);
ragge
1.12
282                 nl->value = stringbuf-1;
ragge
1.73
283
284                 nl = lookup((usch *)"__STDC_VERSION__"ENTER);
285                 savch(0); savstr((usch *)"199901L"); savch(OBJCT);
286                 nl->value = stringbuf-1;
ragge
1.12
287         }
ragge
1.1
288
ragge
1.60
289         if (Mflag && !dMflag) {
ragge
1.51
290                 usch *c;
291
292                 if (argc < 1)
293                         error("-M and no infile");
294                 if ((c = (usch *)strrchr(argv[0], '/')) == NULL)
295                         c = (usch *)argv[0];
296                 else
297                         c++;
298                 Mfile = stringbuf;
299                 savstr(c); savch(0);
300                 if ((c = (usch *)strrchr((char *)Mfile'.')) == NULL)
301                         error("-M and no extension: ");
302                 c[1] = 'o';
303                 c[2] = 0;
304         }
305
ragge
1.26
306         if (argc == 2) {
ragge
1.37
307                 if ((ofd = open(argv[1], O_WRONLY|O_CREAT0600)) < 0)
308                         error("Can't creat %s"argv[1]);
ragge
1.26
309         } else
ragge
1.37
310                 ofd = 1/* stdout */
311         istty = isatty(ofd);
ragge
1.26
312
ragge
1.41
313         if (pushfile((usch *)(argc && strcmp(argv[0], "-") ? argv[0] : NULL)))
ragge
1.26
314                 error("cannot open %s"argv[0]);
315
ragge
1.37
316         flbuf();
317         close(ofd);
318         return 0;
ragge
1.26
319 }
320
ragge
1.37
321 /*
322  * Expand the symbol nl read from input.
323  * Return a pointer to the fully expanded result.
324  * It is the responsibility of the caller to reset the heap usage.
325  */
326 usch *
ragge
1.36
327 gotident(struct symtab *nl)
ragge
1.35
328 {
ragge
1.36
329         struct symtab *thisnl;
ragge
1.37
330         usch *osp, *ss2, *base;
ragge
1.36
331         int c;
332
333         thisnl = NULL;
334         slow = 1;
ragge
1.79
335         readmac++;
ragge
1.37
336         base = osp = stringbuf;
ragge
1.36
337         goto found;
ragge
1.35
338
ragge
1.36
339         while ((c = yylex()) != 0) {
ragge
1.35
340                 switch (c) {
ragge
1.36
341                 case IDENT:
342                         if (flslvl)
343                                 break;
344                         osp = stringbuf;
ragge
1.35
345
ragge
1.36
346                         DPRINT(("IDENT0: %s\n"yytext));
ragge
1.39
347                         nl = lookup((usch *)yytextFIND);
ragge
1.36
348                         if (nl == 0 || thisnl == 0)
349                                 goto found;
350                         if (thisnl == nl) {
351                                 nl = 0;
352                                 goto found;
353                         }
354                         ss2 = stringbuf;
355                         if ((c = yylex()) == WSPACE) {
ragge
1.39
356                                 savstr((usch *)yytext);
ragge
1.36
357                                 c = yylex();
358                         }
359                         if (c != EXPAND) {
ragge
1.39
360                                 unpstr((usch *)yytext);
ragge
1.36
361                                 if (ss2 != stringbuf)
362                                         unpstr(ss2);
363                                 unpstr(nl->namep);
364                                 (void)yylex(); /* get yytext correct */
365                                 nl = 0/* ignore */
ragge
1.35
366                         } else {
ragge
1.36
367                                 thisnl = NULL;
368                                 if (nl->value[0] == OBJCT) {
369                                         unpstr(nl->namep);
370                                         (void)yylex(); /* get yytext correct */
371                                         nl = 0;
ragge
1.35
372                                 }
373                         }
ragge
1.36
374                         stringbuf = ss2;
375
376 found:                  if (nl == 0 || subst(nlNULL) == 0) {
ragge
1.37
377                                 if (nl)
378                                         savstr(nl->namep);
379                                 else
ragge
1.39
380                                         savstr((usch *)yytext);
ragge
1.36
381                         } else if (osp != stringbuf) {
382                                 DPRINT(("IDENT1: unput osp %p stringbuf %p\n",
383                                     ospstringbuf));
384                                 ss2 = stringbuf;
385                                 cunput(EXPAND);
386                                 while (ss2 > osp)
387                                         cunput(*--ss2);
388                                 thisnl = nl;
ragge
1.37
389                                 stringbuf = osp/* clean up heap */
ragge
1.35
390                         }
391                         break;
392
ragge
1.36
393                 case EXPAND:
394                         DPRINT(("EXPAND!\n"));
395                         thisnl = NULL;
ragge
1.35
396                         break;
397
ragge
1.79
398                 case CMNT:
399                         getcmnt();
400                         break;
401
ragge
1.36
402                 case STRING:
403                 case '\n':
404                 case NUMBER:
405                 case FPOINT:
406                 case WSPACE:
ragge
1.39
407                         savstr((usch *)yytext);
ragge
1.35
408                         break;
409
ragge
1.36
410                 default:
ragge
1.39
411                         if (c < 256)
412                                 savch(c);
413                         else
414                                 savstr((usch *)yytext);
ragge
1.35
415                         break;
ragge
1.36
416                 }
417                 if (thisnl == NULL) {
418                         slow = 0;
ragge
1.79
419                         readmac--;
ragge
1.37
420                         savch(0);
421                         return base;
ragge
1.1
422                 }
423         }
gmcgarry
1.83
424         error("premature EOF");
ragge
1.37
425         /* NOTREACHED */
426         return NULL/* XXX gcc */
ragge
1.1
427 }
428
429 void
ragge
1.9
430 line()
431 {
ragge
1.37
432         static usch *lbuf;
433         static int llen;
ragge
1.9
434         int c;
435
ragge
1.37
436         slow = 1;
ragge
1.9
437         if (yylex() != WSPACE)
438                 goto bad;
ragge
1.52
439         if ((c = yylex()) != IDENT || !isdigit((int)yytext[0]))
ragge
1.9
440                 goto bad;
ragge
1.37
441         ifiles->lineno = atoi(yytext);
ragge
1.9
442
ragge
1.36
443         if ((c = yylex()) != '\n' && c != WSPACE)
ragge
1.9
444                 goto bad;
ragge
1.37
445         if (c == '\n') {
446                 slow = 0;
447                 return;
448         }
ragge
1.72
449         if (yylex() != STRING || yytext[0] == 'L')
ragge
1.9
450                 goto bad;
ragge
1.39
451         c = strlen((char *)yytext);
ragge
1.37
452         if (llen < c) {
ragge
1.52
453                 /* XXX may loose heap space */
ragge
1.37
454                 lbuf = stringbuf;
455                 stringbuf += c;
456                 llen = c;
457         }
ragge
1.36
458         yytext[strlen(yytext)-1] = 0;
ragge
1.63
459         if (strlcpy((char *)lbuf, &yytext[1], SBSIZE) >= SBSIZE)
460                 error("line exceeded buffer size");
461
ragge
1.37
462         ifiles->fname = lbuf;
463         if (yylex() != '\n')
464                 goto bad;
465         slow = 0;
ragge
1.9
466         return;
467
468 bad:    error("bad line directive");
469 }
470
ragge
1.10
471 /*
472  * Include a file. Include order:
ragge
1.20
473  * - For <...> files, first search -I directories, then system directories.
474  * - For "..." files, first search "current" dir, then as <...> files.
ragge
1.10
475  */
ragge
1.9
476 void
ragge
1.3
477 include()
478 {
ragge
1.10
479         struct incs *w;
ragge
1.3
480         struct symtab *nl;
ragge
1.10
481         usch *osp;
ragge
1.62
482         usch *fn, *safefn;
ragge
1.10
483         int icit;
ragge
1.3
484
ragge
1.37
485         if (flslvl)
486                 return;
ragge
1.10
487         osp = stringbuf;
ragge
1.37
488         slow = 1;
ragge
1.57
489 again:
ragge
1.56
490         if ((c = yylex()) == WSPACE)
491                 c = yylex();
ragge
1.57
492         if (c != STRING && c != '<' && c != IDENT)
ragge
1.3
493                 goto bad;
494
495         if (c == IDENT) {
ragge
1.39
496                 if ((nl = lookup((usch *)yytextFIND)) == NULL)
ragge
1.3
497                         goto bad;
ragge
1.35
498                 if (subst(nlNULL) == 0)
ragge
1.3
499                         goto bad;
500                 savch('\0');
ragge
1.10
501                 unpstr(osp);
502                 goto again;
503         } else if (c == '<') {
504                 fn = stringbuf;
ragge
1.36
505                 while ((c = yylex()) != '>' && c != '\n') {
506                         if (c == '\n')
ragge
1.10
507                                 goto bad;
ragge
1.39
508                         savstr((usch *)yytext);
ragge
1.10
509                 }
510                 savch('\0');
ragge
1.37
511                 while ((c = yylex()) == WSPACE)
512                         ;
513                 if (c != '\n')
514                         goto bad;
ragge
1.20
515                 it = SYSINC;
ragge
1.62
516                 safefn = fn;
ragge
1.3
517         } else {
ragge
1.20
518                 usch *nm = stringbuf;
519
ragge
1.36
520                 yytext[strlen(yytext)-1] = 0;
ragge
1.39
521                 fn = (usch *)&yytext[1];
ragge
1.20
522                 /* first try to open file relative to previous file */
ragge
1.53
523                 /* but only if it is not an absolute path */
524                 if (*fn != '/') {
525                         savstr(ifiles->orgfn);
526                         if ((stringbuf =
527                             (usch *)strrchr((char *)nm'/')) == NULL)
528                                 stringbuf = nm;
529                         else
530                                 stringbuf++;
531                 }
ragge
1.62
532                 safefn = stringbuf;
ragge
1.20
533                 savstr(fn); savch(0);
ragge
1.37
534                 while ((c = yylex()) == WSPACE)
535                         ;
536                 if (c != '\n')
537                         goto bad;
538                 slow = 0;
ragge
1.20
539                 if (pushfile(nm) == 0)
ragge
1.37
540                         return;
ragge
1.62
541                 /* XXX may loose stringbuf space */
ragge
1.10
542         }
543
544         /* create search path and try to open file */
ragge
1.37
545         slow = 0;
ragge
1.20
546         for (i = 0i < 2i++) {
ragge
1.10
547                 for (w = incdir[i]; ww = w->next) {
548                         usch *nm = stringbuf;
549
550                         savstr(w->dir); savch('/');
ragge
1.62
551                         savstr(safefn); savch(0);
ragge
1.10
552                         if (pushfile(nm) == 0)
ragge
1.37
553                                 return;
ragge
1.10
554                         stringbuf = nm;
555                 }
ragge
1.3
556         }
ragge
1.62
557         error("cannot find '%s'"safefn);
ragge
1.37
558         /* error() do not return */
ragge
1.3
559
560 bad:    error("bad include");
ragge
1.37
561         /* error() do not return */
562 }
563
564 static int
565 definp(void)
566 {
567         int c;
568
569         do
570                 c = yylex();
571         while (c == WSPACE);
572         return c;
ragge
1.3
573 }
574
ragge
1.80
575 void
ragge
1.79
576 getcmnt(void)
577 {
578         int c;
579
580         savstr((usch *)yytext);
581         for (;;) {
582                 c = cinput();
583                 if (c == '*') {
584                         c = cinput();
585                         if (c == '/') {
586                                 savstr((usch *)"*/");
587                                 return;
588                         }
589                         cunput(c);
590                         c = '*';
591                 }
592                 savch(c);
593         }
594 }
595
596 /*
597  * Compare two replacement lists, taking in account comments etc.
598  */
599 static int
600 cmprepl(usch *ousch *n)
601 {
602         for (; *oo--, n--) {
603                 /* comment skip */
604                 if (*o == '/' && o[-1] == '*') {
605                         while (*o != '*' || o[-1] != '/')
606                                 o--;
607                         o -= 2;
608                 }
609                 if (*n == '/' && n[-1] == '*') {
610                         while (*n != '*' || n[-1] != '/')
611                                 n--;
612                         n -= 2;
613                 }
614                 while (*o == ' ' || *o == '\t')
615                         o--;
616                 while (*n == ' ' || *n == '\t')
617                         n--;
618                 if (*o != *n)
619                         return 1;
620         }
621         return 0;
622 }
623
ragge
1.3
624 void
ragge
1.1
625 define()
626 {
627         struct symtab *np;
ragge
1.15
628         usch *args[MAXARG], *ubuf, *sbeg;
629         int ciredef;
ragge
1.1
630         int mkstr = 0narg = -1;
ragge
1.37
631         int ellips = 0;
ragge
1.86
632 #ifdef GCC_VARI
633         usch *gccvari = NULL;
ragge
1.91
634         int wascon;
ragge
1.86
635 #endif
ragge
1.1
636
ragge
1.37
637         if (flslvl)
638                 return;
ragge
1.36
639         slow = 1;
640         if (yylex() != WSPACE || yylex() != IDENT)
ragge
1.37
641                 goto bad;
ragge
1.36
642
ragge
1.51
643         if (isdigit((int)yytext[0]))
644                 goto bad;
645
ragge
1.39
646         np = lookup((usch *)yytextENTER);
ragge
1.15
647         redef = np->value != NULL;
ragge
1.1
648
ragge
1.79
649         readmac = 1;
ragge
1.15
650         sbeg = stringbuf;
ragge
1.1
651         if ((c = yylex()) == '(') {
652                 narg = 0;
653                 /* function-like macros, deal with identifiers */
ragge
1.72
654                 c = definp();
ragge
1.37
655                 for (;;) {
ragge
1.1
656                         if (c == ')')
657                                 break;
ragge
1.37
658                         if (c == ELLIPS) {
659                                 ellips = 1;
660                                 if (definp() != ')')
661                                         goto bad;
662                                 break;
663                         }
664                         if (c == IDENT) {
ragge
1.72
665                                 /* make sure there is no arg of same name */
666                                 for (i = 0i < nargi++)
667                                         if (!strcmp((char *) args[i], yytext))
668                                                 error("Duplicate macro "
669                                                   "parameter \"%s\""yytext);
ragge
1.90
670                                 args[narg++] = xstrdup(yytext);
ragge
1.72
671                                 if ((c = definp()) == ',') {
672                                         if ((c = definp()) == ')')
673                                                 goto bad;
ragge
1.37
674                                         continue;
ragge
1.72
675                                 }
ragge
1.86
676 #ifdef GCC_VARI
677                                 if (c == ELLIPS) {
678                                         if (definp() != ')')
679                                                 goto bad;
680                                         gccvari = args[--narg];
681                                         break;
682                                 }
683 #endif
ragge
1.37
684                                 if (c == ')')
685                                         break;
686                         }
687                         goto bad;
ragge
1.1
688                 }
ragge
1.36
689                 c = yylex();
690         } else if (c == '\n') {
ragge
1.8
691                 /* #define foo */
ragge
1.36
692                 ;
ragge
1.1
693         } else if (c != WSPACE)
ragge
1.37
694                 goto bad;
ragge
1.1
695
ragge
1.31
696         while (c == WSPACE)
ragge
1.1
697                 c = yylex();
698
ragge
1.72
699         /* replacement list cannot start with ## operator */
700         if (c == CONCAT)
701                 goto bad;
702
ragge
1.1
703         /* parse replacement-list, substituting arguments */
704         savch('\0');
ragge
1.36
705         while (c != '\n') {
ragge
1.91
706 #ifdef GCC_VARI
707                 wascon = 0;
708 loop:
709 #endif
ragge
1.1
710                 switch (c) {
711                 case WSPACE:
712                         /* remove spaces if it surrounds a ## directive */
ragge
1.2
713                         ubuf = stringbuf;
ragge
1.39
714                         savstr((usch *)yytext);
ragge
1.1
715                         c = yylex();
716                         if (c == CONCAT) {
ragge
1.2
717                                 stringbuf = ubuf;
ragge
1.1
718                                 savch(CONC);
719                                 if ((c = yylex()) == WSPACE)
720                                         c = yylex();
ragge
1.91
721 #ifdef GCC_VARI
722                                 if (c == '\n')
723                                         break;
724                                 wascon = 1;
725                                 goto loop;
726 #endif
ragge
1.1
727                         }
728                         continue;
729
730                 case CONCAT:
731                         /* No spaces before concat op */
732                         savch(CONC);
733                         if ((c = yylex()) == WSPACE)
734                                 c = yylex();
ragge
1.91
735 #ifdef GCC_VARI
736                         if (c == '\n')
737                                 break;
738                         wascon = 1;
739                         goto loop;
740 #else
ragge
1.1
741                         continue;
ragge
1.91
742 #endif
ragge
1.1
743
744                 case MKSTR:
745                         if (narg < 0) {
746                                 /* no meaning in object-type macro */
747                                 savch('#');
748                                 break;
749                         }
750                         /* remove spaces between # and arg */
751                         savch(SNUFF);
752                         if ((c = yylex()) == WSPACE)
753                                 c = yylex(); /* whitespace, ignore */
754                         mkstr = 1;
ragge
1.37
755                         if (c == VA_ARGS)
756                                 continue;
ragge
1.1
757
758                         /* FALLTHROUGH */
759                 case IDENT:
760                         if (narg < 0)
761                                 goto id/* just add it if object */
762                         /* check if its an argument */
763                         for (i = 0i < nargi++)
ragge
1.39
764                                 if (strcmp(yytext, (char *)args[i]) == 0)
ragge
1.1
765                                         break;
766                         if (i == narg) {
ragge
1.86
767 #ifdef GCC_VARI
ragge
1.87
768                                 if (gccvari &&
769                                     strcmp(yytext, (char *)gccvari) == 0) {
ragge
1.91
770                                         savch(wascon ? GCCARG : VARG);
ragge
1.86
771                                         savch(WARN);
772                                         if (mkstr)
773                                                 savch(SNUFF), mkstr = 0;
774                                         break;
775                                 }
776 #endif
ragge
1.1
777                                 if (mkstr)
778                                         error("not argument");
779                                 goto id;
780                         }
781                         savch(i);
782                         savch(WARN);
783                         if (mkstr)
784                                 savch(SNUFF), mkstr = 0;
785                         break;
786
ragge
1.37
787                 case VA_ARGS:
788                         if (ellips == 0)
789                                 error("unwanted %s"yytext);
790                         savch(VARG);
791                         savch(WARN);
792                         if (mkstr)
793                                 savch(SNUFF), mkstr = 0;
794                         break;
795
ragge
1.79
796                 case CMNT/* save comments */
797                         getcmnt();
798                         break;
799
ragge
1.1
800                 default:
ragge
1.39
801 id:                     savstr((usch *)yytext);
ragge
1.1
802                         break;
803                 }
804                 c = yylex();
805         }
ragge
1.79
806         readmac = 0;
ragge
1.20
807         /* remove trailing whitespace */
808         while (stringbuf > sbeg) {
809                 if (stringbuf[-1] == ' ' || stringbuf[-1] == '\t')
810                         stringbuf--;
ragge
1.72
811                 /* replacement list cannot end with ## operator */
812                 else if (stringbuf[-1] == CONC)
813                         goto bad;
ragge
1.20
814                 else
815                         break;
816         }
ragge
1.86
817 #ifdef GCC_VARI
818         if (gccvari) {
819                 savch(narg);
820                 savch(VARG);
821         } else
822 #endif
ragge
1.37
823         if (ellips) {
824                 savch(narg);
825                 savch(VARG);
826         } else
827                 savch(narg < 0 ? OBJCT : narg);
ragge
1.15
828         if (redef) {
ragge
1.79
829                 if (cmprepl(np->valuestringbuf-1))
ragge
1.53
830                         error("%s redefined\nprevious define: %s:%d",
831                             np->namepnp->filenp->line);
ragge
1.15
832                 stringbuf = sbeg;  /* forget this space */
833         } else
834                 np->value = stringbuf-1;
ragge
1.1
835
836 #ifdef CPP_DEBUG
837         if (dflag) {
838                 usch *w = np->value;
839
840                 printf("!define: ");
841                 if (*w == OBJCT)
842                         printf("[object]");
ragge
1.37
843                 else if (*w == VARG)
844                         printf("[VARG%d]", *--w);
ragge
1.1
845                 while (*--w) {
846                         switch (*w) {
847                         case WARNprintf("<%d>", *--w); break;
848                         case CONCprintf("<##>"); break;
849                         case SNUFFprintf("<\">"); break;
850                         defaultputchar(*w); break;
851                         }
852                 }
853                 putchar('\n');
854         }
855 #endif
ragge
1.36
856         slow = 0;
ragge
1.90
857         for (i = 0i < nargi++)
858                 free(args[i]);
ragge
1.37
859         return;
860
861 bad:    error("bad define");
ragge
1.1
862 }
863
864 void
stefan
1.68
865 xwarning(usch *s)
stefan
1.67
866 {
867         usch *t;
868         usch *sb = stringbuf;
869
870         flbuf();
871         savch(0);
872         if (ifiles != NULL) {
873                 t = sheap("%s:%d: warning: "ifiles->fnameifiles->lineno);
874                 write (2tstrlen((char *)t));
875         }
876         write (2sstrlen((char *)s));
877         write (2"\n"1);
878         stringbuf = sb;
879 }
880
881 void
ragge
1.37
882 xerror(usch *s)
ragge
1.1
883 {
ragge
1.37
884         usch *t;
ragge
1.1
885
ragge
1.48
886         flbuf();
ragge
1.38
887         savch(0);
ragge
1.37
888         if (ifiles != NULL) {
ragge
1.70
889                 t = sheap("%s:%d: error: "ifiles->fnameifiles->lineno);
ragge
1.39
890                 write (2tstrlen((char *)t));
ragge
1.37
891         }
ragge
1.39
892         write (2sstrlen((char *)s));
ragge
1.37
893         write (2"\n"1);
894         exit(1);
ragge
1.1
895 }
896
897 /*
898  * store a character into the "define" buffer.
899  */
900 void
901 savch(c)
902 {
ragge
1.49
903         if (stringbuf-sbf < SBSIZE) {
904                 *stringbuf++ = c;
905         } else {
906                 stringbuf = sbf/* need space to write error message */
907                 error("Too much defining");
908         } 
ragge
1.1
909 }
910
911 /*
ragge
1.65
912  * convert _Pragma to #pragma for output.
913  */
914 static void
915 pragoper(void)
916 {
917         usch *opb;
ragge
1.75
918         int tplev;
ragge
1.65
919
ragge
1.92
920         slow++;
ragge
1.65
921         if ((t = yylex()) == WSPACE)
922                 t = yylex();
923         if (t != '(')
924                 goto bad;
925         if ((t = yylex()) == WSPACE)
926                 t = yylex();
927         opb = stringbuf;
ragge
1.75
928         for (plev = 0; ; t = yylex()) {
929                 if (t == '(')
930                         plev++;
931                 if (t == ')')
932   &nbs