Quick Search:

View

Revision:
Expand:  
Changeset: MAIN:ragge:20080815152927

Diff

Diff from 1.91 to:

Annotations

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

Annotated File View

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