Quick Search:

View

Revision:
Expand:  
Changeset: MAIN:ragge:20070924154200

Diff

Diff from 1.64 to:

Annotations

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

Annotated File View

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