1 /* Id: cpp.c,v 1.252 2016/02/06 09:39:21 ragge Exp */
2 /* $NetBSD: cpp.c,v 1.4 2016/02/09 20:37:32 plunky Exp $ */
3
4 /*
5 * Copyright (c) 2004,2010 Anders Magnusson (ragge@ludd.luth.se).
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 /*
30 * The C preprocessor.
31 * This code originates from the V6 preprocessor with some additions
32 * from V7 cpp, and at last ansi/c99 support.
33 *
34 * - kfind() expands the input buffer onto XXX
35 * - exparg() expand one buffer into another.
36 * Recurses into submac() for fun-like macros.
37 * - submac() replaces the given macro.
38 * Recurses into subarg() for fun-like macros.
39 * - subarg() expands fun-like macros.
40 * Create strings, concats args, recurses into exparg.
41 */
42
43 #include "config.h"
44
45 #include <sys/stat.h>
46
47 #include <fcntl.h>
48 #ifdef HAVE_UNISTD_H
49 #include <unistd.h>
50 #endif
51 #include <stdio.h>
52 #include <stdarg.h>
53 #include <stdlib.h>
54 #include <string.h>
55 #include <time.h>
56
57 #include "compat.h"
58 #include "cpp.h"
59
60 #ifndef S_ISDIR
61 #define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
62 #endif
63
64 #define SBSIZE 1000000
65
66 static usch sbf[SBSIZE];
67 static int counter;
68 /* C command */
69
70 int tflag; /* traditional cpp syntax */
71 #ifdef PCC_DEBUG
72 int dflag; /* debug printouts */
73 //static void imp(const char *);
74 static void prline(const usch *s);
75 static void prrep(const usch *s);
76 #define DPRINT(x) if (dflag) printf x
77 #define DDPRINT(x) if (dflag > 1) printf x
78 #define IMP(x) if (dflag > 1) imp(x)
79 #else
80 #define DPRINT(x)
81 #define DDPRINT(x)
82 #define IMP(x)
83 #endif
84
85 int Aflag, Cflag, Eflag, Mflag, dMflag, Pflag, MPflag, MMDflag;
86 char *Mfile, *MPfile;
87 struct initar *initar;
88 char *Mxfile;
89 int warnings, Mxlen;
90 FILE *of;
91
92 /* include dirs */
93 struct incs {
94 struct incs *next;
95 usch *dir;
96 dev_t dev;
97 ino_t ino;
98 } *incdir[2];
99
100 static struct symtab *filloc;
101 static struct symtab *linloc;
102 static struct symtab *pragloc;
103 static struct symtab *defloc;
104 static struct symtab *ctrloc;
105 int trulvl;
106 int flslvl;
107 int elflvl;
108 int elslvl;
109 usch *stringbuf = sbf;
110
111 /*
112 * Macro replacement list syntax:
113 * - For object-type macros, replacement strings are stored as-is.
114 * - For function-type macros, macro args are substituted for the
115 * character WARN followed by the argument number.
116 * - The value element points to the beginning of the string.
117 *
118 * The first character in the replacement list is the number of arguments:
119 * VARG - ends with ellipsis, next char is argcount without ellips.
120 * OBJCT - object-type macro
121 * 0 - empty parenthesis, foo()
122 * 1-> - number of args.
123 *
124 * WARN is used:
125 * - in stored replacement lists to tell that an argument comes
126 * - When expanding replacement lists to tell that the list ended.
127 *
128 * To ensure that an already expanded identifier won't get expanded
129 * again a EBLOCK char + its number is stored directly before any
130 * expanded identifier.
131 */
132
133 /* args for lookup() */
134 #define FIND 0
135 #define ENTER 1
136
137 /*
138 * No-replacement array. If a macro is found and exists in this array
139 * then no replacement shall occur.
140 */
141 struct blocker {
142 struct blocker *next;
143 struct symtab *sp;
144 };
145 struct blocker *blkidx[RECMAX];
146 int blkidp;
147
148 static int readargs2(usch **, struct symtab *sp, const usch **args);
149 static int readargs1(struct symtab *sp, const usch **args);
150 static struct iobuf *exparg(int, struct iobuf *, struct iobuf *, struct blocker *);
151 static struct iobuf *subarg(struct symtab *sp, const usch **args, int, struct blocker *);
152 static void usage(void);
153 static usch *xstrdup(const usch *str);
154 static void addidir(char *idir, struct incs **ww);
155 static void vsheap(const char *, va_list);
156 static int skipws(struct iobuf *ib);
157 static int getyp(usch *s);
158 static void *xrealloc(void *p, int sz);
159 static void *xmalloc(int sz);
160
161 usch locs[] =
162 { FILLOC, LINLOC, PRAGLOC, DEFLOC,
163 'd','e','f','i','n','e','d',0, CTRLOC };
164
165 int
main(int argc,char ** argv)166 main(int argc, char **argv)
167 {
168 struct initar *it;
169 register int ch;
170 const usch *fn1, *fn2;
171
172 #ifdef TIMING
173 struct timeval t1, t2;
174
175 (void)gettimeofday(&t1, NULL);
176 #endif
177
178 while ((ch = getopt(argc, argv, "ACD:d:EI:i:MPS:tU:Vvx:")) != -1) {
179 switch (ch) {
180 case 'A': /* assembler input */
181 Aflag++;
182 break;
183
184 case 'C': /* Do not discard comments */
185 Cflag++;
186 break;
187
188 case 'E': /* treat warnings as errors */
189 Eflag++;
190 break;
191
192 case 'D': /* define something */
193 case 'i': /* include */
194 case 'U': /* undef */
195 /* XXX should not need malloc() here */
196 if ((it = xmalloc(sizeof(struct initar))) == NULL)
197 error("couldn't apply -%c %s", ch, optarg);
198 it->type = ch;
199 it->str = optarg;
200 it->next = initar;
201 initar = it;
202 break;
203
204 case 'd':
205 while (*optarg) {
206 switch(*optarg) {
207 case 'M': /* display macro definitions */
208 dMflag = 1;
209 Mflag = 1;
210 break;
211
212 default: /* ignore others */
213 break;
214 }
215 optarg++;
216 }
217 break;
218
219 case 'I':
220 case 'S':
221 addidir(optarg, &incdir[ch == 'I' ? INCINC : SYSINC]);
222 break;
223
224 case 'M': /* Generate dependencies for make */
225 Mflag++;
226 break;
227
228 case 'P': /* Inhibit generation of line numbers */
229 Pflag++;
230 break;
231
232 case 't':
233 tflag = 1;
234 break;
235
236 #ifdef PCC_DEBUG
237 case 'V':
238 dflag++;
239 break;
240 #endif
241 case 'v':
242 fprintf(stderr, "PCC preprocessor version "VERSSTR"\n");
243 break;
244
245 case 'x':
246 if (strcmp(optarg, "MMD") == 0) {
247 MMDflag++;
248 } else if (strcmp(optarg, "MP") == 0) {
249 MPflag++;
250 } else if (strncmp(optarg, "MT,", 3) == 0 ||
251 strncmp(optarg, "MQ,", 3) == 0) {
252 int l = strlen(optarg+3) + 2;
253 char *cp, *up;
254
255 if (optarg[1] == 'Q')
256 for (cp = optarg+3; *cp; cp++)
257 if (*cp == '$')
258 l++;
259 Mxlen += l;
260 Mxfile = cp = realloc(Mxfile, Mxlen);
261 for (up = Mxfile; *up; up++)
262 ;
263 if (up != Mxfile)
264 *up++ = ' ';
265 for (cp = optarg+3; *cp; cp++) {
266 *up++ = *cp;
267 if (optarg[1] == 'Q' && *cp == '$')
268 *up++ = *cp;
269 }
270 *up = 0;
271 } else
272 usage();
273 break;
274
275 case '?':
276 default:
277 usage();
278 }
279 }
280
281 argc -= optind;
282 argv += optind;
283
284 filloc = lookup((const usch *)"__FILE__", ENTER);
285 linloc = lookup((const usch *)"__LINE__", ENTER);
286 pragloc = lookup((const usch *)"_Pragma", ENTER);
287 defloc = lookup((const usch *)"defined", ENTER);
288 ctrloc = lookup((const usch *)"__COUNTER__", ENTER);
289 filloc->value = locs;
290 linloc->value = locs+1;
291 pragloc->value = locs+2;
292 defloc->value = locs+3; /* also have macro name here */
293 ctrloc->value = locs+12;
294
295 if (Mflag && !dMflag) {
296 char *c;
297
298 if (argc < 1)
299 error("-M and no infile");
300 if ((c = strrchr(argv[0], '/')) == NULL)
301 c = argv[0];
302 else
303 c++;
304 Mfile = (char *)xstrdup((usch *)c);
305 if (MPflag)
306 MPfile = (char *)xstrdup((usch *)c);
307 if (Mxfile)
308 Mfile = Mxfile;
309 if ((c = strrchr(Mfile, '.')) == NULL)
310 error("-M and no extension: ");
311 c[1] = 'o';
312 c[2] = 0;
313 }
314
315 if (argc == 2) {
316 if ((of = freopen(argv[1], "w", stdout)) == NULL)
317 error("Can't creat %s", argv[1]);
318 } else
319 of = stdout;
320
321 if (argc && strcmp(argv[0], "-")) {
322 fn1 = fn2 = (usch *)argv[0];
323 } else {
324 fn1 = NULL;
325 fn2 = (const usch *)"";
326 }
327 if (pushfile(fn1, fn2, 0, NULL))
328 error("cannot open %s", argv[0]);
329
330 fclose(of);
331 #ifdef TIMING
332 (void)gettimeofday(&t2, NULL);
333 t2.tv_sec -= t1.tv_sec;
334 t2.tv_usec -= t1.tv_usec;
335 if (t2.tv_usec < 0) {
336 t2.tv_usec += 1000000;
337 t2.tv_sec -= 1;
338 }
339 fprintf(stderr, "cpp total time: %ld s %ld us\n",
340 (long)t2.tv_sec, (long)t2.tv_usec);
341 #endif
342 if (Eflag && warnings > 0)
343 return 2;
344
345 return 0;
346 }
347
348 /*
349 * Write a character to an out buffer.
350 */
351 static void
putob(struct iobuf * ob,int ch)352 putob(struct iobuf *ob, int ch)
353 {
354 if (ob->cptr == ob->bsz) {
355 int sz = ob->bsz - ob->buf;
356 ob->buf = xrealloc(ob->buf, sz + BUFSIZ);
357 ob->cptr = ob->buf + sz;
358 ob->bsz = ob->buf + sz + BUFSIZ;
359 }
360 // DDPRINT(("putob: iob %p pos %p ch %c (%d)\n", ob, ob->cptr, ch, ch));
361 *ob->cptr++ = ch;
362 }
363
364 static int nbufused;
365 /*
366 * Write a character to an out buffer.
367 */
368 static struct iobuf *
getobuf(void)369 getobuf(void)
370 {
371 struct iobuf *iob = xmalloc(sizeof(struct iobuf));
372
373 nbufused++;
374 iob->buf = iob->cptr = xmalloc(BUFSIZ);
375 iob->bsz = iob->buf + BUFSIZ;
376 iob->ro = 0;
377 return iob;
378 }
379
380 /*
381 * Create a read-only input buffer.
382 */
383 static struct iobuf *
mkrobuf(const usch * s)384 mkrobuf(const usch *s)
385 {
386 struct iobuf *iob = xmalloc(sizeof(struct iobuf));
387
388 nbufused++;
389 DPRINT(("mkrobuf %s\n", s));
390 iob->buf = iob->cptr = (usch *)s;
391 iob->bsz = iob->buf + strlen((char *)iob->buf);
392 iob->ro = 1;
393 return iob;
394 }
395
396 /*
397 * Copy a string to a buffer.
398 */
399 static struct iobuf *
strtobuf(usch * str,struct iobuf * iob)400 strtobuf(usch *str, struct iobuf *iob)
401 {
402 DPRINT(("strtobuf iob %p buf %p str %s\n", iob, iob->buf, str));
403 if (iob == NULL)
404 iob = getobuf();
405 do {
406 putob(iob, *str);
407 } while (*str++);
408 iob->cptr--;
409 return iob;
410 }
411
412 static void
bufree(struct iobuf * iob)413 bufree(struct iobuf *iob)
414 {
415 nbufused--;
416 if (iob->ro == 0)
417 free(iob->buf);
418 free(iob);
419 }
420
421 static void
addidir(char * idir,struct incs ** ww)422 addidir(char *idir, struct incs **ww)
423 {
424 struct incs *w;
425 struct stat st;
426
427 if (stat(idir, &st) == -1 || !S_ISDIR(st.st_mode))
428 return; /* ignore */
429 if (*ww != NULL) {
430 for (w = *ww; w->next; w = w->next) {
431 #ifdef _WIN32
432 if (strcmp(w->dir, idir) == 0)
433 return;
434 #else
435 if (w->dev == st.st_dev && w->ino == st.st_ino)
436 return;
437 #endif
438 }
439 #ifdef _WIN32
440 if (strcmp(w->dir, idir) == 0)
441 return;
442 #else
443 if (w->dev == st.st_dev && w->ino == st.st_ino)
444 return;
445 #endif
446 ww = &w->next;
447 }
448 if ((w = calloc(sizeof(struct incs), 1)) == NULL)
449 error("couldn't add path %s", idir);
450 w->dir = (usch *)idir;
451 w->dev = st.st_dev;
452 w->ino = st.st_ino;
453 *ww = w;
454 }
455
456 void
line(void)457 line(void)
458 {
459 struct symtab *nl;
460 int c, n, ln;
461 usch *cp;
462
463 cp = stringbuf;
464 c = skipws(0);
465 if (ISID0(c)) { /* expand macro */
466 heapid(c);
467 stringbuf = cp;
468 if ((nl = lookup(cp, FIND)) == 0 || kfind(nl) == 0)
469 goto bad;
470 } else {
471 do {
472 savch(c);
473 } while (ISDIGIT(c = cinput()));
474 cunput(c);
475 savch(0);
476 }
477
478 stringbuf = cp;
479 n = 0;
480 while (ISDIGIT(*cp))
481 n = n * 10 + *cp++ - '0';
482 if (*cp != 0)
483 goto bad;
484
485 /* Can only be decimal number here between 1-2147483647 */
486 if (n < 1 || n > 2147483647)
487 goto bad;
488
489 ln = n;
490 ifiles->escln = 0;
491 if ((c = skipws(NULL)) != '\n') {
492 if (c == 'L' || c == 'U' || c == 'u') {
493 n = c, c = cinput();
494 if (n == 'u' && c == '8')
495 c = cinput();
496 if (c == '\"')
497 warning("#line only allows character literals");
498 }
499 if (c != '\"')
500 goto bad;
501 /* loses space on heap... does it matter? */
502 ifiles->fname = stringbuf+1;
503 faststr(c, savch);
504 stringbuf--;
505 savch(0);
506
507 c = skipws(0);
508 }
509 if (c != '\n')
510 goto bad;
511
512 ifiles->lineno = ln;
513 prtline(1);
514 ifiles->lineno--;
515 cunput('\n');
516 return;
517
518 bad: error("bad #line");
519 }
520
521 #ifdef MACHOABI
522
523 /*
524 * Search for framework header file.
525 * Return 1 on success.
526 */
527
528 static int
fsrch_macos_framework(const usch * fn,const usch * dir)529 fsrch_macos_framework(const usch *fn, const usch *dir)
530 {
531 usch *saved_stringbuf = stringbuf;
532 usch *s = (usch *)strchr((const char*)fn, '/');
533 usch *nm;
534 usch *p;
535 int len = s - fn;
536
537 if (s == NULL)
538 return 0;
539
540 // fprintf(stderr, "searching for %s in %s\n", (const char *)fn, (const char *)dir);
541
542 nm = savstr(dir);
543 savch(0);
544 p = savstr(fn);
545 stringbuf = p + len;
546 savch(0);
547 // fprintf(stderr, "comparing \"%s\" against \"%.*s\"\n", nm, len, fn);
548 p = (usch *)strstr((const char *)nm, (const char *)p);
549 // fprintf(stderr, "p = %s\n", (const char *)p);
550 if (p != NULL) {
551 stringbuf = p;
552 savch(0);
553 return fsrch_macos_framework(fn, nm);
554 }
555
556 p = nm + strlen((char *)nm) - 1;
557 while (*p == '/')
558 p--;
559 while (*p != '/')
560 p--;
561 stringbuf = ++p;
562 savstr((const usch *)"Frameworks/");
563 stringbuf = savstr(fn) + len;
564 savstr((const usch*)".framework/Headers");
565 savstr(s);
566 savch(0);
567
568 // fprintf(stderr, "nm: %s\n", nm);
569
570 if (pushfile(nm, fn, SYSINC, NULL) == 0)
571 return 1;
572 // fprintf(stderr, "not found %s, continuing...\n", nm);
573
574 stringbuf = saved_stringbuf;
575
576 return 0;
577 }
578
579 #endif
580
581 /*
582 * Search for and include next file.
583 * Return 1 on success.
584 */
585 static int
fsrch(const usch * fn,int idx,struct incs * w)586 fsrch(const usch *fn, int idx, struct incs *w)
587 {
588 int i;
589
590 for (i = idx; i < 2; i++) {
591 if (i > idx)
592 w = incdir[i];
593 for (; w; w = w->next) {
594 usch *nm = stringbuf;
595
596 savstr(w->dir); savch('/');
597 savstr(fn); savch(0);
598 if (pushfile(nm, fn, i, w->next) == 0)
599 return 1;
600 stringbuf = nm;
601 }
602 }
603
604 #ifdef MACHOABI
605 /*
606 * On MacOS, we may have to do some clever stuff
607 * to resolve framework headers.
608 */
609 {
610 usch *dir = stringbuf;
611 savstr(ifiles->orgfn);
612 stringbuf = (usch *)strrchr((char *)dir, '/');
613 if (stringbuf != NULL) {
614 stringbuf++;
615 savch(0);
616 if (fsrch_macos_framework(fn, dir) == 1)
617 return 1;
618 }
619 stringbuf = dir;
620
621 if (fsrch_macos_framework(fn, (const usch *)"/Library/Frameworks/") == 1)
622 return 1;
623
624 if (fsrch_macos_framework(fn, (const usch *)"/System/Library/Frameworks/") == 1)
625 return 1;
626 }
627 #endif
628
629 return 0;
630 }
631
632 static void
prem(void)633 prem(void)
634 {
635 error("premature EOF");
636 }
637
638 static struct iobuf *
incfn(void)639 incfn(void)
640 {
641 struct iobuf *ob;
642 struct symtab *nl;
643 usch *sb;
644 int c;
645
646 sb = stringbuf;
647 if (spechr[c = skipws(NULL)] & C_ID0) {
648 heapid(c);
649 if ((nl = lookup(sb, FIND)) == NULL)
650 return NULL;
651
652 stringbuf = sb;
653 if (kfind(nl) == 0)
654 return NULL;
655 ob = strtobuf(sb, NULL);
656 } else {
657 ob = getobuf();
658 putob(ob, c);
659 while ((c = cinput()) && c != '\n')
660 putob(ob, c);
661 if (c != '\n')
662 return NULL;
663 cunput(c);
664 }
665 putob(ob, 0);
666 ob->cptr--;
667
668 /* now we have an (expanded?) filename in obuf */
669 while (ob->buf < ob->cptr && ISWS(ob->cptr[-1]))
670 ob->cptr--;
671
672 if (ob->buf[0] != '\"' && ob->buf[0] != '<')
673 return NULL;
674 if (ob->cptr[-1] != '\"' && ob->cptr[-1] != '>')
675 return NULL;
676 ob->cptr[-1] = 0;
677 return ob;
678 }
679
680 /*
681 * Include a file. Include order:
682 * - For <...> files, first search -I directories, then system directories.
683 * - For "..." files, first search "current" dir, then as <...> files.
684 */
685 void
include(void)686 include(void)
687 {
688 struct iobuf *ob;
689 usch *fn, *nm = NULL;
690
691 if (flslvl)
692 return;
693
694 if ((ob = incfn()) == NULL) /* get include file name in obuf */
695 error("bad #include");
696
697 fn = xstrdup(ob->buf) + 1; /* Save on string heap? */
698 bufree(ob);
699 /* test absolute path first */
700 if (fn[0] == '/' && pushfile(fn, fn, 0, NULL) == 0)
701 goto okret;
702 if (fn[-1] == '\"') {
703 /* nope, failed, try to create a path for it */
704 if ((nm = (usch *)strrchr((char *)ifiles->orgfn, '/'))) {
705 ob = strtobuf((usch *)ifiles->orgfn, NULL);
706 ob->cptr = ob->buf + (nm - ifiles->orgfn) + 1;
707 strtobuf(fn, ob);
708 putob(ob, 0);
709 nm = xstrdup(ob->buf);
710 bufree(ob);
711 } else {
712 nm = xstrdup(fn);
713 }
714 if (pushfile(nm, nm, 0, NULL) == 0) {
715 free(fn-1);
716 goto okret;
717 }
718 }
719 if (fsrch(fn, 0, incdir[0]))
720 goto okret;
721
722 error("cannot find '%s'", fn);
723 /* error() do not return */
724
725 okret:
726 if (nm)
727 free(nm);
728 prtline(1);
729 }
730
731 void
include_next(void)732 include_next(void)
733 {
734 struct iobuf *ob;
735 usch *nm;
736
737 if (flslvl)
738 return;
739
740 if ((ob = incfn()) == NULL) /* get include file name in obuf */
741 error("bad #include_next");
742
743 nm = xstrdup(ob->buf+1);
744 bufree(ob);
745
746 if (fsrch(nm, ifiles->idx, ifiles->incs) == 0)
747 error("cannot find '%s'", nm);
748 prtline(1);
749 }
750
751 /*
752 * Compare two replacement lists, taking in account comments etc.
753 */
754 static int
cmprepl(const usch * o,const usch * n)755 cmprepl(const usch *o, const usch *n)
756 {
757 for (; *o; o++, n++) {
758 /* comment skip */
759 if (*o == '/' && o[1] == '*') {
760 while (*o != '*' || o[1] != '/')
761 o++;
762 o += 2;
763 }
764 if (*n == '/' && n[1] == '*') {
765 while (*n != '*' || n[1] != '/')
766 n++;
767 n += 2;
768 }
769 while (*o == ' ' || *o == '\t')
770 o++;
771 while (*n == ' ' || *n == '\t')
772 n++;
773 if (*o != *n)
774 return 1;
775 }
776 return 0;
777 }
778
779 static int
isell(void)780 isell(void)
781 {
782 if (cinput() != '.' || cinput() != '.')
783 return 0;
784 return 1;
785 }
786
787 static int
skipwscmnt(struct iobuf * ib)788 skipwscmnt(struct iobuf *ib)
789 {
790 /* XXX comment */
791 return skipws(ib);
792 }
793
794 static int
findarg(usch * s,usch ** args,int narg)795 findarg(usch *s, usch **args, int narg)
796 {
797 int i;
798
799 for (i = 0; i < narg; i++)
800 if (strcmp((char *)s, (char *)args[i]) == 0)
801 return i;
802 return -1;
803 }
804
805 /*
806 * gcc extensions:
807 * #define e(a...) f(s, a) -> a works as __VA_ARGS__
808 * #define e(fmt, ...) f(s, fmt , ##__VA_ARGS__) -> remove , if no args
809 */
810 void
define(void)811 define(void)
812 {
813 struct symtab *np;
814 usch *args[MAXARGS+1], *sbeg, *bp, cc[2], *vararg;
815 int c, i, redef, oCflag, t;
816 int narg = -1;
817 int wascon;
818
819 if (flslvl)
820 return;
821
822 oCflag = Cflag, Cflag = 0; /* Ignore comments here */
823 if (!ISID0(c = skipws(0)))
824 goto bad;
825
826 bp = heapid(c);
827 np = lookup(bp, ENTER);
828 if (np->value) {
829 stringbuf = bp;
830 redef = 1;
831 } else
832 redef = 0;
833
834 vararg = NULL;
835 sbeg = stringbuf++;
836 if ((c = cinput()) == '(') {
837 narg = 0;
838 /* function-like macros, deal with identifiers */
839 c = skipws(0);
840 for (;;) {
841 switch (c) {
842 case ')':
843 break;
844 case '.':
845 if (isell() == 0 || (c = skipws(0)) != ')')
846 goto bad;
847 vararg = (usch *)"__VA_ARGS__";
848 break;
849 default:
850 if (!ISID0(c))
851 goto bad;
852
853 bp = heapid(c);
854 /* make sure there is no arg of same name */
855 if (findarg(bp, args, narg) >= 0)
856 error("Duplicate parameter \"%s\"", bp);
857 if (narg == MAXARGS)
858 error("Too many macro args");
859 args[narg++] = xstrdup(bp);
860 stringbuf = bp;
861 switch ((c = skipws(0))) {
862 case ',': break;
863 case ')': continue;
864 case '.':
865 if (isell() == 0 || skipws(0) != ')')
866 goto bad;
867 vararg = args[--narg];
868 c = ')';
869 continue;
870 default:
871 goto bad;
872 }
873 c = skipws(0);
874 }
875 if (c == ')')
876 break;
877 }
878 c = skipws(0);
879 } else if (c == '\n') {
880 /* #define foo */
881 ;
882 } else if (c == 0) {
883 prem();
884 } else if (!ISWS(c))
885 goto bad;
886
887 Cflag = oCflag; /* Enable comments again */
888
889 if (vararg)
890 stringbuf++;
891
892 if (ISWS(c))
893 c = skipwscmnt(0);
894
895 #define DELEWS() while (stringbuf > sbeg+1+(vararg!=NULL) && ISWS(stringbuf[-1])) stringbuf--
896
897 /* parse replacement-list, substituting arguments */
898 wascon = 0;
899 while (c != '\n') {
900 cc[0] = c, cc[1] = inc2();
901 t = getyp(cc);
902 cunput(cc[1]);
903
904 switch (t) {
905 case ' ':
906 case '\t':
907 savch(' '); /* save only one space */
908 while ((c = cinput()) == ' ' || c == '\t')
909 ;
910 continue;
911
912 case '#':
913 if (cc[1] == '#') {
914 /* concat op */
915 (void)cinput(); /* eat # */
916 DELEWS();
917 savch(CONC);
918 if (ISID0(c = skipws(0)) && narg >= 0)
919 wascon = 1;
920 if (c == '\n')
921 goto bad; /* 6.10.3.3 p1 */
922 continue;
923 }
924
925 if (narg < 0) {
926 /* no meaning in object-type macro */
927 savch('#');
928 break;
929 }
930
931 /* remove spaces between # and arg */
932 savch(SNUFF);
933 c = skipws(0); /* whitespace, ignore */
934 if (!ISID0(c))
935 goto bad;
936 bp = heapid(c);
937 if (vararg && strcmp((char *)bp, (char *)vararg) == 0) {
938 stringbuf = bp;
939 savch(WARN);
940 savch(VARG);
941 savch(SNUFF);
942 break;
943
944 }
945 if ((i = findarg(bp, args, narg)) < 0)
946 goto bad;
947 stringbuf = bp;
948 savch(WARN);
949 savch(i);
950 savch(SNUFF);
951 break;
952
953 case NUMBER:
954 c = fastnum(c, savch);
955 continue;
956
957 case STRING:
958 if (c == 'L' || c == 'u' || c == 'U') {
959 savch(c);
960 if ((c = cinput()) == '8') {
961 savch(c);
962 c = cinput();
963 }
964 }
965 if (tflag)
966 savch(c);
967 else
968 faststr(c, savch);
969 break;
970
971 case IDENT:
972 bp = heapid(c);
973 stringbuf--; /* remove \0 */
974 if (narg < 0)
975 break; /* keep on heap */
976 if (vararg && strcmp((char *)bp, (char *)vararg) == 0) {
977 stringbuf = bp;
978 savch(WARN);
979 savch(wascon ? GCCARG : VARG);
980 break;
981 }
982
983 /* check if its an argument */
984 if ((i = findarg(bp, args, narg)) < 0)
985 break;
986 stringbuf = bp;
987 savch(WARN);
988 savch(i);
989 break;
990
991 case 0:
992 goto bad;
993
994 default:
995 savch(c);
996 break;
997 }
998 wascon = 0;
999 c = cinput();
1000 }
1001 cunput(c);
1002 /* remove trailing whitespace */
1003 DELEWS();
1004
1005 if (sbeg[1+(vararg != 0)] == CONC)
1006 goto bad; /* 6.10.3.3 p1 */
1007
1008 if (vararg) {
1009 sbeg[0] = VARG;
1010 sbeg[1] = narg;
1011 } else
1012 sbeg[0] = (narg < 0 ? OBJCT : narg);
1013 savch(0);
1014
1015 if (redef && ifiles->idx != SYSINC) {
1016 if (cmprepl(np->value, sbeg)) { /* not equal */
1017 np->value = sbeg;
1018 warning("%s redefined (previously defined at \"%s\" line %d)",
1019 np->namep, np->file, np->line);
1020 } else
1021 stringbuf = sbeg; /* forget this space */
1022 } else
1023 np->value = sbeg;
1024
1025 #ifdef PCC_DEBUG
1026 if (dflag) {
1027 const usch *w = np->value;
1028
1029 printf("!define %s: ", np->namep);
1030 if (*w == OBJCT)
1031 printf("[object]");
1032 else if (*w == VARG)
1033 printf("[VARG%d]", *++w);
1034 else
1035 printf("[%d]", *w);
1036 putchar('\'');
1037 prrep(++w);
1038 printf("\'\n");
1039 }
1040 #endif
1041 for (i = 0; i < narg; i++)
1042 free(args[i]);
1043 return;
1044
1045 bad: error("bad #define");
1046 }
1047
1048 void
warning(const char * fmt,...)1049 warning(const char *fmt, ...)
1050 {
1051 va_list ap;
1052
1053 if (ifiles != NULL)
1054 fprintf(stderr, "%s:%d: warning: ",
1055 ifiles->fname, ifiles->lineno);
1056
1057 va_start(ap,fmt);
1058 vfprintf(stderr, fmt, ap);
1059 va_end(ap);
1060 fputc('\n', stderr);
1061
1062 warnings++;
1063 }
1064
1065 void
error(const char * fmt,...)1066 error(const char *fmt, ...)
1067 {
1068 va_list ap;
1069
1070 if (ifiles != NULL)
1071 fprintf(stderr, "%s:%d: error: ",
1072 ifiles->fname, ifiles->lineno);
1073
1074 va_start(ap, fmt);
1075 vfprintf(stderr, fmt, ap);
1076 va_end(ap);
1077 fputc('\n', stderr);
1078 exit(1);
1079 }
1080
1081 /*
1082 * store a character into the "define" buffer.
1083 */
1084 void
savch(int c)1085 savch(int c)
1086 {
1087 if (stringbuf >= &sbf[SBSIZE])
1088 error("out of macro space!");
1089
1090 *stringbuf++ = (usch)c;
1091 }
1092
1093 static int
pragwin(struct iobuf * ib)1094 pragwin(struct iobuf *ib)
1095 {
1096 return ib ? *ib->cptr++ : cinput();
1097 }
1098
1099 static int
skipws(struct iobuf * ib)1100 skipws(struct iobuf *ib)
1101 {
1102 int t;
1103
1104 while ((t = pragwin(ib)) == ' ' || t == '\t')
1105 ;
1106 return t;
1107 }
1108
1109 /*
1110 * convert _Pragma() to #pragma for output.
1111 * Syntax is already correct.
1112 */
1113 static void
pragoper(struct iobuf * ib)1114 pragoper(struct iobuf *ib)
1115 {
1116 int t;
1117 usch *bp = stringbuf;
1118
1119 if (skipws(ib) != '(' || ((t = skipws(ib)) != '\"' && t != 'L'))
1120 goto err;
1121 if (t == 'L' && (t = pragwin(ib)) != '\"')
1122 goto err;
1123 savstr((const usch *)"\n#pragma ");
1124 while ((t = pragwin(ib)) != '\"') {
1125 if (t == BLKID) {
1126 pragwin(ib);
1127 continue;
1128 }
1129 if (t == '\"')
1130 continue;
1131 if (t == '\\') {
1132 if ((t = pragwin(ib)) != '\"' && t != '\\')
1133 savch('\\');
1134 }
1135 savch(t);
1136 }
1137 sheap("\n# %d \"%s\"\n", ifiles->lineno, ifiles->fname);
1138 putstr(bp);
1139 stringbuf = bp;
1140 if (skipws(ib) == ')')
1141 return;
1142
1143 err: error("_Pragma() syntax error");
1144 }
1145
1146 static int
expok(struct symtab * sp,int l)1147 expok(struct symtab *sp, int l)
1148 {
1149 struct blocker *w;
1150
1151 if (l == 0)
1152 return 1;
1153 #ifdef PCC_DEBUG
1154 if (dflag) { printf("expok blocked: "); for (w = blkidx[l]; w; w = w->next) printf("%s ", w->sp->namep); printf("\n"); }
1155 #endif
1156 w = blkidx[l];
1157 while (w) {
1158 if (w->sp == sp)
1159 return 0;
1160 w = w->next;
1161 }
1162 return 1;
1163 }
1164
1165 static int
expokb(struct symtab * sp,struct blocker * bl)1166 expokb(struct symtab *sp, struct blocker *bl)
1167 {
1168 struct blocker *w;
1169
1170 if (bl == 0)
1171 return 1;
1172 #ifdef PCC_DEBUG
1173 if (dflag) { printf("expokb blocked: "); for (w = bl; w; w = w->next) printf("%s ", w->sp->namep); printf("\n"); }
1174 #endif
1175 w = bl;
1176 while (w) {
1177 if (w->sp == sp)
1178 return 0;
1179 w = w->next;
1180 }
1181 return 1;
1182 }
1183
1184 static struct blocker *
blkget(struct symtab * sp,struct blocker * obl)1185 blkget(struct symtab *sp, struct blocker *obl)
1186 {
1187 struct blocker *bl = calloc(sizeof(*obl), 1);
1188
1189 bl->sp = sp;
1190 bl->next = obl;
1191 return bl;
1192 }
1193
1194 static int
blkix(struct blocker * obl)1195 blkix(struct blocker *obl)
1196 {
1197 if (blkidp > 1 && blkidx[blkidp-1] == obl)
1198 return blkidp-1;
1199 if (blkidp == RECMAX)
1200 error("blkix");
1201 blkidx[blkidp] = obl;
1202 return blkidp++;
1203 }
1204
1205 static struct blocker *
mergeadd(struct blocker * bl,int m)1206 mergeadd(struct blocker *bl, int m)
1207 {
1208 struct blocker *w, *ww;
1209
1210 DPRINT(("mergeadd: %p %d\n", bl, m));
1211 if (bl == 0)
1212 return blkidx[m];
1213 if (m == 0)
1214 return bl;
1215
1216 blkidx[blkidp] = bl;
1217 for (w = blkidx[m]; w; w = w->next) {
1218 ww = calloc(sizeof(*w), 1);
1219 ww->sp = w->sp;
1220 ww->next = blkidx[blkidp];
1221 blkidx[blkidp] = ww;
1222 }
1223 DPRINT(("mergeadd return: %d ", blkidp));
1224 #ifdef PCC_DEBUG
1225 if (dflag) {
1226 for (w = blkidx[blkidp]; w; w = w->next)
1227 printf("%s ", w->sp->namep);
1228 printf("\n");
1229 }
1230 #endif
1231 return blkidx[blkidp++];
1232 }
1233
1234 static void
storeblk(int l,struct iobuf * ob)1235 storeblk(int l, struct iobuf *ob)
1236 {
1237 DPRINT(("storeblk: %d\n", l));
1238 putob(ob, BLKID);
1239 putob(ob, l);
1240 }
1241
1242 /*
1243 * Save filename on heap (with escaped chars).
1244 */
1245 static usch *
unfname(void)1246 unfname(void)
1247 {
1248 usch *sb = stringbuf;
1249 const usch *bp = ifiles->fname;
1250
1251 savch('\"');
1252 for (; *bp; bp++) {
1253 if (*bp == '\"' || *bp == '\'' || *bp == '\\')
1254 savch('\\');
1255 savch(*bp);
1256 }
1257 savch('\"');
1258 *stringbuf = 0;
1259 return sb;
1260 }
1261
1262 /*
1263 * Version of fastnum that reads from a string and saves in ob.
1264 * We know that it is a number before calling this routine.
1265 */
1266 static usch *
fstrnum(usch * s,struct iobuf * ob)1267 fstrnum(usch *s, struct iobuf *ob)
1268 {
1269 if (*s == '.') {
1270 /* not digit, dot. Next will be digit */
1271 putob(ob, *s++);
1272 }
1273 for (;;) {
1274 putob(ob, *s++);
1275 if ((spechr[*s] & C_EP)) {
1276 if (s[1] != '-' && s[1] != '+')
1277 break;
1278 putob(ob, *s++);
1279 } else if ((*s != '.') && ((spechr[*s] & C_ID) == 0))
1280 break;
1281 }
1282 return s;
1283 }
1284
1285 /*
1286 * get a string or character constant.
1287 * similar to faststr.
1288 */
1289 static usch *
fstrstr(usch * s,struct iobuf * ob)1290 fstrstr(usch *s, struct iobuf *ob)
1291 {
1292 int ch;
1293
1294 if (*s == 'L' || *s == 'U' || *s == 'u')
1295 putob(ob, *s++);
1296 if (*s == '8')
1297 putob(ob, *s++);
1298 ch = *s;
1299 putob(ob, *s++);
1300 while (*s != ch) {
1301 if (*s == '\\')
1302 putob(ob, *s++);
1303 putob(ob, *s++);
1304 }
1305 putob(ob, *s++);
1306 return s;
1307 }
1308
1309 /*
1310 * Save standard comments if found.
1311 */
1312 static usch *
fcmnt(usch * s,struct iobuf * ob)1313 fcmnt(usch *s, struct iobuf *ob)
1314 {
1315 putob(ob, *s++); /* / */
1316 putob(ob, *s++); /* * */
1317 for (;;s++) {
1318 putob(ob, *s);
1319 if (s[-1] == '*' && *s == '/')
1320 break;
1321 }
1322 return s+1;
1323 }
1324
1325 static int
getyp(usch * s)1326 getyp(usch *s)
1327 {
1328
1329 if (ISID0(*s)) return IDENT;
1330 if ((*s == 'L' || *s == 'U' || *s == 'u') &&
1331 (s[1] == '\'' || s[1] == '\"')) return STRING;
1332 if (s[0] == 'u' && s[1] == 'U' && s[2] == '\"') return STRING;
1333 if (s[0] == '\'' || s[0] == '\"') return STRING;
1334 if (spechr[*s] & C_DIGIT) return NUMBER;
1335 if (*s == '.' && (spechr[s[1]] & C_DIGIT)) return NUMBER;
1336 if (*s == '/' && (s[1] == '/' || s[1] == '*')) return CMNT;
1337 return *s;
1338
1339 }
1340
1341 /*
1342 * Check ib and print out the symbols there.
1343 * If expandable symbols found recurse and expand them.
1344 * If last identifier on the input list is expandable return it.
1345 * Expect ib to be zero-terminated.
1346 */
1347 static struct symtab *
loopover(struct iobuf * ib)1348 loopover(struct iobuf *ib)
1349 {
1350 struct iobuf *xb, *xob;
1351 struct symtab *sp;
1352 usch *cp;
1353 int l, c, t;
1354
1355 ib->cptr = ib->buf; /* start from beginning */
1356 #ifdef PCC_DEBUG
1357 if (dflag) {
1358 printf("loopover: '");
1359 prline(ib->cptr);
1360 printf("'\n");
1361 }
1362 #endif
1363
1364 xb = getobuf();
1365 while ((c = *ib->cptr)) {
1366 switch (t = getyp(ib->cptr)) {
1367 case CMNT:
1368 xb->cptr = xb->buf;
1369 ib->cptr = fcmnt(ib->cptr, xb);
1370 *xb->cptr = 0;
1371 savstr(xb->buf);
1372 continue;
1373 case NUMBER:
1374 xb->cptr = xb->buf;
1375 ib->cptr = fstrnum(ib->cptr, xb);
1376 *xb->cptr = 0;
1377 savstr(xb->buf);
1378 continue;
1379 case STRING:
1380 xb->cptr = xb->buf;
1381 ib->cptr = fstrstr(ib->cptr,xb);
1382 *xb->cptr = 0;
1383 for (cp = xb->buf; *cp; cp++) {
1384 if (*cp <= BLKID) {
1385 if (*cp == BLKID)
1386 cp++;
1387 continue;
1388 }
1389 savch(*cp);
1390 }
1391 continue;
1392 case BLKID:
1393 l = ib->cptr[1];
1394 ib->cptr+=2;
1395 /* FALLTHROUGH */
1396 case IDENT:
1397 if (t != BLKID)
1398 l = 0;
1399 /*
1400 * Tricky: if this is the last identifier
1401 * in the expanded list, and it is defined
1402 * as a function-like macro, then push it
1403 * back on the input stream and let fastscan
1404 * handle it as a new macro.
1405 * BUT: if this macro is blocked then this
1406 * should not be done.
1407 */
1408 for (cp = ib->cptr; ISID(*ib->cptr); ib->cptr++)
1409 ;
1410 if ((sp = lookup(cp, FIND)) == NULL) {
1411 sstr: for (; cp < ib->cptr; cp++)
1412 savch(*cp);
1413 continue;
1414 }
1415 if (expok(sp, l) == 0) {
1416 /* blocked */
1417 goto sstr;
1418 } else {
1419 if (*sp->value != OBJCT) {
1420 cp = ib->cptr;
1421 while (ISWS(*ib->cptr))
1422 ib->cptr++;
1423 if (*ib->cptr == 0) {
1424 bufree(xb);
1425 return sp;
1426 }
1427 ib->cptr = cp;
1428 }
1429 newmac: if ((xob = submac(sp, 1, ib, NULL)) == NULL) {
1430 savstr(sp->namep);
1431 } else {
1432 sp = loopover(xob);
1433 bufree(xob);
1434 if (sp != NULL)
1435 goto newmac;
1436 }
1437 }
1438 continue;
1439 default:
1440 savch(c);
1441 }
1442
1443 ib->cptr++;
1444 }
1445
1446 bufree(xb);
1447 DPRINT(("loopover return 0\n"));
1448 return 0;
1449 }
1450
1451 /*
1452 * Handle defined macro keywords found on input stream.
1453 * When finished print out the full expanded line.
1454 * Input here is from the lex buffer.
1455 * Return 1 if success, 0 otherwise. fastscan restores stringbuf.
1456 * Scanned data is stored on heap. Last scan prints out the buffer.
1457 */
1458 int
kfind(struct symtab * sp)1459 kfind(struct symtab *sp)
1460 {
1461 extern int inexpr;
1462 struct blocker *bl;
1463 struct iobuf *ib, *ob;
1464 const usch *argary[MAXARGS+1], *sbp;
1465 int c, n = 0;
1466
1467 blkidp = 1;
1468 sbp = stringbuf;
1469 DPRINT(("%d:enter kfind(%s)\n",0,sp->namep));
1470 switch (*sp->value) {
1471 case FILLOC:
1472 unfname();
1473 return 1;
1474
1475 case LINLOC:
1476 sheap("%d", ifiles->lineno);
1477 return 1;
1478
1479 case PRAGLOC:
1480 pragoper(NULL);
1481 return 1;
1482
1483 case DEFLOC:
1484 case OBJCT:
1485 bl = blkget(sp, NULL);
1486 ib = mkrobuf(sp->value+1);
1487 ob = getobuf();
1488 ob = exparg(1, ib, ob, bl);
1489 bufree(ib);
1490 break;
1491
1492 case CTRLOC:
1493 sheap("%d", counter++);
1494 return 1;
1495
1496 default:
1497 /* Search for '(' */
1498 while (ISWSNL(c = cinput()))
1499 if (c == '\n')
1500 n++;
1501 if (c != '(') {
1502 if (inexpr == 0)
1503 putstr(sp->namep);
1504 if (n == 0)
1505 putch(' ');
1506 else for (ifiles->lineno += n; n; n--)
1507 putch('\n');
1508 cunput(c);
1509 return 0; /* Failed */
1510 }
1511
1512 /* fetch arguments */
1513 again: if (readargs1(sp, argary))
1514 error("readargs");
1515
1516 bl = blkget(sp, NULL);
1517 ib = subarg(sp, argary, 1, bl);
1518 ob = getobuf();
1519 ob = exparg(1, ib, ob, bl);
1520 bufree(ib);
1521 break;
1522 }
1523
1524 /*
1525 * Loop over stringbuf, output the data and remove remaining
1526 * directives. Start with extracting the last keyword (if any).
1527 */
1528 putob(ob, 0); /* XXX needed? */
1529
1530 stringbuf = (usch *)sbp; /* XXX should check cleanup */
1531 if ((sp = loopover(ob))) {
1532 /* Search for '(' */
1533 while (ISWSNL(c = cinput()))
1534 if (c == '\n')
1535 n++;
1536 if (c == '(') {
1537 bufree(ob);
1538 goto again;
1539 }
1540 cunput(c);
1541 savstr(sp->namep);
1542 }
1543 bufree(ob);
1544
1545 for (ifiles->lineno += n; n; n--)
1546 savch('\n');
1547 savch(0);
1548 stringbuf = (usch *)sbp;
1549 if (nbufused)
1550 error("lost buffer");
1551 return 1;
1552 }
1553
1554 /*
1555 * Replace and push-back on input stream the eventual replaced macro.
1556 * The check for whether it can expand or not should already have been done.
1557 * Blocks for this identifier will be added via insblock() after expansion.
1558 * The same as kfind but read a string.
1559 */
1560 struct iobuf *
submac(struct symtab * sp,int lvl,struct iobuf * ib,struct blocker * obl)1561 submac(struct symtab *sp, int lvl, struct iobuf *ib, struct blocker *obl)
1562 {
1563 struct blocker *bl;
1564 struct iobuf *ob;
1565 const usch *argary[MAXARGS+1];
1566 usch *cp, *pr;
1567
1568 DPRINT(("%d:submac: trying '%s'\n", lvl, sp->namep));
1569 switch (*sp->value) {
1570 case FILLOC:
1571 ob = strtobuf(unfname(), NULL);
1572 break;
1573 case LINLOC:
1574 ob = strtobuf(sheap("%d", ifiles->lineno), NULL);
1575 break;
1576 case PRAGLOC:
1577 pragoper(ib);
1578 ob = strtobuf((usch *)"", NULL);
1579 break;
1580 case OBJCT:
1581 bl = blkget(sp, obl);
1582 ib = mkrobuf(sp->value+1);
1583 ob = getobuf();
1584 DPRINT(("%d:submac: calling exparg\n", lvl));
1585 ob = exparg(lvl+1, ib, ob, bl);
1586 bufree(ib);
1587 DPRINT(("%d:submac: return exparg\n", lvl));
1588 break;
1589 case CTRLOC:
1590 ob = strtobuf(sheap("%d", counter++), NULL);
1591 break;
1592 default:
1593 cp = ib->cptr;
1594 while (ISWSNL(*ib->cptr))
1595 ib->cptr++;
1596 if (*ib->cptr != '(') {
1597 ib->cptr = cp;
1598 return 0;
1599 }
1600 cp = ib->cptr++;
1601 pr = stringbuf;
1602 if (readargs2(&ib->cptr, sp, argary)) {
1603 /* Bailed out in the middle of arg list */
1604 ib->cptr = cp; /* XXX */
1605 return 0;
1606 }
1607 bl = blkget(sp, obl);
1608 ib = subarg(sp, argary, lvl+1, bl);
1609 stringbuf = pr;
1610
1611 ob = getobuf();
1612 DPRINT(("%d:submac(: calling exparg\n", lvl));
1613 ob = exparg(lvl+1, ib, ob, bl);
1614 bufree(ib);
1615 DPRINT(("%d:submac(: return exparg\n", lvl));
1616 break;
1617 }
1618 putob(ob, 0);
1619 ob->cptr--;
1620
1621 return ob;
1622 }
1623
1624 static int
isdir(void)1625 isdir(void)
1626 {
1627 usch ch;
1628
1629 while ((ch = cinput()) == ' ' || ch == '\t')
1630 ;
1631 if (ch == '#')
1632 return 1;
1633 cunput(ch);
1634 return 0;
1635 }
1636
1637 /*
1638 * Deal with directives inside a macro.
1639 * Doing so is really ugly but gcc allows it, so...
1640 */
1641 static void
chkdir(void)1642 chkdir(void)
1643 {
1644 usch ch;
1645
1646 for (;;) {
1647 if (isdir()) {
1648 #ifndef GCC_COMPAT
1649 warning("conditionals inside macro arg list");
1650 #endif
1651 ppdir();
1652 }
1653 if (flslvl == 0)
1654 return;
1655 while ((ch = cinput()) != '\n')
1656 ;
1657 ifiles->lineno++;
1658 putch('\n');
1659 }
1660 }
1661
1662 static int
ra1_wsnl(int sp)1663 ra1_wsnl(int sp)
1664 {
1665 int c;
1666
1667 while (ISWSNL(c = cinput())) {
1668 if (c == '\n') {
1669 putch('\n');
1670 chkdir();
1671 ifiles->lineno++;
1672 if (sp) savch(' ');
1673 }
1674 }
1675 return c;
1676 }
1677
1678 /*
1679 * Read arguments and put in argument array.
1680 * If EOF is encountered return 1, otherwise 0.
1681 */
1682 int
readargs1(struct symtab * sp,const usch ** args)1683 readargs1(struct symtab *sp, const usch **args)
1684 {
1685 const usch *vp = sp->value;
1686 int c, i, plev, narg, ellips = 0;
1687
1688 DPRINT(("readargs1\n"));
1689 narg = *vp++;
1690 if (narg == VARG) {
1691 narg = *vp++;
1692 ellips = 1;
1693 }
1694 #ifdef PCC_DEBUG
1695 if (dflag > 1) {
1696 printf("narg %d varg %d: ", narg, ellips);
1697 prrep(vp);
1698 printf("\n");
1699 }
1700 #endif
1701
1702 /*
1703 * read arguments and store them on heap.
1704 */
1705 c = '(';
1706 for (i = 0; i < narg && c != ')'; i++) {
1707 args[i] = stringbuf;
1708 plev = 0;
1709
1710 c = ra1_wsnl(0);
1711 for (;;) {
1712 if (plev == 0 && (c == ')' || c == ','))
1713 break;
1714 if (c == '(') plev++;
1715 if (c == ')') plev--;
1716 if (c == 0)
1717 error("eof in macro");
1718 else if (c == '/') Ccmnt(savch);
1719 else if (c == '\"' || c == '\'') faststr(c, savch);
1720 else if (ISID0(c)) {
1721 usch *bp = stringbuf;
1722 do {
1723 savch(c);
1724 } while ((spechr[c = cinput()] & C_ID));
1725 if ((sp = lookup(bp, FIND)) != NULL) {
1726 if (sp == linloc) {
1727 stringbuf = bp;
1728 sheap("%d", ifiles->lineno);
1729 } else if (sp == ctrloc) {
1730 stringbuf = bp;
1731 sheap("%d", counter++);
1732 }
1733 }
1734 cunput(c);
1735 } else
1736 savch(c);
1737 if ((c = cinput()) == '\n') {
1738 chkdir();
1739 ifiles->lineno++, putch(c), c = ' ';
1740 }
1741 }
1742
1743 while (args[i] < stringbuf && ISWSNL(stringbuf[-1]))
1744 stringbuf--;
1745 savch('\0');
1746 #ifdef PCC_DEBUG
1747 if (dflag) {
1748 printf("readargs: save arg %d '", i);
1749 prline(args[i]);
1750 printf("'\n");
1751 }
1752 #endif
1753 }
1754
1755 /* Handle varargs readin */
1756 if (ellips)
1757 args[i] = (const usch *)"";
1758 if (ellips && c != ')') {
1759 args[i] = stringbuf;
1760 plev = 0;
1761 c = ra1_wsnl(0);
1762 for (;;) {
1763 if (plev == 0 && c == ')')
1764 break;
1765 if (c == '(') plev++;
1766 if (c == ')') plev--;
1767 if (c == '\"' || c == '\'') faststr(c, savch);
1768 else
1769 savch(c);
1770 if ((c = cinput()) == '\n')
1771 ifiles->lineno++, c = ' ';
1772 }
1773 while (args[i] < stringbuf && ISWSNL(stringbuf[-1]))
1774 stringbuf--;
1775 savch('\0');
1776 #ifdef PCC_DEBUG
1777 if (dflag) {
1778 printf("readargs: vararg arg %d '", i);
1779 prline(args[i]);
1780 printf("'\n");
1781 }
1782 #endif
1783
1784 }
1785 if (narg == 0 && ellips == 0)
1786 c = ra1_wsnl(0);
1787
1788 if (c != ')' || (i != narg && ellips == 0) || (i < narg && ellips == 1))
1789 error("wrong arg count");
1790 return 0;
1791 }
1792
1793 static usch *raptr;
1794 static int
raread(void)1795 raread(void)
1796 {
1797 int rv;
1798
1799 if (raptr) {
1800 if ((rv = *raptr))
1801 raptr++;
1802 } else
1803 rv = cinput();
1804 return rv;
1805 }
1806
1807
1808 /*
1809 * Read arguments and put in argument array.
1810 * If EOF is encountered return 1, otherwise 0.
1811 */
1812 int
readargs2(usch ** inp,struct symtab * sp,const usch ** args)1813 readargs2(usch **inp, struct symtab *sp, const usch **args)
1814 {
1815 const usch *vp = sp->value;
1816 usch *bp;
1817 int c, i, plev, narg, ellips = 0;
1818
1819 DPRINT(("readargs2 %s '", sp->namep));
1820 #ifdef PCC_DEBUG
1821 if (dflag && inp) {
1822 prline(*inp);
1823 printf("'\n");
1824 }
1825 #endif
1826 raptr = inp ? *inp : 0;
1827 narg = *vp++;
1828 if (narg == VARG) {
1829 narg = *vp++;
1830 ellips = 1;
1831 }
1832 #ifdef PCC_DEBUG
1833 if (dflag > 1) {
1834 prrep(vp);
1835 printf("\n");
1836 }
1837 #endif
1838
1839
1840 /*
1841 * read arguments and store them on heap.
1842 */
1843 c = '(';
1844 for (i = 0; i < narg && c != ')'; i++) {
1845 args[i] = stringbuf;
1846 plev = 0;
1847
1848 while ((c = raread()) == ' ' || c == '\t')
1849 ;
1850 for (;;) {
1851 if (plev == 0 && (c == ')' || c == ','))
1852 break;
1853 if (c == '(') plev++;
1854 if (c == ')') plev--;
1855 if (c == 0) {
1856 if (raptr) {
1857 *inp = raptr;
1858 raptr = 0;
1859 } else
1860 error("eof in macro");
1861 } else if (c == BLKID) {
1862 savch(c), savch(raread());
1863 } else if (c == '/') {
1864 if ((c = raread()) == '*')
1865 error("FIXME ccmnt");
1866 savch('/');
1867 continue;
1868 } else if (c == '\"' || c == '\'') {
1869 if (raptr) {
1870 struct iobuf *xob = getobuf();
1871 raptr = fstrstr(raptr-1, xob);
1872 *xob->cptr = 0;
1873 savstr(xob->buf);
1874 bufree(xob);
1875 } else
1876 faststr(c, savch);
1877 } else if (ISID0(c)) {
1878 bp = stringbuf;
1879 do {
1880 savch(c);
1881 } while (ISID(c = raread()));
1882 *stringbuf = 0;
1883 if ((sp = lookup(bp, FIND)) && (sp == linloc)) {
1884 stringbuf = bp;
1885 sheap("%d", ifiles->lineno);
1886 }
1887 continue;
1888 } else
1889 savch(c);
1890 c = raread();
1891 }
1892
1893 while (args[i] < stringbuf && ISWSNL(stringbuf[-1]))
1894 stringbuf--;
1895 savch('\0');
1896 #ifdef PCC_DEBUG
1897 if (dflag) {
1898 printf("readargs2: save arg %d '", i);
1899 prline(args[i]);
1900 printf("'\n");
1901 }
1902 #endif
1903 }
1904
1905 /* Handle varargs readin */
1906 if (ellips)
1907 args[i] = (const usch *)"";
1908 if (ellips && c != ')') {
1909 args[i] = stringbuf;
1910 plev = 0;
1911 while ((c = raread()) == ' ' || c == '\t')
1912 ;
1913 for (;;) {
1914 if (plev == 0 && c == ')')
1915 break;
1916 if (c == '(') plev++;
1917 if (c == ')') plev--;
1918 if (c == '\"' || c == '\'') {
1919 if (raptr) {
1920 struct iobuf *xob = getobuf();
1921 raptr = fstrstr(raptr-1, xob);
1922 *xob->cptr = 0;
1923 savstr(xob->buf);
1924 bufree(xob);
1925 } else
1926 faststr(c, savch);
1927 } else
1928 savch(c);
1929 c = raread();
1930 }
1931 while (args[i] < stringbuf && ISWSNL(stringbuf[-1]))
1932 stringbuf--;
1933 savch('\0');
1934
1935 }
1936 if (narg == 0 && ellips == 0) {
1937 while ((c = raread()) == ' ' || c == '\t')
1938 ;
1939 }
1940
1941 if (c != ')' || (i != narg && ellips == 0) || (i < narg && ellips == 1))
1942 error("wrong arg count");
1943 if (raptr)
1944 *inp = raptr;
1945 return 0;
1946 }
1947
1948 /*
1949 * expand a function-like macro.
1950 * vp points to end of replacement-list
1951 * reads function arguments from input stream.
1952 * result is pushed-back for more scanning.
1953 */
1954 struct iobuf *
subarg(struct symtab * nl,const usch ** args,int lvl,struct blocker * bl)1955 subarg(struct symtab *nl, const usch **args, int lvl, struct blocker *bl)
1956 {
1957 struct blocker *w;
1958 struct iobuf *ob, *cb, *nb;
1959 int narg, instr, snuff;
1960 const usch *sp, *bp, *ap, *vp, *tp;
1961
1962 DPRINT(("%d:subarg '%s'\n", lvl, nl->namep));
1963 ob = getobuf();
1964 vp = nl->value;
1965 narg = *vp++;
1966 if (narg == VARG)
1967 narg = *vp++;
1968
1969 sp = vp;
1970 instr = snuff = 0;
1971 #ifdef PCC_DEBUG
1972 if (dflag>1) {
1973 printf("%d:subarg ARGlist for %s: '", lvl, nl->namep);
1974 prrep(vp);
1975 printf("' ");
1976 for (w = bl; w; w = w->next)
1977 printf("%s ", w->sp->namep);
1978 printf("\n");
1979 }
1980 #endif
1981
1982 /*
1983 * walk forward over replacement-list while replacing
1984 * arguments. Arguments are macro-expanded if required.
1985 */
1986 while (*sp) {
1987 if (*sp == SNUFF)
1988 putob(ob, '\"'), snuff ^= 1;
1989 else if (*sp == CONC)
1990 ;
1991 else if (*sp == WARN) {
1992
1993 if (sp[1] == VARG) {
1994 bp = ap = args[narg];
1995 sp++;
1996 #ifdef GCC_COMPAT
1997 } else if (sp[1] == GCCARG) {
1998 /* XXX remove last , not add 0 */
1999 ap = args[narg];
2000 if (ap[0] == 0)
2001 ap = (const usch *)"0";
2002 bp = ap;
2003 sp++;
2004 #endif
2005 } else
2006 bp = ap = args[(int)*++sp];
2007 #ifdef PCC_DEBUG
2008 if (dflag>1){
2009 printf("%d:subarg GOTwarn; arglist '", lvl);
2010 prline(bp);
2011 printf("'\n");
2012 }
2013 #endif
2014 if (sp[-2] != CONC && !snuff && sp[1] != CONC) {
2015 /*
2016 * Expand an argument; 6.10.3.1:
2017 * "A parameter in the replacement list,
2018 * is replaced by the corresponding argument
2019 * after all macros contained therein have
2020 * been expanded.".
2021 */
2022 w = bl ? bl->next : NULL;
2023 cb = mkrobuf(bp);
2024 nb = getobuf();
2025 DPRINT(("%d:subarg: calling exparg\n", lvl));
2026 nb = exparg(lvl+1, cb, nb, w);
2027 DPRINT(("%d:subarg: return exparg\n", lvl));
2028 bufree(cb);
2029 strtobuf(nb->buf, ob);
2030 bufree(nb);
2031 } else {
2032 while (*bp) {
2033 if (snuff && !instr && ISWS(*bp)) {
2034 while (ISWS(*bp))
2035 bp++;
2036 putob(ob, ' ');
2037 }
2038
2039 if (snuff &&
2040 (*bp == '\'' || *bp == '"')) {
2041 instr ^= 1;
2042 for (tp = bp - 1; *tp == '\\'; tp--)
2043 instr ^= 1;
2044 if (*bp == '"')
2045 putob(ob, '\\');
2046 }
2047 if (snuff && instr && *bp == '\\')
2048 putob(ob, '\\');
2049 putob(ob, *bp);
2050 bp++;
2051 }
2052 }
2053 } else if (ISID0(*sp)) {
2054 if (lookup(sp, FIND))
2055 storeblk(blkix(bl), ob);
2056 while (ISID(*sp))
2057 putob(ob, *sp++);
2058 sp--;
2059 } else
2060 putob(ob, *sp);
2061 sp++;
2062 }
2063 putob(ob, 0);
2064 ob->cptr = ob->buf;
2065 DPRINT(("%d:subarg retline %s\n", lvl, ob->buf));
2066 return ob;
2067 }
2068
2069 /*
2070 * Do a (correct) expansion of a WARN-terminated buffer of tokens.
2071 * Data is read from the lex buffer, result on lex buffer, WARN-terminated.
2072 * Expansion blocking is not altered here unless when tokens are
2073 * concatenated, in which case they are removed.
2074 */
2075 struct iobuf *
exparg(int lvl,struct iobuf * ib,struct iobuf * ob,struct blocker * bl)2076 exparg(int lvl, struct iobuf *ib, struct iobuf *ob, struct blocker *bl)
2077 {
2078 extern int inexpr;
2079 struct iobuf *nob;
2080 struct symtab *nl;
2081 int c, m;
2082 usch *cp, *bp, *sbp;
2083
2084 DPRINT(("%d:exparg: entry ib %s\n", lvl, ib->cptr));
2085 #ifdef PCC_DEBUG
2086 if (dflag > 1) {
2087 printf("exparg entry: full ");
2088 prline(ib->cptr);
2089 printf("\n");
2090 }
2091 #endif
2092
2093 while ((c = getyp(ib->cptr)) != 0) {
2094 ib->cptr++;
2095
2096 switch (c) {
2097
2098 case CMNT:
2099 ib->cptr = fcmnt(ib->cptr-1, ob);
2100 break;
2101 case NUMBER:
2102 ib->cptr = fstrnum(ib->cptr-1, ob);
2103 break;
2104 case STRING:
2105 ib->cptr = fstrstr(ib->cptr-1, ob);
2106 break;
2107 case BLKID:
2108 m = *ib->cptr++;
2109 ib->cptr++;
2110 /* FALLTHROUGH */
2111 case IDENT:
2112 if (c != BLKID)
2113 m = 0;
2114 for (cp = ib->cptr-1; ISID(*cp); cp++)
2115 ;
2116 #ifdef PCC_DEBUG
2117 if (dflag) { printf("!! ident "); prline(ib->cptr-1); printf("\n"); }
2118 #endif
2119 sbp = stringbuf;
2120 if (*cp == BLKID) {
2121 /* concatenation */
2122 bp = stringbuf;
2123 for (cp = ib->cptr-1;
2124 ISID(*cp) || *cp == BLKID; cp++) {
2125 if (*cp == BLKID) {
2126 /* XXX add to block list */
2127 cp++;
2128 } else
2129 savch(*cp);
2130 }
2131 ib->cptr = cp;
2132 cp = stringbuf;
2133 savch(0);
2134 } else {
2135 bp = ib->cptr-1;
2136 ib->cptr = cp;
2137 }
2138 #ifdef PCC_DEBUG
2139 if (dflag) { printf("!! ident2 "); prline(bp); printf("\n"); }
2140 #endif
2141 if ((nl = lookup(bp, FIND)) == NULL) {
2142 sstr: for (; bp < cp; bp++)
2143 putob(ob, *bp);
2144 stringbuf = sbp;
2145 break;
2146 } else if (inexpr && *nl->value == DEFLOC) {
2147 int gotlp = 0;
2148 while (ISWS(*ib->cptr)) ib->cptr++;
2149 if (*ib->cptr == '(')
2150 gotlp++, ib->cptr++;
2151 while (ISWS(*ib->cptr)) ib->cptr++;
2152 if (!ISID0(*ib->cptr))
2153 error("bad defined");
2154 putob(ob, lookup(ib->cptr, FIND) ? '1' : '0');
2155 while (ISID(*ib->cptr)) ib->cptr++;
2156 while (ISWS(*ib->cptr)) ib->cptr++;
2157 if (gotlp && *ib->cptr != ')')
2158 error("bad defined");
2159 ib->cptr++;
2160 break;
2161 }
2162 stringbuf = sbp;
2163 if (expokb(nl, bl) && expok(nl, m)) {
2164 if ((nob = submac(nl, lvl+1, ib, bl))) {
2165 if (nob->buf[0] == '-' ||
2166 nob->buf[0] == '+')
2167 putob(ob, ' ');
2168 strtobuf(nob->buf, ob);
2169 if (ob->cptr[-1] == '-' ||
2170 ob->cptr[-1] == '+')
2171 putob(ob, ' ');
2172 bufree(nob);
2173 } else {
2174 goto sblk;
2175 }
2176 } else {
2177 /* blocked */
2178 sblk: storeblk(blkix(mergeadd(bl, m)), ob);
2179 goto sstr;
2180 }
2181 break;
2182
2183 default:
2184 putob(ob, c);
2185 break;
2186 }
2187 }
2188 putob(ob, 0);
2189 ob->cptr--;
2190 DPRINT(("%d:exparg return: ob %s\n", lvl, ob->buf));
2191 #ifdef PCC_DEBUG
2192 if (dflag > 1) {
2193 printf("%d:exparg: full ", lvl);
2194 prline(ob->buf);
2195 printf("\n");
2196 }
2197 #endif
2198 return ob;
2199 }
2200
2201 #ifdef PCC_DEBUG
2202
2203 static void
prrep(const usch * s)2204 prrep(const usch *s)
2205 {
2206 while (*s) {
2207 switch (*s) {
2208 case WARN:
2209 if (s[1] == VARG) printf("<VARG>");
2210 else if (s[1] == GCCARG) printf("<GCCARG>");
2211 else printf("<ARG(%d)>", s[1]);
2212 s++;
2213 break;
2214 case CONC: printf("<CONC>"); break;
2215 case SNUFF: printf("<SNUFF>"); break;
2216 case BLKID: printf("<BLKID(%d)>",s[1]); s++; break;
2217 default: printf("%c", *s); break;
2218 }
2219 s++;
2220 }
2221 }
2222
2223 static void
prline(const usch * s)2224 prline(const usch *s)
2225 {
2226 while (*s) {
2227 switch (*s) {
2228 case BLKID: printf("<BLKID(%d)>", *++s); break;
2229 case WARN: printf("<WARN>"); break;
2230 case CONC: printf("<CONC>"); break;
2231 case SNUFF: printf("<SNUFF>"); break;
2232 case '\n': printf("<NL>"); break;
2233 default:
2234 if (*s > 0x7f)
2235 printf("<0x%x>", *s);
2236 else
2237 printf("%c", *s);
2238 break;
2239 }
2240 s++;
2241 }
2242 }
2243 #endif
2244
2245 usch *
savstr(const usch * str)2246 savstr(const usch *str)
2247 {
2248 usch *rv = stringbuf;
2249
2250 do {
2251 if (stringbuf >= &sbf[SBSIZE])
2252 error("out of macro space!");
2253 } while ((*stringbuf++ = *str++));
2254 stringbuf--;
2255 return rv;
2256 }
2257
2258 void
putch(int ch)2259 putch(int ch)
2260 {
2261 if (Mflag)
2262 return;
2263 fputc(ch, stdout);
2264 }
2265
2266 void
putstr(const usch * s)2267 putstr(const usch *s)
2268 {
2269 for (; *s; s++) {
2270 if (Mflag == 0)
2271 fputc(*s, stdout);
2272 }
2273 }
2274
2275 /*
2276 * convert a number to an ascii string. Store it on the heap.
2277 */
2278 static void
num2str(int num)2279 num2str(int num)
2280 {
2281 static usch buf[12];
2282 usch *b = buf;
2283 int m = 0;
2284
2285 if (num < 0)
2286 num = -num, m = 1;
2287 do {
2288 *b++ = (usch)(num % 10 + '0');
2289 num /= 10;
2290 } while (num);
2291 if (m)
2292 *b++ = '-';
2293 while (b > buf)
2294 savch(*--b);
2295 }
2296
2297 /*
2298 * similar to sprintf, but only handles %c, %s and %d.
2299 * saves result on heap.
2300 */
2301 static void
vsheap(const char * fmt,va_list ap)2302 vsheap(const char *fmt, va_list ap)
2303 {
2304 for (; *fmt; fmt++) {
2305 if (*fmt == '%') {
2306 fmt++;
2307 switch (*fmt) {
2308 case 's':
2309 savstr(va_arg(ap, usch *));
2310 break;
2311 case 'd':
2312 num2str(va_arg(ap, int));
2313 break;
2314 case 'c':
2315 savch(va_arg(ap, int));
2316 break;
2317 default:
2318 error("bad sheap");
2319 }
2320 } else
2321 savch(*fmt);
2322 }
2323 *stringbuf = 0;
2324 }
2325
2326 usch *
sheap(const char * fmt,...)2327 sheap(const char *fmt, ...)
2328 {
2329 va_list ap;
2330 usch *op = stringbuf;
2331
2332 va_start(ap, fmt);
2333 vsheap(fmt, ap);
2334 va_end(ap);
2335
2336 return op;
2337 }
2338
2339 static void
usage(void)2340 usage(void)
2341 {
2342 error("Usage: cpp [-Cdt] [-Dvar=val] [-Uvar] [-Ipath] [-Spath]");
2343 }
2344
2345 #ifdef notyet
2346 /*
2347 * Symbol table stuff.
2348 * The data structure used is a patricia tree implementation using only
2349 * bytes to store offsets.
2350 * The information stored is (lower address to higher):
2351 *
2352 * unsigned char bitno[2]; bit number in the string
2353 * unsigned char left[3]; offset from base to left element
2354 * unsigned char right[3]; offset from base to right element
2355 */
2356 #endif
2357
2358 /*
2359 * This patricia implementation is more-or-less the same as
2360 * used in ccom for string matching.
2361 */
2362 struct tree {
2363 int bitno;
2364 struct tree *lr[2];
2365 };
2366
2367 #define BITNO(x) ((x) & ~(LEFT_IS_LEAF|RIGHT_IS_LEAF))
2368 #define LEFT_IS_LEAF 0x80000000
2369 #define RIGHT_IS_LEAF 0x40000000
2370 #define IS_LEFT_LEAF(x) (((x) & LEFT_IS_LEAF) != 0)
2371 #define IS_RIGHT_LEAF(x) (((x) & RIGHT_IS_LEAF) != 0)
2372 #define P_BIT(key, bit) (key[bit >> 3] >> (bit & 7)) & 1
2373 #define CHECKBITS 8
2374
2375 static struct tree *sympole;
2376 static int numsyms;
2377
2378 static struct tree *
gtree(void)2379 gtree(void)
2380 {
2381 static int ntrees;
2382 static struct tree *tp;
2383
2384 if (ntrees == 0) {
2385 tp = xmalloc(BUFSIZ);
2386 ntrees = BUFSIZ/sizeof(*tp);
2387 }
2388 return &tp[--ntrees];
2389 }
2390
2391 /*
2392 * Allocate a symtab struct and store the string.
2393 */
2394 static struct symtab *
getsymtab(const usch * str)2395 getsymtab(const usch *str)
2396 {
2397 static int nsyms;
2398 static struct symtab *spp;
2399 struct symtab *sp;
2400
2401 if (nsyms == 0) {
2402 spp = xmalloc(BUFSIZ);
2403 nsyms = BUFSIZ/sizeof(*sp);
2404 }
2405 sp = &spp[--nsyms];
2406
2407 sp->namep = str;
2408 sp->value = NULL;
2409 sp->file = ifiles ? ifiles->orgfn : (const usch *)"<initial>";
2410 sp->line = ifiles ? ifiles->lineno : 0;
2411 return sp;
2412 }
2413
2414 /*
2415 * Do symbol lookup in a patricia tree.
2416 * Only do full string matching, no pointer optimisations.
2417 */
2418 struct symtab *
lookup(const usch * key,int enterf)2419 lookup(const usch *key, int enterf)
2420 {
2421 struct symtab *sp;
2422 struct tree *w, *new, *last;
2423 int len, cix, bit, fbit, svbit, ix, bitno;
2424 const usch *k, *m;
2425
2426 /* Count full string length */
2427 for (k = key, len = 0; ISID(*k) & C_ID; k++, len++)
2428 ;
2429
2430 switch (numsyms) {
2431 case 0: /* no symbols yet */
2432 if (enterf != ENTER)
2433 return NULL;
2434 sympole = (struct tree *)getsymtab(key);
2435 numsyms++;
2436 return (struct symtab *)sympole;
2437
2438 case 1:
2439 w = sympole;
2440 svbit = 0; /* XXX gcc */
2441 break;
2442
2443 default:
2444 w = sympole;
2445 bitno = len * CHECKBITS;
2446 for (;;) {
2447 bit = BITNO(w->bitno);
2448 fbit = bit >= bitno ? 0 : P_BIT(key, bit);
2449 svbit = fbit ? IS_RIGHT_LEAF(w->bitno) :
2450 IS_LEFT_LEAF(w->bitno);
2451 w = w->lr[fbit];
2452 if (svbit)
2453 break;
2454 }
2455 }
2456
2457 sp = (struct symtab *)w;
2458
2459 m = sp->namep;
2460 k = key;
2461
2462 /* Check for correct string and return */
2463 for (cix = 0; *m && ISID(*k) && *m == *k; m++, k++, cix += CHECKBITS)
2464 ;
2465 if (*m == 0 && ISID(*k) == 0) {
2466 if (enterf != ENTER && sp->value == NULL)
2467 return NULL;
2468 return sp;
2469 }
2470
2471 if (enterf != ENTER)
2472 return NULL; /* no string found and do not enter */
2473
2474 ix = *m ^ *k;
2475 while ((ix & 1) == 0)
2476 ix >>= 1, cix++;
2477
2478 /* Create new node */
2479 new = gtree();
2480 bit = P_BIT(key, cix);
2481 new->bitno = cix | (bit ? RIGHT_IS_LEAF : LEFT_IS_LEAF);
2482 new->lr[bit] = (struct tree *)getsymtab(key);
2483
2484 if (numsyms++ == 1) {
2485 new->lr[!bit] = sympole;
2486 new->bitno |= (bit ? LEFT_IS_LEAF : RIGHT_IS_LEAF);
2487 sympole = new;
2488 return (struct symtab *)new->lr[bit];
2489 }
2490
2491 w = sympole;
2492 last = NULL;
2493 for (;;) {
2494 fbit = w->bitno;
2495 bitno = BITNO(w->bitno);
2496 if (bitno == cix)
2497 error("bitno == cix");
2498 if (bitno > cix)
2499 break;
2500 svbit = P_BIT(key, bitno);
2501 last = w;
2502 w = w->lr[svbit];
2503 if (fbit & (svbit ? RIGHT_IS_LEAF : LEFT_IS_LEAF))
2504 break;
2505 }
2506
2507 new->lr[!bit] = w;
2508 if (last == NULL) {
2509 sympole = new;
2510 } else {
2511 last->lr[svbit] = new;
2512 last->bitno &= ~(svbit ? RIGHT_IS_LEAF : LEFT_IS_LEAF);
2513 }
2514 if (bitno < cix)
2515 new->bitno |= (bit ? LEFT_IS_LEAF : RIGHT_IS_LEAF);
2516 return (struct symtab *)new->lr[bit];
2517 }
2518
2519 static void *
xmalloc(int sz)2520 xmalloc(int sz)
2521 {
2522 usch *rv;
2523
2524 if ((rv = (void *)malloc(sz)) == NULL)
2525 error("xmalloc: out of mem");
2526 return rv;
2527 }
2528
2529 static void *
xrealloc(void * p,int sz)2530 xrealloc(void *p, int sz)
2531 {
2532 usch *rv;
2533
2534 if ((rv = (void *)realloc(p, sz)) == NULL)
2535 error("xrealloc: out of mem");
2536 return rv;
2537 }
2538
2539 static usch *
xstrdup(const usch * str)2540 xstrdup(const usch *str)
2541 {
2542 usch *rv;
2543
2544 if ((rv = (usch *)strdup((const char *)str)) == NULL)
2545 error("xstrdup: out of mem");
2546 return rv;
2547 }
2548