Quick Search:

View

Revision:
Expand:  
Changeset: MAIN:ragge:20060617082329

Diff

Diff from 1.30 to:

Annotations

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

Annotated File View

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