source: mainline/uspace/app/pcc/cc/cpp/cpp.c@ a7de7182

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since a7de7182 was a7de7182, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 14 years ago

Added pcc source tree (contents of pcc-1.0.0.tgz)

  • Property mode set to 100644
File size: 37.5 KB
Line 
1/* $Id: cpp.c,v 1.124.2.2 2011/03/27 13:17:19 ragge Exp $ */
2
3/*
4 * Copyright (c) 2004,2010 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 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28/*
29 * The C preprocessor.
30 * This code originates from the V6 preprocessor with some additions
31 * from V7 cpp, and at last ansi/c99 support.
32 */
33
34#include "config.h"
35
36#ifdef HAVE_SYS_WAIT_H
37#include <sys/wait.h>
38#endif
39#include <sys/stat.h>
40
41#include <fcntl.h>
42#ifdef HAVE_UNISTD_H
43#include <unistd.h>
44#endif
45#include <stdio.h>
46#include <stdarg.h>
47#include <stdlib.h>
48#include <string.h>
49#include <time.h>
50#include <ctype.h>
51
52#include "compat.h"
53#include "cpp.h"
54#include "y.tab.h"
55
56#define SBSIZE 1000000
57
58static usch sbf[SBSIZE];
59/* C command */
60
61int tflag; /* traditional cpp syntax */
62#ifdef CPP_DEBUG
63int dflag; /* debug printouts */
64#define DPRINT(x) if (dflag) printf x
65#define DDPRINT(x) if (dflag > 1) printf x
66#else
67#define DPRINT(x)
68#define DDPRINT(x)
69#endif
70
71int ofd;
72usch outbuf[CPPBUF];
73int obufp, istty;
74int Cflag, Mflag, dMflag, Pflag;
75usch *Mfile;
76struct initar *initar;
77int readmac, lastoch;
78
79/* include dirs */
80struct incs {
81 struct incs *next;
82 usch *dir;
83 dev_t dev;
84 ino_t ino;
85} *incdir[2];
86#define INCINC 0
87#define SYSINC 1
88
89static struct symtab *filloc;
90static struct symtab *linloc;
91static struct symtab *pragloc;
92int trulvl;
93int flslvl;
94int elflvl;
95int elslvl;
96usch *stringbuf = sbf;
97
98/*
99 * Macro replacement list syntax:
100 * - For object-type macros, replacement strings are stored as-is.
101 * - For function-type macros, macro args are substituted for the
102 * character WARN followed by the argument number.
103 * - The value element points to the end of the string, to simplify
104 * pushback onto the input queue.
105 *
106 * The first character (from the end) in the replacement list is
107 * the number of arguments:
108 * VARG - ends with ellipsis, next char is argcount without ellips.
109 * OBJCT - object-type macro
110 * 0 - empty parenthesis, foo()
111 * 1-> - number of args.
112 *
113 * WARN is used:
114 * - in stored replacement lists to tell that an argument comes
115 * - When expanding replacement lists to tell that the list ended.
116 *
117 * To ensure that an already expanded identifier won't get expanded
118 * again a EBLOCK char + its number is stored directly before any
119 * expanded identifier.
120 */
121
122/* args for lookup() */
123#define FIND 0
124#define ENTER 1
125
126static int readargs(struct symtab *sp, const usch **args);
127void prline(const usch *s);
128static void prrep(const usch *s);
129static void exparg(int);
130static void subarg(struct symtab *sp, const usch **args, int);
131void define(void);
132void include(void);
133void include_next(void);
134void line(void);
135void flbuf(void);
136void usage(void);
137usch *xstrdup(const usch *str);
138static void addidir(char *idir, struct incs **ww);
139void imp(const char *);
140#define IMP(x) if (dflag>1) imp(x)
141
142int
143main(int argc, char **argv)
144{
145 struct initar *it;
146 struct symtab *nl;
147 register int ch;
148 const usch *fn1, *fn2;
149
150#ifdef TIMING
151 struct timeval t1, t2;
152
153 (void)gettimeofday(&t1, NULL);
154#endif
155
156 while ((ch = getopt(argc, argv, "CD:I:MPS:U:d:i:tvV?")) != -1)
157 switch (ch) {
158 case 'C': /* Do not discard comments */
159 Cflag++;
160 break;
161
162 case 'i': /* include */
163 case 'U': /* undef */
164 case 'D': /* define something */
165 /* XXX should not need malloc() here */
166 if ((it = malloc(sizeof(struct initar))) == NULL)
167 error("couldn't apply -%c %s", ch, optarg);
168 it->type = ch;
169 it->str = optarg;
170 it->next = initar;
171 initar = it;
172 break;
173
174 case 'M': /* Generate dependencies for make */
175 Mflag++;
176 break;
177
178 case 'P': /* Inhibit generation of line numbers */
179 Pflag++;
180 break;
181
182 case 'S':
183 case 'I':
184 addidir(optarg, &incdir[ch == 'I' ? INCINC : SYSINC]);
185 break;
186
187#ifdef CPP_DEBUG
188 case 'V':
189 dflag++;
190 break;
191#endif
192 case 'v':
193 printf("cpp: %s\n", VERSSTR);
194 break;
195 case 'd':
196 if (optarg[0] == 'M') {
197 dMflag = 1;
198 Mflag = 1;
199 }
200 /* ignore others */
201 break;
202
203 case 't':
204 tflag = 1;
205 break;
206
207 case '?':
208 usage();
209 default:
210 error("bad arg %c\n", ch);
211 }
212 argc -= optind;
213 argv += optind;
214
215 filloc = lookup((const usch *)"__FILE__", ENTER);
216 linloc = lookup((const usch *)"__LINE__", ENTER);
217 filloc->value = linloc->value = stringbuf;
218 savch(OBJCT);
219
220 /* create a complete macro for pragma */
221 pragloc = lookup((const usch *)"_Pragma", ENTER);
222 savch(0);
223 savstr((const usch *)"_Pragma(");
224 savch(0);
225 savch(WARN);
226 savch(')');
227 pragloc->value = stringbuf;
228 savch(1);
229
230 if (tflag == 0) {
231 time_t t = time(NULL);
232 usch *n = (usch *)ctime(&t);
233
234 /*
235 * Manually move in the predefined macros.
236 */
237 nl = lookup((const usch *)"__TIME__", ENTER);
238 savch(0); savch('"'); n[19] = 0; savstr(&n[11]); savch('"');
239 savch(OBJCT);
240 nl->value = stringbuf-1;
241
242 nl = lookup((const usch *)"__DATE__", ENTER);
243 savch(0); savch('"'); n[24] = n[11] = 0; savstr(&n[4]);
244 savstr(&n[20]); savch('"'); savch(OBJCT);
245 nl->value = stringbuf-1;
246
247 nl = lookup((const usch *)"__STDC__", ENTER);
248 savch(0); savch('1'); savch(OBJCT);
249 nl->value = stringbuf-1;
250
251 nl = lookup((const usch *)"__STDC_VERSION__", ENTER);
252 savch(0); savstr((const usch *)"199901L"); savch(OBJCT);
253 nl->value = stringbuf-1;
254 }
255
256 if (Mflag && !dMflag) {
257 usch *c;
258
259 if (argc < 1)
260 error("-M and no infile");
261 if ((c = (usch *)strrchr(argv[0], '/')) == NULL)
262 c = (usch *)argv[0];
263 else
264 c++;
265 Mfile = stringbuf;
266 savstr(c); savch(0);
267 if ((c = (usch *)strrchr((char *)Mfile, '.')) == NULL)
268 error("-M and no extension: ");
269 c[1] = 'o';
270 c[2] = 0;
271 }
272
273 if (argc == 2) {
274 if ((ofd = open(argv[1], O_WRONLY|O_CREAT, 0600)) < 0)
275 error("Can't creat %s", argv[1]);
276 } else
277 ofd = 1; /* stdout */
278 istty = isatty(ofd);
279
280 if (argc && strcmp(argv[0], "-")) {
281 fn1 = fn2 = (usch *)argv[0];
282 } else {
283 fn1 = NULL;
284 fn2 = (const usch *)"";
285 }
286 if (pushfile(fn1, fn2, 0, NULL))
287 error("cannot open %s", argv[0]);
288
289 flbuf();
290 close(ofd);
291#ifdef TIMING
292 (void)gettimeofday(&t2, NULL);
293 t2.tv_sec -= t1.tv_sec;
294 t2.tv_usec -= t1.tv_usec;
295 if (t2.tv_usec < 0) {
296 t2.tv_usec += 1000000;
297 t2.tv_sec -= 1;
298 }
299 fprintf(stderr, "cpp total time: %ld s %ld us\n",
300 t2.tv_sec, t2.tv_usec);
301#endif
302 return 0;
303}
304
305static void
306addidir(char *idir, struct incs **ww)
307{
308 struct incs *w;
309 struct stat st;
310
311 if (stat(idir, &st) == -1 || S_ISDIR(st.st_mode) == 0)
312 return; /* ignore */
313 if (*ww != NULL) {
314 for (w = *ww; w->next; w = w->next) {
315 if (w->dev == st.st_dev && w->ino == st.st_ino)
316 return;
317 }
318 if (w->dev == st.st_dev && w->ino == st.st_ino)
319 return;
320 ww = &w->next;
321 }
322 if ((w = calloc(sizeof(struct incs), 1)) == NULL)
323 error("couldn't add path %s", idir);
324 w->dir = (usch *)idir;
325 w->dev = st.st_dev;
326 w->ino = st.st_ino;
327 *ww = w;
328}
329
330void
331line()
332{
333 static usch *lbuf;
334 static int llen;
335 usch *p;
336 int c;
337
338 if ((c = yylex()) != NUMBER)
339 goto bad;
340 ifiles->lineno = (int)(yylval.node.nd_val - 1);
341
342 if ((c = yylex()) == '\n')
343 return;
344
345 if (c != STRING)
346 goto bad;
347
348 p = (usch *)yytext;
349 if (*p == 'L')
350 p++;
351 c = strlen((char *)p);
352 if (llen < c) {
353 /* XXX may loose heap space */
354 lbuf = stringbuf;
355 stringbuf += c;
356 llen = c;
357 }
358 p[strlen((char *)p)-1] = 0;
359 if (strlcpy((char *)lbuf, (char *)&p[1], SBSIZE) >= SBSIZE)
360 error("line exceeded buffer size");
361
362 ifiles->fname = lbuf;
363 if (yylex() == '\n')
364 return;
365
366bad: error("bad line directive");
367}
368
369/*
370 * Search for and include next file.
371 * Return 1 on success.
372 */
373static int
374fsrch(const usch *fn, int idx, struct incs *w)
375{
376 int i;
377
378 for (i = idx; i < 2; i++) {
379 if (i > idx)
380 w = incdir[i];
381 for (; w; w = w->next) {
382 usch *nm = stringbuf;
383
384 savstr(w->dir); savch('/');
385 savstr(fn); savch(0);
386 if (pushfile(nm, fn, i, w->next) == 0)
387 return 1;
388 stringbuf = nm;
389 }
390 }
391 return 0;
392}
393
394/*
395 * Include a file. Include order:
396 * - For <...> files, first search -I directories, then system directories.
397 * - For "..." files, first search "current" dir, then as <...> files.
398 */
399void
400include()
401{
402 struct symtab *nl;
403 usch *osp;
404 usch *fn, *safefn;
405 int c, it;
406
407 if (flslvl)
408 return;
409 osp = stringbuf;
410
411 while ((c = sloscan()) == WSPACE)
412 ;
413 if (c == IDENT) {
414 /* sloscan() will not expand idents */
415 if ((nl = lookup((usch *)yytext, FIND)) == NULL)
416 goto bad;
417 if (kfind(nl))
418 unpstr(stringbuf);
419 else
420 unpstr(nl->namep);
421 stringbuf = osp;
422 c = yylex();
423 }
424 if (c != STRING && c != '<')
425 goto bad;
426
427 if (c == '<') {
428 fn = stringbuf;
429 while ((c = sloscan()) != '>' && c != '\n') {
430 if (c == '\n') /* XXX check - cannot reach */
431 goto bad;
432 savstr((usch *)yytext);
433 }
434 savch('\0');
435 while ((c = sloscan()) == WSPACE)
436 ;
437 if (c != '\n')
438 goto bad;
439 it = SYSINC;
440 safefn = fn;
441 } else {
442 usch *nm = stringbuf;
443
444 yytext[strlen((char *)yytext)-1] = 0;
445 fn = (usch *)&yytext[1];
446 /* first try to open file relative to previous file */
447 /* but only if it is not an absolute path */
448 if (*fn != '/') {
449 savstr(ifiles->orgfn);
450 if ((stringbuf =
451 (usch *)strrchr((char *)nm, '/')) == NULL)
452 stringbuf = nm;
453 else
454 stringbuf++;
455 }
456 safefn = stringbuf;
457 savstr(fn); savch(0);
458 c = yylex();
459 if (c != '\n')
460 goto bad;
461 if (pushfile(nm, safefn, 0, NULL) == 0)
462 goto okret;
463 /* XXX may loose stringbuf space */
464 }
465
466 if (fsrch(safefn, 0, incdir[0]))
467 goto okret;
468
469 error("cannot find '%s'", safefn);
470 /* error() do not return */
471
472bad: error("bad include");
473 /* error() do not return */
474okret:
475 prtline();
476}
477
478void
479include_next()
480{
481 struct symtab *nl;
482 usch *osp;
483 usch *fn;
484 int c;
485
486 if (flslvl)
487 return;
488 osp = stringbuf;
489 while ((c = sloscan()) == WSPACE)
490 ;
491 if (c == IDENT) {
492 /* sloscan() will not expand idents */
493 if ((nl = lookup((usch *)yytext, FIND)) == NULL)
494 goto bad;
495 if (kfind(nl))
496 unpstr(stringbuf);
497 else
498 unpstr(nl->namep);
499 stringbuf = osp;
500 c = yylex();
501 }
502 if (c != STRING && c != '<')
503 goto bad;
504
505 fn = stringbuf;
506 if (c == STRING) {
507 savstr((usch *)&yytext[1]);
508 stringbuf[-1] = 0;
509 } else { /* < > */
510 while ((c = sloscan()) != '>') {
511 if (c == '\n')
512 goto bad;
513 savstr((usch *)yytext);
514 }
515 savch('\0');
516 }
517 while ((c = sloscan()) == WSPACE)
518 ;
519 if (c != '\n')
520 goto bad;
521
522 if (fsrch(fn, ifiles->idx, ifiles->incs) == 0)
523 error("cannot find '%s'", fn);
524 prtline();
525 return;
526
527bad: error("bad include");
528 /* error() do not return */
529}
530
531static int
532definp(void)
533{
534 int c;
535
536 do
537 c = sloscan();
538 while (c == WSPACE);
539 return c;
540}
541
542void
543getcmnt(void)
544{
545 int c;
546
547 savstr((usch *)yytext);
548 savch(cinput()); /* Lost * */
549 for (;;) {
550 c = cinput();
551 if (c == '*') {
552 c = cinput();
553 if (c == '/') {
554 savstr((const usch *)"*/");
555 return;
556 }
557 cunput(c);
558 c = '*';
559 }
560 savch(c);
561 }
562}
563
564/*
565 * Compare two replacement lists, taking in account comments etc.
566 */
567static int
568cmprepl(const usch *o, const usch *n)
569{
570 for (; *o; o--, n--) {
571 /* comment skip */
572 if (*o == '/' && o[-1] == '*') {
573 while (*o != '*' || o[-1] != '/')
574 o--;
575 o -= 2;
576 }
577 if (*n == '/' && n[-1] == '*') {
578 while (*n != '*' || n[-1] != '/')
579 n--;
580 n -= 2;
581 }
582 while (*o == ' ' || *o == '\t')
583 o--;
584 while (*n == ' ' || *n == '\t')
585 n--;
586 if (*o != *n)
587 return 1;
588 }
589 return 0;
590}
591
592static int
593isell(void)
594{
595 int ch;
596
597 if ((ch = cinput()) != '.') {
598 cunput(ch);
599 return 0;
600 }
601 if ((ch = cinput()) != '.') {
602 cunput(ch);
603 cunput('.');
604 return 0;
605 }
606 return 1;
607}
608
609void
610define()
611{
612 struct symtab *np;
613 usch *args[MAXARGS+1], *ubuf, *sbeg;
614 int c, i, redef;
615 int mkstr = 0, narg = -1;
616 int ellips = 0;
617#ifdef GCC_COMPAT
618 usch *gccvari = NULL;
619 int wascon;
620#endif
621
622 if (flslvl)
623 return;
624 if (sloscan() != WSPACE || sloscan() != IDENT)
625 goto bad;
626
627 if (isdigit((int)yytext[0]))
628 goto bad;
629
630 np = lookup((usch *)yytext, ENTER);
631 redef = np->value != NULL;
632
633 readmac = 1;
634 sbeg = stringbuf;
635 if ((c = sloscan()) == '(') {
636 narg = 0;
637 /* function-like macros, deal with identifiers */
638 c = definp();
639 for (;;) {
640 if (c == ')')
641 break;
642 if (c == '.' && isell()) {
643 ellips = 1;
644 if (definp() != ')')
645 goto bad;
646 break;
647 }
648 if (c == IDENT) {
649 /* make sure there is no arg of same name */
650 for (i = 0; i < narg; i++)
651 if (!strcmp((char *) args[i], (char *)yytext))
652 error("Duplicate macro "
653 "parameter \"%s\"", yytext);
654 if (narg == MAXARGS)
655 error("Too many macro args");
656 args[narg++] = xstrdup(yytext);
657 if ((c = definp()) == ',') {
658 if ((c = definp()) == ')')
659 goto bad;
660 continue;
661 }
662#ifdef GCC_COMPAT
663 if (c == '.' && isell()) {
664 if (definp() != ')')
665 goto bad;
666 gccvari = args[--narg];
667 break;
668 }
669#endif
670 if (c == ')')
671 break;
672 }
673 goto bad;
674 }
675 c = sloscan();
676 } else if (c == '\n') {
677 /* #define foo */
678 ;
679 } else if (c != WSPACE)
680 goto bad;
681
682 while (c == WSPACE)
683 c = sloscan();
684
685 /* replacement list cannot start with ## operator */
686 if (c == '#') {
687 if ((c = sloscan()) == '#')
688 goto bad;
689 savch('\0');
690#ifdef GCC_COMPAT
691 wascon = 0;
692#endif
693 goto in2;
694 }
695
696 /* parse replacement-list, substituting arguments */
697 savch('\0');
698 while (c != '\n') {
699#ifdef GCC_COMPAT
700 wascon = 0;
701loop:
702#endif
703 switch (c) {
704 case WSPACE:
705 /* remove spaces if it surrounds a ## directive */
706 ubuf = stringbuf;
707 savstr((usch *)yytext);
708 c = sloscan();
709 if (c == '#') {
710 if ((c = sloscan()) != '#')
711 goto in2;
712 stringbuf = ubuf;
713 savch(CONC);
714 if ((c = sloscan()) == WSPACE)
715 c = sloscan();
716#ifdef GCC_COMPAT
717 if (c == '\n')
718 break;
719 wascon = 1;
720 goto loop;
721#endif
722 }
723 continue;
724
725 case '#':
726 c = sloscan();
727 if (c == '#') {
728 /* concat op */
729 savch(CONC);
730 if ((c = sloscan()) == WSPACE)
731 c = sloscan();
732#ifdef GCC_COMPAT
733 if (c == '\n')
734 break;
735 wascon = 1;
736 goto loop;
737#else
738 continue;
739#endif
740 }
741in2: if (narg < 0) {
742 /* no meaning in object-type macro */
743 savch('#');
744 continue;
745 }
746 /* remove spaces between # and arg */
747 savch(SNUFF);
748 if (c == WSPACE)
749 c = sloscan(); /* whitespace, ignore */
750 mkstr = 1;
751 if (c == IDENT && strcmp((char *)yytext, "__VA_ARGS__") == 0)
752 continue;
753
754 /* FALLTHROUGH */
755 case IDENT:
756 if (strcmp((char *)yytext, "__VA_ARGS__") == 0) {
757 if (ellips == 0)
758 error("unwanted %s", yytext);
759#ifdef GCC_COMPAT
760 savch(wascon ? GCCARG : VARG);
761#else
762 savch(VARG);
763#endif
764
765 savch(WARN);
766 if (mkstr)
767 savch(SNUFF), mkstr = 0;
768 break;
769 }
770 if (narg < 0)
771 goto id; /* just add it if object */
772 /* check if its an argument */
773 for (i = 0; i < narg; i++)
774 if (strcmp((char *)yytext, (char *)args[i]) == 0)
775 break;
776 if (i == narg) {
777#ifdef GCC_COMPAT
778 if (gccvari &&
779 strcmp((char *)yytext, (char *)gccvari) == 0) {
780 savch(wascon ? GCCARG : VARG);
781 savch(WARN);
782 if (mkstr)
783 savch(SNUFF), mkstr = 0;
784 break;
785 }
786#endif
787 if (mkstr)
788 error("not argument");
789 goto id;
790 }
791 savch(i);
792 savch(WARN);
793 if (mkstr)
794 savch(SNUFF), mkstr = 0;
795 break;
796
797 case CMNT: /* save comments */
798 getcmnt();
799 break;
800
801 default:
802id: savstr((usch *)yytext);
803 break;
804 }
805 c = sloscan();
806 }
807 readmac = 0;
808 /* remove trailing whitespace */
809 while (stringbuf > sbeg) {
810 if (stringbuf[-1] == ' ' || stringbuf[-1] == '\t')
811 stringbuf--;
812 /* replacement list cannot end with ## operator */
813 else if (stringbuf[-1] == CONC)
814 goto bad;
815 else
816 break;
817 }
818#ifdef GCC_COMPAT
819 if (gccvari) {
820 savch(narg);
821 savch(VARG);
822 } else
823#endif
824 if (ellips) {
825 savch(narg);
826 savch(VARG);
827 } else
828 savch(narg < 0 ? OBJCT : narg);
829 if (redef && ifiles->idx != SYSINC) {
830 if (cmprepl(np->value, stringbuf-1)) {
831 sbeg = stringbuf;
832 np->value = stringbuf-1;
833 warning("%s redefined\nprevious define: %s:%d",
834 np->namep, np->file, np->line);
835 }
836 stringbuf = sbeg; /* forget this space */
837 } else
838 np->value = stringbuf-1;
839
840#ifdef CPP_DEBUG
841 if (dflag) {
842 const usch *w = np->value;
843
844 printf("!define: ");
845 if (*w == OBJCT)
846 printf("[object]");
847 else if (*w == VARG)
848 printf("[VARG%d]", *--w);
849 while (*--w) {
850 switch (*w) {
851 case WARN: printf("<%d>", *--w); break;
852 case CONC: printf("<##>"); break;
853 case SNUFF: printf("<\">"); break;
854 default: putchar(*w); break;
855 }
856 }
857 putchar('\n');
858 }
859#endif
860 for (i = 0; i < narg; i++)
861 free(args[i]);
862 return;
863
864bad: error("bad define");
865}
866
867void
868xwarning(usch *s)
869{
870 usch *t;
871 usch *sb = stringbuf;
872 int dummy;
873
874 flbuf();
875 savch(0);
876 if (ifiles != NULL) {
877 t = sheap("%s:%d: warning: ", ifiles->fname, ifiles->lineno);
878 write (2, t, strlen((char *)t));
879 }
880 dummy = write (2, s, strlen((char *)s));
881 dummy = write (2, "\n", 1);
882 stringbuf = sb;
883}
884
885void
886xerror(usch *s)
887{
888 usch *t;
889 int dummy;
890
891 flbuf();
892 savch(0);
893 if (ifiles != NULL) {
894 t = sheap("%s:%d: error: ", ifiles->fname, ifiles->lineno);
895 dummy = write (2, t, strlen((char *)t));
896 }
897 dummy = write (2, s, strlen((char *)s));
898 dummy = write (2, "\n", 1);
899 exit(1);
900}
901
902static void
903sss(void)
904{
905 savch(EBLOCK);
906 savch(cinput());
907 savch(cinput());
908}
909
910static int
911addmac(struct symtab *sp)
912{
913 int c, i;
914
915 /* Check if it exists; then save some space */
916 /* May be more difficult to debug cpp */
917 for (i = 1; i < norepptr; i++)
918 if (norep[i] == sp)
919 return i;
920 if (norepptr >= RECMAX)
921 error("too many macros");
922 /* check norepptr */
923 if ((norepptr & 255) == 0)
924 norepptr++;
925 if (((norepptr >> 8) & 255) == 0)
926 norepptr += 256;
927 c = norepptr;
928 norep[norepptr++] = sp;
929 return c;
930}
931
932static void
933doblk(void)
934{
935 int c;
936
937 do {
938 donex();
939 } while ((c = sloscan()) == EBLOCK);
940 if (c != IDENT)
941 error("EBLOCK sync error");
942}
943
944/* Block next nr in lex buffer to expand */
945int
946donex(void)
947{
948 int n, i;
949
950 if (bidx == RECMAX)
951 error("too deep macro recursion");
952 n = cinput();
953 n = MKB(n, cinput());
954 for (i = 0; i < bidx; i++)
955 if (bptr[i] == n)
956 return n; /* already blocked */
957 bptr[bidx++] = n;
958 /* XXX - check for sp buffer overflow */
959 if (dflag>1) {
960 printf("donex %d (%d) blocking:\n", bidx, n);
961 printf("donex %s(%d) blocking:", norep[n]->namep, n);
962 for (i = bidx-1; i >= 0; i--)
963 printf(" '%s'", norep[bptr[i]]->namep);
964 printf("\n");
965 }
966 return n;
967}
968
969/*
970 * store a character into the "define" buffer.
971 */
972void
973savch(int c)
974{
975 if (stringbuf-sbf < SBSIZE) {
976 *stringbuf++ = (usch)c;
977 } else {
978 stringbuf = sbf; /* need space to write error message */
979 error("Too much defining");
980 }
981}
982
983/*
984 * convert _Pragma to #pragma for output.
985 * Syntax is already correct.
986 */
987static void
988pragoper(void)
989{
990 usch *s;
991 int t;
992
993 while ((t = sloscan()) != '(')
994 ;
995
996 while ((t = sloscan()) == WSPACE)
997 ;
998 if (t != STRING)
999 error("pragma must have string argument");
1000 savstr((const usch *)"\n#pragma ");
1001 s = (usch *)yytext;
1002 if (*s == 'L')
1003 s++;
1004 for (; *s; s++) {
1005 if (*s == '\"')
1006 continue;
1007 if (*s == '\\' && (s[1] == '\"' || s[1] == '\\'))
1008 s++;
1009 savch(*s);
1010 }
1011 sheap("\n# %d \"%s\"\n", ifiles->lineno, ifiles->fname);
1012 while ((t = sloscan()) == WSPACE)
1013 ;
1014 if (t != ')')
1015 error("pragma syntax error");
1016}
1017
1018/*
1019 * Return true if it is OK to expand this symbol.
1020 */
1021static int
1022okexp(struct symtab *sp)
1023{
1024 int i;
1025
1026 if (sp == NULL)
1027 return 0;
1028 for (i = 0; i < bidx; i++)
1029 if (norep[bptr[i]] == sp)
1030 return 0;
1031 return 1;
1032}
1033
1034/*
1035 * Insert block(s) before each expanded name.
1036 * Input is in lex buffer, output on lex buffer.
1037 */
1038static void
1039insblock(int bnr)
1040{
1041 usch *bp = stringbuf;
1042 int c, i;
1043
1044 IMP("IB");
1045 while ((c = sloscan()) != WARN) {
1046 if (c == EBLOCK) {
1047 sss();
1048 continue;
1049 }
1050 if (c == IDENT) {
1051 savch(EBLOCK), savch(bnr & 255), savch(bnr >> 8);
1052 for (i = 0; i < bidx; i++)
1053 savch(EBLOCK), savch(bptr[i] & 255),
1054 savch(bptr[i] >> 8);
1055 }
1056 savstr((const usch *)yytext);
1057 if (c == '\n')
1058 (void)cinput();
1059 }
1060 savch(0);
1061 cunput(WARN);
1062 unpstr(bp);
1063 stringbuf = bp;
1064 IMP("IBRET");
1065}
1066
1067/* Delete next WARN on the input stream */
1068static void
1069delwarn(void)
1070{
1071 usch *bp = stringbuf;
1072 int c;
1073
1074 IMP("DELWARN");
1075 while ((c = sloscan()) != WARN) {
1076 if (c == EBLOCK) {
1077 sss();
1078 } else
1079 savstr(yytext);
1080 }
1081 savch(0);
1082 unpstr(bp);
1083 stringbuf = bp;
1084 IMP("DELWRET");
1085}
1086
1087/*
1088 * Handle defined macro keywords found on input stream.
1089 * When finished print out the full expanded line.
1090 * Everything on lex buffer except for the symtab.
1091 */
1092int
1093kfind(struct symtab *sp)
1094{
1095 struct symtab *nl;
1096 const usch *argary[MAXARGS+1], *cbp;
1097 usch *sbp;
1098 int c, o, chkf;
1099
1100 DPRINT(("%d:enter kfind(%s)\n",0,sp->namep));
1101 IMP("KFIND");
1102 if (*sp->value == OBJCT) {
1103 if (sp == filloc) {
1104 unpstr(sheap("\"%s\"", ifiles->fname));
1105 return 1;
1106 } else if (sp == linloc) {
1107 unpstr(sheap("%d", ifiles->lineno));
1108 return 1;
1109 }
1110 IMP("END1");
1111 cunput(WARN);
1112 for (cbp = sp->value-1; *cbp; cbp--)
1113 cunput(*cbp);
1114 insblock(addmac(sp));
1115 IMP("ENDX");
1116 exparg(1);
1117
1118upp: sbp = stringbuf;
1119 chkf = 1;
1120 if (obufp != 0)
1121 lastoch = outbuf[obufp-1];
1122 if (iswsnl(lastoch))
1123 chkf = 0;
1124 while ((c = sloscan()) != WARN) {
1125 switch (c) {
1126 case STRING:
1127 /* Remove embedded directives */
1128 for (cbp = (usch *)yytext; *cbp; cbp++) {
1129 if (*cbp == EBLOCK)
1130 cbp+=2;
1131 else if (*cbp != CONC)
1132 savch(*cbp);
1133 }
1134 break;
1135
1136 case EBLOCK:
1137 doblk();
1138 /* FALLTHROUGH */
1139 case IDENT:
1140 /*
1141 * Tricky: if this is the last identifier
1142 * in the expanded list, and it is defined
1143 * as a function-like macro, then push it
1144 * back on the input stream and let fastscan
1145 * handle it as a new macro.
1146 * BUT: if this macro is blocked then this
1147 * should not be done.
1148 */
1149 nl = lookup((usch *)yytext, FIND);
1150 o = okexp(nl);
1151 bidx = 0;
1152 /* Deal with pragmas here */
1153 if (nl == pragloc) {
1154 pragoper();
1155 break;
1156 }
1157 if (nl == NULL || !o || *nl->value == OBJCT) {
1158 /* Not fun-like macro */
1159 savstr(yytext);
1160 break;
1161 }
1162 c = cinput();
1163 if (c == WARN) {
1164 /* succeeded, push back */
1165 unpstr(yytext);
1166 } else {
1167 savstr(yytext);
1168 }
1169 cunput(c);
1170 break;
1171
1172 default:
1173 if (chkf && c < 127)
1174 putch(' ');
1175 savstr(yytext);
1176 break;
1177 }
1178 chkf = 0;
1179 }
1180 IMP("END2");
1181 norepptr = 1;
1182 savch(0);
1183 stringbuf = sbp;
1184 return 1;
1185 }
1186 /* Is a function-like macro */
1187
1188 /* Search for '(' */
1189 sbp = stringbuf;
1190 while (iswsnl(c = cinput()))
1191 savch(c);
1192 savch(0);
1193 stringbuf = sbp;
1194 if (c != '(') {
1195 cunput(c);
1196 unpstr(sbp);
1197 return 0; /* Failed */
1198 }
1199
1200 /* Found one, output \n to be in sync */
1201 for (; *sbp; sbp++) {
1202 if (*sbp == '\n')
1203 putch('\n'), ifiles->lineno++;
1204 }
1205
1206 /* fetch arguments */
1207 if (readargs(sp, argary))
1208 error("readargs");
1209
1210 c = addmac(sp);
1211 sbp = stringbuf;
1212 cunput(WARN);
1213
1214 IMP("KEXP");
1215 subarg(sp, argary, 1);
1216 IMP("KNEX");
1217 insblock(c);
1218 IMP("KBLK");
1219
1220 stringbuf = sbp;
1221
1222 exparg(1);
1223
1224 IMP("END");
1225
1226 goto upp;
1227
1228}
1229
1230/*
1231 * Replace and push-back on input stream the eventual replaced macro.
1232 * The check for whether it can expand or not should already have been done.
1233 * Blocks for this identifier will be added via insblock() after expansion.
1234 */
1235int
1236submac(struct symtab *sp, int lvl)
1237{
1238 const usch *argary[MAXARGS+1];
1239 const usch *cp;
1240 usch *bp;
1241 int ch;
1242
1243 DPRINT(("%d:submac1: trying '%s'\n", lvl, sp->namep));
1244 if (*sp->value == OBJCT) {
1245 if (sp == filloc) {
1246 unpstr(sheap("\"%s\"", ifiles->fname));
1247 return 1;
1248 } else if (sp == linloc) {
1249 unpstr(sheap("%d", ifiles->lineno));
1250 return 1;
1251 }
1252
1253 DPRINT(("submac: exp object macro '%s'\n",sp->namep));
1254 /* expand object-type macros */
1255 ch = addmac(sp);
1256 cunput(WARN);
1257
1258 for (cp = sp->value-1; *cp; cp--)
1259 cunput(*cp);
1260 insblock(ch);
1261 delwarn();
1262 return 1;
1263 }
1264
1265 /*
1266 * Function-like macro; see if it is followed by a (
1267 * Be careful about the expand/noexpand balance.
1268 * Store read data on heap meanwhile.
1269 * For directive #define foo() kaka
1270 * If input is <NEX><NEX>foo<EXP>()<EXP> then
1271 * output should be <NEX><NEX><EXP>kaka<EXP>.
1272 */
1273 bp = stringbuf;
1274 while (iswsnl(ch = cinput()))
1275 savch(ch);
1276 savch(0);
1277 stringbuf = bp;
1278 if (ch != '(') {
1279 cunput(ch);
1280 unpstr(bp);
1281 return 0; /* Failed */
1282 }
1283
1284 /* no \n should be here */
1285
1286 /*
1287 * A function-like macro has been found. Read in the arguments,
1288 * expand them and push-back everything for another scan.
1289 */
1290 DPRINT(("%d:submac: continue macro '%s'\n", lvl, sp->namep));
1291 savch(0);
1292 if (readargs(sp, argary)) {
1293 /* Bailed out in the middle of arg list */
1294 unpstr(bp);
1295 if (dflag>1)printf("%d:noreadargs\n", lvl);
1296 stringbuf = bp;
1297 return 0;
1298 }
1299
1300 /* when all args are read from input stream */
1301 ch = addmac(sp);
1302
1303 DDPRINT(("%d:submac pre\n", lvl));
1304 cunput(WARN);
1305
1306 subarg(sp, argary, lvl+1);
1307
1308 DDPRINT(("%d:submac post\n", lvl));
1309 insblock(ch);
1310 delwarn();
1311
1312 stringbuf = bp; /* Reset heap */
1313 DPRINT(("%d:Return submac\n", lvl));
1314 IMP("SM1");
1315 return 1;
1316}
1317
1318/*
1319 * Read arguments and put in argument array.
1320 * If WARN is encountered return 1, otherwise 0.
1321 */
1322int
1323readargs(struct symtab *sp, const usch **args)
1324{
1325 const usch *vp = sp->value;
1326 int c, i, plev, narg, ellips = 0;
1327 int warn;
1328
1329 DPRINT(("readargs\n"));
1330
1331 narg = *vp--;
1332 if (narg == VARG) {
1333 narg = *vp--;
1334 ellips = 1;
1335 }
1336
1337 IMP("RDA1");
1338 /*
1339 * read arguments and store them on heap.
1340 */
1341 warn = 0;
1342 c = '(';
1343 for (i = 0; i < narg && c != ')'; i++) {
1344 args[i] = stringbuf;
1345 plev = 0;
1346 while ((c = sloscan()) == WSPACE || c == '\n')
1347 if (c == '\n')
1348 putch(cinput());
1349 for (;;) {
1350 while (c == EBLOCK) {
1351 sss();
1352 c = sloscan();
1353 }
1354 if (c == WARN) {
1355 warn++;
1356 goto oho;
1357 }
1358 if (plev == 0 && (c == ')' || c == ','))
1359 break;
1360 if (c == '(')
1361 plev++;
1362 if (c == ')')
1363 plev--;
1364 savstr((usch *)yytext);
1365oho: while ((c = sloscan()) == '\n') {
1366 putch(cinput());
1367 savch(' ');
1368 }
1369 while (c == CMNT) {
1370 getcmnt();
1371 c = sloscan();
1372 }
1373 if (c == 0)
1374 error("eof in macro");
1375 }
1376 while (args[i] < stringbuf &&
1377 iswsnl(stringbuf[-1]) && stringbuf[-3] != EBLOCK)
1378 stringbuf--;
1379 savch('\0');
1380 if (dflag) {
1381 printf("readargs: save arg %d '", i);
1382 prline(args[i]);
1383 printf("'\n");
1384 }
1385 }
1386
1387 IMP("RDA2");
1388 /* Handle varargs readin */
1389 if (ellips)
1390 args[i] = (const usch *)"";
1391 if (ellips && c != ')') {
1392 args[i] = stringbuf;
1393 plev = 0;
1394 while ((c = sloscan()) == WSPACE)
1395 ;
1396 for (;;) {
1397 if (plev == 0 && c == ')')
1398 break;
1399 if (c == '(')
1400 plev++;
1401 if (c == ')')
1402 plev--;
1403 if (c == EBLOCK) {
1404 sss();
1405 } else
1406 savstr((usch *)yytext);
1407 while ((c = sloscan()) == '\n') {
1408 cinput();
1409 savch(' ');
1410 }
1411 }
1412 while (args[i] < stringbuf && iswsnl(stringbuf[-1]))
1413 stringbuf--;
1414 savch('\0');
1415
1416 }
1417 if (narg == 0 && ellips == 0)
1418 while ((c = sloscan()) == WSPACE || c == '\n')
1419 if (c == '\n')
1420 cinput();
1421
1422 if (c != ')' || (i != narg && ellips == 0) || (i < narg && ellips == 1))
1423 error("wrong arg count");
1424 while (warn)
1425 cunput(WARN), warn--;
1426 return 0;
1427}
1428
1429#if 0
1430/*
1431 * Maybe an indentifier (for macro expansion).
1432 */
1433static int
1434mayid(usch *s)
1435{
1436 for (; *s; s++)
1437 if (!isdigit(*s) && !isalpha(*s) && *s != '_')
1438 return 0;
1439 return 1;
1440}
1441#endif
1442
1443/*
1444 * expand a function-like macro.
1445 * vp points to end of replacement-list
1446 * reads function arguments from sloscan()
1447 * result is pushed-back for more scanning.
1448 */
1449void
1450subarg(struct symtab *nl, const usch **args, int lvl)
1451{
1452 int narg, instr, snuff;
1453 const usch *sp, *bp, *ap, *vp;
1454
1455 DPRINT(("%d:subarg '%s'\n", lvl, nl->namep));
1456 vp = nl->value;
1457 narg = *vp--;
1458 if (narg == VARG)
1459 narg = *vp--;
1460
1461 sp = vp;
1462 instr = snuff = 0;
1463 if (dflag>1) {
1464 printf("%d:subarg ARGlist for %s: '", lvl, nl->namep);
1465 prrep(vp);
1466 printf("'\n");
1467 }
1468
1469 /*
1470 * push-back replacement-list onto lex buffer while replacing
1471 * arguments. Arguments are macro-expanded if required.
1472 */
1473 while (*sp != 0) {
1474 if (*sp == SNUFF)
1475 cunput('\"'), snuff ^= 1;
1476 else if (*sp == CONC)
1477 ;
1478 else if (*sp == WARN) {
1479
1480 if (sp[-1] == VARG) {
1481 bp = ap = args[narg];
1482 sp--;
1483#ifdef GCC_COMPAT
1484 } else if (sp[-1] == GCCARG) {
1485 ap = args[narg];
1486 if (ap[0] == 0)
1487 ap = (const usch *)"0";
1488 bp = ap;
1489 sp--;
1490#endif
1491 } else
1492 bp = ap = args[(int)*--sp];
1493 if (dflag>1){
1494 printf("%d:subarg GOTwarn; arglist '", lvl);
1495 prline(bp);
1496 printf("'\n");
1497 }
1498 if (sp[2] != CONC && !snuff && sp[-1] != CONC) {
1499 /*
1500 * Expand an argument; 6.10.3.1:
1501 * "A parameter in the replacement list,
1502 * is replaced by the corresponding argument
1503 * after all macros contained therein have
1504 * been expanded.".
1505 */
1506 cunput(WARN);
1507 unpstr(bp);
1508 exparg(lvl+1);
1509 delwarn();
1510 } else {
1511 while (*bp)
1512 bp++;
1513 while (bp > ap) {
1514 bp--;
1515 if (snuff && !instr && iswsnl(*bp)) {
1516 while (iswsnl(*bp))
1517 bp--;
1518 cunput(' ');
1519 }
1520
1521 cunput(*bp);
1522 if ((*bp == '\'' || *bp == '"')
1523 && bp[-1] != '\\' && snuff) {
1524 instr ^= 1;
1525 if (instr == 0 && *bp == '"')
1526 cunput('\\');
1527 }
1528 if (instr && (*bp == '\\' || *bp == '"'))
1529 cunput('\\');
1530 }
1531 }
1532 } else
1533 cunput(*sp);
1534 sp--;
1535 }
1536 DPRINT(("%d:Return subarg\n", lvl));
1537 IMP("SUBARG");
1538}
1539
1540/*
1541 * Do a (correct) expansion of a WARN-terminated buffer of tokens.
1542 * Data is read from the lex buffer, result on lex buffer, WARN-terminated.
1543 * Expansion blocking is not altered here unless when tokens are
1544 * concatenated, in which case they are removed.
1545 */
1546void
1547exparg(int lvl)
1548{
1549 struct symtab *nl;
1550 int c, i;
1551 usch *och;
1552 usch *osb = stringbuf;
1553 int anychange;
1554
1555 DPRINT(("%d:exparg\n", lvl));
1556 IMP("EXPARG");
1557
1558 readmac++;
1559rescan:
1560 anychange = 0;
1561 while ((c = sloscan()) != WARN) {
1562 DDPRINT(("%d:exparg swdata %d\n", lvl, c));
1563 IMP("EA0");
1564 switch (c) {
1565
1566 case EBLOCK:
1567 doblk();
1568 /* FALLTHROUGH */
1569 case IDENT:
1570 /*
1571 * Handle argument concatenation here.
1572 * In case of concatenation, scratch all blockings.
1573 */
1574 DDPRINT(("%d:exparg ident %d\n", lvl, c));
1575 och = stringbuf;
1576
1577sav: savstr(yytext);
1578
1579 if ((c = cinput()) == EBLOCK) {
1580 /* yep, are concatenating; forget blocks */
1581 do {
1582 (void)cinput();
1583 (void)cinput();
1584 } while ((c = sloscan()) == EBLOCK);
1585 bidx = 0;
1586 goto sav;
1587 }
1588 cunput(c);
1589
1590 DPRINT(("%d:exparg: str '%s'\n", lvl, och));
1591 IMP("EA1");
1592 /* see if ident is expandable */
1593 if ((nl = lookup(och, FIND)) && okexp(nl)) {
1594 if (submac(nl, lvl+1)) {
1595 /* Could expand, result on lexbuffer */
1596 stringbuf = och; /* clear saved name */
1597 anychange = 1;
1598 }
1599 } else if (bidx) {
1600 /* must restore blocks */
1601 stringbuf = och;
1602 for (i = 0; i < bidx; i++)
1603 savch(EBLOCK), savch(bptr[i] & 255),
1604 savch(bptr[i] >> 8);
1605 savstr(yytext);
1606 }
1607 bidx = 0;
1608 IMP("EA2");
1609 break;
1610
1611 case CMNT:
1612 getcmnt();
1613 break;
1614
1615 case '\n':
1616 cinput();
1617 savch(' ');
1618 break;
1619
1620 default:
1621 savstr((usch *)yytext);
1622 break;
1623 }
1624 }
1625 *stringbuf = 0;
1626 cunput(WARN);
1627 unpstr(osb);
1628 DPRINT(("%d:exparg return: change %d\n", lvl, anychange));
1629 IMP("EXPRET");
1630 stringbuf = osb;
1631 if (anychange)
1632 goto rescan;
1633 readmac--;
1634}
1635
1636void
1637imp(const char *str)
1638{
1639 printf("%s (%d) '", str, bidx);
1640 prline(ifiles->curptr);
1641 printf("'\n");
1642}
1643
1644void
1645prrep(const usch *s)
1646{
1647 while (*s) {
1648 switch (*s) {
1649 case WARN: printf("<ARG(%d)>", *--s); break;
1650 case CONC: printf("<CONC>"); break;
1651 case SNUFF: printf("<SNUFF>"); break;
1652 case EBLOCK: printf("<E(%d)>",s[-1] + s[-2] * 256); s-=2; break;
1653 default: printf("%c", *s); break;
1654 }
1655 s--;
1656 }
1657}
1658
1659void
1660prline(const usch *s)
1661{
1662 while (*s) {
1663 switch (*s) {
1664 case WARN: printf("<WARN>"); break;
1665 case CONC: printf("<CONC>"); break;
1666 case SNUFF: printf("<SNUFF>"); break;
1667 case EBLOCK: printf("<E(%d)>",s[1] + s[2] * 256); s+=2; break;
1668 case '\n': printf("<NL>"); break;
1669 default: printf("%c", *s); break;
1670 }
1671 s++;
1672 }
1673}
1674
1675usch *
1676savstr(const usch *str)
1677{
1678 usch *rv = stringbuf;
1679
1680 do {
1681 if (stringbuf >= &sbf[SBSIZE]) {
1682 stringbuf = sbf; /* need space to write error message */
1683 error("out of macro space!");
1684 }
1685 } while ((*stringbuf++ = *str++));
1686 stringbuf--;
1687 return rv;
1688}
1689
1690void
1691unpstr(const usch *c)
1692{
1693 const usch *d = c;
1694
1695#if 0
1696 if (dflag>1) {
1697 printf("Xunpstr: '");
1698 prline(c);
1699 printf("'\n");
1700 }
1701#endif
1702 while (*d) {
1703 if (*d == EBLOCK)
1704 d += 2;
1705 d++;
1706 }
1707 while (d > c) {
1708 cunput(*--d);
1709 }
1710}
1711
1712void
1713flbuf()
1714{
1715 if (obufp == 0)
1716 return;
1717 if (Mflag == 0 && write(ofd, outbuf, obufp) < 0)
1718 error("obuf write error");
1719 lastoch = outbuf[obufp-1];
1720 obufp = 0;
1721}
1722
1723void
1724putch(int ch)
1725{
1726 outbuf[obufp++] = (usch)ch;
1727 if (obufp == CPPBUF || (istty && ch == '\n'))
1728 flbuf();
1729}
1730
1731void
1732putstr(const usch *s)
1733{
1734 for (; *s; s++) {
1735 outbuf[obufp++] = *s;
1736 if (obufp == CPPBUF || (istty && *s == '\n'))
1737 flbuf();
1738 }
1739}
1740
1741/*
1742 * convert a number to an ascii string. Store it on the heap.
1743 */
1744static void
1745num2str(int num)
1746{
1747 static usch buf[12];
1748 usch *b = buf;
1749 int m = 0;
1750
1751 if (num < 0)
1752 num = -num, m = 1;
1753 do {
1754 *b++ = (usch)(num % 10 + '0');
1755 num /= 10;
1756 } while (num);
1757 if (m)
1758 *b++ = '-';
1759 while (b > buf)
1760 savch(*--b);
1761}
1762
1763/*
1764 * similar to sprintf, but only handles %s and %d.
1765 * saves result on heap.
1766 */
1767usch *
1768sheap(const char *fmt, ...)
1769{
1770 va_list ap;
1771 usch *op = stringbuf;
1772
1773 va_start(ap, fmt);
1774 for (; *fmt; fmt++) {
1775 if (*fmt == '%') {
1776 fmt++;
1777 switch (*fmt) {
1778 case 's':
1779 savstr(va_arg(ap, usch *));
1780 break;
1781 case 'd':
1782 num2str(va_arg(ap, int));
1783 break;
1784 case 'c':
1785 savch(va_arg(ap, int));
1786 break;
1787 default:
1788 break; /* cannot call error() here */
1789 }
1790 } else
1791 savch(*fmt);
1792 }
1793 va_end(ap);
1794 *stringbuf = 0;
1795 return op;
1796}
1797
1798void
1799usage()
1800{
1801 error("Usage: cpp [-Cdt] [-Dvar=val] [-Uvar] [-Ipath] [-Spath]");
1802}
1803
1804#ifdef notyet
1805/*
1806 * Symbol table stuff.
1807 * The data structure used is a patricia tree implementation using only
1808 * bytes to store offsets.
1809 * The information stored is (lower address to higher):
1810 *
1811 * unsigned char bitno[2]; bit number in the string
1812 * unsigned char left[3]; offset from base to left element
1813 * unsigned char right[3]; offset from base to right element
1814 */
1815#endif
1816
1817/*
1818 * This patricia implementation is more-or-less the same as
1819 * used in ccom for string matching.
1820 */
1821struct tree {
1822 int bitno;
1823 struct tree *lr[2];
1824};
1825
1826#define BITNO(x) ((x) & ~(LEFT_IS_LEAF|RIGHT_IS_LEAF))
1827#define LEFT_IS_LEAF 0x80000000
1828#define RIGHT_IS_LEAF 0x40000000
1829#define IS_LEFT_LEAF(x) (((x) & LEFT_IS_LEAF) != 0)
1830#define IS_RIGHT_LEAF(x) (((x) & RIGHT_IS_LEAF) != 0)
1831#define P_BIT(key, bit) (key[bit >> 3] >> (bit & 7)) & 1
1832#define CHECKBITS 8
1833
1834static struct tree *sympole;
1835static int numsyms;
1836
1837/*
1838 * Allocate a symtab struct and store the string.
1839 */
1840static struct symtab *
1841getsymtab(const usch *str)
1842{
1843 struct symtab *sp = malloc(sizeof(struct symtab));
1844
1845 if (sp == NULL)
1846 error("getsymtab: couldn't allocate symtab");
1847 sp->namep = savstr(str);
1848 savch('\0');
1849 sp->value = NULL;
1850 sp->file = ifiles ? ifiles->orgfn : (const usch *)"<initial>";
1851 sp->line = ifiles ? ifiles->lineno : 0;
1852 return sp;
1853}
1854
1855/*
1856 * Do symbol lookup in a patricia tree.
1857 * Only do full string matching, no pointer optimisations.
1858 */
1859struct symtab *
1860lookup(const usch *key, int enterf)
1861{
1862 struct symtab *sp;
1863 struct tree *w, *new, *last;
1864 int len, cix, bit, fbit, svbit, ix, bitno;
1865 const usch *k, *m, *sm;
1866
1867 /* Count full string length */
1868 for (k = key, len = 0; *k; k++, len++)
1869 ;
1870
1871 switch (numsyms) {
1872 case 0: /* no symbols yet */
1873 if (enterf != ENTER)
1874 return NULL;
1875 sympole = (struct tree *)getsymtab(key);
1876 numsyms++;
1877 return (struct symtab *)sympole;
1878
1879 case 1:
1880 w = sympole;
1881 svbit = 0; /* XXX gcc */
1882 break;
1883
1884 default:
1885 w = sympole;
1886 bitno = len * CHECKBITS;
1887 for (;;) {
1888 bit = BITNO(w->bitno);
1889 fbit = bit > bitno ? 0 : P_BIT(key, bit);
1890 svbit = fbit ? IS_RIGHT_LEAF(w->bitno) :
1891 IS_LEFT_LEAF(w->bitno);
1892 w = w->lr[fbit];
1893 if (svbit)
1894 break;
1895 }
1896 }
1897
1898 sp = (struct symtab *)w;
1899
1900 sm = m = sp->namep;
1901 k = key;
1902
1903 /* Check for correct string and return */
1904 for (cix = 0; *m && *k && *m == *k; m++, k++, cix += CHECKBITS)
1905 ;
1906 if (*m == 0 && *k == 0) {
1907 if (enterf != ENTER && sp->value == NULL)
1908 return NULL;
1909 return sp;
1910 }
1911
1912 if (enterf != ENTER)
1913 return NULL; /* no string found and do not enter */
1914
1915 ix = *m ^ *k;
1916 while ((ix & 1) == 0)
1917 ix >>= 1, cix++;
1918
1919 /* Create new node */
1920 if ((new = malloc(sizeof *new)) == NULL)
1921 error("getree: couldn't allocate tree");
1922 bit = P_BIT(key, cix);
1923 new->bitno = cix | (bit ? RIGHT_IS_LEAF : LEFT_IS_LEAF);
1924 new->lr[bit] = (struct tree *)getsymtab(key);
1925
1926 if (numsyms++ == 1) {
1927 new->lr[!bit] = sympole;
1928 new->bitno |= (bit ? LEFT_IS_LEAF : RIGHT_IS_LEAF);
1929 sympole = new;
1930 return (struct symtab *)new->lr[bit];
1931 }
1932
1933 w = sympole;
1934 last = NULL;
1935 for (;;) {
1936 fbit = w->bitno;
1937 bitno = BITNO(w->bitno);
1938 if (bitno == cix)
1939 error("bitno == cix");
1940 if (bitno > cix)
1941 break;
1942 svbit = P_BIT(key, bitno);
1943 last = w;
1944 w = w->lr[svbit];
1945 if (fbit & (svbit ? RIGHT_IS_LEAF : LEFT_IS_LEAF))
1946 break;
1947 }
1948
1949 new->lr[!bit] = w;
1950 if (last == NULL) {
1951 sympole = new;
1952 } else {
1953 last->lr[svbit] = new;
1954 last->bitno &= ~(svbit ? RIGHT_IS_LEAF : LEFT_IS_LEAF);
1955 }
1956 if (bitno < cix)
1957 new->bitno |= (bit ? LEFT_IS_LEAF : RIGHT_IS_LEAF);
1958 return (struct symtab *)new->lr[bit];
1959}
1960
1961usch *
1962xstrdup(const usch *str)
1963{
1964 size_t len = strlen((const char *)str)+1;
1965 usch *rv;
1966
1967 if ((rv = malloc(len)) == NULL)
1968 error("xstrdup: out of mem");
1969 strlcpy((char *)rv, (const char *)str, len);
1970 return rv;
1971}
Note: See TracBrowser for help on using the repository browser.