scc

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

cpp.c (20189B)


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