Quick Search:

View

Revision:
Expand:  
Changeset: MAIN:ragge:20050320162112

Diff

Diff from 1.24 to:

Annotations

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

Annotated File View

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