xref: /plan9/sys/src/cmd/cpp/eval.c (revision 2a7824990d644563b93ed8d4abf1407c40b2087a)
13e12c5d1SDavid du Colombier #include <u.h>
23e12c5d1SDavid du Colombier #include <libc.h>
33e12c5d1SDavid du Colombier #include "cpp.h"
43e12c5d1SDavid du Colombier 
5*2a782499SDavid du Colombier #define	NSTAK	1024
63e12c5d1SDavid du Colombier #define	SGN	0
73e12c5d1SDavid du Colombier #define	UNS	1
83e12c5d1SDavid du Colombier #define	UND	2
93e12c5d1SDavid du Colombier 
103e12c5d1SDavid du Colombier #define	UNSMARK	0x1000
113e12c5d1SDavid du Colombier 
123e12c5d1SDavid du Colombier struct value {
133e12c5d1SDavid du Colombier 	long	val;
143e12c5d1SDavid du Colombier 	int	type;
153e12c5d1SDavid du Colombier };
163e12c5d1SDavid du Colombier 
173e12c5d1SDavid du Colombier /* conversion types */
183e12c5d1SDavid du Colombier #define	RELAT	1
193e12c5d1SDavid du Colombier #define	ARITH	2
203e12c5d1SDavid du Colombier #define	LOGIC	3
213e12c5d1SDavid du Colombier #define	SPCL	4
223e12c5d1SDavid du Colombier #define	SHIFT	5
233e12c5d1SDavid du Colombier #define	UNARY	6
243e12c5d1SDavid du Colombier 
253e12c5d1SDavid du Colombier /* operator priority, arity, and conversion type, indexed by tokentype */
263e12c5d1SDavid du Colombier const struct pri {
273e12c5d1SDavid du Colombier 	char	pri;
283e12c5d1SDavid du Colombier 	char	arity;
293e12c5d1SDavid du Colombier 	char	ctype;
303e12c5d1SDavid du Colombier } priority[] = {
313e12c5d1SDavid du Colombier 	{ 0, 0, 0 },		/* END */
323e12c5d1SDavid du Colombier 	{ 0, 0, 0 },		/* UNCLASS */
333e12c5d1SDavid du Colombier 	{ 0, 0, 0 },		/* NAME */
343e12c5d1SDavid du Colombier 	{ 0, 0, 0 },		/* NUMBER */
353e12c5d1SDavid du Colombier 	{ 0, 0, 0 },		/* STRING */
363e12c5d1SDavid du Colombier 	{ 0, 0, 0 },		/* CCON */
373e12c5d1SDavid du Colombier 	{ 0, 0, 0 },		/* NL */
383e12c5d1SDavid du Colombier 	{ 0, 0, 0 },		/* WS */
393e12c5d1SDavid du Colombier 	{ 0, 0, 0 },		/* DSHARP */
403e12c5d1SDavid du Colombier 	{ 11, 2, RELAT },	/* EQ */
413e12c5d1SDavid du Colombier 	{ 11, 2, RELAT },	/* NEQ */
423e12c5d1SDavid du Colombier 	{ 12, 2, RELAT },	/* LEQ */
433e12c5d1SDavid du Colombier 	{ 12, 2, RELAT },	/* GEQ */
443e12c5d1SDavid du Colombier 	{ 13, 2, SHIFT },	/* LSH */
453e12c5d1SDavid du Colombier 	{ 13, 2, SHIFT },	/* RSH */
463e12c5d1SDavid du Colombier 	{ 7, 2, LOGIC },	/* LAND */
473e12c5d1SDavid du Colombier 	{ 6, 2, LOGIC },	/* LOR */
483e12c5d1SDavid du Colombier 	{ 0, 0, 0 },		/* PPLUS */
493e12c5d1SDavid du Colombier 	{ 0, 0, 0 },		/* MMINUS */
503e12c5d1SDavid du Colombier 	{ 0, 0, 0 },		/* ARROW */
513e12c5d1SDavid du Colombier 	{ 0, 0, 0 },		/* SBRA */
523e12c5d1SDavid du Colombier 	{ 0, 0, 0 },		/* SKET */
533e12c5d1SDavid du Colombier 	{ 3, 0, 0 },		/* LP */
543e12c5d1SDavid du Colombier 	{ 3, 0, 0 },		/* RP */
553e12c5d1SDavid du Colombier 	{ 0, 0, 0 },		/* DOT */
563e12c5d1SDavid du Colombier 	{ 10, 2, ARITH },	/* AND */
573e12c5d1SDavid du Colombier 	{ 15, 2, ARITH },	/* STAR */
583e12c5d1SDavid du Colombier 	{ 14, 2, ARITH },	/* PLUS */
593e12c5d1SDavid du Colombier 	{ 14, 2, ARITH },	/* MINUS */
603e12c5d1SDavid du Colombier 	{ 16, 1, UNARY },	/* TILDE */
613e12c5d1SDavid du Colombier 	{ 16, 1, UNARY },	/* NOT */
623e12c5d1SDavid du Colombier 	{ 15, 2, ARITH },	/* SLASH */
633e12c5d1SDavid du Colombier 	{ 15, 2, ARITH },	/* PCT */
643e12c5d1SDavid du Colombier 	{ 12, 2, RELAT },	/* LT */
653e12c5d1SDavid du Colombier 	{ 12, 2, RELAT },	/* GT */
663e12c5d1SDavid du Colombier 	{ 9, 2, ARITH },	/* CIRC */
673e12c5d1SDavid du Colombier 	{ 8, 2, ARITH },	/* OR */
683e12c5d1SDavid du Colombier 	{ 5, 2, SPCL },		/* QUEST */
693e12c5d1SDavid du Colombier 	{ 5, 2, SPCL },		/* COLON */
703e12c5d1SDavid du Colombier 	{ 0, 0, 0 },		/* ASGN */
713e12c5d1SDavid du Colombier 	{ 4, 2, 0 },		/* COMMA */
723e12c5d1SDavid du Colombier 	{ 0, 0, 0 },		/* SHARP */
733e12c5d1SDavid du Colombier 	{ 0, 0, 0 },		/* SEMIC */
743e12c5d1SDavid du Colombier 	{ 0, 0, 0 },		/* CBRA */
753e12c5d1SDavid du Colombier 	{ 0, 0, 0 },		/* CKET */
763e12c5d1SDavid du Colombier 	{ 0, 0, 0 },		/* ASPLUS */
773e12c5d1SDavid du Colombier  	{ 0, 0, 0 },		/* ASMINUS */
783e12c5d1SDavid du Colombier  	{ 0, 0, 0 },		/* ASSTAR */
793e12c5d1SDavid du Colombier  	{ 0, 0, 0 },		/* ASSLASH */
803e12c5d1SDavid du Colombier  	{ 0, 0, 0 },		/* ASPCT */
813e12c5d1SDavid du Colombier  	{ 0, 0, 0 },		/* ASCIRC */
823e12c5d1SDavid du Colombier  	{ 0, 0, 0 },		/* ASLSH */
833e12c5d1SDavid du Colombier 	{ 0, 0, 0 },		/* ASRSH */
843e12c5d1SDavid du Colombier  	{ 0, 0, 0 },		/* ASOR */
853e12c5d1SDavid du Colombier  	{ 0, 0, 0 },		/* ASAND */
863e12c5d1SDavid du Colombier 	{ 0, 0, 0 },		/* ELLIPS */
873e12c5d1SDavid du Colombier 	{ 0, 0, 0 },		/* DSHARP1 */
883e12c5d1SDavid du Colombier 	{ 0, 0, 0 },		/* NAME1 */
893e12c5d1SDavid du Colombier 	{ 16, 1, UNARY },	/* DEFINED */
903e12c5d1SDavid du Colombier 	{ 16, 0, UNARY },	/* UMINUS */
913e12c5d1SDavid du Colombier };
923e12c5d1SDavid du Colombier 
933e12c5d1SDavid du Colombier int	evalop(struct pri);
943e12c5d1SDavid du Colombier struct	value tokval(Token *);
95*2a782499SDavid du Colombier struct value vals[NSTAK + 1], *vp;
96*2a782499SDavid du Colombier enum toktype ops[NSTAK + 1], *op;
973e12c5d1SDavid du Colombier 
983e12c5d1SDavid du Colombier /*
993e12c5d1SDavid du Colombier  * Evaluate an #if #elif #ifdef #ifndef line.  trp->tp points to the keyword.
1003e12c5d1SDavid du Colombier  */
1013e12c5d1SDavid du Colombier long
eval(Tokenrow * trp,int kw)1023e12c5d1SDavid du Colombier eval(Tokenrow *trp, int kw)
1033e12c5d1SDavid du Colombier {
1043e12c5d1SDavid du Colombier 	Token *tp;
1053e12c5d1SDavid du Colombier 	Nlist *np;
1063e12c5d1SDavid du Colombier 	int ntok, rand;
1073e12c5d1SDavid du Colombier 
1083e12c5d1SDavid du Colombier 	trp->tp++;
1093e12c5d1SDavid du Colombier 	if (kw==KIFDEF || kw==KIFNDEF) {
1103e12c5d1SDavid du Colombier 		if (trp->lp - trp->bp != 4 || trp->tp->type!=NAME) {
1113e12c5d1SDavid du Colombier 			error(ERROR, "Syntax error in #ifdef/#ifndef");
1123e12c5d1SDavid du Colombier 			return 0;
1133e12c5d1SDavid du Colombier 		}
1143e12c5d1SDavid du Colombier 		np = lookup(trp->tp, 0);
115219b2ee8SDavid du Colombier 		return (kw==KIFDEF) == (np && np->flag&(ISDEFINED|ISMAC));
1163e12c5d1SDavid du Colombier 	}
117bd389b36SDavid du Colombier 	ntok = trp->tp - trp->bp;
118bd389b36SDavid du Colombier 	kwdefined->val = KDEFINED;	/* activate special meaning of defined */
11905dd1647SDavid du Colombier 	expandrow(trp, "<if>", Notinmacro);
120bd389b36SDavid du Colombier 	kwdefined->val = NAME;
1213e12c5d1SDavid du Colombier 	vp = vals;
1223e12c5d1SDavid du Colombier 	op = ops;
1233e12c5d1SDavid du Colombier 	*op++ = END;
1243e12c5d1SDavid du Colombier 	for (rand=0, tp = trp->bp+ntok; tp < trp->lp; tp++) {
125*2a782499SDavid du Colombier 		if(op >= ops + NSTAK)
126*2a782499SDavid du Colombier 			sysfatal("cpp: can't evaluate #if: increase NSTAK");
1273e12c5d1SDavid du Colombier 		switch(tp->type) {
1283e12c5d1SDavid du Colombier 		case WS:
1293e12c5d1SDavid du Colombier 		case NL:
1303e12c5d1SDavid du Colombier 			continue;
1313e12c5d1SDavid du Colombier 
1323e12c5d1SDavid du Colombier 		/* nilary */
1333e12c5d1SDavid du Colombier 		case NAME:
1343e12c5d1SDavid du Colombier 		case NAME1:
1353e12c5d1SDavid du Colombier 		case NUMBER:
1363e12c5d1SDavid du Colombier 		case CCON:
1373e12c5d1SDavid du Colombier 		case STRING:
1383e12c5d1SDavid du Colombier 			if (rand)
1393e12c5d1SDavid du Colombier 				goto syntax;
1403e12c5d1SDavid du Colombier 			*vp++ = tokval(tp);
1413e12c5d1SDavid du Colombier 			rand = 1;
1423e12c5d1SDavid du Colombier 			continue;
1433e12c5d1SDavid du Colombier 
1443e12c5d1SDavid du Colombier 		/* unary */
1453e12c5d1SDavid du Colombier 		case DEFINED:
1463e12c5d1SDavid du Colombier 		case TILDE:
1473e12c5d1SDavid du Colombier 		case NOT:
1483e12c5d1SDavid du Colombier 			if (rand)
1493e12c5d1SDavid du Colombier 				goto syntax;
1503e12c5d1SDavid du Colombier 			*op++ = tp->type;
1513e12c5d1SDavid du Colombier 			continue;
1523e12c5d1SDavid du Colombier 
1533e12c5d1SDavid du Colombier 		/* unary-binary */
1543e12c5d1SDavid du Colombier 		case PLUS: case MINUS: case STAR: case AND:
1553e12c5d1SDavid du Colombier 			if (rand==0) {
1563e12c5d1SDavid du Colombier 				if (tp->type==MINUS)
1573e12c5d1SDavid du Colombier 					*op++ = UMINUS;
1583e12c5d1SDavid du Colombier 				if (tp->type==STAR || tp->type==AND) {
1594dc626cdSDavid du Colombier 					error(ERROR, "Illegal operator * or & in #if/#elif");
1603e12c5d1SDavid du Colombier 					return 0;
1613e12c5d1SDavid du Colombier 				}
1623e12c5d1SDavid du Colombier 				continue;
1633e12c5d1SDavid du Colombier 			}
1643e12c5d1SDavid du Colombier 			/* flow through */
1653e12c5d1SDavid du Colombier 
1663e12c5d1SDavid du Colombier 		/* plain binary */
1673e12c5d1SDavid du Colombier 		case EQ: case NEQ: case LEQ: case GEQ: case LSH: case RSH:
1683e12c5d1SDavid du Colombier 		case LAND: case LOR: case SLASH: case PCT:
1693e12c5d1SDavid du Colombier 		case LT: case GT: case CIRC: case OR: case QUEST:
1703e12c5d1SDavid du Colombier 		case COLON: case COMMA:
1713e12c5d1SDavid du Colombier 			if (rand==0)
1723e12c5d1SDavid du Colombier 				goto syntax;
1733e12c5d1SDavid du Colombier 			if (evalop(priority[tp->type])!=0)
1743e12c5d1SDavid du Colombier 				return 0;
1753e12c5d1SDavid du Colombier 			*op++ = tp->type;
1763e12c5d1SDavid du Colombier 			rand = 0;
1773e12c5d1SDavid du Colombier 			continue;
1783e12c5d1SDavid du Colombier 
1793e12c5d1SDavid du Colombier 		case LP:
1803e12c5d1SDavid du Colombier 			if (rand)
1813e12c5d1SDavid du Colombier 				goto syntax;
1823e12c5d1SDavid du Colombier 			*op++ = LP;
1833e12c5d1SDavid du Colombier 			continue;
1843e12c5d1SDavid du Colombier 
1853e12c5d1SDavid du Colombier 		case RP:
1863e12c5d1SDavid du Colombier 			if (!rand)
1873e12c5d1SDavid du Colombier 				goto syntax;
1883e12c5d1SDavid du Colombier 			if (evalop(priority[RP])!=0)
1893e12c5d1SDavid du Colombier 				return 0;
1903e12c5d1SDavid du Colombier 			if (op<=ops || op[-1]!=LP) {
1913e12c5d1SDavid du Colombier 				goto syntax;
1923e12c5d1SDavid du Colombier 			}
1933e12c5d1SDavid du Colombier 			op--;
1943e12c5d1SDavid du Colombier 			continue;
1953e12c5d1SDavid du Colombier 
1963e12c5d1SDavid du Colombier 		default:
1974dc626cdSDavid du Colombier 			error(ERROR,"Bad operator (%t) in #if/#elif", tp);
1983e12c5d1SDavid du Colombier 			return 0;
1993e12c5d1SDavid du Colombier 		}
2003e12c5d1SDavid du Colombier 	}
2013e12c5d1SDavid du Colombier 	if (rand==0)
2023e12c5d1SDavid du Colombier 		goto syntax;
2033e12c5d1SDavid du Colombier 	if (evalop(priority[END])!=0)
2043e12c5d1SDavid du Colombier 		return 0;
2053e12c5d1SDavid du Colombier 	if (op!=&ops[1] || vp!=&vals[1]) {
2064dc626cdSDavid du Colombier 		error(ERROR, "Botch in #if/#elif");
2073e12c5d1SDavid du Colombier 		return 0;
2083e12c5d1SDavid du Colombier 	}
2093e12c5d1SDavid du Colombier 	if (vals[0].type==UND)
2103e12c5d1SDavid du Colombier 		error(ERROR, "Undefined expression value");
2113e12c5d1SDavid du Colombier 	return vals[0].val;
2123e12c5d1SDavid du Colombier syntax:
2134dc626cdSDavid du Colombier 	error(ERROR, "Syntax error in #if/#elif");
2143e12c5d1SDavid du Colombier 	return 0;
2153e12c5d1SDavid du Colombier }
2163e12c5d1SDavid du Colombier 
2173e12c5d1SDavid du Colombier int
evalop(struct pri pri)2183e12c5d1SDavid du Colombier evalop(struct pri pri)
2193e12c5d1SDavid du Colombier {
2203e12c5d1SDavid du Colombier 	struct value v1, v2;
2213e12c5d1SDavid du Colombier 	long rv1, rv2;
2223e12c5d1SDavid du Colombier 	int rtype, oper;
2233e12c5d1SDavid du Colombier 
2243e12c5d1SDavid du Colombier 	rv2=0;
2253e12c5d1SDavid du Colombier 	rtype=0;
2263e12c5d1SDavid du Colombier 	while (pri.pri < priority[op[-1]].pri) {
2273e12c5d1SDavid du Colombier 		oper = *--op;
2283e12c5d1SDavid du Colombier 		if (priority[oper].arity==2) {
2293e12c5d1SDavid du Colombier 			v2 = *--vp;
2303e12c5d1SDavid du Colombier 			rv2 = v2.val;
2313e12c5d1SDavid du Colombier 		}
2323e12c5d1SDavid du Colombier 		v1 = *--vp;
2333e12c5d1SDavid du Colombier 		rv1 = v1.val;
2343e12c5d1SDavid du Colombier 		switch (priority[oper].ctype) {
2353e12c5d1SDavid du Colombier 		case 0:
2363e12c5d1SDavid du Colombier 		default:
2373e12c5d1SDavid du Colombier 			error(WARNING, "Syntax error in #if/#endif");
2383e12c5d1SDavid du Colombier 			return 1;
2393e12c5d1SDavid du Colombier 		case ARITH:
2403e12c5d1SDavid du Colombier 		case RELAT:
2413e12c5d1SDavid du Colombier 			if (v1.type==UNS || v2.type==UNS)
2423e12c5d1SDavid du Colombier 				rtype = UNS;
2433e12c5d1SDavid du Colombier 			else
2443e12c5d1SDavid du Colombier 				rtype = SGN;
2453e12c5d1SDavid du Colombier 			if (v1.type==UND || v2.type==UND)
2463e12c5d1SDavid du Colombier 				rtype = UND;
2473e12c5d1SDavid du Colombier 			if (priority[oper].ctype==RELAT && rtype==UNS) {
2483e12c5d1SDavid du Colombier 				oper |= UNSMARK;
2493e12c5d1SDavid du Colombier 				rtype = SGN;
2503e12c5d1SDavid du Colombier 			}
2513e12c5d1SDavid du Colombier 			break;
2523e12c5d1SDavid du Colombier 		case SHIFT:
2533e12c5d1SDavid du Colombier 			if (v1.type==UND || v2.type==UND)
2543e12c5d1SDavid du Colombier 				rtype = UND;
2553e12c5d1SDavid du Colombier 			else
2563e12c5d1SDavid du Colombier 				rtype = v1.type;
2573e12c5d1SDavid du Colombier 			if (rtype==UNS)
2583e12c5d1SDavid du Colombier 				oper |= UNSMARK;
2593e12c5d1SDavid du Colombier 			break;
2603e12c5d1SDavid du Colombier 		case UNARY:
2613e12c5d1SDavid du Colombier 			rtype = v1.type;
2623e12c5d1SDavid du Colombier 			break;
2633e12c5d1SDavid du Colombier 		case LOGIC:
2643e12c5d1SDavid du Colombier 		case SPCL:
2653e12c5d1SDavid du Colombier 			break;
2663e12c5d1SDavid du Colombier 		}
2673e12c5d1SDavid du Colombier 		switch (oper) {
2683e12c5d1SDavid du Colombier 		case EQ: case EQ|UNSMARK:
2693e12c5d1SDavid du Colombier 			rv1 = rv1==rv2; break;
2703e12c5d1SDavid du Colombier 		case NEQ: case NEQ|UNSMARK:
2713e12c5d1SDavid du Colombier 			rv1 = rv1!=rv2; break;
2723e12c5d1SDavid du Colombier 		case LEQ:
2733e12c5d1SDavid du Colombier 			rv1 = rv1<=rv2; break;
2743e12c5d1SDavid du Colombier 		case GEQ:
2753e12c5d1SDavid du Colombier 			rv1 = rv1>=rv2; break;
2763e12c5d1SDavid du Colombier 		case LT:
2773e12c5d1SDavid du Colombier 			rv1 = rv1<rv2; break;
2783e12c5d1SDavid du Colombier 		case GT:
2793e12c5d1SDavid du Colombier 			rv1 = rv1>rv2; break;
2803e12c5d1SDavid du Colombier 		case LEQ|UNSMARK:
2813e12c5d1SDavid du Colombier 			rv1 = (unsigned long)rv1<=rv2; break;
2823e12c5d1SDavid du Colombier 		case GEQ|UNSMARK:
2833e12c5d1SDavid du Colombier 			rv1 = (unsigned long)rv1>=rv2; break;
2843e12c5d1SDavid du Colombier 		case LT|UNSMARK:
2853e12c5d1SDavid du Colombier 			rv1 = (unsigned long)rv1<rv2; break;
2863e12c5d1SDavid du Colombier 		case GT|UNSMARK:
2873e12c5d1SDavid du Colombier 			rv1 = (unsigned long)rv1>rv2; break;
2883e12c5d1SDavid du Colombier 		case LSH:
2893e12c5d1SDavid du Colombier 			rv1 <<= rv2; break;
2903e12c5d1SDavid du Colombier 		case LSH|UNSMARK:
2913e12c5d1SDavid du Colombier 			rv1 = (unsigned long)rv1<<rv2; break;
2923e12c5d1SDavid du Colombier 		case RSH:
2933e12c5d1SDavid du Colombier 			rv1 >>= rv2; break;
2943e12c5d1SDavid du Colombier 		case RSH|UNSMARK:
2953e12c5d1SDavid du Colombier 			rv1 = (unsigned long)rv1>>rv2; break;
2963e12c5d1SDavid du Colombier 		case LAND:
2973e12c5d1SDavid du Colombier 			rtype = UND;
2983e12c5d1SDavid du Colombier 			if (v1.type==UND)
2993e12c5d1SDavid du Colombier 				break;
3003e12c5d1SDavid du Colombier 			if (rv1!=0) {
3013e12c5d1SDavid du Colombier 				if (v2.type==UND)
3023e12c5d1SDavid du Colombier 					break;
3033e12c5d1SDavid du Colombier 				rv1 = rv2!=0;
3043e12c5d1SDavid du Colombier 			} else
3053e12c5d1SDavid du Colombier 				rv1 = 0;
3063e12c5d1SDavid du Colombier 			rtype = SGN;
3073e12c5d1SDavid du Colombier 			break;
3083e12c5d1SDavid du Colombier 		case LOR:
3093e12c5d1SDavid du Colombier 			rtype = UND;
3103e12c5d1SDavid du Colombier 			if (v1.type==UND)
3113e12c5d1SDavid du Colombier 				break;
3123e12c5d1SDavid du Colombier 			if (rv1==0) {
3133e12c5d1SDavid du Colombier 				if (v2.type==UND)
3143e12c5d1SDavid du Colombier 					break;
3153e12c5d1SDavid du Colombier 				rv1 = rv2!=0;
3163e12c5d1SDavid du Colombier 			} else
3173e12c5d1SDavid du Colombier 				rv1 = 1;
3183e12c5d1SDavid du Colombier 			rtype = SGN;
3193e12c5d1SDavid du Colombier 			break;
3203e12c5d1SDavid du Colombier 		case AND:
3213e12c5d1SDavid du Colombier 			rv1 &= rv2; break;
3223e12c5d1SDavid du Colombier 		case STAR:
3233e12c5d1SDavid du Colombier 			rv1 *= rv2; break;
3243e12c5d1SDavid du Colombier 		case PLUS:
3253e12c5d1SDavid du Colombier 			rv1 += rv2; break;
3263e12c5d1SDavid du Colombier 		case MINUS:
3273e12c5d1SDavid du Colombier 			rv1 -= rv2; break;
3283e12c5d1SDavid du Colombier 		case UMINUS:
3293e12c5d1SDavid du Colombier 			if (v1.type==UND)
3303e12c5d1SDavid du Colombier 				rtype = UND;
3313e12c5d1SDavid du Colombier 			rv1 = -rv1; break;
3323e12c5d1SDavid du Colombier 		case OR:
3333e12c5d1SDavid du Colombier 			rv1 |= rv2; break;
3343e12c5d1SDavid du Colombier 		case CIRC:
3353e12c5d1SDavid du Colombier 			rv1 ^= rv2; break;
3363e12c5d1SDavid du Colombier 		case TILDE:
3373e12c5d1SDavid du Colombier 			rv1 = ~rv1; break;
3383e12c5d1SDavid du Colombier 		case NOT:
3393e12c5d1SDavid du Colombier 			rv1 = !rv1; if (rtype!=UND) rtype = SGN; break;
3403e12c5d1SDavid du Colombier 		case SLASH:
3413e12c5d1SDavid du Colombier 			if (rv2==0) {
3423e12c5d1SDavid du Colombier 				rtype = UND;
3433e12c5d1SDavid du Colombier 				break;
3443e12c5d1SDavid du Colombier 			}
3453e12c5d1SDavid du Colombier 			if (rtype==UNS)
3463e12c5d1SDavid du Colombier 				rv1 /= (unsigned long)rv2;
3473e12c5d1SDavid du Colombier 			else
3483e12c5d1SDavid du Colombier 				rv1 /= rv2;
3493e12c5d1SDavid du Colombier 			break;
3503e12c5d1SDavid du Colombier 		case PCT:
3513e12c5d1SDavid du Colombier 			if (rv2==0) {
3523e12c5d1SDavid du Colombier 				rtype = UND;
3533e12c5d1SDavid du Colombier 				break;
3543e12c5d1SDavid du Colombier 			}
3553e12c5d1SDavid du Colombier 			if (rtype==UNS)
3563e12c5d1SDavid du Colombier 				rv1 %= (unsigned long)rv2;
3573e12c5d1SDavid du Colombier 			else
3583e12c5d1SDavid du Colombier 				rv1 %= rv2;
3593e12c5d1SDavid du Colombier 			break;
3603e12c5d1SDavid du Colombier 		case COLON:
3613e12c5d1SDavid du Colombier 			if (op[-1] != QUEST)
3623e12c5d1SDavid du Colombier 				error(ERROR, "Bad ?: in #if/endif");
3633e12c5d1SDavid du Colombier 			else {
3643e12c5d1SDavid du Colombier 				op--;
3653e12c5d1SDavid du Colombier 				if ((--vp)->val==0)
3663e12c5d1SDavid du Colombier 					v1 = v2;
3673e12c5d1SDavid du Colombier 				rtype = v1.type;
3683e12c5d1SDavid du Colombier 				rv1 = v1.val;
3693e12c5d1SDavid du Colombier 			}
3703e12c5d1SDavid du Colombier 			break;
3713e12c5d1SDavid du Colombier 		case DEFINED:
3723e12c5d1SDavid du Colombier 			break;
3733e12c5d1SDavid du Colombier 		default:
3743e12c5d1SDavid du Colombier 			error(ERROR, "Eval botch (unknown operator)");
3753e12c5d1SDavid du Colombier 			return 1;
3763e12c5d1SDavid du Colombier 		}
3773e12c5d1SDavid du Colombier 		v1.val = rv1;
3783e12c5d1SDavid du Colombier 		v1.type = rtype;
3793e12c5d1SDavid du Colombier 		*vp++ = v1;
3803e12c5d1SDavid du Colombier 	}
3813e12c5d1SDavid du Colombier 	return 0;
3823e12c5d1SDavid du Colombier }
3833e12c5d1SDavid du Colombier 
3843e12c5d1SDavid du Colombier struct value
tokval(Token * tp)3853e12c5d1SDavid du Colombier tokval(Token *tp)
3863e12c5d1SDavid du Colombier {
3873e12c5d1SDavid du Colombier 	struct value v;
3883e12c5d1SDavid du Colombier 	Nlist *np;
3893e12c5d1SDavid du Colombier 	int i, base, c, longcc;
3903e12c5d1SDavid du Colombier 	unsigned long n;
3913e12c5d1SDavid du Colombier 	Rune r;
3923e12c5d1SDavid du Colombier 	uchar *p;
3933e12c5d1SDavid du Colombier 
3943e12c5d1SDavid du Colombier 	v.type = SGN;
3953e12c5d1SDavid du Colombier 	v.val = 0;
3963e12c5d1SDavid du Colombier 	switch (tp->type) {
3973e12c5d1SDavid du Colombier 
3983e12c5d1SDavid du Colombier 	case NAME:
3993e12c5d1SDavid du Colombier 		v.val = 0;
4003e12c5d1SDavid du Colombier 		break;
4013e12c5d1SDavid du Colombier 
4023e12c5d1SDavid du Colombier 	case NAME1:
403219b2ee8SDavid du Colombier 		if ((np = lookup(tp, 0)) && np->flag&(ISDEFINED|ISMAC))
4043e12c5d1SDavid du Colombier 			v.val = 1;
4053e12c5d1SDavid du Colombier 		break;
4063e12c5d1SDavid du Colombier 
4073e12c5d1SDavid du Colombier 	case NUMBER:
4083e12c5d1SDavid du Colombier 		n = 0;
4093e12c5d1SDavid du Colombier 		base = 10;
4103e12c5d1SDavid du Colombier 		p = tp->t;
4113e12c5d1SDavid du Colombier 		c = p[tp->len];
4123e12c5d1SDavid du Colombier 		p[tp->len] = '\0';
4133e12c5d1SDavid du Colombier 		if (*p=='0') {
4143e12c5d1SDavid du Colombier 			base = 8;
4153e12c5d1SDavid du Colombier 			if (p[1]=='x' || p[1]=='X') {
4163e12c5d1SDavid du Colombier 				base = 16;
4173e12c5d1SDavid du Colombier 				p++;
4183e12c5d1SDavid du Colombier 			}
4193e12c5d1SDavid du Colombier 			p++;
4203e12c5d1SDavid du Colombier 		}
4213e12c5d1SDavid du Colombier 		for (;; p++) {
4223e12c5d1SDavid du Colombier 			if ((i = digit(*p)) < 0)
4233e12c5d1SDavid du Colombier 				break;
4243e12c5d1SDavid du Colombier 			if (i>=base)
4253e12c5d1SDavid du Colombier 				error(WARNING,
4263e12c5d1SDavid du Colombier 				  "Bad digit in number %t", tp);
4273e12c5d1SDavid du Colombier 			n *= base;
4283e12c5d1SDavid du Colombier 			n += i;
4293e12c5d1SDavid du Colombier 		}
4303e12c5d1SDavid du Colombier 		if (n>=0x80000000 && base!=10)
4313e12c5d1SDavid du Colombier 			v.type = UNS;
4323e12c5d1SDavid du Colombier 		for (; *p; p++) {
4333e12c5d1SDavid du Colombier 			if (*p=='u' || *p=='U')
4343e12c5d1SDavid du Colombier 				v.type = UNS;
4353e12c5d1SDavid du Colombier 			else if (*p=='l' || *p=='L')
4369a747e4fSDavid du Colombier 				{}
4373e12c5d1SDavid du Colombier 			else {
4383e12c5d1SDavid du Colombier 				error(ERROR,
4394dc626cdSDavid du Colombier 				  "Bad number %t in #if/#elif", tp);
4403e12c5d1SDavid du Colombier 				break;
4413e12c5d1SDavid du Colombier 			}
4423e12c5d1SDavid du Colombier 		}
4433e12c5d1SDavid du Colombier 		v.val = n;
4443e12c5d1SDavid du Colombier 		tp->t[tp->len] = c;
4453e12c5d1SDavid du Colombier 		break;
4463e12c5d1SDavid du Colombier 
4473e12c5d1SDavid du Colombier 	case CCON:
4483e12c5d1SDavid du Colombier 		n = 0;
4493e12c5d1SDavid du Colombier 		p = tp->t;
4503e12c5d1SDavid du Colombier 		longcc = 0;
4513e12c5d1SDavid du Colombier 		if (*p=='L') {
4523e12c5d1SDavid du Colombier 			p += 1;
4533e12c5d1SDavid du Colombier 			longcc = 1;
4543e12c5d1SDavid du Colombier 		}
4553e12c5d1SDavid du Colombier 		p += 1;
4563e12c5d1SDavid du Colombier 		if (*p=='\\') {
4573e12c5d1SDavid du Colombier 			p += 1;
4583e12c5d1SDavid du Colombier 			if ((i = digit(*p))>=0 && i<=7) {
4593e12c5d1SDavid du Colombier 				n = i;
4603e12c5d1SDavid du Colombier 				p += 1;
4613e12c5d1SDavid du Colombier 				if ((i = digit(*p))>=0 && i<=7) {
4623e12c5d1SDavid du Colombier 					p += 1;
4633e12c5d1SDavid du Colombier 					n <<= 3;
4643e12c5d1SDavid du Colombier 					n += i;
4653e12c5d1SDavid du Colombier 					if ((i = digit(*p))>=0 && i<=7) {
4663e12c5d1SDavid du Colombier 						p += 1;
4673e12c5d1SDavid du Colombier 						n <<= 3;
4683e12c5d1SDavid du Colombier 						n += i;
4693e12c5d1SDavid du Colombier 					}
4703e12c5d1SDavid du Colombier 				}
4713e12c5d1SDavid du Colombier 			} else if (*p=='x') {
4723e12c5d1SDavid du Colombier 				p += 1;
4733e12c5d1SDavid du Colombier 				while ((i = digit(*p))>=0 && i<=15) {
4743e12c5d1SDavid du Colombier 					p += 1;
4753e12c5d1SDavid du Colombier 					n <<= 4;
4763e12c5d1SDavid du Colombier 					n += i;
4773e12c5d1SDavid du Colombier 				}
4783e12c5d1SDavid du Colombier 			} else {
4793e12c5d1SDavid du Colombier 				static char cvcon[]
4803e12c5d1SDavid du Colombier 				  = "a\ab\bf\fn\nr\rt\tv\v''\"\"??\\\\";
4813e12c5d1SDavid du Colombier 				for (i=0; i<sizeof(cvcon); i+=2) {
4823e12c5d1SDavid du Colombier 					if (*p == cvcon[i]) {
4833e12c5d1SDavid du Colombier 						n = cvcon[i+1];
4843e12c5d1SDavid du Colombier 						break;
4853e12c5d1SDavid du Colombier 					}
4863e12c5d1SDavid du Colombier 				}
4873e12c5d1SDavid du Colombier 				p += 1;
4883e12c5d1SDavid du Colombier 				if (i>=sizeof(cvcon))
4893e12c5d1SDavid du Colombier 					error(WARNING,
4903e12c5d1SDavid du Colombier 					 "Undefined escape in character constant");
4913e12c5d1SDavid du Colombier 			}
4923e12c5d1SDavid du Colombier 		} else if (*p=='\'')
4933e12c5d1SDavid du Colombier 			error(ERROR, "Empty character constant");
4943e12c5d1SDavid du Colombier 		else {
4953e12c5d1SDavid du Colombier 			i = chartorune(&r, (char*)p);
4963e12c5d1SDavid du Colombier 			n = r;
4973e12c5d1SDavid du Colombier 			p += i;
4983e12c5d1SDavid du Colombier 			if (i>1 && longcc==0)
4993e12c5d1SDavid du Colombier 				error(WARNING, "Undefined character constant");
5003e12c5d1SDavid du Colombier 		}
5013e12c5d1SDavid du Colombier 		if (*p!='\'')
5023e12c5d1SDavid du Colombier 			error(WARNING, "Multibyte character constant undefined");
5033e12c5d1SDavid du Colombier 		else if (n>127 && longcc==0)
5043e12c5d1SDavid du Colombier 			error(WARNING, "Character constant taken as not signed");
5053e12c5d1SDavid du Colombier 		v.val = n;
5063e12c5d1SDavid du Colombier 		break;
5073e12c5d1SDavid du Colombier 
5083e12c5d1SDavid du Colombier 	case STRING:
5094dc626cdSDavid du Colombier 		error(ERROR, "String in #if/#elif");
5103e12c5d1SDavid du Colombier 		break;
5113e12c5d1SDavid du Colombier 	}
5123e12c5d1SDavid du Colombier 	return v;
5133e12c5d1SDavid du Colombier }
5143e12c5d1SDavid du Colombier 
5153e12c5d1SDavid du Colombier int
digit(int i)5163e12c5d1SDavid du Colombier digit(int i)
5173e12c5d1SDavid du Colombier {
5183e12c5d1SDavid du Colombier 	if ('0'<=i && i<='9')
5193e12c5d1SDavid du Colombier 		i -= '0';
5203e12c5d1SDavid du Colombier 	else if ('a'<=i && i<='f')
5213e12c5d1SDavid du Colombier 		i -= 'a'-10;
5223e12c5d1SDavid du Colombier 	else if ('A'<=i && i<='F')
5233e12c5d1SDavid du Colombier 		i -= 'A'-10;
5243e12c5d1SDavid du Colombier 	else
5253e12c5d1SDavid du Colombier 		i = -1;
5263e12c5d1SDavid du Colombier 	return i;
5273e12c5d1SDavid du Colombier }
528