Quick Search:

View

Revision:
Expand:  
Changeset: MAIN:ragge:20080729091014

Diff

Diff from 1.88 to:

Annotations

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

Annotated File View

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