Quick Search:

View

Revision:
Expand:  
Changeset: MAIN:ragge:20060928111007

Diff

Diff from 1.36 to:

Annotations

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

Annotated File View

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