Quick Search:

View

Revision:
Expand:  
Changeset: MAIN:ragge:20050511193259

Diff

Diff from 1.26 to:

Annotations

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

Annotated File View

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