Quick Search:

View

Revision:
Expand:  
Changeset: MAIN:ragge:20060730125240

Diff

Diff from 1.33 to:

Annotations

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

Annotated File View

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