Quick Search:

View

Revision:
Expand:  
Changeset: MAIN:ragge:20061007154735

Diff

Diff from 1.38 to:

Annotations

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

Annotated File View

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