Quick Search:

View

Revision:
Expand:  
Changeset: MAIN:ragge:20060715150203

Diff

Diff from 1.31 to:

Annotations

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

Annotated File View

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