Quick Search:

View

Revision:
Expand:  
Changeset: MAIN:ragge:20040904082906

Diff

Diff from 1.16 to:

Annotations

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

Annotated File View

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