515 lines · 9.2 KB · C
RawDownload
#include <u.h>#include <libc.h>#include "cpp.h" #define	NSTAK	128#define	SGN	0#define	UNS	1#define	UND	2 #define	UNSMARK	0x1000 struct value {	vlong	val;	int	type;}; /* conversion types */enum {	NONE,	RELAT,	ARITH,	LOGIC,	SPCL,	SHIFT,	UNARY}; /* operator priority, arity, and conversion type, indexed by tokentype */const struct pri {	char	pri;	char	assoc;	char	arity;	char	ctype;} priority[MAXTOK] = {	[END]		{ 0, 0, 0, 0 },	[EQ]		{ 11, 0, 2, RELAT },	[NEQ]		{ 11, 0, 2, RELAT },	[LEQ]		{ 12, 0, 2, RELAT },	[GEQ]		{ 12, 0, 2, RELAT },	[LSH]		{ 13, 0, 2, SHIFT },	[RSH]		{ 13, 0, 2, SHIFT },	[LAND]		{ 7, 0, 2, LOGIC },	[LOR]		{ 6, 0, 2, LOGIC },	[LP]		{ 3, 1, 0, 0 },	[RP]		{ 3, 1, 0, 0 },	[AND]		{ 10, 0, 2, ARITH },	[STAR]		{ 15, 0, 2, ARITH },	[PLUS]		{ 14, 0, 2, ARITH },	[MINUS]		{ 14, 0, 2, ARITH },	[TILDE]		{ 16, 0, 1, UNARY },	[NOT]		{ 16, 0, 1, UNARY },	[SLASH]		{ 15, 0, 2, ARITH },	[PCT]		{ 15, 0, 2, ARITH },	[LT]		{ 12, 0, 2, RELAT },	[GT]		{ 12, 0, 2, RELAT },	[CIRC]		{ 9, 0, 2, ARITH },	[OR]		{ 8, 0, 2, ARITH },	[QUEST]		{ 5, 1, 2, SPCL },	[COLON]		{ 5, 1, 2, SPCL },	[COMMA]		{ 4, 0, 2, 0 },	[XCOMMA]	{ 4, 0, 2, 0 },	[DEFINED]	{ 16, 0, 1, UNARY },	[UMINUS]	{ 16, 0, 0, UNARY },}; int	evalop(struct pri);struct	value tokval(Token *);struct value vals[NSTAK], *vp;enum toktype ops[NSTAK], *op; /* * Evaluate an #if #elif #ifdef #ifndef line.  trp->tp points to the keyword. * Using shunting yard algorithm. */vlongeval(Tokenrow *trp, int kw){	Token *tp;	Nlist *np;	int ntok, rand; 	trp->tp++;	if (kw==KIFDEF || kw==KIFNDEF) {		if (trp->lp - trp->bp != 4 || trp->tp->type!=NAME) {			error(ERROR, "Syntax error in #ifdef/#ifndef");			return 0;		}		np = lookup(trp->tp, 0);		return (kw==KIFDEF) == (np && np->flag&(ISDEFINED|ISMAC));	}	ntok = trp->tp - trp->bp;	kwdefined->val = KDEFINED;	/* activate special meaning of defined */	expandrow(trp, "<if>");	kwdefined->val = NAME;	vp = vals;	op = ops;	for (rand=0, tp = trp->bp+ntok; tp < trp->lp; tp++) {		switch(tp->type) {		case WS:		case NL:			continue; 		/* nilary */		case NAME:		case NAME1:		case NUMBER:		case CCON:		case STRING:			if (rand)				goto syntax;			if(vp == vals + NSTAK)				goto fullstakdeveloper;			*vp++ = tokval(tp);			rand = 1;			continue; 		/* unary */		case DEFINED:		case TILDE:		case NOT:			if (rand)				goto syntax;			if(op == ops + NSTAK)				goto fullstakdeveloper;			*op++ = tp->type;			continue; 		/* unary-binary */		case PLUS: case MINUS: case STAR: case AND:			if (rand==0) {				if(op == ops + NSTAK)					goto fullstakdeveloper;				if (tp->type==MINUS)					*op++ = UMINUS;				if (tp->type==STAR || tp->type==AND) {					error(ERROR, "Illegal operator * or & in #if/#elif");					return 0;				}				continue;			}			/* flow through */ 		/* plain binary */		case EQ: case NEQ: case LEQ: case GEQ: case LSH: case RSH:		case LAND: case LOR: case SLASH: case PCT:		case LT: case GT: case CIRC: case OR: case QUEST:		case COLON: case COMMA: case XCOMMA:			if (rand==0)				goto syntax;			if (evalop(priority[tp->type])!=0)				return 0;			if(op == ops + NSTAK)				goto fullstakdeveloper;			*op++ = tp->type;			rand = 0;			continue; 		case LP:			if (rand)				goto syntax;			if(op == ops + NSTAK)				goto fullstakdeveloper;			*op++ = LP;			continue; 		case RP:			if (!rand)				goto syntax;			if (evalop(priority[RP])!=0)				return 0;			if (op<=ops || op[-1]!=LP) {				goto syntax;			}			op--;			continue; 		default:			error(ERROR,"Bad operator (%t) in #if/#elif", tp);			return 0;		}	}	if (rand==0)		goto syntax;	if (evalop(priority[END])!=0)		return 0;	if (op!=ops || vp!=&vals[1]) {		error(ERROR, "Botch in #if/#elif");		return 0;	}	if (vals[0].type==UND)		error(ERROR, "Undefined expression value");	return vals[0].val;syntax:	error(ERROR, "Syntax xx error in #if/#elif");	return 0;fullstakdeveloper:	error(ERROR, "Out of stack space evaluating #if");	return 0;} intevalop(struct pri pri){	struct value v1, v2;	vlong rv1, rv2;	int rtype, oper; 	rv2=0;	rtype=0;	while (op != ops && pri.pri + pri.assoc <= priority[op[-1]].pri) {		oper = *--op;		if (priority[oper].arity==2) {			v2 = *--vp;			rv2 = v2.val;		}		v1 = *--vp;		rv1 = v1.val;		switch (priority[oper].ctype) {		case 0:		default:			error(WARNING, "Syntax error in #if/#endif");			return 1;		case ARITH:		case RELAT:			if (v1.type==UNS || v2.type==UNS)				rtype = UNS;			else				rtype = SGN;			if (v1.type==UND || v2.type==UND)				rtype = UND;			if (priority[oper].ctype==RELAT && rtype==UNS) {				oper |= UNSMARK;				rtype = SGN;			}			break;		case SHIFT:			if (v1.type==UND || v2.type==UND)				rtype = UND;			else				rtype = v1.type;			if (rtype==UNS)				oper |= UNSMARK;			break;		case UNARY:			rtype = v1.type;			break;		case LOGIC:		case SPCL:			break;		}		switch (oper) {		case EQ: case EQ|UNSMARK:			rv1 = rv1==rv2; break;		case NEQ: case NEQ|UNSMARK:			rv1 = rv1!=rv2; break;		case LEQ:			rv1 = rv1<=rv2; break;		case GEQ:			rv1 = rv1>=rv2; break;		case LT:			rv1 = rv1<rv2; break;		case GT:			rv1 = rv1>rv2; break;		case LEQ|UNSMARK:			rv1 = (uvlong)rv1<=rv2; break;		case GEQ|UNSMARK:			rv1 = (uvlong)rv1>=rv2; break;		case LT|UNSMARK:			rv1 = (uvlong)rv1<rv2; break;		case GT|UNSMARK:			rv1 = (uvlong)rv1>rv2; break;		case LSH:			rv1 <<= rv2; break;		case LSH|UNSMARK:			rv1 = (uvlong)rv1<<rv2; break;		case RSH:			rv1 >>= rv2; break;		case RSH|UNSMARK:			rv1 = (uvlong)rv1>>rv2; break;		case LAND:			rtype = UND;			if (v1.type==UND)				break;			if (rv1!=0) {				if (v2.type==UND)					break;				rv1 = rv2!=0;			} else				rv1 = 0;			rtype = SGN;			break;		case LOR:			rtype = UND;			if (v1.type==UND)				break;			if (rv1==0) {				if (v2.type==UND)					break;				rv1 = rv2!=0;			} else				rv1 = 1;			rtype = SGN;			break;		case AND:			rv1 &= rv2; break;		case STAR:			rv1 *= rv2; break;		case PLUS:			rv1 += rv2; break;		case MINUS:			rv1 -= rv2; break;		case UMINUS:			if (v1.type==UND)				rtype = UND;			rv1 = -rv1; break;		case OR:			rv1 |= rv2; break;		case CIRC:			rv1 ^= rv2; break;		case TILDE:			rv1 = ~rv1; break;		case NOT:			rv1 = !rv1; if (rtype!=UND) rtype = SGN; break;		case SLASH:			if (rv2==0) {				rtype = UND;				break;			}			if (rtype==UNS)				rv1 /= (uvlong)rv2;			else				rv1 /= rv2;			break;		case PCT:			if (rv2==0) {				rtype = UND;				break;			}			if (rtype==UNS)				rv1 %= (uvlong)rv2;			else				rv1 %= rv2;			break;		case COLON:			if (op[-1] != QUEST)				error(ERROR, "Bad ?: in #if/endif");			else {				op--;				if ((--vp)->val==0)					v1 = v2;				rtype = v1.type;				rv1 = v1.val;			}			break;		case DEFINED:			break;		default:			error(ERROR, "Eval botch (unknown operator)");			return 1;		}		v1.val = rv1;		v1.type = rtype;		if(op == ops + NSTAK){			error(ERROR, "Out of stack space evaluating #if");			return 0;		}		*vp++ = v1;	}	return 0;} struct valuetokval(Token *tp){	struct value v;	Nlist *np;	int i, base, c, longcc;	uvlong n;	Rune r;	uchar *p; 	v.type = SGN;	v.val = 0;	switch (tp->type) { 	case NAME:		v.val = 0;		break; 	case NAME1:		if ((np = lookup(tp, 0)) && np->flag&(ISDEFINED|ISMAC))			v.val = 1;		break; 	case NUMBER:		n = 0;		base = 10;		p = tp->t;		c = p[tp->len];		p[tp->len] = '\0';		if (*p=='0') {			base = 8;			if (p[1]=='x' || p[1]=='X') {				base = 16;				p++;			}			p++;		}		for (;; p++) {			if ((i = digit(*p)) < 0)				break;			if (i>=base)				error(WARNING,				  "Bad digit in number %t", tp);			n *= base;			n += i;		}		if (n>=(1ULL<<63) && base!=10)			v.type = UNS;		for (; *p; p++) {			if (*p=='u' || *p=='U')				v.type = UNS;			else if (*p=='l' || *p=='L')				{}			else {				error(ERROR,				  "Bad number %t in #if/#elif", tp);				break;			}		}		v.val = n;		tp->t[tp->len] = c;		break; 	case CCON:		n = 0;		p = tp->t;		longcc = 0;		if (*p=='L') {			p += 1;			longcc = 1;		}		p += 1;		if (*p=='\\') {			p += 1;			if ((i = digit(*p))>=0 && i<=7) {				n = i;				p += 1;				if ((i = digit(*p))>=0 && i<=7) {					p += 1;					n <<= 3;					n += i;					if ((i = digit(*p))>=0 && i<=7) {						p += 1;						n <<= 3;						n += i;					}				}			} else if (*p=='x') {				p += 1;				while ((i = digit(*p))>=0 && i<=15) {					p += 1;					n <<= 4;					n += i;				}			} else {				static char cvcon[]				  = "a\ab\bf\fn\nr\rt\tv\v''\"\"??\\\\";				for (i=0; i<sizeof(cvcon); i+=2) {					if (*p == cvcon[i]) {						n = cvcon[i+1];						break;					}				}				p += 1;				if (i>=sizeof(cvcon))					error(WARNING,					 "Undefined escape in character constant");			}		} else if (*p=='\'')			error(ERROR, "Empty character constant");		else {			i = chartorune(&r, (char*)p);			n = r;			p += i;			if (i>1 && longcc==0)				error(WARNING, "Undefined character constant");		}		if (*p!='\'')			error(WARNING, "Multibyte character constant undefined");		else if (n>127 && longcc==0)			error(WARNING, "Character constant taken as not signed");		v.val = n;		break; 	case STRING:		error(ERROR, "String in #if/#elif");		break;	}	return v;

Lines 1–500 of 515.