scc

simple c99 compiler
git clone git://git.simple-cc.org/scc
Log | Files | Refs | Submodules | README | LICENSE

cpp.c (20960B)


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