Quick Search:

View

Revision:
Expand:  
Changeset: MAIN:ragge:20080412171427

Diff

Diff from 1.79 to:

Annotations

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

Annotated File View

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