scc

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

cpp.c (21385B)


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