Quick Search:

View

Revision:
Expand:  
Changeset: MAIN:ragge:20070805082645

Diff

Diff from 1.50 to:

Annotations

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

Annotated File View

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