Quick Search:

View

Revision:
Expand:  
Changeset: MAIN:ragge:20061217132713

Diff

Diff from 1.41 to:

Annotations

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

Annotated File View

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