Quick Search:

View

Revision:
Expand:  
Changeset: MAIN:ragge:20070917174925

Diff

Diff from 1.59 to:

Annotations

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

Annotated File View

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