scc

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

cpp.c (21885B)


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