Quick Search:

View

Revision:
Expand:  
Changeset: MAIN:gmcgarry:20080420014749

Diff

Diff from 1.82 to:

Annotations

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

Annotated File View

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