Quick Search:

View

Revision:
Expand:  
Changeset: MAIN:ragge:20081124071309

Diff

Diff from 1.94 to:

Annotations

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

Annotated File View

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