scc

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

cpp.c (21891B)


      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 		siz = strlen(arg);
    357 		if (siz >= bufsiz) {
    358 			siz = -1;
    359 		} else {
    360 			memcpy(buf, arg, siz);
    361 			buf += siz;
    362 		}
    363 	} else {
    364 		addinput(IPARAM, arg, FAIL);
    365 		for (siz = 0; ; siz += yylen) {
    366 			yyspace = '\0';
    367 			if (next() == EOFTOK)
    368 				break;
    369 			if (yylen > bufsiz-2) {
    370 				siz = -1;
    371 				break;
    372 			}
    373 
    374 			if (yyspace) {
    375 				*buf++ = ' ';
    376 				bufsiz--;
    377 				siz++;
    378 			}
    379 
    380 			memcpy(buf, yytext, yylen);
    381 			bufsiz -= yylen;
    382 			buf += yylen;
    383 		}
    384 
    385 		delinput();
    386 	}
    387 	*buf = '\0';
    388 
    389 	DBG("MACRO parameter '%s' expanded to '%s'", arg, s);
    390 
    391 	return siz;
    392 }
    393 
    394 static int
    395 copymacro(Macro *mp)
    396 {
    397 	int delim, c, esc;
    398 	char *s, *p, *arg, *bp;
    399 	int size, bufsiz;
    400 
    401 	if (mp->sym == symfile)
    402 		return sprintf(mp->buffer, "\"%s\" ", filenam);
    403 	if (mp->sym == symline)
    404 		return sprintf(mp->buffer, "%d ", lineno);
    405 
    406 	bp = mp->buffer;
    407 	bufsiz = mp->bufsiz;
    408 	for (s = mp->def; c = *s; ++s) {
    409 		switch (c) {
    410 		case '\'':
    411 			delim = '\'';
    412 			goto search_delim;
    413 		case '\"':
    414 			delim = '"';
    415 		search_delim:
    416 			esc = 0;
    417 			p = s;
    418 			for (++s; c = *s; ++s) {
    419 				if (c == '\\' && !esc)
    420 					esc = 1;
    421 				else if (c == delim &&!esc)
    422 					break;
    423 				else
    424 					esc = 0;
    425 			}
    426 			size = s - p + 1;
    427 			if (size > bufsiz)
    428 				goto expansion_too_long;
    429 			memcpy(bp, p, size);
    430 			bufsiz -= size;
    431 			bp += size;
    432 			break;
    433 		case CONCAT:
    434 			/* token concatenation operator */
    435 			DBG("MACRO concat");
    436 			while (cppspace(bp[-1]))
    437 				--bp, ++bufsiz;
    438 			while (cppspace(s[1]))
    439 				++s;
    440 			break;
    441 		case STRINGIZE:
    442 			/* stringfier operator */
    443 			DBG("MACRO stringize");
    444 			arg = mp->arglist[atoi(s += 2)];
    445 			s += 2;
    446 
    447 			if (!stringoper(&bp, &bufsiz, arg))
    448 				goto expansion_too_long;
    449 			break;
    450 		case MACROPAR:
    451 			/* parameter substitution */
    452 			arg = mp->arglist[atoi(s+1)];
    453 			size = expandarg(arg, mp->def, s, bp, bufsiz);
    454 			if (size < 0)
    455 				goto expansion_too_long;
    456 			bp += size;
    457 			bufsiz -= size;
    458 			s += 3;
    459 			break;
    460 		default:
    461 			if (bufsiz-- == 0)
    462 				goto expansion_too_long;
    463 			*bp++ = c;
    464 			break;
    465 		}
    466 	}
    467 	*bp = '\0';
    468 
    469 	return bp - mp->buffer;
    470 
    471 expansion_too_long:
    472 	error("macro expansion of \"%s\" too long", mp->sym->name);
    473 }
    474 
    475 static void
    476 addhideset(Input *ip,  Symbol *sym)
    477 {
    478 	Symbol **set;
    479 	Symbol **p;
    480 
    481 	set = ip->macro->hideset;
    482 	for (p = set; p < &set[NR_MACROARG] && *p; ++p) {
    483 		if (*p == sym)
    484 			return;
    485 	}
    486 
    487 	if (p == &set[NR_MACROARG])
    488 		error("too complex macro expansion");
    489 
    490 	*p = sym;
    491 	DBG("MACRO Adding %s to hideset of %s",
    492 	    sym->name, ip->macro->sym->name);
    493 }
    494 
    495 static void
    496 hide(Symbol *sym)
    497 {
    498 	DBG("SYM: hidding symbol %s %d", sym->name, sym->hide);
    499 	sym->hide = 1;
    500 }
    501 
    502 static void
    503 unhide(Symbol *sym)
    504 {
    505 	DBG("SYM: unhidding symbol %s %d", sym->name, sym->hide);
    506 	sym->hide = 0;
    507 }
    508 
    509 void
    510 delmacro(Macro *mp)
    511 {
    512 	int i;
    513 	Symbol **p;
    514 
    515 	if (!mp)
    516 		return;
    517 
    518 	if (mp->arglist) {
    519 		for (i = 0; i < mp->npars; i++)
    520 			free(mp->arglist[i]);
    521 	}
    522 
    523 	for (p = mp->hideset; p < &mp->hideset[NR_MACROARG] && *p; ++p)
    524 		unhide(*p);
    525 
    526 	free(mp->arglist);
    527 	free(mp);
    528 }
    529 
    530 Macro *
    531 newmacro(Symbol *sym)
    532 {
    533 	Macro *mp;
    534 
    535 	mp = xmalloc(sizeof(*mp));
    536 	*mp = (Macro) {0};
    537 	mp->sym = sym;
    538 	mp->def = sym->u.s + 3;
    539 	if (sym->u.s)
    540 		mp->npars = atoi(sym->u.s);
    541 
    542 	return mp;
    543 }
    544 
    545 int
    546 expand(Symbol *sym)
    547 {
    548 	int siz;
    549 	Macro *mp;
    550 	Input *ip;
    551 	Symbol **p;
    552 
    553 	DBG("MACRO '%s' detected disexpand=%d hide=%d",
    554 	    sym->name, disexpand, sym->hide);
    555 
    556 	if (disexpand || sym->hide || sym->token != IDEN)
    557 		return 0;
    558 
    559 	mp = newmacro(sym);
    560 	mp->fname = filenam;
    561 
    562 	if (!parsepars(mp)) {
    563 		delmacro(mp);
    564 		return 0;
    565 	}
    566 
    567 	addinput(IMACRO, mp, FAIL);
    568 	mp->buffer = input->line;
    569 	mp->bufsiz = INPUTSIZ-1;
    570 
    571 	siz = copymacro(mp);
    572 	mp->buffer[siz] = '\0';
    573 
    574 	for (ip = input; ip; ip = ip->next) {
    575                 if ((ip->flags & ITYPE) == IMACRO)
    576 			addhideset(ip, sym);
    577 	}
    578 
    579 	for (p = mp->hideset; p < &mp->hideset[NR_MACROARG] && *p; ++p)
    580 		hide(*p);
    581 
    582 	DBG("MACRO '%s' expanded to :'%s'", mp->sym->name, mp->buffer);
    583 
    584 	return 1;
    585 }
    586 
    587 static int
    588 getpars(Symbol *args[NR_MACROARG])
    589 {
    590 	int n, c;
    591 	Symbol *sym;
    592 
    593 	if (*input->p != '(')
    594 		return -1;
    595 
    596 	/* skip the '(' */
    597 	next();
    598 	next();
    599 	if (yytoken == ')')
    600 		return 0;
    601 
    602 	n = 0;
    603 	do {
    604 		if (n == NR_MACROARG) {
    605 			cpperror("too many parameters in macro");
    606 			return NR_MACROARG;
    607 		}
    608 
    609 		if (yytoken == ELLIPSIS) {
    610 			sym = newsym(NS_MACROPAR, "__VA_ARGS__");
    611 		} else if (yytoken == IDEN) {
    612 			sym = yylval.sym;
    613 			next();
    614 		} else {
    615 			cpperror("macro arguments must be identifiers");
    616 			return NR_MACROARG;
    617 		}
    618 
    619 		if (!install(NS_MACROPAR, sym)) {
    620 			errorp("duplicated macro parameter '%s'", sym->name);
    621 		} else {
    622 			sym->flags |= SUSED;
    623 			args[n++] = sym;
    624 		}
    625 
    626 		if (accept(ELLIPSIS))
    627 			break;
    628 
    629 	} while (accept(','));
    630 
    631 	if (yytoken != ')') {
    632 		cpperror("expected ')' at the end of macro argument list");
    633 		return NR_MACROARG;
    634 	}
    635 
    636 	return n;
    637 }
    638 
    639 static int
    640 getdefs(Symbol *args[NR_MACROARG], int nargs, char *buffer, size_t bufsiz)
    641 {
    642 	Symbol **argp;
    643 	char c, *bp, *s, *p;
    644 	int len, id, token, prevc, ispar;
    645 
    646 	while (cppspace(*input->p))
    647 		++input->p;
    648 
    649 	bp = buffer;
    650 	for (prevc = 0; (c = *input->p) != '\n' && c != '\0'; ++input->p) {
    651 		len = 1;
    652 		ispar = 0;
    653 		s = &c;
    654 		token = c;
    655 
    656 		if (c == '#') {
    657 			if (input->p[1] == '#') {
    658 				c = token = CONCAT;
    659 				++input->p;
    660 			} else {
    661 				c = token = STRINGIZE;
    662 				while (cppspace(input->p[1]))
    663 					++input->p;
    664 			}
    665 		} else if (c == '"' || c == '\'' || c == '_' || isalpha(c)) {
    666 			next();
    667 			assert(yytoken == STRING ||
    668 			       yytoken == CONSTANT ||
    669 			       yytoken == IDEN);
    670 			token = yytoken;
    671 			s = yytext;
    672 			len = yylen;
    673 			--input->p;
    674 		}
    675 
    676 		if (token == IDEN && nargs > 0) {
    677 			for (argp = args; argp < &args[nargs]; ++argp) {
    678 				if (*argp == yylval.sym) {
    679 					id = argp - args;
    680 					sprintf(yytext,
    681 						"%c%02d%c", MACROPAR, id, MACROPAR);
    682 					ispar = 1;
    683 					yylen = len = 4;
    684 					break;
    685 				}
    686 			}
    687 		}
    688 
    689 		if (prevc == 0 && token == CONCAT)
    690 			goto wrong_concat;
    691 
    692 		if (prevc == STRINGIZE && !ispar) {
    693 			cpperror("'#' is not followed by a macro parameter");
    694 			return 0;
    695 		}
    696 
    697 		if (len >= bufsiz) {
    698 			cpperror("macro too long");
    699 			return 0;
    700 		}
    701 
    702 		memcpy(bp, s, len);
    703 		bp += len;
    704 		bufsiz -= len;
    705 		prevc = token;
    706 	}
    707 
    708 end_loop:
    709 	if ((yytoken = c) == '\0')
    710 		yytoken = EOFTOK;
    711 	if (prevc == CONCAT)
    712 		goto wrong_concat;
    713 	for ( ; bp > buffer && cppspace(bp[-1]); --bp);
    714 		;
    715 	*bp = '\0';
    716 	return 1;
    717 
    718 wrong_concat:
    719 	cpperror("'##' cannot appear at either ends of a macro expansion");
    720 	return 0;
    721 }
    722 
    723 static void
    724 define(void)
    725 {
    726 	int n;
    727 	Symbol *sym,*args[NR_MACROARG];
    728 	char buff[LINESIZ+1];
    729 	unsigned flags = SDECLARED|SSTRING;
    730 
    731 	if (cppoff)
    732 		return;
    733 
    734 	namespace = NS_CPP;
    735 	next();
    736 
    737 	if (yytoken != IDEN) {
    738 		cpperror("macro names must be identifiers");
    739 		return;
    740 	}
    741 	sym = yylval.sym;
    742 
    743 	namespace = NS_MACROPAR;   /* Avoid polution in NS_CPP */
    744 	if ((n = getpars(args)) == NR_MACROARG)
    745 		goto delete;
    746 	if (n > 0 && strcmp(args[n-1]->name, "__VA_ARGS__") == 0)
    747 		flags |= SVARIADIC;
    748 
    749 	sprintf(buff, "%02d#", n);
    750 	if (!getdefs(args, n, buff+3, LINESIZ-3))
    751 		goto delete;
    752 
    753 	if (sym->flags & SDECLARED) {
    754 		if (strcmp(sym->u.s, buff) != 0)
    755 			warn("'%s' redefined", sym->name);
    756 		free(sym->u.s);
    757 	} else {
    758 		sym = install(NS_CPP, sym);
    759 		sym->flags |= flags;
    760 	}
    761 
    762 	sym->u.s = xstrdup(buff);
    763 	DBG("MACRO '%s' defined as '%s'", sym->name, buff);
    764 	return;
    765 
    766 delete:
    767 	killsym(sym);
    768 }
    769 
    770 void
    771 incdir(char *dir)
    772 {
    773 	if (!dir || *dir == '\0')
    774 		die("cc1: incorrect -I flag");
    775 	newitem(&dirinclude, dir);
    776 }
    777 
    778 static int
    779 includefile(char *dir, char *file, size_t filelen)
    780 {
    781 	size_t dirlen;
    782 	char path[FILENAME_MAX];
    783 
    784 	if (!dir) {
    785 		dirlen = 0;
    786 		if (filelen > FILENAME_MAX-1)
    787 			return 0;
    788 	} else {
    789 		dirlen = strlen(dir);
    790 		if (dirlen + filelen > FILENAME_MAX-2)
    791 			return 0;
    792 		memcpy(path, dir, dirlen);
    793 		if (dir[dirlen-1] != '/')
    794 			path[dirlen++] = '/';
    795 	}
    796 	memcpy(path+dirlen, file, filelen);
    797 	path[dirlen + filelen] = '\0';
    798 
    799 	return addinput(IFILE, path, NOFAIL);
    800 }
    801 
    802 static char *
    803 cwd(char *buf)
    804 {
    805 	char *p, *s = filenam;
    806 	size_t len;
    807 
    808 	if ((p = strrchr(s, '/')) == NULL)
    809 		return NULL;
    810 	if ((len = p - s) >= FILENAME_MAX)
    811 		die("cc1: current work directory too long");
    812 	memcpy(buf, s, len);
    813 	buf[len] = '\0';
    814 	return buf;
    815 }
    816 
    817 static void
    818 include(void)
    819 {
    820 	char dir[FILENAME_MAX], file[FILENAME_MAX], *p, **bp;
    821 	size_t filelen;
    822 	int n;
    823 
    824 	if (cppoff)
    825 		return;
    826 
    827 	disexpand = 0;
    828 	namespace = NS_IDEN;
    829 	next();
    830 
    831 	switch (*yytext) {
    832 	case '<':
    833 		if ((p = strchr(input->begin, '>')) == NULL || p[-1] == '<')
    834 			goto bad_include;
    835 		filelen = p - input->begin;
    836 		if (filelen >= FILENAME_MAX)
    837 			goto too_long;
    838 		memcpy(file, input->begin, filelen);
    839 		file[filelen] = '\0';
    840 
    841 		input->begin = input->p = p+1;
    842 		if (next() != '\n')
    843 			goto trailing_characters;
    844 
    845 		break;
    846 	case '"':
    847 		if (yylen < 3)
    848 			goto bad_include;
    849 		filelen = yylen-2;
    850 		if (filelen >= FILENAME_MAX)
    851 			goto too_long;
    852 		memcpy(file, yytext+1, filelen);
    853 		file[filelen] = '\0';
    854 
    855 		if (next() != '\n')
    856 			goto trailing_characters;
    857 
    858 		if (includefile(cwd(dir), file, filelen))
    859 			goto its_done;
    860 		break;
    861 	default:
    862 		goto bad_include;
    863 	}
    864 
    865 	n = dirinclude.n;
    866 	for (bp = dirinclude.s; n--; ++bp) {
    867 		if (includefile(*bp, file, filelen))
    868 			goto its_done;
    869 	}
    870 	cpperror("included file '%s' not found", file);
    871 
    872 its_done:
    873 	return;
    874 
    875 trailing_characters:
    876 	cpperror("trailing characters after preprocessor directive");
    877 	return;
    878 
    879 too_long:
    880 	cpperror("too long file name in #include");
    881 	return;
    882 
    883 bad_include:
    884 	cpperror("#include expects \"FILENAME\" or <FILENAME>");
    885 	return;
    886 }
    887 
    888 static void
    889 line(void)
    890 {
    891 	long n;
    892 	char *endp, *fname;
    893 
    894 	if (cppoff)
    895 		return;
    896 
    897 	disexpand = 0;
    898 	next();
    899 	n = strtol(yytext, &endp, 10);
    900 	if (n <= 0 || n > USHRT_MAX || *endp != '\0') {
    901 		cpperror("first parameter of #line is not a positive integer");
    902 		return;
    903 	}
    904 
    905 	next();
    906 	if (yytoken == '\n') {
    907 		fname = NULL;
    908 	} else {
    909 		if (*yytext != '\"' || yylen == 1) {
    910 			cpperror("second parameter of #line is not a valid filename");
    911 			return;
    912 		}
    913 		fname = yylval.sym->u.s;
    914 	}
    915 	setloc(fname, n - 1);
    916 	if (yytoken != '\n')
    917 		next();
    918 }
    919 
    920 static void
    921 pragma(void)
    922 {
    923 	if (cppoff)
    924 		return;
    925 	next();
    926 	warn("ignoring pragma '%s'", yytext);
    927 	*input->p = '\0';
    928 	next();
    929 }
    930 
    931 static void
    932 usererr(void)
    933 {
    934 	if (cppoff)
    935 		return;
    936 	cpperror("#error %s", input->p);
    937 	exit(EXIT_FAILURE);
    938 	next();
    939 }
    940 
    941 
    942 Node *
    943 defined(void)
    944 {
    945 	Symbol *sym;
    946 	int paren;
    947 
    948 	disexpand = 1;
    949 	next();
    950 	paren = accept('(');
    951 	if (yytoken != IDEN && yytoken != TYPEIDEN)
    952 		cpperror("operator 'defined' requires an identifier");
    953 	if (yytoken == TYPEIDEN || !(yylval.sym->flags & SDECLARED))
    954 		sym = zero;
    955 	else
    956 		sym = one;
    957 	disexpand = 0;
    958 	next();
    959 	if (paren)
    960 		expect(')');
    961 	return constnode(sym);
    962 }
    963 
    964 static void
    965 ifclause(int negate, int isifdef)
    966 {
    967 	Symbol *sym;
    968 	unsigned n;
    969 	int enabled, done;
    970 	Node *expr;
    971 
    972 	if (cppctx == NR_COND-1)
    973 		error("too many nesting levels of conditional inclusion");
    974 	n = cppctx++;
    975 	DBG("CPP ifclause updates cppctx=%d", cppctx);
    976 
    977 	if (n > 0 && !ifstate[n-1].enabled) {
    978 		done = 1;
    979 		enabled = 0;
    980 		goto disabled;
    981 	}
    982 
    983 	namespace = NS_CPP;
    984 	next();
    985 
    986 	if (isifdef) {
    987 		if (yytoken != IDEN) {
    988 			cpperror("no macro name given in #%s directive",
    989 			         (negate) ? "ifndef" : "ifdef");
    990 			return;
    991 		}
    992 		sym = yylval.sym;
    993 		next();
    994 		enabled = (sym->flags & SDECLARED) != 0;
    995 		if (!enabled)
    996 			killsym(sym);
    997 	} else {
    998 		/* TODO: catch recovery here */
    999 		if ((expr = iconstexpr()) == NULL) {
   1000 			cpperror("parameter of #if is not an integer constant expression");
   1001 			return;
   1002 		}
   1003 		DBG("CPP if expr=%d", expr->sym->u.i);
   1004 		enabled = expr->sym->u.i != 0;
   1005 		freetree(expr);
   1006 	}
   1007 
   1008 	if (negate)
   1009 		enabled = !enabled;
   1010 	done = enabled;
   1011 
   1012 disabled:
   1013 	cppoff = !enabled;
   1014 	DBG("CPP if result=%d", enabled);
   1015 	ifstate[n].done = done;
   1016 	ifstate[n].enabled = enabled;
   1017 	ifstate[n].iselse = 0;
   1018 }
   1019 
   1020 static void
   1021 cppif(void)
   1022 {
   1023 	DBG("CPP line=%u if cppctx=%d", lineno, cppctx);
   1024 	disexpand = 0;
   1025 	ifclause(0, 0);
   1026 }
   1027 
   1028 static void
   1029 ifdef(void)
   1030 {
   1031 	DBG("CPP line=%u ifdef cppctx=%d", lineno, cppctx);
   1032 	ifclause(0, 1);
   1033 }
   1034 
   1035 static void
   1036 ifndef(void)
   1037 {
   1038 	DBG("CPP line=%u ifndef cppctx=%d", lineno, cppctx);
   1039 	ifclause(1, 1);
   1040 }
   1041 
   1042 static void
   1043 cppelse(void)
   1044 {
   1045 	DBG("CPP line=%u else cppctx=%d", lineno, cppctx);
   1046 
   1047 	if (cppctx == 0 || ifstate[cppctx-1].iselse) {
   1048 		cpperror("#else without #ifdef/ifndef");
   1049 		return;
   1050 	}
   1051 
   1052 	/*
   1053 	 * If we are disabled by a upper ifdef then ifclause() already
   1054 	 * marked us as disabled and done. So if we are done then we
   1055 	 * disable cpp because or ifclause was true, or it was disabled
   1056 	 * by the upper. If we are not done, then it is our turn.
   1057 	 */
   1058 	if (ifstate[cppctx-1].done) {
   1059 		ifstate[cppctx-1].enabled = 0;
   1060 		cppoff = 1;
   1061 	} else {
   1062 		ifstate[cppctx-1].done = 1;
   1063 		ifstate[cppctx-1].enabled = 1;
   1064 		cppoff = 0;
   1065 	}
   1066 	ifstate[cppctx-1].iselse = 1;
   1067 
   1068 	next();
   1069 }
   1070 
   1071 static void
   1072 elif(void)
   1073 {
   1074 	DBG("CPP line=%u elif cppctx=%d", lineno, cppctx);
   1075 
   1076 	if (cppctx == 0 || ifstate[cppctx-1].iselse) {
   1077 		cpperror("#elif without #ifdef/ifndef");
   1078 		return;
   1079 	}
   1080 
   1081 	/*
   1082 	 * If we are disabled by a upper ifdef then ifclause() already
   1083 	 * marked us as disabled and done. So if we are done then we
   1084 	 * disable cpp because or ifclause was true, or it was disabled
   1085 	 * by the upper. If we are not done, then we have to evaluate
   1086 	 * the if condition.
   1087 	 */
   1088 	if (ifstate[cppctx-1].done) {
   1089 		ifstate[cppctx-1].enabled = 0;
   1090 		cppoff = 1;
   1091 	} else {
   1092 		--cppctx;
   1093 		DBG("elif updates cppctx=%d", cppctx);
   1094 		cppif();
   1095 	}
   1096 }
   1097 
   1098 static void
   1099 endif(void)
   1100 {
   1101 	DBG("CPP line=%u endif cppctx=%d", lineno, cppctx);
   1102 
   1103 	if (cppctx == 0)
   1104 		error("#endif without #if");
   1105 
   1106 	if (cppctx > 1)
   1107 		cppoff = !ifstate[cppctx - 2].enabled;
   1108 	else
   1109 		cppoff = 0;
   1110 
   1111 	--cppctx;
   1112 	DBG("CPP endif updates cppctx=%d", cppctx);
   1113 	next();
   1114 }
   1115 
   1116 static void
   1117 undef(void)
   1118 {
   1119 	if (cppoff)
   1120 		return;
   1121 
   1122 	namespace = NS_CPP;
   1123 	next();
   1124 	if (yytoken != IDEN) {
   1125 		error("no macro name given in #undef directive");
   1126 		return;
   1127 	}
   1128 	killsym(yylval.sym);
   1129 	next();
   1130 }
   1131 
   1132 int
   1133 cpp(void)
   1134 {
   1135 	static struct {
   1136 		unsigned char token;
   1137 		void (*fun)(void);
   1138 	} *bp, clauses [] = {
   1139 		{DEFINE, define},
   1140 		{INCLUDE, include},
   1141 		{LINE, line},
   1142 		{IFDEF, ifdef},
   1143 		{IF, cppif},
   1144 		{ELIF, elif},
   1145 		{IFNDEF, ifndef},
   1146 		{ELSE, cppelse},
   1147 		{ENDIF, endif},
   1148 		{UNDEF, undef},
   1149 		{PRAGMA, pragma},
   1150 		{ERROR, usererr},
   1151 		{0, NULL}
   1152 	};
   1153 	int ns;
   1154 	char *p;
   1155 
   1156 	for (p = input->p; cppspace(*p); ++p)
   1157 		;
   1158 
   1159 	if (*p != '#') {
   1160 		if (cppoff)
   1161 			*input->p = '\0';
   1162 		return cppoff;
   1163 	}
   1164 	input->p = p+1;
   1165 
   1166 	disexpand = 1;
   1167 	lexmode = CPPMODE;
   1168 	ns = namespace;
   1169 	namespace = NS_CPPCLAUSES;
   1170 	next();
   1171 	namespace = NS_IDEN;
   1172 
   1173 	if (yytoken == '\n')
   1174 		goto ret;
   1175 
   1176 	for (bp = clauses; bp->token && bp->token != yytoken; ++bp)
   1177 		;
   1178 	if (!bp->token) {
   1179 		errorp("incorrect preprocessor directive '%s'", yytext);
   1180 		goto ret;
   1181 	}
   1182 
   1183 	DBG("CPP %s", yytext);
   1184 
   1185 	/*
   1186 	 * create a new context to avoid polish the current context,
   1187 	 * and to get all the symbols freed at the end
   1188 	 */
   1189 	pushctx();
   1190 	(*bp->fun)();
   1191 	popctx();
   1192 
   1193 	/*
   1194 	 * #include changes the content of input->line, so the correctness
   1195 	 * of the line must be checked in the own include(), and we have
   1196 	 * to skip this tests. For the same reason include() is the only
   1197 	 * function which does not prepare the next token
   1198 	 */
   1199 	if (bp->token == INCLUDE)
   1200 		goto ret;
   1201 
   1202 	if (yytoken != '\n' && yytoken != EOFTOK && !cppoff)
   1203 		cpperror("trailing characters after preprocessor directive");
   1204 
   1205 ret:
   1206 	disexpand = 0;
   1207 	lexmode = CCMODE;
   1208 	namespace = ns;
   1209 
   1210 	/*
   1211 	 * at this point we know that the cpp line is processed, and any error
   1212 	 * is generated but as next is called we cannot be sure that input is
   1213 	 * valid anymore, but in case of begin valid we want to discard any
   1214 	 * pending input in the current line
   1215 	 */
   1216 	if (input)
   1217 		*input->p = '\0';
   1218 
   1219 	return 1;
   1220 }
   1221 
   1222 void
   1223 ppragmaln(void)
   1224 {
   1225 	static char file[FILENAME_MAX];
   1226 	static unsigned nline;
   1227 	char *s;
   1228 
   1229 	putchar('\n');
   1230 	if (strcmp(file, filenam)) {
   1231 		strcpy(file, filenam);
   1232 		s = "#line %u \"%s\"\n";
   1233 	} else if (nline+1 != lineno) {
   1234 		s = "#line %u\n";
   1235 	} else {
   1236 		s = "";
   1237 	}
   1238 	nline = lineno;
   1239 	printf(s, nline, file);
   1240 }
   1241 
   1242 void
   1243 outcpp(void)
   1244 {
   1245 	int c;
   1246 	char *s, *t;
   1247 
   1248 	for (next(); yytoken != EOFTOK; next()) {
   1249 		if (onlyheader)
   1250 			continue;
   1251 		printf("%s ", yytext);
   1252 	}
   1253 	putchar('\n');
   1254 }