Quick Search:

View

Revision:
Expand:  
Changeset: MAIN:ragge:20080810144930

Diff

Diff from 1.90 to:

Annotations

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

Annotated File View

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