Quick Search:

View

Revision:
Expand:  
Changeset: MAIN:ragge:20040902213333

Diff

Diff from 1.15 to:

Annotations

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

Annotated File View

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