Quick Search:

View

Revision:
Expand:  
Changeset: MAIN:ragge:20071027103937

Diff

Diff from 1.71 to:

Annotations

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

Annotated File View

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