Quick Search:

View

Revision:
Expand:  
Changeset: MAIN:ragge:20060730125320

Diff

Diff from 1.34 to:

Annotations

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

Annotated File View

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