Quick Search:

View

Revision:
Expand:  
Changeset: MAIN:ragge:20040828143636

Diff

Diff from 1.11 to:

Annotations

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

Annotated File View

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