Quick Search:

View

Revision:
Expand:  
Changeset: MAIN:ragge:20060730093330

Diff

Diff from 1.32 to:

Annotations

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

Annotated File View

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