Quick Search:

View

Revision:
Expand:  
Changeset: MAIN:ragge:20070916194249

Diff

Diff from 1.58 to:

Annotations

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

Annotated File View

ragge
1.58
1 /*      $Id: cpp.c,v 1.58 2007/09/16 19:42:51 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.56
107 usch outbuf[CPPBUF];
108 int obufpistty;
ragge
1.51
109 int CflagMflag;
110 usch *Mfile;
ragge
1.53
111 struct initar *initar;
ragge
1.1
112
113 /* avoid recursion */
114 struct recur {
115         struct recur *next;
116         struct symtab *sp;
117 };
118
ragge
1.10
119 /* include dirs */
120 struct incs {
121         struct incs *next;
ragge
1.39
122         usch *dir;
ragge
1.20
123 } *incdir[2];
124 #define INCINC 0
125 #define SYSINC 1
ragge
1.10
126
ragge
1.1
127 static struct symtab *filloc;
128 static struct symtab *linloc;
ragge
1.10
129 int     trulvl;
130 int     flslvl;
131 int     elflvl;
132 int     elslvl;
133 usch *stringbuf = sbf;
ragge
1.1
134
135 /*
136  * Macro replacement list syntax:
137  * - For object-type macros, replacement strings are stored as-is.
138  * - For function-type macros, macro args are substituted for the
139  *   character WARN followed by the argument number.
ragge
1.12
140  * - The value element points to the end of the string, to simplify
141  *   pushback onto the input queue.
ragge
1.1
142  * 
ragge
1.12
143  * The first character (from the end) in the replacement list is
144  * the number of arguments:
ragge
1.37
145  *   VARG  - ends with ellipsis, next char is argcount without ellips.
ragge
1.1
146  *   OBJCT - object-type macro
147  *   0     - empty parenthesis, foo()
148  *   1->   - number of args.
149  */
150
ragge
1.37
151 #define VARG    0xfe    /* has varargs */
ragge
1.1
152 #define OBJCT   0xff
153 #define WARN    1       /* SOH, not legal char */
154 #define CONC    2       /* STX, not legal char */
155 #define SNUFF   3       /* ETX, not legal char */
156 #define NOEXP   4       /* EOT, not legal char */
157 #define EXPAND  5       /* ENQ, not legal char */
158
159 /* args for lookup() */
160 #define FIND    0
161 #define ENTER   1
162
163 static void expdef(usch *protostruct recur *, int gotwarn);
ragge
1.36
164 void define(void);
ragge
1.1
165 static int canexpand(struct recur *, struct symtab *np);
ragge
1.36
166 void include(void);
167 void line(void);
ragge
1.37
168 void flbuf(void);
169 void usage(void);
ragge
1.1
170
171 int
172 main(int argcchar **argv)
173 {
ragge
1.53
174         struct initar *it;
ragge
1.20
175         struct incs *w, *w2;
ragge
1.26
176         struct symtab *nl;
177         register int ch;
ragge
1.53
178 //      usch *osp;
ragge
1.15
179
ragge
1.53
180         while ((ch = getopt(argcargv"CD:I:MS:U:di:t")) != -1)
ragge
1.1
181                 switch (ch) {
ragge
1.22
182                 case 'C'/* Do not discard comments */
183                         Cflag++;
184                         break;
185
ragge
1.53
186                 case 'i'/* include */
187                 case 'U'/* undef */
188                 case 'D'/* define something */
ragge
1.58
189                         /* XXX should not need malloc() here */
190                         if ((it = malloc(sizeof(struct initar))) == NULL)
191                                 error("couldn't apply -%c %s"choptarg);
ragge
1.53
192                         it->type = ch;
193                         it->str = optarg;
194                         it->next = initar;
195                         initar = it;
196 #if 0
ragge
1.39
197                         osp = (usch *)optarg;
ragge
1.7
198                         while (*osp && *osp != '=')
199                                 osp++;
200                         if (*osp == '=') {
ragge
1.10
201                                 *osp++ = 0;
202                                 while (*osp)
203                                         osp++;
204                                 *osp = OBJCT;
ragge
1.7
205                         } else {
ragge
1.39
206                                 static usch c[3] = { 0'1'OBJCT };
ragge
1.10
207                                 osp = &c[2];
ragge
1.7
208                         }
ragge
1.39
209                         nl = lookup((usch *)optargENTER);
ragge
1.42
210                         if (nl->value) {
211                                 /* check for redefinition */
212                                 usch *o = nl->value, *n = osp;
213                                 while (*o && *o == *n)
214                                         o--, n--;
215                                 if (*o || *o != *n)
216                                         error("%s redefined"optarg);
217                         }
ragge
1.7
218                         nl->value = osp;
ragge
1.53
219 #endif
ragge
1.7
220                         break;
221
ragge
1.51
222                 case 'M'/* Generate dependencies for make */
223                         Mflag++;
224                         break;
225
ragge
1.7
226                 case 'S':
ragge
1.10
227                 case 'I':
ragge
1.58
228                         if ((w = calloc(sizeof(struct incs), 1)) == NULL)
229                                 error("couldn't apply -%c %s"choptarg);
ragge
1.39
230                         w->dir = (usch *)optarg;
ragge
1.10
231                         w2 = incdir[ch == 'I' ? INCINC : SYSINC];
232                         if (w2 != NULL) {
233                                 while (w2->next)
234                                         w2 = w2->next;
235                                 w2->next = w;
236                         } else
237                                 incdir[ch == 'I' ? INCINC : SYSINC] = w;
ragge
1.7
238                         break;
239
ragge
1.53
240 #if 0
ragge
1.7
241                 case 'U':
ragge
1.39
242                         if ((nl = lookup((usch *)optargFIND)))
ragge
1.7
243                                 nl->value = NULL;
244                         break;
ragge
1.53
245 #endif
ragge
1.1
246 #ifdef CPP_DEBUG
247                 case 'd':
ragge
1.18
248                         dflag++;
ragge
1.1
249                         break;
250 #endif
251                 case 't':
252                         tflag = 1;
253                         break;
254
ragge
1.53
255 #if 0
256                 case 'i':
257                         if (ifile)
258                                 error("max 1 -i entry");
259                         ifile = optarg;
260                         break;
261 #endif
262
ragge
1.37
263                 case '?':
264                         usage();
ragge
1.1
265                 default:
ragge
1.37
266                         error("bad arg %c\n"ch);
ragge
1.1
267                 }
268         argc -= optind;
269         argv += optind;
270
ragge
1.39
271         filloc = lookup((usch *)"__FILE__"ENTER);
272         linloc = lookup((usch *)"__LINE__"ENTER);
273         filloc->value = linloc->value = (usch *)""/* Just something */
ragge
1.15
274
ragge
1.12
275         if (tflag == 0) {
276                 time_t t = time(NULL);
ragge
1.39
277                 usch *n = (usch *)ctime(&t);
ragge
1.12
278
279                 /*
280                  * Manually move in the predefined macros.
281                  */
ragge
1.39
282                 nl = lookup((usch *)"__TIME__"ENTER);
ragge
1.13
283                 savch(0); savch('"');  n[19] = 0savstr(&n[11]); savch('"');
ragge
1.12
284                 savch(OBJCT);
285                 nl->value = stringbuf-1;
286
ragge
1.39
287                 nl = lookup((usch *)"__DATE__"ENTER);
ragge
1.13
288                 savch(0); savch('"'); n[24] = n[11] = 0savstr(&n[4]);
289                 savstr(&n[20]); savch('"'); savch(OBJCT);
ragge
1.12
290                 nl->value = stringbuf-1;
291
ragge
1.39
292                 nl = lookup((usch *)"__STDC__"ENTER);
ragge
1.13
293                 savch(0); savch('1'); savch(OBJCT);
ragge
1.12
294                 nl->value = stringbuf-1;
295         }
ragge
1.1
296
ragge
1.51
297         if (Mflag) {
298                 usch *c;
299
300                 if (argc < 1)
301                         error("-M and no infile");
302                 if ((c = (usch *)strrchr(argv[0], '/')) == NULL)
303                         c = (usch *)argv[0];
304                 else
305                         c++;
306                 Mfile = stringbuf;
307                 savstr(c); savch(0);
308                 if ((c = (usch *)strrchr((char *)Mfile'.')) == NULL)
309                         error("-M and no extension: ");
310                 c[1] = 'o';
311                 c[2] = 0;
312         }
313
ragge
1.26
314         if (argc == 2) {
ragge
1.37
315                 if ((ofd = open(argv[1], O_WRONLY|O_CREAT0600)) < 0)
316                         error("Can't creat %s"argv[1]);
ragge
1.26
317         } else
ragge
1.37
318                 ofd = 1/* stdout */
319         istty = isatty(ofd);
ragge
1.26
320
ragge
1.41
321         if (pushfile((usch *)(argc && strcmp(argv[0], "-") ? argv[0] : NULL)))
ragge
1.26
322                 error("cannot open %s"argv[0]);
323
ragge
1.37
324         flbuf();
325         close(ofd);
326         return 0;
ragge
1.26
327 }
328
ragge
1.37
329 /*
330  * Expand the symbol nl read from input.
331  * Return a pointer to the fully expanded result.
332  * It is the responsibility of the caller to reset the heap usage.
333  */
334 usch *
ragge
1.36
335 gotident(struct symtab *nl)
ragge
1.35
336 {
ragge
1.36
337         struct symtab *thisnl;
ragge
1.37
338         usch *osp, *ss2, *base;
ragge
1.36
339         int c;
340
341         thisnl = NULL;
342         slow = 1;
ragge
1.37
343         base = osp = stringbuf;
ragge
1.36
344         goto found;
ragge
1.35
345
ragge
1.36
346         while ((c = yylex()) != 0) {
ragge
1.35
347                 switch (c) {
ragge
1.36
348                 case IDENT:
349                         if (flslvl)
350                                 break;
351                         osp = stringbuf;
ragge
1.35
352
ragge
1.36
353                         DPRINT(("IDENT0: %s\n"yytext));
ragge
1.39
354                         nl = lookup((usch *)yytextFIND);
ragge
1.36
355                         if (nl == 0 || thisnl == 0)
356                                 goto found;
357                         if (thisnl == nl) {
358                                 nl = 0;
359                                 goto found;
360                         }
361                         ss2 = stringbuf;
362                         if ((c = yylex()) == WSPACE) {
ragge
1.39
363                                 savstr((usch *)yytext);
ragge
1.36
364                                 c = yylex();
365                         }
366                         if (c != EXPAND) {
ragge
1.39
367                                 unpstr((usch *)yytext);
ragge
1.36
368                                 if (ss2 != stringbuf)
369                                         unpstr(ss2);
370                                 unpstr(nl->namep);
371                                 (void)yylex(); /* get yytext correct */
372                                 nl = 0/* ignore */
ragge
1.35
373                         } else {
ragge
1.36
374                                 thisnl = NULL;
375                                 if (nl->value[0] == OBJCT) {
376                                         unpstr(nl->namep);
377                                         (void)yylex(); /* get yytext correct */
378                                         nl = 0;
ragge
1.35
379                                 }
380                         }
ragge
1.36
381                         stringbuf = ss2;
382
383 found:                  if (nl == 0 || subst(nlNULL) == 0) {
ragge
1.37
384                                 if (nl)
385                                         savstr(nl->namep);
386                                 else
ragge
1.39
387                                         savstr((usch *)yytext);
ragge
1.36
388                         } else if (osp != stringbuf) {
389                                 DPRINT(("IDENT1: unput osp %p stringbuf %p\n",
390                                     ospstringbuf));
391                                 ss2 = stringbuf;
392                                 cunput(EXPAND);
393                                 while (ss2 > osp)
394                                         cunput(*--ss2);
395                                 thisnl = nl;
ragge
1.37
396                                 stringbuf = osp/* clean up heap */
ragge
1.35
397                         }
398                         break;
399
ragge
1.36
400                 case EXPAND:
401                         DPRINT(("EXPAND!\n"));
402                         thisnl = NULL;
ragge
1.35
403                         break;
404
ragge
1.36
405                 case STRING:
406                 case '\n':
407                 case NUMBER:
408                 case FPOINT:
409                 case WSPACE:
ragge
1.39
410                         savstr((usch *)yytext);
ragge
1.35
411                         break;
412
ragge
1.36
413                 default:
ragge
1.39
414                         if (c < 256)
415                                 savch(c);
416                         else
417                                 savstr((usch *)yytext);
ragge
1.35
418                         break;
ragge
1.36
419                 }
420                 if (thisnl == NULL) {
421                         slow = 0;
ragge
1.37
422                         savch(0);
423                         return base;
ragge
1.1
424                 }
425         }
ragge
1.37
426         error("preamture EOF");
427         /* NOTREACHED */
428         return NULL/* XXX gcc */
ragge
1.1
429 }
430
431 void
ragge
1.9
432 line()
433 {
ragge
1.37
434         static usch *lbuf;
435         static int llen;
ragge
1.9
436         int c;
437
ragge
1.37
438         slow = 1;
ragge
1.9
439         if (yylex() != WSPACE)
440                 goto bad;
ragge
1.52
441         if ((c = yylex()) != IDENT || !isdigit((int)yytext[0]))
ragge
1.9
442                 goto bad;
ragge
1.37
443         ifiles->lineno = atoi(yytext);
ragge
1.9
444
ragge
1.36
445         if ((c = yylex()) != '\n' && c != WSPACE)
ragge
1.9
446                 goto bad;
ragge
1.37
447         if (c == '\n') {
448                 slow = 0;
449                 return;
450         }
ragge
1.9
451         if (yylex() != STRING)
452                 goto bad;
ragge
1.39
453         c = strlen((char *)yytext);
ragge
1.37
454         if (llen < c) {
ragge
1.52
455                 /* XXX may loose heap space */
ragge
1.37
456                 lbuf = stringbuf;
457                 stringbuf += c;
458                 llen = c;
459         }
ragge
1.36
460         yytext[strlen(yytext)-1] = 0;
ragge
1.39
461         strcpy((char *)lbuf, &yytext[1]);
ragge
1.37
462         ifiles->fname = lbuf;
463         if (yylex() != '\n')
464                 goto bad;
465         slow = 0;
ragge
1.9
466         return;
467
468 bad:    error("bad line directive");
469 }
470
ragge
1.10
471 /*
472  * Include a file. Include order:
ragge
1.20
473  * - For <...> files, first search -I directories, then system directories.
474  * - For "..." files, first search "current" dir, then as <...> files.
ragge
1.10
475  */
ragge
1.9
476 void
ragge
1.3
477 include()
478 {
ragge
1.10
479         struct incs *w;
ragge
1.3
480         struct symtab *nl;
ragge
1.10
481         usch *osp;
ragge
1.39
482         usch *fn;
ragge
1.10
483         int icit;
ragge
1.3
484
ragge
1.37
485         if (flslvl)
486                 return;
ragge
1.10
487         osp = stringbuf;
ragge
1.37
488         slow = 1;
ragge
1.57
489 again:
ragge
1.56
490         if ((c = yylex()) == WSPACE)
491                 c = yylex();
ragge
1.57
492         if (c != STRING && c != '<' && c != IDENT)
ragge
1.3
493                 goto bad;
494
495         if (c == IDENT) {
ragge
1.39
496                 if ((nl = lookup((usch *)yytextFIND)) == NULL)
ragge
1.3
497                         goto bad;
ragge
1.35
498                 if (subst(nlNULL) == 0)
ragge
1.3
499                         goto bad;
500                 savch('\0');
ragge
1.10
501                 unpstr(osp);
502                 goto again;
503         } else if (c == '<') {
504                 fn = stringbuf;
ragge
1.36
505                 while ((c = yylex()) != '>' && c != '\n') {
506                         if (c == '\n')
ragge
1.10
507                                 goto bad;
ragge
1.39
508                         savstr((usch *)yytext);
ragge
1.10
509                 }
510                 savch('\0');
ragge
1.37
511                 while ((c = yylex()) == WSPACE)
512                         ;
513                 if (c != '\n')
514                         goto bad;
ragge
1.20
515                 it = SYSINC;
ragge
1.3
516         } else {
ragge
1.20
517                 usch *nm = stringbuf;
518
ragge
1.36
519                 yytext[strlen(yytext)-1] = 0;
ragge
1.39
520                 fn = (usch *)&yytext[1];
ragge
1.20
521                 /* first try to open file relative to previous file */
ragge
1.53
522                 /* but only if it is not an absolute path */
523                 if (*fn != '/') {
524                         savstr(ifiles->orgfn);
525                         if ((stringbuf =
526                             (usch *)strrchr((char *)nm'/')) == NULL)
527                                 stringbuf = nm;
528                         else
529                                 stringbuf++;
530                 }
ragge
1.20
531                 savstr(fn); savch(0);
ragge
1.37
532                 while ((c = yylex()) == WSPACE)
533                         ;
534                 if (c != '\n')
535                         goto bad;
536                 slow = 0;
ragge
1.20
537                 if (pushfile(nm) == 0)
ragge
1.37
538                         return;
ragge
1.20
539                 stringbuf = nm;
ragge
1.10
540         }
541
542         /* create search path and try to open file */
ragge
1.37
543         slow = 0;
ragge
1.20
544         for (i = 0i < 2i++) {
ragge
1.10
545                 for (w = incdir[i]; ww = w->next) {
546                         usch *nm = stringbuf;
547
548                         savstr(w->dir); savch('/');
549                         savstr(fn); savch(0);
550                         if (pushfile(nm) == 0)
ragge
1.37
551                                 return;
ragge
1.10
552                         stringbuf = nm;
553                 }
ragge
1.3
554         }
ragge
1.10
555         error("cannot find '%s'"fn);
ragge
1.37
556         /* error() do not return */
ragge
1.3
557
558 bad:    error("bad include");
ragge
1.37
559         /* error() do not return */
560 }
561
562 static int
563 definp(void)
564 {
565         int c;
566
567         do
568                 c = yylex();
569         while (c == WSPACE);
570         return c;
ragge
1.3
571 }
572
573 void
ragge
1.1
574 define()
575 {
576         struct symtab *np;
ragge
1.15
577         usch *args[MAXARG], *ubuf, *sbeg;
578         int ciredef;
ragge
1.1
579         int mkstr = 0narg = -1;
ragge
1.37
580         int ellips = 0;
ragge
1.1
581
ragge
1.37
582         if (flslvl)
583                 return;
ragge
1.36
584         slow = 1;
585         if (yylex() != WSPACE || yylex() != IDENT)
ragge
1.37
586                 goto bad;
ragge
1.36
587
ragge
1.51
588         if (isdigit((int)yytext[0]))
589                 goto bad;
590
ragge
1.39
591         np = lookup((usch *)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 */
ragge
1.37
598                 for (;;) {
599                         c = definp();
ragge
1.1
600                         if (c == ')')
601                                 break;
ragge
1.37
602                         if (c == ELLIPS) {
603                                 ellips = 1;
604                                 if (definp() != ')')
605                                         goto bad;
606                                 break;
607                         }
608                         if (c == IDENT) {
609                                 args[narg] = alloca(strlen(yytext)+1);
ragge
1.39
610                                 strcpy((char *)args[narg], yytext);
ragge
1.37
611                                 narg++;
612                                 if ((c = definp()) == ',')
613                                         continue;
614                                 if (c == ')')
615                                         break;
616                                 goto bad;
617                         }
618                         goto bad;
ragge
1.1
619                 }
ragge
1.36
620                 c = yylex();
621         } else if (c == '\n') {
ragge
1.8
622                 /* #define foo */
ragge
1.36
623                 ;
ragge
1.1
624         } else if (c != WSPACE)
ragge
1.37
625                 goto bad;
ragge
1.1
626
ragge
1.31
627         while (c == WSPACE)
ragge
1.1
628                 c = yylex();
629
630         /* parse replacement-list, substituting arguments */
631         savch('\0');
ragge
1.36
632         while (c != '\n') {
ragge
1.1
633                 switch (c) {
634                 case WSPACE:
635                         /* remove spaces if it surrounds a ## directive */
ragge
1.2
636                         ubuf = stringbuf;
ragge
1.39
637                         savstr((usch *)yytext);
ragge
1.1
638                         c = yylex();
639                         if (c == CONCAT) {
ragge
1.2
640                                 stringbuf = ubuf;
ragge
1.1
641                                 savch(CONC);
642                                 if ((c = yylex()) == WSPACE)
643                                         c = yylex();
644                         }
645                         continue;
646
647                 case CONCAT:
648                         /* No spaces before concat op */
649                         savch(CONC);
650                         if ((c = yylex()) == WSPACE)
651                                 c = yylex();
652                         continue;
653
654                 case MKSTR:
655                         if (narg < 0) {
656                                 /* no meaning in object-type macro */
657                                 savch('#');
658                                 break;
659                         }
660                         /* remove spaces between # and arg */
661                         savch(SNUFF);
662                         if ((c = yylex()) == WSPACE)
663                                 c = yylex(); /* whitespace, ignore */
664                         mkstr = 1;
ragge
1.37
665                         if (c == VA_ARGS)
666                                 continue;
ragge
1.1
667
668                         /* FALLTHROUGH */
669                 case IDENT:
670                         if (narg < 0)
671                                 goto id/* just add it if object */
672                         /* check if its an argument */
673                         for (i = 0i < nargi++)
ragge
1.39
674                                 if (strcmp(yytext, (char *)args[i]) == 0)
ragge
1.1
675                                         break;
676                         if (i == narg) {
677                                 if (mkstr)
678                                         error("not argument");
679                                 goto id;
680                         }
681                         savch(i);
682                         savch(WARN);
683                         if (mkstr)
684                                 savch(SNUFF), mkstr = 0;
685                         break;
686
ragge
1.37
687                 case VA_ARGS:
688                         if (ellips == 0)
689                                 error("unwanted %s"yytext);
690                         savch(VARG);
691                         savch(WARN);
692                         if (mkstr)
693                                 savch(SNUFF), mkstr = 0;
694                         break;
695
ragge
1.1
696                 default:
ragge
1.39
697 id:                     savstr((usch *)yytext);
ragge
1.1
698                         break;
699                 }
700                 c = yylex();
701         }
ragge
1.20
702         /* remove trailing whitespace */
703         while (stringbuf > sbeg) {
704                 if (stringbuf[-1] == ' ' || stringbuf[-1] == '\t')
705                         stringbuf--;
706                 else
707                         break;
708         }
ragge
1.37
709         if (ellips) {
710                 savch(narg);
711                 savch(VARG);
712         } else
713                 savch(narg < 0 ? OBJCT : narg);
ragge
1.15
714         if (redef) {
715                 usch *o = np->value, *n = stringbuf-1;
716
717                 /* Redefinition to identical replacement-list is allowed */
718                 while (*o && *o == *n)
719                         o--, n--;
720                 if (*o || *o != *n)
ragge
1.53
721                         error("%s redefined\nprevious define: %s:%d",
722                             np->namepnp->filenp->line);
ragge
1.15
723                 stringbuf = sbeg;  /* forget this space */
724         } else
725                 np->value = stringbuf-1;
ragge
1.1
726
727 #ifdef CPP_DEBUG
728         if (dflag) {
729                 usch *w = np->value;
730
731                 printf("!define: ");
732                 if (*w == OBJCT)
733                         printf("[object]");
ragge
1.37
734                 else if (*w == VARG)
735                         printf("[VARG%d]", *--w);
ragge
1.1
736                 while (*--w) {
737                         switch (*w) {
738                         case WARNprintf("<%d>", *--w); break;
739                         case CONCprintf("<##>"); break;
740                         case SNUFFprintf("<\">"); break;
741                         defaultputchar(*w); break;
742                         }
743                 }
744                 putchar('\n');
745         }
746 #endif
ragge
1.36
747         slow = 0;
ragge
1.37
748         return;
749
750 bad:    error("bad define");
ragge
1.1
751 }
752
753 void
ragge
1.37
754 xerror(usch *s)
ragge
1.1
755 {
ragge
1.37
756         usch *t;
ragge
1.1
757
ragge
1.48
758         flbuf();
ragge
1.38
759         savch(0);
ragge
1.37
760         if (ifiles != NULL) {
761                 t = sheap("%s:%d: "ifiles->fnameifiles->lineno);
ragge
1.39
762                 write (2tstrlen((char *)t));
ragge
1.37
763         }
ragge
1.39
764         write (2sstrlen((char *)s));
ragge
1.37
765         write (2"\n"1);
766         exit(1);
ragge
1.1
767 }
768
769 /*
770  * store a character into the "define" buffer.
771  */
772 void
773 savch(c)
774 {
ragge
1.49
775         if (stringbuf-sbf < SBSIZE) {
776                 *stringbuf++ = c;
777         } else {
778                 stringbuf = sbf/* need space to write error message */
779                 error("Too much defining");
780         } 
ragge
1.1
781 }
782
783 /*
784  * substitute namep for sp->value.
785  */
786 int
ragge
1.36
787 subst(sprp)
ragge
1.1
788 struct symtab *sp;
789 struct recur *rp;
790 {
791         struct recur rp2;
792         register usch *vp, *cp;
ragge
1.52
793         int crv = 0ws;
ragge
1.1
794
ragge
1.37
795         DPRINT(("subst: %s\n"sp->namep));
ragge
1.17
796         /*
797          * First check for special macros.
798          */
799         if (sp == filloc) {
ragge
1.37
800                 (void)sheap("\"%s\""ifiles->fname);
ragge
1.17
801                 return 1;
802         } else if (sp == linloc) {
ragge
1.37
803                 (void)sheap("%d"ifiles->lineno);
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;
ragge
1.52
817                 ws = 0;
ragge
1.1
818                 do {
ragge
1.36
819                         c = yylex();
ragge
1.1
820                         if (c == WARN) {
821                                 gotwarn++;
822                                 if (rp == NULL)
823                                         goto noid;
ragge
1.57
824                         } else if (c == WSPACE || c == '\n')
ragge
1.52
825                                 ws = 1;
ragge
1.36
826                 } while (c == WSPACE || c == '\n' || c == WARN);
ragge
1.1
827
ragge
1.39
828                 cp = (usch *)yytext;
ragge
1.1
829                 while (*cp)
830                         cp++;
ragge
1.36
831                 while (cp > (usch *)yytext)
ragge
1.1
832                         cunput(*--cp);
ragge
1.36
833                 DPRINT(("c %d\n"c));
ragge
1.1
834                 if (c == '(' ) {
835                         expdef(vp, &rp2gotwarn);
ragge
1.36
836                         return rv;
ragge
1.1
837                 } else {
838                         /* restore identifier */
839 noid:                   while (gotwarn--)
840                                 cunput(WARN);
ragge
1.52
841                         if (ws)
842                                 cunput(' ');
ragge
1.1
843                         cp = sp->namep;
844                         while (*cp)
845                                 cp++;
846                         while (cp > sp->namep)
847                                 cunput(*--cp);
848                         if ((c = yylex()) != IDENT)
849                                 error("internal sync error");
850                         return 0;
851                 }
852         } else {
853                 cunput(WARN);
854                 cp = vp;
855                 while (*cp) {
856                         if (*cp != CONC)
857                                 cunput(*cp);
858                         cp--;
859                 }
860                 expmac(&rp2);
861         }
862         return 1;
863 }
864
865 /*
866  * do macro-expansion until WARN character read.
ragge
1.44
867  * read from lex buffer and store result on heap.
ragge
1.1
868  * will recurse into lookup() for recursive expansion.
869  * when returning all expansions on the token list is done.
870  */
871 void
872 expmac(struct recur *rp)
873 {
874         struct symtab *nl;
ragge
1.43
875         int cnoexp = 0orgexp;
ragge
1.36
876         usch *och, *stksv;
877         extern int yyleng;
ragge
1.1
878
ragge
1.22
879 #ifdef CPP_DEBUG
880         if (dflag) {
881                 struct recur *rp2 = rp;
882                 printf("\nexpmac\n");
883                 while (rp2) {
884                         printf("do not expand %s\n"rp->sp->namep);
885                         rp2 = rp2->next;
886                 }
887         }
888 #endif
ragge
1.1
889         while ((c = yylex()) != WARN) {
890                 switch (c) {
891                 case NOEXPnoexp++; break;
892                 case EXPANDnoexp--; break;
893
894                 case IDENT:
ragge
1.43
895                         /*
896                          * Handle argument concatenation here.
897                          * If an identifier is found and directly 
ragge
1.44
898                          * after EXPAND or NOEXP then push the
ragge
1.43
899                          * identifier back on the input stream and
900                          * call yylex() again.
901                          * Be careful to keep the noexp balance.
902                          */
903                         och = stringbuf;
904                         savstr((usch *)yytext);
905                         DDPRINT(("id: str %s\n"och));
ragge
1.44
906
907                         orgexp = 0;
908                         while ((c = yylex()) == EXPAND || c == NOEXP)
ragge
1.43
909                                 if (c == EXPAND)
ragge
1.44
910                                         orgexp--;
ragge
1.43
911                                 else
ragge
1.44
912                                         orgexp++;
913
914                         DDPRINT(("id1: noexp %d orgexp %d\n"noexporgexp));
915                         if (c == IDENT) { /* XXX numbers? */
916                                 DDPRINT(("id2: str %s\n"yytext));
917                                 /* OK to always expand here? */
918                                 savstr((usch *)yytext);
919                                 switch (orgexp) {
920                                 case 0/* been EXP+NOEXP */
ragge
1.47
921                                         if (noexp == 0)
922                                                 break;
ragge
1.44
923                                         if (noexp != 1)
924                                                 error("case 0");
925                                         cunput(NOEXP);
926                                         noexp = 0;
927                                         break;
928                                 case -1/* been EXP */
929                                         if (noexp != 1)
930                                                 error("case -1");
931                                         noexp = 0;
932                                         break;
933                                 case 1:
934                                         if (noexp != 0)
935                                                 error("case 1");
936                                         cunput(NOEXP);
937                                         break;