cpp.c - scc - simple c99 compiler
HTML git clone git://git.simple-cc.org/scc
DIR Log
DIR Files
DIR Refs
DIR Submodules
DIR README
DIR LICENSE
---
cpp.c (21385B)
---
1 #include <assert.h>
2 #include <ctype.h>
3 #include <limits.h>
4 #include <stdio.h>
5 #include <stdlib.h>
6 #include <string.h>
7 #include <time.h>
8
9 #include <scc/cstd.h>
10 #include <scc/scc.h>
11 #include "cc1.h"
12
13 struct ifstate {
14 unsigned char done;
15 unsigned char enabled;
16 unsigned char iselse;
17 };
18
19 static unsigned ncmdlines;
20 static Symbol *symline, *symfile;
21 static struct ifstate ifstate[NR_COND];
22 static int cppoff;
23 static struct items dirinclude;
24
25 unsigned cppctx;
26 int disexpand;
27 int disescape;
28
29 void
30 defdefine(char *name, char *val, char *source)
31 {
32 char buffer[INPUTSIZ+1];
33 char *def, *fmt = "#define %s %s\n";
34 Symbol *sym = &(Symbol) {
35 .name = name,
36 .flags = SDECLARED,
37 };
38
39 if (!val)
40 val = "";
41 if (strlen(fmt) + strlen(name) + strlen(val) > INPUTSIZ) {
42 errorp("macro definition '%s' too big", name);
43 return;
44 }
45
46 sprintf(buffer, fmt, name, val);
47 lineno = ++ncmdlines;
48
49 addinput(IPARAM, buffer, FAIL);
50 cpp();
51 delinput();
52 }
53
54 void
55 undefmacro(char *s)
56 {
57 killsym(lookup(NS_CPP, s, NOALLOC));
58 }
59
60 void
61 icpp(void)
62 {
63 struct tm *tm;
64 time_t t;
65 static char sdate[14], stime[11];
66 static struct {
67 char *name;
68 char *value;
69 } *bp, list[] = {
70 {"__STDC__", "1"},
71 {"__STDC_HOSTED__", "1"},
72 {"__SCC__", "1"},
73 {"__DATE__", sdate},
74 {"__TIME__", stime},
75 {"__STDC_VERSION__", STDC_VERSION},
76 {"__LINE__", NULL},
77 {"__FILE__", NULL},
78 {"__FLT_EVAL_METHOD__", "0"},
79 {NULL, NULL}
80 };
81
82 t = time(NULL);
83 tm = localtime(&t);
84 strftime(sdate, sizeof(sdate), "\"%b %d %Y\"", tm);
85 strftime(stime, sizeof(stime), "\"%H:%M:%S\"", tm);
86
87 for (bp = list; bp->name; ++bp)
88 defdefine(bp->name, bp->value, "built-in");
89
90 symline = lookup(NS_CPP, "__LINE__", ALLOC);
91 symfile = lookup(NS_CPP, "__FILE__", ALLOC);
92
93 ncmdlines = 0;
94 }
95
96 static void
97 nextcpp(Macro *mp)
98 {
99 int len, siz;
100 char *arg;
101
102 next();
103 if (yytoken == EOFTOK) {
104 error("unterminated argument list invoking macro \"%s\"",
105 mp->sym->name);
106 }
107
108 if (yytoken == IDEN)
109 yylval.sym->flags |= SUSED;
110
111 len = strlen(yytext);
112 siz = mp->argsiz;
113 if (len+1 > INT_MAX - siz) {
114 error("too long argument invoking macro \"%s\"",
115 mp->sym->name);
116 }
117
118 arg = xrealloc(mp->arg, siz + len + 1);
119 if (siz > 0) {
120 arg[siz-1] = ' ';
121 memcpy(arg + siz, yytext, len+1);
122 } else {
123 memcpy(arg, yytext, len+1);
124 }
125
126 mp->arg = arg;
127 mp->argsiz = siz + len + 1;
128 }
129
130 static void
131 paren(Macro *mp)
132 {
133 for (;;) {
134 nextcpp(mp);
135 switch (yytoken) {
136 case ')':
137 return;
138 case '(':
139 paren(mp);
140 break;
141 }
142 }
143 }
144
145 static char *
146 parameter(Macro *mp)
147 {
148 int siz;
149 char *s, *begin, *end;
150 Input *ip = input;
151
152 mp->arg = NULL;
153 mp->argsiz = 0;
154 for (;;) {
155 nextcpp(mp);
156 switch (yytoken) {
157 case ')':
158 case ',':
159 /* remove "," or ")"*/
160 begin = mp->arg;
161 end = mp->arg + mp->argsiz - 2;
162
163 while (end > begin && isspace(end[-1]))
164 --end;
165 while (begin < end && isspace(begin[0]))
166 ++begin;
167
168 siz = end - begin;
169 s = memcpy(xmalloc(siz+1), begin, siz);
170 s[siz] = '\0';
171 free(mp->arg);
172
173 return s;
174 case '(':
175 paren(mp);
176 break;
177 }
178 }
179 }
180
181 static int
182 parsepars(Macro *mp)
183 {
184 int n;
185
186 if (mp->npars == -1)
187 return 1;
188 if (ahead() != '(')
189 return 0;
190
191 disexpand = 1;
192 next();
193 n = 0;
194
195 if (mp->npars == 0 && ahead() == ')') {
196 next();
197 } else {
198 do {
199 mp->arglist = xrealloc(mp->arglist, (n+1)*sizeof(char *));
200 mp->arglist[n] = parameter(mp);
201 DBG("MACRO fetched arg '%s'", mp->arglist[n]);
202 } while (++n < NR_MACROARG && yytoken == ',');
203 }
204
205 if (yytoken != ')')
206 error("incorrect macro function-alike invocation");
207 disexpand = 0;
208
209 if (n == NR_MACROARG)
210 error("too many parameters in macro \"%s\"", mp->sym->name);
211 if (n != mp->npars) {
212 error("macro \"%s\" received %d arguments, but it takes %d",
213 mp->sym->name, n, mp->npars);
214 }
215
216 return 1;
217 }
218
219 static int
220 concatoper(char *def, char *cur)
221 {
222 char *s;
223
224 for (s = cur + 4; isspace(*s); ++s)
225 ;
226 if (*s == CONCAT)
227 return 1;
228
229 for (s = cur; s > def && isspace(s[-1]); --s)
230 ;
231 if (s > def && s[-1] == CONCAT)
232 return 1;
233
234 return 0;
235 }
236
237 static int
238 expandarg(char *arg, char *def, char *curdef, char *buf, int bufsiz)
239 {
240 int siz;
241 char *s = buf;
242
243 /* gives priority to concatenation operators */
244 if (concatoper(def, curdef)) {
245 siz = strlen(arg);
246 if (siz >= bufsiz) {
247 siz = -1;
248 } else {
249 memcpy(buf, arg, siz);
250 buf += siz;
251 }
252 } else {
253 addinput(IPARAM, arg, FAIL);
254 for (siz = 0; next() != EOFTOK; siz += yylen+1) {
255 if (yylen > bufsiz-2) {
256 siz = -1;
257 break;
258 }
259 memcpy(buf, yytext, yylen);
260 bufsiz -= yylen + 1;
261 buf += yylen;
262 *buf++ = ' ';
263 }
264
265 delinput();
266 }
267 *buf = '\0';
268
269 DBG("MACRO parameter '%s' expanded to '%s'", arg, s);
270
271 return siz;
272 }
273
274 static int
275 copymacro(Macro *mp)
276 {
277 int delim, c, esc;
278 char *s, *p, *arg, *bp;
279 int size, bufsiz;
280
281 if (mp->sym == symfile)
282 return sprintf(mp->buffer, "\"%s\" ", filenam);
283 if (mp->sym == symline)
284 return sprintf(mp->buffer, "%d ", lineno);
285
286 bp = mp->buffer;
287 bufsiz = mp->bufsiz;
288 for (s = mp->def; c = *s; ++s) {
289 switch (c) {
290 case '\'':
291 delim = '\'';
292 goto search_delim;
293 case '\"':
294 delim = '"';
295 search_delim:
296 esc = 0;
297 p = s;
298 for (++s; c = *s; ++s) {
299 if (c == '\\' && !esc)
300 esc = 1;
301 else if (c == delim &&!esc)
302 break;
303 else
304 esc = 0;
305 }
306 size = s - p + 1;
307 if (size > bufsiz)
308 goto expansion_too_long;
309 memcpy(bp, p, size);
310 bufsiz -= size;
311 bp += size;
312 break;
313 case CONCAT:
314 /* token concatenation operator */
315 DBG("MACRO concat");
316 while (bp[-1] == ' ')
317 --bp, ++bufsiz;
318 while (s[1] == ' ')
319 ++s;
320 break;
321 case STRINGIZE:
322 /* stringfier operator */
323 DBG("MACRO stringize");
324 arg = mp->arglist[atoi(s += 2)];
325 s += 2;
326
327 if (bufsiz < 3)
328 goto expansion_too_long;
329
330 *bp++ = '"';
331 while ((c = *arg++) != '\0') {
332 if (c == '"') {
333 if (bufsiz < 3)
334 goto expansion_too_long;
335 *bp++ = '\\';
336 *bp++ = '"';
337 bufsiz -= 2;
338 } else {
339 if (bufsiz < 2)
340 goto expansion_too_long;
341 *bp++ = c;
342 bufsiz--;
343 }
344 }
345 *bp++ = '"';
346
347 break;
348 case MACROPAR:
349 /* parameter substitution */
350 arg = mp->arglist[atoi(s+1)];
351 size = expandarg(arg, mp->def, s, bp, bufsiz);
352 if (size < 0)
353 goto expansion_too_long;
354 bp += size;
355 bufsiz -= size;
356 s += 3;
357 break;
358 default:
359 if (bufsiz-- == 0)
360 goto expansion_too_long;
361 *bp++ = c;
362 break;
363 }
364 }
365 *bp = '\0';
366
367 return bp - mp->buffer;
368
369 expansion_too_long:
370 error("macro expansion of \"%s\" too long", mp->sym->name);
371 }
372
373 static void
374 addhideset(Input *ip, Symbol *sym)
375 {
376 Symbol **set;
377 Symbol **p;
378
379 set = ip->macro->hideset;
380 for (p = set; p < &set[NR_MACROARG] && *p; ++p) {
381 if (*p == sym)
382 return;
383 }
384
385 if (p == &set[NR_MACROARG])
386 error("too complex macro expansion");
387
388 *p = sym;
389 DBG("MACRO Adding %s to hideset of %s",
390 sym->name, ip->macro->sym->name);
391 }
392
393 static void
394 hide(Symbol *sym)
395 {
396 DBG("SYM: hidding symbol %s %d", sym->name, sym->hide);
397 sym->hide = 1;
398 }
399
400 static void
401 unhide(Symbol *sym)
402 {
403 DBG("SYM: unhidding symbol %s %d", sym->name, sym->hide);
404 sym->hide = 0;
405 }
406
407 void
408 delmacro(Macro *mp)
409 {
410 int i;
411 Symbol **p;
412
413 if (!mp)
414 return;
415
416 if (mp->arglist) {
417 for (i = 0; i < mp->npars; i++)
418 free(mp->arglist[i]);
419 }
420
421 for (p = mp->hideset; p < &mp->hideset[NR_MACROARG] && *p; ++p)
422 unhide(*p);
423
424 free(mp->arglist);
425 free(mp);
426 }
427
428 Macro *
429 newmacro(Symbol *sym)
430 {
431 Macro *mp;
432
433 mp = xmalloc(sizeof(*mp));
434 *mp = (Macro) {0};
435 mp->sym = sym;
436 mp->def = sym->u.s + 3;
437 if (sym->u.s)
438 mp->npars = atoi(sym->u.s);
439
440 return mp;
441 }
442
443 int
444 expand(Symbol *sym)
445 {
446 int siz;
447 Macro *mp;
448 Input *ip;
449 Symbol **p;
450
451 DBG("MACRO '%s' detected disexpand=%d hide=%d",
452 sym->name, disexpand, sym->hide);
453
454 if (disexpand || sym->hide || sym->token != IDEN)
455 return 0;
456
457 mp = newmacro(sym);
458 mp->fname = filenam;
459
460 if (!parsepars(mp)) {
461 delmacro(mp);
462 return 0;
463 }
464
465 addinput(IMACRO, mp, FAIL);
466 mp->buffer = input->line;
467 mp->bufsiz = INPUTSIZ-1;
468
469 siz = copymacro(mp);
470 mp->buffer[siz] = '\0';
471
472 for (ip = input; ip; ip = ip->next) {
473 if ((ip->flags & ITYPE) == IMACRO)
474 addhideset(ip, sym);
475 }
476
477 for (p = mp->hideset; p < &mp->hideset[NR_MACROARG] && *p; ++p)
478 hide(*p);
479
480 DBG("MACRO '%s' expanded to :'%s'", mp->sym->name, mp->buffer);
481
482 return 1;
483 }
484
485 static int
486 getpars(Symbol *args[NR_MACROARG])
487 {
488 int n, c;
489 Symbol *sym;
490
491 if (*input->p != '(')
492 return -1;
493
494 /* skip the '(' */
495 next();
496 next();
497 if (yytoken == ')')
498 return 0;
499
500 n = 0;
501 do {
502 if (n == NR_MACROARG) {
503 cpperror("too many parameters in macro");
504 return NR_MACROARG;
505 }
506 if (accept(ELLIPSIS)) {
507 args[n++] = NULL;
508 break;
509 }
510 if (yytoken != IDEN) {
511 cpperror("macro arguments must be identifiers");
512 return NR_MACROARG;
513 }
514 if ((sym = install(NS_IDEN, yylval.sym)) == NULL) {
515 errorp("duplicated macro parameter '%s'", yytext);
516 } else {
517 sym->flags |= SUSED;
518 args[n++] = sym;
519 }
520 next();
521 } while (accept(','));
522
523 if (yytoken != ')') {
524 cpperror("expected ')' at the end of macro argument list");
525 return NR_MACROARG;
526 }
527
528 return n;
529 }
530
531 static int
532 getdefs(Symbol *args[NR_MACROARG], int nargs, char *buffer, size_t bufsiz)
533 {
534 size_t len;
535 char *bp, *p;
536 Symbol **argp, *sym;
537 int c, id, token, prevc, ispar;
538
539 while (isspace(*input->p))
540 ++input->p;
541
542 bp = buffer;
543 for (prevc = 0; (c = *input->p) != '\n' && c != '\0'; ++input->p) {
544 len = 1;
545 ispar = 0;
546 token = c;
547 sym = NULL;
548
549 if (c == '#') {
550 if (input->p[1] == '#') {
551 token = CONCAT;
552 ++input->p;
553 } else {
554 token = STRINGIZE;
555 }
556 } else if (c == '_' || isalpha(c)) {
557 token = IDEN;
558 for (p = input->p; isalnum(*p) || *p == '_'; ++p)
559 ;
560 len = p - input->p;
561 if (len > INTIDENTSIZ) {
562 cpperror("identifier too long in macro definition");
563 return 0;
564 }
565 memcpy(yytext, input->p, len);
566 yytext[len] = '\0';
567 yylen = len;
568 input->p = p - 1;
569 sym = lookup(NS_IDEN, yytext, NOALLOC);
570 } else if (c == '"') {
571 next();
572 assert(yytoken == STRING);
573 token = STRING;
574 len = yylen;
575 }
576
577 if (sym && nargs > 0) {
578 for (argp = args; argp < &args[nargs]; ++argp) {
579 if (*argp == sym)
580 break;
581 }
582 if (argp != &args[nargs]) {
583 id = argp - args;
584 sprintf(yytext,
585 "%c%02d%c", MACROPAR, id, MACROPAR);
586 ispar = 1;
587 yylen = len = 4;
588 }
589 }
590
591 if (prevc == 0 && token == CONCAT)
592 goto wrong_concat;
593
594 if (prevc == STRINGIZE && !ispar) {
595 cpperror("'#' is not followed by a macro parameter");
596 return 0;
597 }
598
599 if (len >= bufsiz) {
600 cpperror("macro too long");
601 return 0;
602 }
603
604 if (token == IDEN || token == STRING)
605 memcpy(bp, yytext, yylen);
606 else
607 *bp = token;
608
609 bp += len;
610 bufsiz -= len;
611 prevc = token;
612 }
613
614 end_loop:
615 if ((yytoken = c) == '\0')
616 yytoken = EOFTOK;
617 if (prevc == CONCAT)
618 goto wrong_concat;
619 for ( ; bp > buffer && isspace(bp[-1]); --bp);
620 ;
621 *bp = '\0';
622 return 1;
623
624 wrong_concat:
625 cpperror("'##' cannot appear at either ends of a macro expansion");
626 return 0;
627 }
628
629 static void
630 define(void)
631 {
632 Symbol *sym,*args[NR_MACROARG];
633 char buff[LINESIZ+1];
634 int n;
635
636 if (cppoff)
637 return;
638
639 disescape = 1;
640 namespace = NS_CPP;
641 next();
642
643 if (yytoken != IDEN) {
644 cpperror("macro names must be identifiers");
645 return;
646 }
647 sym = yylval.sym;
648
649 namespace = NS_IDEN; /* Avoid polution in NS_CPP */
650 if ((n = getpars(args)) == NR_MACROARG)
651 goto delete;
652 if (n > 0 && !args[n-1]) /* it is a variadic function */
653 --n;
654
655 sprintf(buff, "%02d#", n);
656 if (!getdefs(args, n, buff+3, LINESIZ-3))
657 goto delete;
658
659 if (sym->flags & SDECLARED) {
660 if (strcmp(sym->u.s, buff) != 0)
661 warn("'%s' redefined", sym->name);
662 free(sym->u.s);
663 } else {
664 sym = install(NS_CPP, sym);
665 sym->flags |= SDECLARED|SSTRING;
666 }
667
668 sym->u.s = xstrdup(buff);
669 DBG("MACRO '%s' defined as '%s'", sym->name, buff);
670 return;
671
672 delete:
673 killsym(sym);
674 }
675
676 void
677 incdir(char *dir)
678 {
679 if (!dir || *dir == '\0')
680 die("cc1: incorrect -I flag");
681 newitem(&dirinclude, dir);
682 }
683
684 static int
685 includefile(char *dir, char *file, size_t filelen)
686 {
687 size_t dirlen;
688 char path[FILENAME_MAX];
689
690 if (!dir) {
691 dirlen = 0;
692 if (filelen > FILENAME_MAX-1)
693 return 0;
694 } else {
695 dirlen = strlen(dir);
696 if (dirlen + filelen > FILENAME_MAX-2)
697 return 0;
698 memcpy(path, dir, dirlen);
699 if (dir[dirlen-1] != '/')
700 path[dirlen++] = '/';
701 }
702 memcpy(path+dirlen, file, filelen);
703 path[dirlen + filelen] = '\0';
704
705 return addinput(IFILE, path, NOFAIL);
706 }
707
708 static char *
709 cwd(char *buf)
710 {
711 char *p, *s = filenam;
712 size_t len;
713
714 if ((p = strrchr(s, '/')) == NULL)
715 return NULL;
716 if ((len = p - s) >= FILENAME_MAX)
717 die("cc1: current work directory too long");
718 memcpy(buf, s, len);
719 buf[len] = '\0';
720 return buf;
721 }
722
723 static void
724 include(void)
725 {
726 char dir[FILENAME_MAX], file[FILENAME_MAX], *p, **bp;
727 size_t filelen;
728 int n;
729
730 if (cppoff)
731 return;
732
733 disexpand = 0;
734 namespace = NS_IDEN;
735 next();
736
737 switch (*yytext) {
738 case '<':
739 if ((p = strchr(input->begin, '>')) == NULL || p[-1] == '<')
740 goto bad_include;
741 filelen = p - input->begin;
742 if (filelen >= FILENAME_MAX)
743 goto too_long;
744 memcpy(file, input->begin, filelen);
745 file[filelen] = '\0';
746
747 input->begin = input->p = p+1;
748 if (next() != '\n')
749 goto trailing_characters;
750
751 break;
752 case '"':
753 if (yylen < 3)
754 goto bad_include;
755 filelen = yylen-2;
756 if (filelen >= FILENAME_MAX)
757 goto too_long;
758 memcpy(file, yytext+1, filelen);
759 file[filelen] = '\0';
760
761 if (next() != '\n')
762 goto trailing_characters;
763
764 if (includefile(cwd(dir), file, filelen))
765 goto its_done;
766 break;
767 default:
768 goto bad_include;
769 }
770
771 n = dirinclude.n;
772 for (bp = dirinclude.s; n--; ++bp) {
773 if (includefile(*bp, file, filelen))
774 goto its_done;
775 }
776 cpperror("included file '%s' not found", file);
777
778 its_done:
779 return;
780
781 trailing_characters:
782 cpperror("trailing characters after preprocessor directive");
783 return;
784
785 too_long:
786 cpperror("too long file name in #include");
787 return;
788
789 bad_include:
790 cpperror("#include expects \"FILENAME\" or <FILENAME>");
791 return;
792 }
793
794 static void
795 line(void)
796 {
797 long n;
798 char *endp, *fname;
799
800 if (cppoff)
801 return;
802
803 disexpand = 0;
804 next();
805 n = strtol(yytext, &endp, 10);
806 if (n <= 0 || n > USHRT_MAX || *endp != '\0') {
807 cpperror("first parameter of #line is not a positive integer");
808 return;
809 }
810
811 next();
812 if (yytoken == '\n') {
813 fname = NULL;
814 } else {
815 if (*yytext != '\"' || yylen == 1) {
816 cpperror("second parameter of #line is not a valid filename");
817 return;
818 }
819 fname = yylval.sym->u.s;
820 }
821 setloc(fname, n - 1);
822 if (yytoken != '\n')
823 next();
824 }
825
826 static void
827 pragma(void)
828 {
829 if (cppoff)
830 return;
831 next();
832 warn("ignoring pragma '%s'", yytext);
833 *input->p = '\0';
834 next();
835 }
836
837 static void
838 usererr(void)
839 {
840 if (cppoff)
841 return;
842 cpperror("#error %s", input->p);
843 exit(EXIT_FAILURE);
844 next();
845 }
846
847
848 Node *
849 defined(void)
850 {
851 Symbol *sym;
852 int paren;
853
854 disexpand = 1;
855 next();
856 paren = accept('(');
857 if (yytoken != IDEN && yytoken != TYPEIDEN)
858 cpperror("operator 'defined' requires an identifier");
859 if (yytoken == TYPEIDEN || !(yylval.sym->flags & SDECLARED))
860 sym = zero;
861 else
862 sym = one;
863 disexpand = 0;
864 next();
865 if (paren)
866 expect(')');
867 return constnode(sym);
868 }
869
870 static void
871 ifclause(int negate, int isifdef)
872 {
873 Symbol *sym;
874 unsigned n;
875 int enabled, done;
876 Node *expr;
877
878 if (cppctx == NR_COND-1)
879 error("too many nesting levels of conditional inclusion");
880 n = cppctx++;
881 DBG("CPP ifclause updates cppctx=%d", cppctx);
882
883 if (n > 0 && !ifstate[n-1].enabled) {
884 done = 1;
885 enabled = 0;
886 goto disabled;
887 }
888
889 namespace = NS_CPP;
890 next();
891
892 if (isifdef) {
893 if (yytoken != IDEN) {
894 cpperror("no macro name given in #%s directive",
895 (negate) ? "ifndef" : "ifdef");
896 return;
897 }
898 sym = yylval.sym;
899 next();
900 enabled = (sym->flags & SDECLARED) != 0;
901 if (!enabled)
902 killsym(sym);
903 } else {
904 /* TODO: catch recovery here */
905 if ((expr = constexpr()) == NULL) {
906 cpperror("parameter of #if is not an integer constant expression");
907 return;
908 }
909 DBG("CPP if expr=%d", expr->sym->u.i);
910 enabled = expr->sym->u.i != 0;
911 freetree(expr);
912 }
913
914 if (negate)
915 enabled = !enabled;
916 done = enabled;
917
918 disabled:
919 cppoff = !enabled;
920 DBG("CPP if result=%d", enabled);
921 ifstate[n].done = done;
922 ifstate[n].enabled = enabled;
923 ifstate[n].iselse = 0;
924 }
925
926 static void
927 cppif(void)
928 {
929 DBG("CPP line=%u if cppctx=%d", lineno, cppctx);
930 disexpand = 0;
931 ifclause(0, 0);
932 }
933
934 static void
935 ifdef(void)
936 {
937 DBG("CPP line=%u ifdef cppctx=%d", lineno, cppctx);
938 ifclause(0, 1);
939 }
940
941 static void
942 ifndef(void)
943 {
944 DBG("CPP line=%u ifndef cppctx=%d", lineno, cppctx);
945 ifclause(1, 1);
946 }
947
948 static void
949 cppelse(void)
950 {
951 DBG("CPP line=%u else cppctx=%d", lineno, cppctx);
952
953 if (cppctx == 0 || ifstate[cppctx-1].iselse) {
954 cpperror("#else without #ifdef/ifndef");
955 return;
956 }
957
958 /*
959 * If we are disabled by a upper ifdef then ifclause() already
960 * marked us as disabled and done. So if we are done then we
961 * disable cpp because or ifclause was true, or it was disabled
962 * by the upper. If we are not done, then it is our turn.
963 */
964 if (ifstate[cppctx-1].done) {
965 ifstate[cppctx-1].enabled = 0;
966 cppoff = 1;
967 } else {
968 ifstate[cppctx-1].done = 1;
969 ifstate[cppctx-1].enabled = 1;
970 cppoff = 0;
971 }
972 ifstate[cppctx-1].iselse = 1;
973
974 next();
975 }
976
977 static void
978 elif(void)
979 {
980 DBG("CPP line=%u elif cppctx=%d", lineno, cppctx);
981
982 if (cppctx == 0 || ifstate[cppctx-1].iselse) {
983 cpperror("#elif without #ifdef/ifndef");
984 return;
985 }
986
987 /*
988 * If we are disabled by a upper ifdef then ifclause() already
989 * marked us as disabled and done. So if we are done then we
990 * disable cpp because or ifclause was true, or it was disabled
991 * by the upper. If we are not done, then we have to evaluate
992 * the if condition.
993 */
994 if (ifstate[cppctx-1].done) {
995 ifstate[cppctx-1].enabled = 0;
996 cppoff = 1;
997 } else {
998 --cppctx;
999 DBG("elif updates cppctx=%d", cppctx);
1000 cppif();
1001 }
1002 }
1003
1004 static void
1005 endif(void)
1006 {
1007 DBG("CPP line=%u endif cppctx=%d", lineno, cppctx);
1008
1009 if (cppctx == 0)
1010 error("#endif without #if");
1011
1012 if (cppctx > 1)
1013 cppoff = !ifstate[cppctx - 2].enabled;
1014 else
1015 cppoff = 0;
1016
1017 --cppctx;
1018 DBG("CPP endif updates cppctx=%d", cppctx);
1019 next();
1020 }
1021
1022 static void
1023 undef(void)
1024 {
1025 if (cppoff)
1026 return;
1027
1028 namespace = NS_CPP;
1029 next();
1030 if (yytoken != IDEN) {
1031 error("no macro name given in #undef directive");
1032 return;
1033 }
1034 killsym(yylval.sym);
1035 next();
1036 }
1037
1038 int
1039 cpp(void)
1040 {
1041 static struct {
1042 unsigned char token;
1043 void (*fun)(void);
1044 } *bp, clauses [] = {
1045 {DEFINE, define},
1046 {INCLUDE, include},
1047 {LINE, line},
1048 {IFDEF, ifdef},
1049 {IF, cppif},
1050 {ELIF, elif},
1051 {IFNDEF, ifndef},
1052 {ELSE, cppelse},
1053 {ENDIF, endif},
1054 {UNDEF, undef},
1055 {PRAGMA, pragma},
1056 {ERROR, usererr},
1057 {0, NULL}
1058 };
1059 int ns;
1060 char *p;
1061
1062 for (p = input->p; isspace(*p); ++p)
1063 ;
1064
1065 if (*p != '#') {
1066 if (cppoff)
1067 *input->p = '\0';
1068 return cppoff;
1069 }
1070 input->p = p+1;
1071
1072 disexpand = 1;
1073 lexmode = CPPMODE;
1074 ns = namespace;
1075 namespace = NS_CPPCLAUSES;
1076 next();
1077 namespace = NS_IDEN;
1078
1079 if (yytoken == '\n')
1080 goto ret;
1081
1082 for (bp = clauses; bp->token && bp->token != yytoken; ++bp)
1083 ;
1084 if (!bp->token) {
1085 errorp("incorrect preprocessor directive '%s'", yytext);
1086 goto ret;
1087 }
1088
1089 DBG("CPP %s", yytext);
1090
1091 /*
1092 * create a new context to avoid polish the current context,
1093 * and to get all the symbols freed at the end
1094 */
1095 pushctx();
1096 (*bp->fun)();
1097 popctx();
1098
1099 /*
1100 * #include changes the content of input->line, so the correctness
1101 * of the line must be checked in the own include(), and we have
1102 * to skip this tests. For the same reason include() is the only
1103 * function which does not prepare the next token
1104 */
1105 if (bp->token == INCLUDE)
1106 goto ret;
1107
1108 if (yytoken != '\n' && yytoken != EOFTOK && !cppoff)
1109 cpperror("trailing characters after preprocessor directive");
1110
1111 ret:
1112 disescape = 0;
1113 disexpand = 0;
1114 lexmode = CCMODE;
1115 namespace = ns;
1116
1117 /*
1118 * at this point we know that the cpp line is processed, and any error
1119 * is generated but as next is called we cannot be sure that input is
1120 * valid anymore, but in case of begin valid we want to discard any
1121 * pending input in the current line
1122 */
1123 if (input)
1124 *input->p = '\0';
1125
1126 return 1;
1127 }
1128
1129 void
1130 ppragmaln(void)
1131 {
1132 static char file[FILENAME_MAX];
1133 static unsigned nline;
1134 char *s;
1135
1136 putchar('\n');
1137 if (strcmp(file, filenam)) {
1138 strcpy(file, filenam);
1139 s = "#line %u \"%s\"\n";
1140 } else if (nline+1 != lineno) {
1141 s = "#line %u\n";
1142 } else {
1143 s = "";
1144 }
1145 nline = lineno;
1146 printf(s, nline, file);
1147 }
1148
1149 void
1150 outcpp(void)
1151 {
1152 int c;
1153 char *s, *t;
1154
1155 for (next(); yytoken != EOFTOK; next()) {
1156 if (onlyheader)
1157 continue;
1158 if (yytoken != STRING) {
1159 printf("%s ", yytext);
1160 continue;
1161 }
1162 for (s = yytext; (c = *s) != '\0'; ++s) {
1163 switch (c) {
1164 case '\n':
1165 t = "\\n";
1166 goto print_str;
1167 case '\v':
1168 t = "\\v";
1169 goto print_str;
1170 case '\b':
1171 t = "\\b";
1172 goto print_str;
1173 case '\t':
1174 t = "\\t";
1175 goto print_str;
1176 case '\a':
1177 t = "\\a";
1178 goto print_str;
1179 case '\f':
1180 t = "\\f";
1181 goto print_str;
1182 case '\r':
1183 t = "\\r";
1184 goto print_str;
1185 case '"':
1186 if (s == yytext || s[1] == '\0')
1187 goto print_chr;
1188 t = "\\\"";
1189 goto print_str;
1190 case '\'':
1191 t = "\\'";
1192 goto print_str;
1193 case '\?':
1194 t = "\\\?";
1195 goto print_str;
1196 case '\\':
1197 putchar('\\');
1198 default:
1199 print_chr:
1200 if (!isprint(c))
1201 printf("\\x%x", c);
1202 else
1203 putchar(c);
1204 break;
1205 print_str:
1206 fputs(t, stdout);
1207 break;
1208 }
1209 }
1210 putchar(' ');
1211 }
1212 putchar('\n');
1213 }