Quick Search:

View

Revision:
Expand:  
Changeset: MAIN:ragge:20041231112125

Diff

Diff from 1.19 to:

Annotations

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

Annotated File View

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