xref: /plan9/sys/src/cmd/cpp/eval.c (revision 3e12c5d1bb89fc02707907988834ef147769ddaf)
1*3e12c5d1SDavid du Colombier #include <u.h>
2*3e12c5d1SDavid du Colombier #include <libc.h>
3*3e12c5d1SDavid du Colombier #include "cpp.h"
4*3e12c5d1SDavid du Colombier 
5*3e12c5d1SDavid du Colombier #define	NSTAK	32
6*3e12c5d1SDavid du Colombier #define	SGN	0
7*3e12c5d1SDavid du Colombier #define	UNS	1
8*3e12c5d1SDavid du Colombier #define	UND	2
9*3e12c5d1SDavid du Colombier 
10*3e12c5d1SDavid du Colombier #define	UNSMARK	0x1000
11*3e12c5d1SDavid du Colombier 
12*3e12c5d1SDavid du Colombier struct value {
13*3e12c5d1SDavid du Colombier 	long	val;
14*3e12c5d1SDavid du Colombier 	int	type;
15*3e12c5d1SDavid du Colombier };
16*3e12c5d1SDavid du Colombier 
17*3e12c5d1SDavid du Colombier /* conversion types */
18*3e12c5d1SDavid du Colombier #define	RELAT	1
19*3e12c5d1SDavid du Colombier #define	ARITH	2
20*3e12c5d1SDavid du Colombier #define	LOGIC	3
21*3e12c5d1SDavid du Colombier #define	SPCL	4
22*3e12c5d1SDavid du Colombier #define	SHIFT	5
23*3e12c5d1SDavid du Colombier #define	UNARY	6
24*3e12c5d1SDavid du Colombier 
25*3e12c5d1SDavid du Colombier /* operator priority, arity, and conversion type, indexed by tokentype */
26*3e12c5d1SDavid du Colombier const struct pri {
27*3e12c5d1SDavid du Colombier 	char	pri;
28*3e12c5d1SDavid du Colombier 	char	arity;
29*3e12c5d1SDavid du Colombier 	char	ctype;
30*3e12c5d1SDavid du Colombier } priority[] = {
31*3e12c5d1SDavid du Colombier 	{ 0, 0, 0 },		/* END */
32*3e12c5d1SDavid du Colombier 	{ 0, 0, 0 },		/* UNCLASS */
33*3e12c5d1SDavid du Colombier 	{ 0, 0, 0 },		/* NAME */
34*3e12c5d1SDavid du Colombier 	{ 0, 0, 0 },		/* NUMBER */
35*3e12c5d1SDavid du Colombier 	{ 0, 0, 0 },		/* STRING */
36*3e12c5d1SDavid du Colombier 	{ 0, 0, 0 },		/* CCON */
37*3e12c5d1SDavid du Colombier 	{ 0, 0, 0 },		/* NL */
38*3e12c5d1SDavid du Colombier 	{ 0, 0, 0 },		/* WS */
39*3e12c5d1SDavid du Colombier 	{ 0, 0, 0 },		/* DSHARP */
40*3e12c5d1SDavid du Colombier 	{ 11, 2, RELAT },	/* EQ */
41*3e12c5d1SDavid du Colombier 	{ 11, 2, RELAT },	/* NEQ */
42*3e12c5d1SDavid du Colombier 	{ 12, 2, RELAT },	/* LEQ */
43*3e12c5d1SDavid du Colombier 	{ 12, 2, RELAT },	/* GEQ */
44*3e12c5d1SDavid du Colombier 	{ 13, 2, SHIFT },	/* LSH */
45*3e12c5d1SDavid du Colombier 	{ 13, 2, SHIFT },	/* RSH */
46*3e12c5d1SDavid du Colombier 	{ 7, 2, LOGIC },	/* LAND */
47*3e12c5d1SDavid du Colombier 	{ 6, 2, LOGIC },	/* LOR */
48*3e12c5d1SDavid du Colombier 	{ 0, 0, 0 },		/* PPLUS */
49*3e12c5d1SDavid du Colombier 	{ 0, 0, 0 },		/* MMINUS */
50*3e12c5d1SDavid du Colombier 	{ 0, 0, 0 },		/* ARROW */
51*3e12c5d1SDavid du Colombier 	{ 0, 0, 0 },		/* SBRA */
52*3e12c5d1SDavid du Colombier 	{ 0, 0, 0 },		/* SKET */
53*3e12c5d1SDavid du Colombier 	{ 3, 0, 0 },		/* LP */
54*3e12c5d1SDavid du Colombier 	{ 3, 0, 0 },		/* RP */
55*3e12c5d1SDavid du Colombier 	{ 0, 0, 0 },		/* DOT */
56*3e12c5d1SDavid du Colombier 	{ 10, 2, ARITH },	/* AND */
57*3e12c5d1SDavid du Colombier 	{ 15, 2, ARITH },	/* STAR */
58*3e12c5d1SDavid du Colombier 	{ 14, 2, ARITH },	/* PLUS */
59*3e12c5d1SDavid du Colombier 	{ 14, 2, ARITH },	/* MINUS */
60*3e12c5d1SDavid du Colombier 	{ 16, 1, UNARY },	/* TILDE */
61*3e12c5d1SDavid du Colombier 	{ 16, 1, UNARY },	/* NOT */
62*3e12c5d1SDavid du Colombier 	{ 15, 2, ARITH },	/* SLASH */
63*3e12c5d1SDavid du Colombier 	{ 15, 2, ARITH },	/* PCT */
64*3e12c5d1SDavid du Colombier 	{ 12, 2, RELAT },	/* LT */
65*3e12c5d1SDavid du Colombier 	{ 12, 2, RELAT },	/* GT */
66*3e12c5d1SDavid du Colombier 	{ 9, 2, ARITH },	/* CIRC */
67*3e12c5d1SDavid du Colombier 	{ 8, 2, ARITH },	/* OR */
68*3e12c5d1SDavid du Colombier 	{ 5, 2, SPCL },		/* QUEST */
69*3e12c5d1SDavid du Colombier 	{ 5, 2, SPCL },		/* COLON */
70*3e12c5d1SDavid du Colombier 	{ 0, 0, 0 },		/* ASGN */
71*3e12c5d1SDavid du Colombier 	{ 4, 2, 0 },		/* COMMA */
72*3e12c5d1SDavid du Colombier 	{ 0, 0, 0 },		/* SHARP */
73*3e12c5d1SDavid du Colombier 	{ 0, 0, 0 },		/* SEMIC */
74*3e12c5d1SDavid du Colombier 	{ 0, 0, 0 },		/* CBRA */
75*3e12c5d1SDavid du Colombier 	{ 0, 0, 0 },		/* CKET */
76*3e12c5d1SDavid du Colombier 	{ 0, 0, 0 },		/* ASPLUS */
77*3e12c5d1SDavid du Colombier  	{ 0, 0, 0 },		/* ASMINUS */
78*3e12c5d1SDavid du Colombier  	{ 0, 0, 0 },		/* ASSTAR */
79*3e12c5d1SDavid du Colombier  	{ 0, 0, 0 },		/* ASSLASH */
80*3e12c5d1SDavid du Colombier  	{ 0, 0, 0 },		/* ASPCT */
81*3e12c5d1SDavid du Colombier  	{ 0, 0, 0 },		/* ASCIRC */
82*3e12c5d1SDavid du Colombier  	{ 0, 0, 0 },		/* ASLSH */
83*3e12c5d1SDavid du Colombier 	{ 0, 0, 0 },		/* ASRSH */
84*3e12c5d1SDavid du Colombier  	{ 0, 0, 0 },		/* ASOR */
85*3e12c5d1SDavid du Colombier  	{ 0, 0, 0 },		/* ASAND */
86*3e12c5d1SDavid du Colombier 	{ 0, 0, 0 },		/* ELLIPS */
87*3e12c5d1SDavid du Colombier 	{ 0, 0, 0 },		/* DSHARP1 */
88*3e12c5d1SDavid du Colombier 	{ 0, 0, 0 },		/* NAME1 */
89*3e12c5d1SDavid du Colombier 	{ 16, 1, UNARY },	/* DEFINED */
90*3e12c5d1SDavid du Colombier 	{ 16, 0, UNARY },	/* UMINUS */
91*3e12c5d1SDavid du Colombier };
92*3e12c5d1SDavid du Colombier 
93*3e12c5d1SDavid du Colombier int	evalop(struct pri);
94*3e12c5d1SDavid du Colombier struct	value tokval(Token *);
95*3e12c5d1SDavid du Colombier struct value vals[NSTAK], *vp;
96*3e12c5d1SDavid du Colombier enum toktype ops[NSTAK], *op;
97*3e12c5d1SDavid du Colombier 
98*3e12c5d1SDavid du Colombier /*
99*3e12c5d1SDavid du Colombier  * Evaluate an #if #elif #ifdef #ifndef line.  trp->tp points to the keyword.
100*3e12c5d1SDavid du Colombier  */
101*3e12c5d1SDavid du Colombier long
102*3e12c5d1SDavid du Colombier eval(Tokenrow *trp, int kw)
103*3e12c5d1SDavid du Colombier {
104*3e12c5d1SDavid du Colombier 	Token *tp;
105*3e12c5d1SDavid du Colombier 	Nlist *np;
106*3e12c5d1SDavid du Colombier 	int ntok, rand;
107*3e12c5d1SDavid du Colombier 
108*3e12c5d1SDavid du Colombier 	trp->tp++;
109*3e12c5d1SDavid du Colombier 	if (kw==KIFDEF || kw==KIFNDEF) {
110*3e12c5d1SDavid du Colombier 		if (trp->lp - trp->bp != 4 || trp->tp->type!=NAME) {
111*3e12c5d1SDavid du Colombier 			error(ERROR, "Syntax error in #ifdef/#ifndef");
112*3e12c5d1SDavid du Colombier 			return 0;
113*3e12c5d1SDavid du Colombier 		}
114*3e12c5d1SDavid du Colombier 		np = lookup(trp->tp, 0);
115*3e12c5d1SDavid du Colombier 		return (kw==KIFDEF) == (np && np->flag&ISDEFINED);
116*3e12c5d1SDavid du Colombier 	}
117*3e12c5d1SDavid du Colombier 	/* replace 'defined name',  'defined(name)' to prevent evaluation */
118*3e12c5d1SDavid du Colombier 	for (tp=trp->tp, ntok=tp-trp->bp; tp < trp->lp; tp++) {
119*3e12c5d1SDavid du Colombier 		if (tp->type!=NAME)
120*3e12c5d1SDavid du Colombier 			continue;
121*3e12c5d1SDavid du Colombier 		if ((np=lookup(tp, 0))!=NULL && np->val==KDEFINED) {
122*3e12c5d1SDavid du Colombier 			tp->type = DEFINED;
123*3e12c5d1SDavid du Colombier 			if ((tp+1)<trp->lp && (tp+1)->type==NAME)
124*3e12c5d1SDavid du Colombier 				(tp+1)->type = NAME1;
125*3e12c5d1SDavid du Colombier 			else if ((tp+3)<trp->lp && (tp+1)->type==LP
126*3e12c5d1SDavid du Colombier 			 && (tp+2)->type==NAME && (tp+3)->type==RP)
127*3e12c5d1SDavid du Colombier 				(tp+2)->type = NAME1;
128*3e12c5d1SDavid du Colombier 			else
129*3e12c5d1SDavid du Colombier 				error(ERROR, "Incorrect syntax for `defined'");
130*3e12c5d1SDavid du Colombier 		}
131*3e12c5d1SDavid du Colombier 	}
132*3e12c5d1SDavid du Colombier 	expandrow(trp, "<if>");
133*3e12c5d1SDavid du Colombier 	vp = vals;
134*3e12c5d1SDavid du Colombier 	op = ops;
135*3e12c5d1SDavid du Colombier 	*op++ = END;
136*3e12c5d1SDavid du Colombier 	for (rand=0, tp = trp->bp+ntok; tp < trp->lp; tp++) {
137*3e12c5d1SDavid du Colombier 		switch(tp->type) {
138*3e12c5d1SDavid du Colombier 		case WS:
139*3e12c5d1SDavid du Colombier 		case NL:
140*3e12c5d1SDavid du Colombier 			continue;
141*3e12c5d1SDavid du Colombier 
142*3e12c5d1SDavid du Colombier 		/* nilary */
143*3e12c5d1SDavid du Colombier 		case NAME:
144*3e12c5d1SDavid du Colombier 		case NAME1:
145*3e12c5d1SDavid du Colombier 		case NUMBER:
146*3e12c5d1SDavid du Colombier 		case CCON:
147*3e12c5d1SDavid du Colombier 		case STRING:
148*3e12c5d1SDavid du Colombier 			if (rand)
149*3e12c5d1SDavid du Colombier 				goto syntax;
150*3e12c5d1SDavid du Colombier 			*vp++ = tokval(tp);
151*3e12c5d1SDavid du Colombier 			rand = 1;
152*3e12c5d1SDavid du Colombier 			continue;
153*3e12c5d1SDavid du Colombier 
154*3e12c5d1SDavid du Colombier 		/* unary */
155*3e12c5d1SDavid du Colombier 		case DEFINED:
156*3e12c5d1SDavid du Colombier 		case TILDE:
157*3e12c5d1SDavid du Colombier 		case NOT:
158*3e12c5d1SDavid du Colombier 			if (rand)
159*3e12c5d1SDavid du Colombier 				goto syntax;
160*3e12c5d1SDavid du Colombier 			*op++ = tp->type;
161*3e12c5d1SDavid du Colombier 			continue;
162*3e12c5d1SDavid du Colombier 
163*3e12c5d1SDavid du Colombier 		/* unary-binary */
164*3e12c5d1SDavid du Colombier 		case PLUS: case MINUS: case STAR: case AND:
165*3e12c5d1SDavid du Colombier 			if (rand==0) {
166*3e12c5d1SDavid du Colombier 				if (tp->type==MINUS)
167*3e12c5d1SDavid du Colombier 					*op++ = UMINUS;
168*3e12c5d1SDavid du Colombier 				if (tp->type==STAR || tp->type==AND) {
169*3e12c5d1SDavid du Colombier 					error(ERROR, "Illegal operator * or & in #if/#elsif");
170*3e12c5d1SDavid du Colombier 					return 0;
171*3e12c5d1SDavid du Colombier 				}
172*3e12c5d1SDavid du Colombier 				continue;
173*3e12c5d1SDavid du Colombier 			}
174*3e12c5d1SDavid du Colombier 			/* flow through */
175*3e12c5d1SDavid du Colombier 
176*3e12c5d1SDavid du Colombier 		/* plain binary */
177*3e12c5d1SDavid du Colombier 		case EQ: case NEQ: case LEQ: case GEQ: case LSH: case RSH:
178*3e12c5d1SDavid du Colombier 		case LAND: case LOR: case SLASH: case PCT:
179*3e12c5d1SDavid du Colombier 		case LT: case GT: case CIRC: case OR: case QUEST:
180*3e12c5d1SDavid du Colombier 		case COLON: case COMMA:
181*3e12c5d1SDavid du Colombier 			if (rand==0)
182*3e12c5d1SDavid du Colombier 				goto syntax;
183*3e12c5d1SDavid du Colombier 			if (evalop(priority[tp->type])!=0)
184*3e12c5d1SDavid du Colombier 				return 0;
185*3e12c5d1SDavid du Colombier 			*op++ = tp->type;
186*3e12c5d1SDavid du Colombier 			rand = 0;
187*3e12c5d1SDavid du Colombier 			continue;
188*3e12c5d1SDavid du Colombier 
189*3e12c5d1SDavid du Colombier 		case LP:
190*3e12c5d1SDavid du Colombier 			if (rand)
191*3e12c5d1SDavid du Colombier 				goto syntax;
192*3e12c5d1SDavid du Colombier 			*op++ = LP;
193*3e12c5d1SDavid du Colombier 			continue;
194*3e12c5d1SDavid du Colombier 
195*3e12c5d1SDavid du Colombier 		case RP:
196*3e12c5d1SDavid du Colombier 			if (!rand)
197*3e12c5d1SDavid du Colombier 				goto syntax;
198*3e12c5d1SDavid du Colombier 			if (evalop(priority[RP])!=0)
199*3e12c5d1SDavid du Colombier 				return 0;
200*3e12c5d1SDavid du Colombier 			if (op<=ops || op[-1]!=LP) {
201*3e12c5d1SDavid du Colombier 				goto syntax;
202*3e12c5d1SDavid du Colombier 			}
203*3e12c5d1SDavid du Colombier 			op--;
204*3e12c5d1SDavid du Colombier 			continue;
205*3e12c5d1SDavid du Colombier 
206*3e12c5d1SDavid du Colombier 		default:
207*3e12c5d1SDavid du Colombier 			error(ERROR,"Bad operator (%t) in #if/#elsif", tp);
208*3e12c5d1SDavid du Colombier 			return 0;
209*3e12c5d1SDavid du Colombier 		}
210*3e12c5d1SDavid du Colombier 	}
211*3e12c5d1SDavid du Colombier 	if (rand==0)
212*3e12c5d1SDavid du Colombier 		goto syntax;
213*3e12c5d1SDavid du Colombier 	if (evalop(priority[END])!=0)
214*3e12c5d1SDavid du Colombier 		return 0;
215*3e12c5d1SDavid du Colombier 	if (op!=&ops[1] || vp!=&vals[1]) {
216*3e12c5d1SDavid du Colombier 		error(ERROR, "Botch in #if/#elsif");
217*3e12c5d1SDavid du Colombier 		return 0;
218*3e12c5d1SDavid du Colombier 	}
219*3e12c5d1SDavid du Colombier 	if (vals[0].type==UND)
220*3e12c5d1SDavid du Colombier 		error(ERROR, "Undefined expression value");
221*3e12c5d1SDavid du Colombier 	return vals[0].val;
222*3e12c5d1SDavid du Colombier syntax:
223*3e12c5d1SDavid du Colombier 	error(ERROR, "Syntax error in #if/#elsif");
224*3e12c5d1SDavid du Colombier 	return 0;
225*3e12c5d1SDavid du Colombier }
226*3e12c5d1SDavid du Colombier 
227*3e12c5d1SDavid du Colombier int
228*3e12c5d1SDavid du Colombier evalop(struct pri pri)
229*3e12c5d1SDavid du Colombier {
230*3e12c5d1SDavid du Colombier 	struct value v1, v2;
231*3e12c5d1SDavid du Colombier 	long rv1, rv2;
232*3e12c5d1SDavid du Colombier 	int rtype, oper;
233*3e12c5d1SDavid du Colombier 
234*3e12c5d1SDavid du Colombier 	rv2=0;
235*3e12c5d1SDavid du Colombier 	rtype=0;
236*3e12c5d1SDavid du Colombier 	while (pri.pri < priority[op[-1]].pri) {
237*3e12c5d1SDavid du Colombier 		oper = *--op;
238*3e12c5d1SDavid du Colombier 		if (priority[oper].arity==2) {
239*3e12c5d1SDavid du Colombier 			v2 = *--vp;
240*3e12c5d1SDavid du Colombier 			rv2 = v2.val;
241*3e12c5d1SDavid du Colombier 		}
242*3e12c5d1SDavid du Colombier 		v1 = *--vp;
243*3e12c5d1SDavid du Colombier 		rv1 = v1.val;
244*3e12c5d1SDavid du Colombier 		switch (priority[oper].ctype) {
245*3e12c5d1SDavid du Colombier 		case 0:
246*3e12c5d1SDavid du Colombier 		default:
247*3e12c5d1SDavid du Colombier 			error(WARNING, "Syntax error in #if/#endif");
248*3e12c5d1SDavid du Colombier 			return 1;
249*3e12c5d1SDavid du Colombier 		case ARITH:
250*3e12c5d1SDavid du Colombier 		case RELAT:
251*3e12c5d1SDavid du Colombier 			if (v1.type==UNS || v2.type==UNS)
252*3e12c5d1SDavid du Colombier 				rtype = UNS;
253*3e12c5d1SDavid du Colombier 			else
254*3e12c5d1SDavid du Colombier 				rtype = SGN;
255*3e12c5d1SDavid du Colombier 			if (v1.type==UND || v2.type==UND)
256*3e12c5d1SDavid du Colombier 				rtype = UND;
257*3e12c5d1SDavid du Colombier 			if (priority[oper].ctype==RELAT && rtype==UNS) {
258*3e12c5d1SDavid du Colombier 				oper |= UNSMARK;
259*3e12c5d1SDavid du Colombier 				rtype = SGN;
260*3e12c5d1SDavid du Colombier 			}
261*3e12c5d1SDavid du Colombier 			break;
262*3e12c5d1SDavid du Colombier 		case SHIFT:
263*3e12c5d1SDavid du Colombier 			if (v1.type==UND || v2.type==UND)
264*3e12c5d1SDavid du Colombier 				rtype = UND;
265*3e12c5d1SDavid du Colombier 			else
266*3e12c5d1SDavid du Colombier 				rtype = v1.type;
267*3e12c5d1SDavid du Colombier 			if (rtype==UNS)
268*3e12c5d1SDavid du Colombier 				oper |= UNSMARK;
269*3e12c5d1SDavid du Colombier 			break;
270*3e12c5d1SDavid du Colombier 		case UNARY:
271*3e12c5d1SDavid du Colombier 			rtype = v1.type;
272*3e12c5d1SDavid du Colombier 			break;
273*3e12c5d1SDavid du Colombier 		case LOGIC:
274*3e12c5d1SDavid du Colombier 		case SPCL:
275*3e12c5d1SDavid du Colombier 			break;
276*3e12c5d1SDavid du Colombier 		}
277*3e12c5d1SDavid du Colombier 		switch (oper) {
278*3e12c5d1SDavid du Colombier 		case EQ: case EQ|UNSMARK:
279*3e12c5d1SDavid du Colombier 			rv1 = rv1==rv2; break;
280*3e12c5d1SDavid du Colombier 		case NEQ: case NEQ|UNSMARK:
281*3e12c5d1SDavid du Colombier 			rv1 = rv1!=rv2; break;
282*3e12c5d1SDavid du Colombier 		case LEQ:
283*3e12c5d1SDavid du Colombier 			rv1 = rv1<=rv2; break;
284*3e12c5d1SDavid du Colombier 		case GEQ:
285*3e12c5d1SDavid du Colombier 			rv1 = rv1>=rv2; break;
286*3e12c5d1SDavid du Colombier 		case LT:
287*3e12c5d1SDavid du Colombier 			rv1 = rv1<rv2; break;
288*3e12c5d1SDavid du Colombier 		case GT:
289*3e12c5d1SDavid du Colombier 			rv1 = rv1>rv2; break;
290*3e12c5d1SDavid du Colombier 		case LEQ|UNSMARK:
291*3e12c5d1SDavid du Colombier 			rv1 = (unsigned long)rv1<=rv2; break;
292*3e12c5d1SDavid du Colombier 		case GEQ|UNSMARK:
293*3e12c5d1SDavid du Colombier 			rv1 = (unsigned long)rv1>=rv2; break;
294*3e12c5d1SDavid du Colombier 		case LT|UNSMARK:
295*3e12c5d1SDavid du Colombier 			rv1 = (unsigned long)rv1<rv2; break;
296*3e12c5d1SDavid du Colombier 		case GT|UNSMARK:
297*3e12c5d1SDavid du Colombier 			rv1 = (unsigned long)rv1>rv2; break;
298*3e12c5d1SDavid du Colombier 		case LSH:
299*3e12c5d1SDavid du Colombier 			rv1 <<= rv2; break;
300*3e12c5d1SDavid du Colombier 		case LSH|UNSMARK:
301*3e12c5d1SDavid du Colombier 			rv1 = (unsigned long)rv1<<rv2; break;
302*3e12c5d1SDavid du Colombier 		case RSH:
303*3e12c5d1SDavid du Colombier 			rv1 >>= rv2; break;
304*3e12c5d1SDavid du Colombier 		case RSH|UNSMARK:
305*3e12c5d1SDavid du Colombier 			rv1 = (unsigned long)rv1>>rv2; break;
306*3e12c5d1SDavid du Colombier 		case LAND:
307*3e12c5d1SDavid du Colombier 			rtype = UND;
308*3e12c5d1SDavid du Colombier 			if (v1.type==UND)
309*3e12c5d1SDavid du Colombier 				break;
310*3e12c5d1SDavid du Colombier 			if (rv1!=0) {
311*3e12c5d1SDavid du Colombier 				if (v2.type==UND)
312*3e12c5d1SDavid du Colombier 					break;
313*3e12c5d1SDavid du Colombier 				rv1 = rv2!=0;
314*3e12c5d1SDavid du Colombier 			} else
315*3e12c5d1SDavid du Colombier 				rv1 = 0;
316*3e12c5d1SDavid du Colombier 			rtype = SGN;
317*3e12c5d1SDavid du Colombier 			break;
318*3e12c5d1SDavid du Colombier 		case LOR:
319*3e12c5d1SDavid du Colombier 			rtype = UND;
320*3e12c5d1SDavid du Colombier 			if (v1.type==UND)
321*3e12c5d1SDavid du Colombier 				break;
322*3e12c5d1SDavid du Colombier 			if (rv1==0) {
323*3e12c5d1SDavid du Colombier 				if (v2.type==UND)
324*3e12c5d1SDavid du Colombier 					break;
325*3e12c5d1SDavid du Colombier 				rv1 = rv2!=0;
326*3e12c5d1SDavid du Colombier 			} else
327*3e12c5d1SDavid du Colombier 				rv1 = 1;
328*3e12c5d1SDavid du Colombier 			rtype = SGN;
329*3e12c5d1SDavid du Colombier 			break;
330*3e12c5d1SDavid du Colombier 		case AND:
331*3e12c5d1SDavid du Colombier 			rv1 &= rv2; break;
332*3e12c5d1SDavid du Colombier 		case STAR:
333*3e12c5d1SDavid du Colombier 			rv1 *= rv2; break;
334*3e12c5d1SDavid du Colombier 		case PLUS:
335*3e12c5d1SDavid du Colombier 			rv1 += rv2; break;
336*3e12c5d1SDavid du Colombier 		case MINUS:
337*3e12c5d1SDavid du Colombier 			rv1 -= rv2; break;
338*3e12c5d1SDavid du Colombier 		case UMINUS:
339*3e12c5d1SDavid du Colombier 			if (v1.type==UND)
340*3e12c5d1SDavid du Colombier 				rtype = UND;
341*3e12c5d1SDavid du Colombier 			rv1 = -rv1; break;
342*3e12c5d1SDavid du Colombier 		case OR:
343*3e12c5d1SDavid du Colombier 			rv1 |= rv2; break;
344*3e12c5d1SDavid du Colombier 		case CIRC:
345*3e12c5d1SDavid du Colombier 			rv1 ^= rv2; break;
346*3e12c5d1SDavid du Colombier 		case TILDE:
347*3e12c5d1SDavid du Colombier 			rv1 = ~rv1; break;
348*3e12c5d1SDavid du Colombier 		case NOT:
349*3e12c5d1SDavid du Colombier 			rv1 = !rv1; if (rtype!=UND) rtype = SGN; break;
350*3e12c5d1SDavid du Colombier 		case SLASH:
351*3e12c5d1SDavid du Colombier 			if (rv2==0) {
352*3e12c5d1SDavid du Colombier 				rtype = UND;
353*3e12c5d1SDavid du Colombier 				break;
354*3e12c5d1SDavid du Colombier 			}
355*3e12c5d1SDavid du Colombier 			if (rtype==UNS)
356*3e12c5d1SDavid du Colombier 				rv1 /= (unsigned long)rv2;
357*3e12c5d1SDavid du Colombier 			else
358*3e12c5d1SDavid du Colombier 				rv1 /= rv2;
359*3e12c5d1SDavid du Colombier 			break;
360*3e12c5d1SDavid du Colombier 		case PCT:
361*3e12c5d1SDavid du Colombier 			if (rv2==0) {
362*3e12c5d1SDavid du Colombier 				rtype = UND;
363*3e12c5d1SDavid du Colombier 				break;
364*3e12c5d1SDavid du Colombier 			}
365*3e12c5d1SDavid du Colombier 			if (rtype==UNS)
366*3e12c5d1SDavid du Colombier 				rv1 %= (unsigned long)rv2;
367*3e12c5d1SDavid du Colombier 			else
368*3e12c5d1SDavid du Colombier 				rv1 %= rv2;
369*3e12c5d1SDavid du Colombier 			break;
370*3e12c5d1SDavid du Colombier 		case COLON:
371*3e12c5d1SDavid du Colombier 			if (op[-1] != QUEST)
372*3e12c5d1SDavid du Colombier 				error(ERROR, "Bad ?: in #if/endif");
373*3e12c5d1SDavid du Colombier 			else {
374*3e12c5d1SDavid du Colombier 				op--;
375*3e12c5d1SDavid du Colombier 				if ((--vp)->val==0)
376*3e12c5d1SDavid du Colombier 					v1 = v2;
377*3e12c5d1SDavid du Colombier 				rtype = v1.type;
378*3e12c5d1SDavid du Colombier 				rv1 = v1.val;
379*3e12c5d1SDavid du Colombier 			}
380*3e12c5d1SDavid du Colombier 			break;
381*3e12c5d1SDavid du Colombier 		case DEFINED:
382*3e12c5d1SDavid du Colombier 			break;
383*3e12c5d1SDavid du Colombier 		default:
384*3e12c5d1SDavid du Colombier 			error(ERROR, "Eval botch (unknown operator)");
385*3e12c5d1SDavid du Colombier 			return 1;
386*3e12c5d1SDavid du Colombier 		}
387*3e12c5d1SDavid du Colombier 		v1.val = rv1;
388*3e12c5d1SDavid du Colombier 		v1.type = rtype;
389*3e12c5d1SDavid du Colombier 		*vp++ = v1;
390*3e12c5d1SDavid du Colombier 	}
391*3e12c5d1SDavid du Colombier 	return 0;
392*3e12c5d1SDavid du Colombier }
393*3e12c5d1SDavid du Colombier 
394*3e12c5d1SDavid du Colombier struct value
395*3e12c5d1SDavid du Colombier tokval(Token *tp)
396*3e12c5d1SDavid du Colombier {
397*3e12c5d1SDavid du Colombier 	struct value v;
398*3e12c5d1SDavid du Colombier 	Nlist *np;
399*3e12c5d1SDavid du Colombier 	int i, base, c, longcc;
400*3e12c5d1SDavid du Colombier 	unsigned long n;
401*3e12c5d1SDavid du Colombier 	Rune r;
402*3e12c5d1SDavid du Colombier 	uchar *p;
403*3e12c5d1SDavid du Colombier 
404*3e12c5d1SDavid du Colombier 	v.type = SGN;
405*3e12c5d1SDavid du Colombier 	v.val = 0;
406*3e12c5d1SDavid du Colombier 	switch (tp->type) {
407*3e12c5d1SDavid du Colombier 
408*3e12c5d1SDavid du Colombier 	case NAME:
409*3e12c5d1SDavid du Colombier 		v.val = 0;
410*3e12c5d1SDavid du Colombier 		break;
411*3e12c5d1SDavid du Colombier 
412*3e12c5d1SDavid du Colombier 	case NAME1:
413*3e12c5d1SDavid du Colombier 		if ((np = lookup(tp, 0)) && np->flag&ISDEFINED)
414*3e12c5d1SDavid du Colombier 			v.val = 1;
415*3e12c5d1SDavid du Colombier 		break;
416*3e12c5d1SDavid du Colombier 
417*3e12c5d1SDavid du Colombier 	case NUMBER:
418*3e12c5d1SDavid du Colombier 		n = 0;
419*3e12c5d1SDavid du Colombier 		base = 10;
420*3e12c5d1SDavid du Colombier 		p = tp->t;
421*3e12c5d1SDavid du Colombier 		c = p[tp->len];
422*3e12c5d1SDavid du Colombier 		p[tp->len] = '\0';
423*3e12c5d1SDavid du Colombier 		if (*p=='0') {
424*3e12c5d1SDavid du Colombier 			base = 8;
425*3e12c5d1SDavid du Colombier 			if (p[1]=='x' || p[1]=='X') {
426*3e12c5d1SDavid du Colombier 				base = 16;
427*3e12c5d1SDavid du Colombier 				p++;
428*3e12c5d1SDavid du Colombier 			}
429*3e12c5d1SDavid du Colombier 			p++;
430*3e12c5d1SDavid du Colombier 		}
431*3e12c5d1SDavid du Colombier 		for (;; p++) {
432*3e12c5d1SDavid du Colombier 			if ((i = digit(*p)) < 0)
433*3e12c5d1SDavid du Colombier 				break;
434*3e12c5d1SDavid du Colombier 			if (i>=base)
435*3e12c5d1SDavid du Colombier 				error(WARNING,
436*3e12c5d1SDavid du Colombier 				  "Bad digit in number %t", tp);
437*3e12c5d1SDavid du Colombier 			n *= base;
438*3e12c5d1SDavid du Colombier 			n += i;
439*3e12c5d1SDavid du Colombier 		}
440*3e12c5d1SDavid du Colombier 		if (n>=0x80000000 && base!=10)
441*3e12c5d1SDavid du Colombier 			v.type = UNS;
442*3e12c5d1SDavid du Colombier 		for (; *p; p++) {
443*3e12c5d1SDavid du Colombier 			if (*p=='u' || *p=='U')
444*3e12c5d1SDavid du Colombier 				v.type = UNS;
445*3e12c5d1SDavid du Colombier 			else if (*p=='l' || *p=='L')
446*3e12c5d1SDavid du Colombier 				;
447*3e12c5d1SDavid du Colombier 			else {
448*3e12c5d1SDavid du Colombier 				error(ERROR,
449*3e12c5d1SDavid du Colombier 				  "Bad number %t in #if/#elsif", tp);
450*3e12c5d1SDavid du Colombier 				break;
451*3e12c5d1SDavid du Colombier 			}
452*3e12c5d1SDavid du Colombier 		}
453*3e12c5d1SDavid du Colombier 		v.val = n;
454*3e12c5d1SDavid du Colombier 		tp->t[tp->len] = c;
455*3e12c5d1SDavid du Colombier 		break;
456*3e12c5d1SDavid du Colombier 
457*3e12c5d1SDavid du Colombier 	case CCON:
458*3e12c5d1SDavid du Colombier 		n = 0;
459*3e12c5d1SDavid du Colombier 		p = tp->t;
460*3e12c5d1SDavid du Colombier 		longcc = 0;
461*3e12c5d1SDavid du Colombier 		if (*p=='L') {
462*3e12c5d1SDavid du Colombier 			p += 1;
463*3e12c5d1SDavid du Colombier 			longcc = 1;
464*3e12c5d1SDavid du Colombier 		}
465*3e12c5d1SDavid du Colombier 		p += 1;
466*3e12c5d1SDavid du Colombier 		if (*p=='\\') {
467*3e12c5d1SDavid du Colombier 			p += 1;
468*3e12c5d1SDavid du Colombier 			if ((i = digit(*p))>=0 && i<=7) {
469*3e12c5d1SDavid du Colombier 				n = i;
470*3e12c5d1SDavid du Colombier 				p += 1;
471*3e12c5d1SDavid du Colombier 				if ((i = digit(*p))>=0 && i<=7) {
472*3e12c5d1SDavid du Colombier 					p += 1;
473*3e12c5d1SDavid du Colombier 					n <<= 3;
474*3e12c5d1SDavid du Colombier 					n += i;
475*3e12c5d1SDavid du Colombier 					if ((i = digit(*p))>=0 && i<=7) {
476*3e12c5d1SDavid du Colombier 						p += 1;
477*3e12c5d1SDavid du Colombier 						n <<= 3;
478*3e12c5d1SDavid du Colombier 						n += i;
479*3e12c5d1SDavid du Colombier 					}
480*3e12c5d1SDavid du Colombier 				}
481*3e12c5d1SDavid du Colombier 			} else if (*p=='x') {
482*3e12c5d1SDavid du Colombier 				p += 1;
483*3e12c5d1SDavid du Colombier 				while ((i = digit(*p))>=0 && i<=15) {
484*3e12c5d1SDavid du Colombier 					p += 1;
485*3e12c5d1SDavid du Colombier 					n <<= 4;
486*3e12c5d1SDavid du Colombier 					n += i;
487*3e12c5d1SDavid du Colombier 				}
488*3e12c5d1SDavid du Colombier 			} else {
489*3e12c5d1SDavid du Colombier 				static char cvcon[]
490*3e12c5d1SDavid du Colombier 				  = "a\ab\bf\fn\nr\rt\tv\v''\"\"??\\\\";
491*3e12c5d1SDavid du Colombier 				for (i=0; i<sizeof(cvcon); i+=2) {
492*3e12c5d1SDavid du Colombier 					if (*p == cvcon[i]) {
493*3e12c5d1SDavid du Colombier 						n = cvcon[i+1];
494*3e12c5d1SDavid du Colombier 						break;
495*3e12c5d1SDavid du Colombier 					}
496*3e12c5d1SDavid du Colombier 				}
497*3e12c5d1SDavid du Colombier 				p += 1;
498*3e12c5d1SDavid du Colombier 				if (i>=sizeof(cvcon))
499*3e12c5d1SDavid du Colombier 					error(WARNING,
500*3e12c5d1SDavid du Colombier 					 "Undefined escape in character constant");
501*3e12c5d1SDavid du Colombier 			}
502*3e12c5d1SDavid du Colombier 		} else if (*p=='\'')
503*3e12c5d1SDavid du Colombier 			error(ERROR, "Empty character constant");
504*3e12c5d1SDavid du Colombier 		else {
505*3e12c5d1SDavid du Colombier 			i = chartorune(&r, (char*)p);
506*3e12c5d1SDavid du Colombier 			n = r;
507*3e12c5d1SDavid du Colombier 			p += i;
508*3e12c5d1SDavid du Colombier 			if (i>1 && longcc==0)
509*3e12c5d1SDavid du Colombier 				error(WARNING, "Undefined character constant");
510*3e12c5d1SDavid du Colombier 		}
511*3e12c5d1SDavid du Colombier 		if (*p!='\'')
512*3e12c5d1SDavid du Colombier 			error(WARNING, "Multibyte character constant undefined");
513*3e12c5d1SDavid du Colombier 		else if (n>127 && longcc==0)
514*3e12c5d1SDavid du Colombier 			error(WARNING, "Character constant taken as not signed");
515*3e12c5d1SDavid du Colombier 		v.val = n;
516*3e12c5d1SDavid du Colombier 		break;
517*3e12c5d1SDavid du Colombier 
518*3e12c5d1SDavid du Colombier 	case STRING:
519*3e12c5d1SDavid du Colombier 		error(ERROR, "String in #if/#elsif");
520*3e12c5d1SDavid du Colombier 		break;
521*3e12c5d1SDavid du Colombier 	}
522*3e12c5d1SDavid du Colombier 	return v;
523*3e12c5d1SDavid du Colombier }
524*3e12c5d1SDavid du Colombier 
525*3e12c5d1SDavid du Colombier int
526*3e12c5d1SDavid du Colombier digit(int i)
527*3e12c5d1SDavid du Colombier {
528*3e12c5d1SDavid du Colombier 	if ('0'<=i && i<='9')
529*3e12c5d1SDavid du Colombier 		i -= '0';
530*3e12c5d1SDavid du Colombier 	else if ('a'<=i && i<='f')
531*3e12c5d1SDavid du Colombier 		i -= 'a'-10;
532*3e12c5d1SDavid du Colombier 	else if ('A'<=i && i<='F')
533*3e12c5d1SDavid du Colombier 		i -= 'A'-10;
534*3e12c5d1SDavid du Colombier 	else
535*3e12c5d1SDavid du Colombier 		i = -1;
536*3e12c5d1SDavid du Colombier 	return i;
537*3e12c5d1SDavid du Colombier }
538