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