Quick Search:

View

Revision:
Expand:  
Changeset: MAIN:gmcgarry:20080415095627

Diff

Diff from 1.81 to:

Annotations

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

Annotated File View

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