Quick Search:

View

Revision:
Expand:  
Changeset: MAIN:gmcgarry:20080808231818

Diff

Diff from 1.89 to:

Annotations

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

Annotated File View

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