Quick Search:

View

Revision:
Expand:  
Changeset: MAIN:ragge:20060805102429

Diff

Diff from 1.35 to:

Annotations

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

Annotated File View

ragge
1.35
1 /*      $Id: cpp.c,v 1.35 2006/08/05 10:24:29 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.28
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.35
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.1
87 #include "cpp.h"
88
89 #define MAXARG  250     /* # of args to a macro, limited by char value */
ragge
1.30
90 #define SBSIZE  400000
91 #define SYMSIZ  10000
ragge
1.1
92
93 static usch     sbf[SBSIZE];
94 /* C command */
95
ragge
1.34
96 #ifdef ragge
97
ragge
1.33
98 #define CHAR_BITS       8 /* XXX - should be checked in autoconf */
99 #define CHAR_MAX        (1 << CHAR_BITS)
100
101 #define TOKTYP  3       /* mask bits for token type */
102 #define S_      1       /* string or char constant start */
103
104 /*
105  * Index into this array to find out whether a char has a special 
106  * meaning.  This is ASCII only, for EBCDIC write a new table.
107  */
108 usch utype[CHAR_MAX] = {
109         0,      0,      0,      0,      0,      0,      0,      0/* 0  - 7  */
110         0,      0,      0,      0,      0,      0,      0,      0/* 8  - 15 */
111         0,      0,      0,      0,      0,      0,      0,      0/* 16 - 23 */
112         0,      0,      0,      0,      0,      0,      0,      0/* 24 - 31 */
113         0,      S_,     0,      0,      0,      0,      0,      S_,/* 32 - 39 */
114         0,      0,      0,      0,      0,      0,      0,      0/* 40 - 47 */
115         0,      0,      0,      0,      0,      0,      0,      0/* 48 - 55 */
116         0,      0,      0,      0,      0,      0,      0,      0/* 56 - 63 */
117         0,      0,      0,      0,      0,      0,      0,      0/* 64 - 71 */
118         0,      0,      0,      0,      0,      0,      0,      0/* 72 - 79 */
119         0,      0,      0,      0,      0,      0,      0,      0/* 80 - 87 */
120         0,      0,      0,      0,      0,      0,      0,      0/* 88 - 95 */
121         0,      0,      0,      0,      0,      0,      0,      0/* 96 - 103*/
122         0,      0,      0,      0,      0,      0,      0,      0/* 104- 111*/
123         0,      0,      0,      0,      0,      0,      0,      0/* 112- 119*/
124         0,      0,      0,      0,      0,      0,      0,      0/* 120- 127*/
125 };
ragge
1.34
126 #endif
ragge
1.33
127
ragge
1.1
128 int tflag;      /* traditional cpp syntax */
129 #ifdef CPP_DEBUG
130 int dflag;      /* debug printouts */
131 #endif
132 FILE *obuf;
133 static int exfail;
ragge
1.10
134 struct symtab symtab[SYMSIZ];
ragge
1.22
135 int Cflag;
ragge
1.1
136
137 /* avoid recursion */
138 struct recur {
139         struct recur *next;
140         struct symtab *sp;
141 };
142
ragge
1.10
143 /* include dirs */
144 struct incs {
145         struct incs *next;
146         char *dir;
ragge
1.20
147 } *incdir[2];
148 #define INCINC 0
149 #define SYSINC 1
ragge
1.10
150
ragge
1.1
151 static struct symtab *filloc;
152 static struct symtab *linloc;
ragge
1.10
153 int     trulvl;
154 int     flslvl;
155 int     elflvl;
156 int     elslvl;
157 usch *stringbuf = sbf;
ragge
1.1
158
159 /*
160  * Macro replacement list syntax:
161  * - For object-type macros, replacement strings are stored as-is.
162  * - For function-type macros, macro args are substituted for the
163  *   character WARN followed by the argument number.
ragge
1.12
164  * - The value element points to the end of the string, to simplify
165  *   pushback onto the input queue.
ragge
1.1
166  * 
ragge
1.12
167  * The first character (from the end) in the replacement list is
168  * the number of arguments:
ragge
1.1
169  *   OBJCT - object-type macro
170  *   0     - empty parenthesis, foo()
171  *   1->   - number of args.
172  */
173
174 #define OBJCT   0xff
175 #define WARN    1       /* SOH, not legal char */
176 #define CONC    2       /* STX, not legal char */
177 #define SNUFF   3       /* ETX, not legal char */
178 #define NOEXP   4       /* EOT, not legal char */
179 #define EXPAND  5       /* ENQ, not legal char */
180
181 /* args for lookup() */
182 #define FIND    0
183 #define ENTER   1
184
185 static void expdef(usch *protostruct recur *, int gotwarn);
ragge
1.35
186 #ifdef ragge
187 static void control(struct includ *);
188 #else
ragge
1.1
189 static void control(void);
ragge
1.35
190 #endif
ragge
1.1
191 static void define(void);
192 static void expmac(struct recur *);
193 static int canexpand(struct recur *, struct symtab *np);
ragge
1.3
194 static void include(void);
ragge
1.9
195 static void line(void);
ragge
1.1
196
197 int
198 main(int argcchar **argv)
199 {
ragge
1.20
200         struct incs *w, *w2;
ragge
1.26
201         struct symtab *nl;
202         register int ch;
203         usch *osp;
ragge
1.15
204
ragge
1.22
205         while ((ch = getopt(argcargv"CD:I:S:U:td")) != -1)
ragge
1.1
206                 switch (ch) {
ragge
1.22
207                 case 'C'/* Do not discard comments */
208                         Cflag++;
209                         break;
210
ragge
1.7
211                 case 'D'/* Define something */
212                         osp = optarg;
213                         while (*osp && *osp != '=')
214                                 osp++;
215                         if (*osp == '=') {
ragge
1.10
216                                 *osp++ = 0;
217                                 while (*osp)
218                                         osp++;
219                                 *osp = OBJCT;
ragge
1.7
220                         } else {
ragge
1.10
221                                 static char c[3] = { 0'1'OBJCT };
222                                 osp = &c[2];
ragge
1.7
223                         }
224                         nl = lookup(optargENTER);
225                         if (nl->value)
226                                 error("%s redefined"optarg);
227                         nl->value = osp;
228                         break;
229
230                 case 'S':
ragge
1.10
231                 case 'I':
232                         w = calloc(sizeof(struct incs), 1);
233                         w->dir = optarg;
234                         w2 = incdir[ch == 'I' ? INCINC : SYSINC];
235                         if (w2 != NULL) {
236                                 while (w2->next)
237                                         w2 = w2->next;
238                                 w2->next = w;
239                         } else
240                                 incdir[ch == 'I' ? INCINC : SYSINC] = w;
ragge
1.7
241                         break;
242
243                 case 'U':
244                         nl = lookup(optargFIND);
ragge
1.15
245                         if ((nl = lookup(optargFIND)))
ragge
1.7
246                                 nl->value = NULL;
247                         break;
ragge
1.1
248 #ifdef CPP_DEBUG
249                 case 'd':
ragge
1.18
250                         dflag++;
ragge
1.1
251                         break;
252 #endif
253                 case 't':
254                         tflag = 1;
255                         break;
256
257                 default:
258                         fprintf(stderr"bad arg %c\n"ch);
259                         exit(1);
260                 }
261         argc -= optind;
262         argv += optind;
263
264         exfail = 0;
265
ragge
1.12
266         filloc = lookup("__FILE__"ENTER);
267         linloc = lookup("__LINE__"ENTER);
ragge
1.15
268         filloc->value = linloc->value = ""/* Just something */
269
ragge
1.12
270         if (tflag == 0) {
271                 time_t t = time(NULL);
272                 char *n = ctime(&t);
273
274                 /*
275                  * Manually move in the predefined macros.
276                  */
277                 nl = lookup("__TIME__"ENTER);
ragge
1.32
278 #ifdef ragge
279                 nl->value = stringbuf;
280                 savch(OBJCT);
281                 savch('"'); savstr(&n[11]); n[19] = 0savch('"'); savch(0);
282 #else
ragge
1.13
283                 savch(0); savch('"');  n[19] = 0savstr(&n[11]); savch('"');
ragge
1.12
284                 savch(OBJCT);
285                 nl->value = stringbuf-1;
ragge
1.32
286 #endif
ragge
1.12
287
288                 nl = lookup("__DATE__"ENTER);
ragge
1.32
289 #ifdef ragge
290                 nl->value = stringbuf;
ragge
1.33
291                 savch(OBJCT); savch('"'); savstr(&n[20]);
ragge
1.32
292                 savstr(&n[4]); n[24] = n[11] = 0savch('"'); savch(0);
293 #else
ragge
1.13
294                 savch(0); savch('"'); n[24] = n[11] = 0savstr(&n[4]);
295                 savstr(&n[20]); savch('"'); savch(OBJCT);
ragge
1.12
296                 nl->value = stringbuf-1;
ragge
1.32
297 #endif
ragge
1.12
298
299                 nl = lookup("__STDC__"ENTER);
ragge
1.32
300 #ifdef ragge
301                 nl->value = stringbuf;
302                 savch(OBJCT); savch('1'); savch(0);
303 #else
ragge
1.13
304                 savch(0); savch('1'); savch(OBJCT);
ragge
1.12
305                 nl->value = stringbuf-1;
ragge
1.32
306 #endif
ragge
1.12
307         }
ragge
1.1
308
ragge
1.26
309         if (argc == 2) {
310                 if ((obuf = fopen(argv[1], "w")) == 0) {
311                         fprintf(stderr"Can't creat %s\n"argv[1]);
312                         exit(8);
313                 }
314         } else
315                 obuf = stdout;
316
317         if (pushfile(argc ? argv[0] : NULL))
318                 error("cannot open %s"argv[0]);
319
320         fclose(obuf);
321         return exfail;
322 }
323
ragge
1.35
324 #ifdef ragge
325 /*
326  * Scan the input file for macros to replace and preprocessor directives.
327  */
328 void
329 scanover(struct includ *ic)
330 {
331         struct symtab *nl;
332         usch *sp, *st;
333         int cocgnl;
334         int wasnl = 1;
335
336         for (;;) {
337                 if ((c = inch(ic)) < 0)
338                         return;
339                 if (c != ' ' && c != '\n' && c != '#')
340                         wasnl = 0/* cannot be control */
341                 switch (c) {
342                 case '\''/* charcon */
343                 case '"'/* string */
344                         gnl = 0;
345                         oc = c;
346                         do {
347                                 if (c == GOTNL)
348                                         gnl++;
349                                 else
350                                         outch(c);
351                                 if (c == '\\'/* avoid escaped chars */
352                                         outch(inch(ic));
353                         } while ((c = inch(ic)) != -1 && c != oc);
354                         outch(c);
355                         while (gnl--)
356                                 putc('\n'obuf);
357                         break;
358
359                 case '0'case '1'case '2'case '3'case '4':
360                 case '5'case '6'case '7'case '8'case '9':
361 #define ONEMORE(c, ic)  (outch(c), inch(ic))
362                         oc = c;
363                         outch(c);
364                         c = inch(ic);
365                         if (oc == '0' && (c == 'x' || c == 'X')) {
366                                 do {
367                                         c = ONEMORE(cic);
368                                 } while (isxdigit(c));
369                         } else {
370                                 while (isdigit(c)) {
371                                         c = ONEMORE(cic);
372                                 }
373                         }
374                         if (c != '.' && c != 'e' && c != 'E') {
375                                 /* not floating point number */
376                                 while (c == 'l' || c == 'L' ||
377                                     c == 'u' || c == 'U') {
378                                         c = ONEMORE(cic);
379                                 }
380                                 unch(icc);
381                                 break/* done here */
382                         }
383                         /* it's a floating point number here */
384                         if (c != '.')
385                                 goto E;
386
387                         /* decimal point */
388 F:                      do { /* may be followed by digits */
389                                 c = ONEMORE(cic);
390                         } while (isdigit(c));
391                         if (c == 'e' || c == 'E') {
392 E:                              c = ONEMORE(cic);
393                                 if (c == '-' || c == '+')
394                                         c = ONEMORE(cic);
395                                 while (isdigit(c))
396                                         c = ONEMORE(cic);
397                         }
398                         if (c == 'f' || c == 'F'||c == 'l' || c == 'L')
399                                 c = ONEMORE(cic);
400                         unch(icc);
401                         break;
402
403                 case '.':
404                         c = ONEMORE(cic);
405                         if (isdigit(c))
406                                 goto F;
407                         unch(icc);
408                         break;
409
410                 case GOTNL:
411                         putch('\n');
412                         break;
413
414                 case ' ':
415                 case '\t'/* whitespace */
416                         while (c == ' ' || c == '\t')
417                                 c = ONEMORE(cic);
418                         /* FALLTHROUGH */
419                 case '#':
420                         if (wasnl && c == '#')
421                                 control(ic);
422                         else
423                                 unch(icc);
424                         break;
425
426                 case '/':
427                         if ((c = inch(ic)) == '/') {
428                                 if (Cflag)
429                                         fprintf(obuf"//");
430                                 while ((c = inch(ic)) >= 0 && c != '\n')
431                                         if (Cflag)
432                                                 putc(cobuf);
433                                 unch(icc);
434                         } else if (c == '*') {
435                                 if (Cflag)
436                                         fprintf(obuf"/*");
437                                 oc = 0;
438                                 do {
439                                         while ((c = inch(ic)) >= 0&& c != '*') {
440                                                 if (c == '\n') {
441                                                         putc(cobuf);
442                                                         ic->lineno++;
443                                                 } else if (Cflag)
444                                                         putc(cobuf);
445                                         }
446                                         if (Cflag)
447                                                 putc(cobuf);
448                                         if ((c = inch(ic)) == '/')
449                                                 break;
450                                         unch(icc);
451                                 } while (c >= 0);
452                                 if (Cflag)
453                                         putc(cobuf);
454                                 if (!tflag)
455                                         putc(' 'obuf);
456                         } else {
457                                 unch(icc);
458                                 putc('/'obuf);
459                         }
460                         break;
461
462                 case 'L'/* may be STRING, CHARCON or identifier */
463                         if ((c = inch(ic)) == '"' || c == '\'') {
464                                 /* just print out L and continue */
465                                 unch(icc);
466                                 putc('L'obuf);
467                                 break;
468                         } else {
469                                 unch(icc);
470                                 c = 'L';
471                         }
472                         /* FALLTHROUGH */
473                 default:
474                         if (!isalpha(c) && c != '_') {
475                                 putc(cobuf);
476                                 break;
477                         }
478                         /*
479                          * got an identifier, store it on the heap and
480                          * try to find a definition.
481                          */
482                         sp = stringbuf;
483                         while (isalpha(c) || isdigit(c) || c == '_') {
484                                 *stringbuf++ = c;
485                                 c = inch(ic);
486                         }
487                         unch(icc);
488                         *stringbuf = 0;
489                         if ((nl = lookup(spFIND)) != NULL &&
490                             (st = subst(nlNULL)) != NULL) {
491                                 fprintf(obuf"%s"st);
492                         } else
493                                 fprintf(obuf"%s"sp);
494                         stringbuf = sp;
495                 }
496         }
497 }
498 #endif
499
500 #ifndef ragge
ragge
1.26
501 void
502 mainscan()
503 {
504         struct symtab *nl, *thisnl;
505         usch *osp, *ss2;
506         int cgotspc;
507
ragge
1.1
508         thisnl = NULL;
509         while ((c = yylex()) != 0) {
510                 switch (c) {
511                 case CONTROL:
512                         control();
513                         break;
514
515                 case IDENT:
ragge
1.8
516                         if (flslvl)
517                                 break;
ragge
1.1
518                         osp = stringbuf;
ragge
1.22
519 if(dflag)printf("IDENT0: %s\n"yystr);
ragge
1.15
520                         nl = lookup(yystrFIND);
ragge
1.22
521 if(dflag)printf("IDENT: %s\n"yystr);
ragge
1.1
522                         if (nl == 0 || thisnl == 0)
523                                 goto found;
524                         if (thisnl == nl) {
525                                 nl = 0;
526                                 goto found;
527                         }
ragge
1.2
528                         gotspc = 0;
ragge
1.1
529                         if ((c = yylex()) == WSPACE)
ragge
1.2
530                                 gotspc = 1c = yylex();
ragge
1.1
531                         if (c != EXPAND) {
ragge
1.15
532                                 unpstr(yystr);
ragge
1.2
533                                 if (gotspc)
534                                         cunput(' ');
ragge
1.1
535                                 unpstr(nl->namep);
ragge
1.15
536                                 (void)yylex(); /* get yystr correct */
ragge
1.1
537                                 nl = 0/* ignore */
ragge
1.21
538                         } else {
ragge
1.1
539                                 thisnl = NULL;
ragge
1.21
540                                 if (nl->value[0] == OBJCT) {
541                                         unpstr(nl->namep);
542                                         (void)yylex(); /* get yystr correct */
543                                         nl = 0;
544                                 }
545                         }
ragge
1.1
546
ragge
1.33
547 #ifdef ragge
548 found:                  if (nl == 0 || subst(nlNULL) == 0) {
549 #else
ragge
1.15
550 found:                  if (nl == 0 || subst(yystrnlNULL) == 0) {
ragge
1.33
551 #endif
ragge
1.15
552                                 fputs(yystrobuf);
ragge
1.1
553                         } else if (osp != stringbuf) {
ragge
1.26
554 if(dflag)printf("IDENT1: unput osp %p stringbuf %p\n"ospstringbuf);
ragge
1.24
555                                 ss2 = stringbuf;
ragge
1.1
556                                 cunput(EXPAND);
ragge
1.24
557                                 while (ss2 > osp)
558                                         cunput(*--ss2);
ragge
1.1
559                                 thisnl = nl;
560                         }
561                         stringbuf = osp/* clean up heap */
562                         break;
563
564                 case EXPAND:
ragge
1.22
565 if(dflag)printf("EXPAND!\n");
ragge
1.1
566                         thisnl = NULL;
567                         break;
568
ragge
1.15
569                 case NL:
ragge
1.29
570                         if (flslvl == 0) {
571                                 if (curline() == 1)
572                                         prtline();
573                                 else
574                                         putch('\n');
575                         }
ragge
1.15
576                         break;
577
ragge
1.29
578                 case CHARCON:
579                 case STRING:
ragge
1.1
580                 case NUMBER:
581                 case FPOINT:
582                 case WSPACE:
ragge
1.29
583                 case ELLIPS:
ragge
1.31
584                 case CONCAT:
585                 case MKSTR:
ragge
1.8
586                         if (flslvl == 0)
ragge
1.15
587                                 fputs(yystrobuf);
ragge
1.1
588                         break;
ragge
1.27
589
590                 default:
591                         if (flslvl == 0) {
592                                 if (c < 256)
593                                         putch(c);
594                                 else
595                                         error("bad dir2 %d"c);
596                         }
597                         break;
ragge
1.1
598                 }
599         }
600 }
ragge
1.35
601 #endif
ragge
1.1
602
ragge
1.32
603 #if 0
604 struct noexp {
605         struct noexp *prev;
606         struct symtab *nl;
607 };
608
609 /*
610  * Create a replace list from nl, avoiding to expand bd.
611  */
612 static usch *
613 replfun(struct symtab *nlstruct noexp *bdinp...)
614 {
615         usch **args;
616
617 }
618
619 /*
620  * Replace the object-type macro nl with its value.
621  */
622 static usch *
623 replobj(struct symtab *nlstruct noexp *bdinp...)
624 {
625         usch *base = stringbuf;
626
627         while ((t = intok(nl->value)) != 0) {
628                 if (t != IDENT) {
629                         wstr(
630 }
631
632 /*
633  * Macro-expand the occurrence of string str with its relacement-list.
634  * Return the expanded and replaced string.
635  */
636 static usch *
637 replace(struct symtab *nlstruct noexp *bdinp...)
638 {
639         struct noexp n;
640
641         n.prev = bd;
642         n.nl = nl;
643
644         /* is this macro something we want? */
645         if (nl->value[0] == OBJCT)
646                 return replobj(nl, &ninp);
647         /* search for first ( */
648         while ((c = tokget(inp)) == WSPACE || c == NL)
649                 if (c == NL/* happens only when read from file */
650                         putc('\n'obuf);
651         if (c != '(')
652                 return tokput(c), NULL/* not correct, ignore */
653         return replfun(nl, &ninp);
654 }
655 #endif
656
ragge
1.1
657 /*
658  * do something when a '#' is found.
659  */
660 void
ragge
1.35
661 #ifdef ragge
662 control(struct includ *ic)
663 #else
ragge
1.1
664 control()
ragge
1.35
665 #endif
ragge
1.1
666 {
667         struct symtab *np;
668         int t;
669
ragge
1.15
670 #define CHECK(x) (yystr[0] == #x[0]) && strcmp(yystr, #x) == 0
ragge
1.8
671
ragge
1.1
672         if ((t = yylex()) == WSPACE)
673                 t = yylex();
ragge
1.14
674         if (t == NL) {
675                 /* Just ignore */
676                 putc('\n'obuf);
677                 return;
678         }
ragge
1.1
679         if (t != IDENT)
ragge
1.15
680                 return error("bad control '%s'"yystr);
ragge
1.1
681
ragge
1.8
682         if (CHECK(include)) {
ragge
1.1
683                 if (flslvl)
684                         goto exit;
ragge
1.3
685                 include();
ragge
1.1
686                 return;
ragge
1.8
687         } else if (CHECK(else)) {
ragge
1.1
688                 if (flslvl) {
ragge
1.10
689                         if (elflvl > trulvl)
690                                 ;
691                         else if (--flslvl!=0) {
ragge
1.1
692                                 flslvl++;
ragge
1.8
693                         } else {
ragge
1.1
694                                 trulvl++;
ragge
1.8
695                                 prtline();
696                         }
ragge
1.1
697                 } else if (trulvl) {
698                         flslvl++;
699                         trulvl--;
700                 } else
701                         error("If-less else");
ragge
1.10
702                 if (elslvl==trulvl+flslvlerror("Too many else");
703                 elslvl=trulvl+flslvl;
ragge
1.8
704         } else if (CHECK(endif)) {
705                 if (flslvl) {
706                         flslvl--;
707                         if (flslvl == 0)
708                                 prtline();
709                 } else if (trulvl)
710                         trulvl--;
711                 else
712                         error("If-less endif");
ragge
1.10
713                 if (flslvl == 0)
714                         elflvl = 0;
715                 elslvl = 0;
ragge
1.8
716         } else if (CHECK(error)) {
717                 usch *ch = stringbuf;
ragge
1.11
718                 if (flslvl)
719                         goto exit;
ragge
1.8
720                 while (yylex() != NL)
ragge
1.15
721                         savstr(yystr);
ragge
1.8
722                 savch('\n');
723                 error("error: %s"ch);
ragge
1.9
724 #define GETID() if (yylex() != WSPACE || yylex() != IDENT) goto cfail
725         } else if (CHECK(define)) {
ragge
1.10
726                 if (flslvl)
727                         goto exit;
ragge
1.9
728                 GETID();
729                 define();
730         } else if (CHECK(ifdef)) {
731                 GETID();
ragge
1.15
732                 if (flslvl == 0 && lookup(yystrFIND) != 0)
ragge
1.9
733                         trulvl++;
734                 else
735                         flslvl++;
736         } else if (CHECK(ifndef)) {
737                 GETID();
ragge
1.15
738                 if (flslvl == 0 && lookup(yystrFIND) == 0)
ragge
1.9
739                         trulvl++;
740                 else
741                         flslvl++;
742         } else if (CHECK(undef)) {
743                 GETID();
ragge
1.15
744                 if (flslvl == 0 && (np = lookup(yystrFIND)))
ragge
1.9
745                         np->value = 0;
746         } else if (CHECK(line)) {
ragge
1.10
747                 if (flslvl)
748                         goto exit;
ragge
1.9
749                 line();
ragge
1.10
750         } else if (CHECK(if)) {
751                 if (flslvl==0 && yyparse())
752                         ++trulvl;
753                 else
754                         ++flslvl;
ragge
1.16
755         } else if (CHECK(pragma)) {
756                 goto exit;
ragge
1.10
757         } else if (CHECK(elif)) {
758                 if (flslvl == 0)
759                         elflvl = trulvl;
760                 if (flslvl) {
761                         if (elflvl > trulvl)
762                                 ;
763                         else if (--flslvl!=0)
764                                 ++flslvl;
765                         else {
766                                 if (yyparse()) {
767                                         ++trulvl;
768                                         prtline();
769                                 } else
770                                         ++flslvl;
771                         }
772                 } else if (trulvl) {
773                         ++flslvl;
774                         --trulvl;
775                 } else
776                         error("If-less elif");
ragge
1.9
777         } else
ragge
1.17
778 #if 0
ragge
1.15
779                 error("undefined control '%s'"yystr);
ragge
1.17
780 #else
781                 goto exit;
782 #endif
ragge
1.9
783
784         return;
785
786 cfail:
787         error("control line syntax error");
ragge
1.1
788
789 exit:
790         while (yylex() != NL)
791                 ;
ragge
1.10
792         putc('\n'obuf);
ragge
1.8
793 #undef CHECK
ragge
1.1
794 }
795
796 void
ragge
1.9
797 line()
798 {
799         struct symtab *nl;
800         int c;
801
802         if (yylex() != WSPACE)
803                 goto bad;
804         if ((c = yylex()) == IDENT) {
805                 /* Do macro preprocessing first */
806                 usch *osp = stringbuf;
ragge
1.15
807                 if ((nl = lookup(yystrFIND)) == NULL)
ragge
1.9
808                         goto bad;
ragge
1.33
809 #ifdef ragge
810                 if (subst(nlNULL) == 0)
811 #else
ragge
1.15
812                 if (subst(yystrnlNULL) == 0)
ragge
1.33
813 #endif
ragge
1.9
814                         goto bad;
815                 while (stringbuf > osp)
816                         cunput(*--stringbuf);
817                 c = yylex();
818         }
819
820         if (c != NUMBER)
821                 goto bad;
ragge
1.15
822         setline(atoi(yystr));
ragge
1.9
823
824         if ((c = yylex()) != NL && c != WSPACE)
825                 goto bad;
826         if (c == NL)
827                 return setline(curline()+1);
828         if (yylex() != STRING)
829                 goto bad;
ragge
1.15
830         yystr[strlen(yystr)-1] = 0;
831         setfile(&yystr[1]);
ragge
1.9
832         return;
833
834 bad:    error("bad line directive");
835 }
836
ragge
1.10
837 /*
838  * Include a file. Include order:
ragge
1.20
839  * - For <...> files, first search -I directories, then system directories.
840  * - For "..." files, first search "current" dir, then as <...> files.
ragge
1.10
841  */
ragge
1.9
842 void
ragge
1.3
843 include()
844 {
ragge
1.10
845         struct incs *w;
ragge
1.3
846         struct symtab *nl;
ragge
1.10
847         usch *osp;
848         char *fn;
849         int icit;
ragge
1.3
850
ragge
1.10
851         osp = stringbuf;
ragge
1.3
852         if (yylex() != WSPACE)
853                 goto bad;
ragge
1.10
854 again:  if ((c = yylex()) != STRING && c != '<' && c != IDENT)
ragge
1.3
855                 goto bad;
856
857         if (c == IDENT) {
ragge
1.15
858                 if ((nl = lookup(yystrFIND)) == NULL)
ragge
1.3
859                         goto bad;
ragge
1.35
860 #ifdef ragge
861                 if (subst(nlNULL) == 0)
862 #else
ragge
1.15
863                 if (subst(yystrnlNULL) == 0)
ragge
1.35
864 #endif
ragge
1.3
865                         goto bad;
866                 savch('\0');
ragge
1.10
867                 unpstr(osp);
868                 goto again;
869         } else if (c == '<') {
870                 fn = stringbuf;
871                 while ((c = yylex()) != '>' && c != NL) {
872                         if (c == NL)
873                                 goto bad;
ragge
1.15
874                         savstr(yystr);
ragge
1.10
875                 }
876                 savch('\0');
ragge
1.20
877                 it = SYSINC;
ragge
1.3
878         } else {
ragge
1.20
879                 usch *nm = stringbuf;
880
ragge
1.15
881                 yystr[strlen(yystr)-1] = 0;
882                 fn = &yystr[1];
ragge
1.20
883                 /* first try to open file relative to previous file */
884                 savstr(curfile());
885                 if ((stringbuf = strrchr(nm'/')) == NULL)
886                         stringbuf = nm;
887                 else
888                         stringbuf++;
889                 savstr(fn); savch(0);
890                 if (pushfile(nm) == 0)
891                         goto ret;
892                 stringbuf = nm;
ragge
1.10
893         }
894
895         /* create search path and try to open file */
ragge
1.20
896         for (i = 0i < 2i++) {
ragge
1.10
897                 for (w = incdir[i]; ww = w->next) {
898                         usch *nm = stringbuf;
899
900                         savstr(w->dir); savch('/');
901                         savstr(fn); savch(0);
902                         if (pushfile(nm) == 0)
903                                 goto ret;
904                         stringbuf = nm;
905                 }
ragge
1.3
906         }
ragge
1.10
907         error("cannot find '%s'"fn);
908         stringbuf = osp;
ragge
1.3
909         return;
910
911 bad:    error("bad include");
ragge
1.26
912         stringbuf = osp;
913 ret:    prtline();
ragge
1.3
914 }
915
916 void
ragge
1.1
917 define()
918 {
919         struct symtab *np;
ragge
1.15
920         usch *args[MAXARG], *ubuf, *sbeg;
921         int ciredef;
ragge
1.32
922 #ifdef ragge
923         int mkstr = 0narg = OBJCT;
924 #else
ragge
1.1
925         int mkstr = 0narg = -1;
ragge
1.32
926 #endif
ragge
1.1
927
ragge
1.15
928         np = lookup(yystrENTER);
929         redef = np->value != NULL;
ragge
1.1
930
ragge
1.15
931         sbeg = stringbuf;
ragge
1.1
932         if ((c = yylex()) == '(') {
933                 narg = 0;
934                 /* function-like macros, deal with identifiers */
935                 while ((c = yylex()) != ')') {
ragge
1.31
936                         while (c == WSPACE)
937                                 c = yylex();
ragge
1.1
938                         if (c == ','c = yylex();
ragge
1.31
939                         while (c == WSPACE)
940                                 c = yylex();
ragge
1.1
941                         if (c == ')')
942                                 break;
ragge
1.15
943                         if (c != IDENT)
ragge
1.31
944                                 error("define error, c %d"c);
ragge
1.15
945                         args[narg] = alloca(strlen(yystr)+1);
946                         strcpy(args[narg], yystr);
ragge
1.1
947                         narg++;
948                 }
ragge
1.8
949         } else if (c == NL) {
950                 /* #define foo */
951                 cunput('\n');
ragge
1.1
952         } else if (c != WSPACE)
953                 error("bad define");
954
ragge
1.31
955         c = yylex();
956         while (c == WSPACE)
ragge
1.1
957                 c = yylex();
958
959         /* parse replacement-list, substituting arguments */
ragge
1.32
960 #ifdef ragge
961         savch(narg);
962 #else
ragge
1.1
963         savch('\0');
ragge
1.32
964 #endif
ragge
1.1
965         while (c != NL) {
966                 switch (c) {
967                 case WSPACE:
968                         /* remove spaces if it surrounds a ## directive */
ragge
1.2
969                         ubuf = stringbuf;
ragge
1.15
970                         savstr(yystr);
ragge
1.1
971                         c = yylex();
972                         if (c == CONCAT) {
ragge
1.2
973                                 stringbuf = ubuf;
ragge
1.1
974                                 savch(CONC);
975                                 if ((c = yylex()) == WSPACE)
976                                         c = yylex();
977                         }
978