Quick Search:

View

Revision:
Expand:  
Changeset: MAIN:gmcgarry:20080702011241

Diff

Diff from 1.85 to:

Annotations

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

Annotated File View

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