Quick Search:

View

Revision:
Expand:  
Changeset: MAIN:ragge:20050218165239

Diff

Diff from 1.22 to:

Annotations

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

Annotated File View

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