Quick Search:

View

Revision:
Expand:  
Changeset: MAIN:ragge:20080413163656

Diff

Diff from 1.80 to:

Annotations

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

Annotated File View

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