Quick Search:

View

Revision:
Expand:  
Changeset: MAIN:ragge:20070819192215

Diff

Diff from 1.52 to:

Annotations

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

Annotated File View

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