scc

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

cpp.c (19265B)


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