Quick Search:

View

Revision:
Expand:  
Changeset: MAIN:ragge:20070920202757

Diff

Diff from 1.63 to:

Annotations

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

Annotated File View

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