Quick Search:

View

Revision:
Expand:  
Changeset: MAIN:ragge:20070801045250

Diff

Diff from 1.49 to:

Annotations

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

Annotated File View

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