Quick Search:

View

Revision:
Expand:  
Changeset: MAIN:ragge:20080406090733

Diff

Diff from 1.78 to:

Annotations

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

Annotated File View

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