Quick Search:

View

Revision:
Expand:  
Changeset: MAIN:ragge:20061008071811

Diff

Diff from 1.39 to:

Annotations

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

Annotated File View

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