Quick Search:

View

Revision:
Expand:  
Changeset: MAIN:ragge:20070925204107

Diff

Diff from 1.65 to:

Annotations

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

Annotated File View

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