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