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