xref: /openbsd/libexec/tradcpp/eval.c (revision 5af055cd)
1 /*-
2  * Copyright (c) 2010 The NetBSD Foundation, Inc.
3  * All rights reserved.
4  *
5  * This code is derived from software contributed to The NetBSD Foundation
6  * by David A. Holland.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
18  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
21  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27  * POSSIBILITY OF SUCH DAMAGE.
28  */
29 
30 #include <stdlib.h>
31 #include <string.h>
32 #include <limits.h>
33 #include <errno.h>
34 
35 //#define DEBUG
36 #ifdef DEBUG
37 #include <stdio.h>
38 #endif
39 
40 #include "utils.h"
41 #include "array.h"
42 #include "mode.h"
43 #include "place.h"
44 #include "eval.h"
45 
46 /*
47  * e ::=
48  *    e1 ? e2 : e3
49  *    e1 || e2
50  *    e1 && e2
51  *    e1 | e2
52  *    e1 ^ e2
53  *    e1 & e2
54  *    e1 == e2  |  e1 != e2
55  *    e1 < e2   |  e1 <= e2  |  e1 > e2  |  e1 >= e2
56  *    e1 << e2  |  e1 >> e2
57  *    e1 + e2   |  e1 - e2
58  *    e1 * e2   |  e1 / e2   |  e1 % e2
59  *    !e  |  ~e  |  -e  |  +e
60  *    ( e )  |  ident
61  */
62 
63 enum tokens {
64 	T_EOF,		/* end of input */
65 	T_VAL,		/* value */
66 	T_LPAREN,	/* parens */
67 	T_RPAREN,
68 	T_PIPEPIPE,	/* operators */
69 	T_AMPAMP,
70 	T_EQEQ,
71 	T_BANGEQ,
72 	T_LTEQ,
73 	T_GTEQ,
74 	T_LTLT,
75 	T_GTGT,
76 	T_QUES,
77 	T_COLON,
78 	T_PIPE,
79 	T_CARET,
80 	T_AMP,
81 	T_LT,
82 	T_GT,
83 	T_PLUS,
84 	T_MINUS,
85 	T_STAR,
86 	T_SLASH,
87 	T_PCT,
88 	T_BANG,
89 	T_TILDE,
90 };
91 
92 static const struct {
93 	char c1, c2;
94 	enum tokens tok;
95 } tokens_2[] = {
96 	{ '|', '|', T_PIPEPIPE },
97 	{ '&', '&', T_AMPAMP },
98 	{ '=', '=', T_EQEQ },
99 	{ '!', '=', T_BANGEQ },
100 	{ '<', '=', T_LTEQ },
101 	{ '>', '=', T_GTEQ },
102 	{ '<', '<', T_LTLT },
103 	{ '>', '>', T_GTGT },
104 };
105 static const unsigned num_tokens_2 = HOWMANY(tokens_2);
106 
107 static const struct {
108 	char c1;
109 	enum tokens tok;
110 } tokens_1[] = {
111 	{ '?', T_QUES },
112 	{ ':', T_COLON },
113 	{ '|', T_PIPE },
114 	{ '^', T_CARET },
115 	{ '&', T_AMP },
116 	{ '<', T_LT },
117 	{ '>', T_GT },
118 	{ '+', T_PLUS },
119 	{ '-', T_MINUS },
120 	{ '*', T_STAR },
121 	{ '/', T_SLASH },
122 	{ '%', T_PCT },
123 	{ '!', T_BANG },
124 	{ '~', T_TILDE },
125 	{ '(', T_LPAREN },
126 	{ ')', T_RPAREN },
127 };
128 static const unsigned num_tokens_1 = HOWMANY(tokens_1);
129 
130 struct token {
131 	struct place place;
132 	enum tokens tok;
133 	int val;
134 };
135 DECLARRAY(token, static UNUSED);
136 DEFARRAY(token, static);
137 
138 static struct tokenarray tokens;
139 
140 static
141 struct token *
142 token_create(const struct place *p, enum tokens tok, int val)
143 {
144 	struct token *t;
145 
146 	t = domalloc(sizeof(*t));
147 	t->place = *p;
148 	t->tok = tok;
149 	t->val = val;
150 	return t;
151 }
152 
153 static
154 void
155 token_destroy(struct token *t)
156 {
157 	dofree(t, sizeof(*t));
158 }
159 
160 DESTROYALL_ARRAY(token, );
161 
162 #ifdef DEBUG
163 static
164 void
165 printtokens(void)
166 {
167 	unsigned i, num;
168 	struct token *t;
169 
170 	fprintf(stderr, "tokens:");
171 	num = tokenarray_num(&tokens);
172 	for (i=0; i<num; i++) {
173 		t = tokenarray_get(&tokens, i);
174 		switch (t->tok) {
175 		    case T_EOF: fprintf(stderr, " <eof>"); break;
176 		    case T_VAL: fprintf(stderr, " %d", t->val); break;
177 		    case T_LPAREN: fprintf(stderr, " ("); break;
178 		    case T_RPAREN: fprintf(stderr, " )"); break;
179 		    case T_PIPEPIPE: fprintf(stderr, " ||"); break;
180 		    case T_AMPAMP: fprintf(stderr, " &&"); break;
181 		    case T_EQEQ: fprintf(stderr, " =="); break;
182 		    case T_BANGEQ: fprintf(stderr, " !="); break;
183 		    case T_LTEQ: fprintf(stderr, " <="); break;
184 		    case T_GTEQ: fprintf(stderr, " >="); break;
185 		    case T_LTLT: fprintf(stderr, " <<"); break;
186 		    case T_GTGT: fprintf(stderr, " >>"); break;
187 		    case T_QUES: fprintf(stderr, " ?"); break;
188 		    case T_COLON: fprintf(stderr, " :"); break;
189 		    case T_PIPE: fprintf(stderr, " |"); break;
190 		    case T_CARET: fprintf(stderr, " ^"); break;
191 		    case T_AMP: fprintf(stderr, " &"); break;
192 		    case T_LT: fprintf(stderr, " <"); break;
193 		    case T_GT: fprintf(stderr, " >"); break;
194 		    case T_PLUS: fprintf(stderr, " +"); break;
195 		    case T_MINUS: fprintf(stderr, " -"); break;
196 		    case T_STAR: fprintf(stderr, " *"); break;
197 		    case T_SLASH: fprintf(stderr, " /"); break;
198 		    case T_PCT: fprintf(stderr, " %%"); break;
199 		    case T_BANG: fprintf(stderr, " !"); break;
200 		    case T_TILDE: fprintf(stderr, " ~"); break;
201 		}
202 	}
203 	fprintf(stderr, "\n");
204 }
205 #endif
206 
207 static
208 bool
209 isuop(enum tokens tok)
210 {
211 	switch (tok) {
212 	    case T_BANG:
213 	    case T_TILDE:
214 	    case T_MINUS:
215 	    case T_PLUS:
216 		return true;
217 	    default:
218 		break;
219 	}
220 	return false;
221 }
222 
223 static
224 bool
225 isbop(enum tokens tok)
226 {
227 	switch (tok) {
228 	    case T_EOF:
229 	    case T_VAL:
230 	    case T_LPAREN:
231 	    case T_RPAREN:
232 	    case T_COLON:
233 	    case T_QUES:
234 	    case T_BANG:
235 	    case T_TILDE:
236 		return false;
237 	    default:
238 		break;
239 	}
240 	return true;
241 }
242 
243 static
244 bool
245 isop(enum tokens tok)
246 {
247 	switch (tok) {
248 	    case T_EOF:
249 	    case T_VAL:
250 	    case T_LPAREN:
251 	    case T_RPAREN:
252 		return false;
253 	    default:
254 		break;
255 	}
256 	return true;
257 }
258 
259 static
260 int
261 getprec(enum tokens tok)
262 {
263 	switch (tok) {
264 	    case T_BANG: case T_TILDE: return -1;
265 	    case T_STAR: case T_SLASH: case T_PCT: return 0;
266 	    case T_PLUS: case T_MINUS: return 1;
267 	    case T_LTLT: case T_GTGT: return 2;
268 	    case T_LT: case T_LTEQ: case T_GT: case T_GTEQ: return 3;
269 	    case T_EQEQ: case T_BANGEQ: return 4;
270 	    case T_AMP: return 5;
271 	    case T_CARET: return 6;
272 	    case T_PIPE: return 7;
273 	    case T_AMPAMP: return 8;
274 	    case T_PIPEPIPE: return 9;
275 	    default: break;
276 	}
277 	return 10;
278 }
279 
280 static
281 bool
282 looser(enum tokens t1, enum tokens t2)
283 {
284 	return getprec(t1) >= getprec(t2);
285 }
286 
287 static
288 int
289 eval_uop(enum tokens op, int val)
290 {
291 	switch (op) {
292 	    case T_BANG: val = !val; break;
293 	    case T_TILDE: val = (int)~(unsigned)val; break;
294 	    case T_MINUS: val = -val; break;
295 	    case T_PLUS: break;
296 	    default: assert(0); break;
297 	}
298 	return val;
299 }
300 
301 static
302 int
303 eval_bop(struct place *p, int lv, enum tokens op, int rv)
304 {
305 	unsigned mask;
306 
307 	switch (op) {
308 	    case T_PIPEPIPE: return lv || rv;
309 	    case T_AMPAMP:   return lv && rv;
310 	    case T_PIPE:     return (int)((unsigned)lv | (unsigned)rv);
311 	    case T_CARET:    return (int)((unsigned)lv ^ (unsigned)rv);
312 	    case T_AMP:      return (int)((unsigned)lv & (unsigned)rv);
313 	    case T_EQEQ:     return lv == rv;
314 	    case T_BANGEQ:   return lv != rv;
315 	    case T_LT:       return lv < rv;
316 	    case T_GT:       return lv > rv;
317 	    case T_LTEQ:     return lv <= rv;
318 	    case T_GTEQ:     return lv >= rv;
319 
320 	    case T_LTLT:
321 	    case T_GTGT:
322 		if (rv < 0) {
323 			complain(p, "Negative bit-shift");
324 			complain_fail();
325 			rv = 0;
326 		}
327 		if ((unsigned)rv >= CHAR_BIT * sizeof(unsigned)) {
328 			complain(p, "Bit-shift farther than type width");
329 			complain_fail();
330 			rv = 0;
331 		}
332 		if (op == T_LTLT) {
333 			return (int)((unsigned)lv << (unsigned)rv);
334 		}
335 		mask = ((unsigned)-1) << (CHAR_BIT * sizeof(unsigned) - rv);
336 		lv = (int)(((unsigned)lv >> (unsigned)rv) | mask);
337 		return lv;
338 
339 	    case T_MINUS:
340 		if (rv == INT_MIN) {
341 			if (lv == INT_MIN) {
342 				return 0;
343 			}
344 			lv--;
345 			rv++;
346 		}
347 		rv = -rv;
348 		/* FALLTHROUGH */
349 	    case T_PLUS:
350 		if (rv > 0 && lv > (INT_MAX - rv)) {
351 			complain(p, "Integer overflow");
352 			complain_fail();
353 			return INT_MAX;
354 		}
355 		if (rv < 0 && lv < (INT_MIN - rv)) {
356 			complain(p, "Integer underflow");
357 			complain_fail();
358 			return INT_MIN;
359 		}
360 		return lv + rv;
361 
362 	    case T_STAR:
363 		if (rv == 0) {
364 			return 0;
365 		}
366 		if (rv == 1) {
367 			return lv;
368 		}
369 		if (rv == -1 && lv == INT_MIN) {
370 			lv++;
371 			lv = -lv;
372 			if (lv == INT_MAX) {
373 				complain(p, "Integer overflow");
374 				complain_fail();
375 				return INT_MAX;
376 			}
377 			lv++;
378 			return lv;
379 		}
380 		if (lv == INT_MIN && rv < 0) {
381 			complain(p, "Integer overflow");
382 			complain_fail();
383 			return INT_MAX;
384 		}
385 		if (lv == INT_MIN && rv > 0) {
386 			complain(p, "Integer underflow");
387 			complain_fail();
388 			return INT_MIN;
389 		}
390 		if (rv < 0) {
391 			rv = -rv;
392 			lv = -lv;
393 		}
394 		if (lv > 0 && lv > INT_MAX / rv) {
395 			complain(p, "Integer overflow");
396 			complain_fail();
397 			return INT_MAX;
398 		}
399 		if (lv < 0 && lv < INT_MIN / rv) {
400 			complain(p, "Integer underflow");
401 			complain_fail();
402 			return INT_MIN;
403 		}
404 		return lv * rv;
405 
406 	    case T_SLASH:
407 		if (rv == 0) {
408 			complain(p, "Division by zero");
409 			complain_fail();
410 			return 0;
411 		}
412 		return lv / rv;
413 
414 	    case T_PCT:
415 		if (rv == 0) {
416 			complain(p, "Modulus by zero");
417 			complain_fail();
418 			return 0;
419 		}
420 		return lv % rv;
421 
422 	    default: assert(0); break;
423 	}
424 	return 0;
425 }
426 
427 static
428 void
429 tryreduce(void)
430 {
431 	unsigned num;
432 	struct token *t1, *t2, *t3, *t4, *t5, *t6;
433 
434 	while (1) {
435 #ifdef DEBUG
436 		printtokens();
437 #endif
438 		num = tokenarray_num(&tokens);
439 		t1 = (num >= 1) ? tokenarray_get(&tokens, num-1) : NULL;
440 		t2 = (num >= 2) ? tokenarray_get(&tokens, num-2) : NULL;
441 		t3 = (num >= 3) ? tokenarray_get(&tokens, num-3) : NULL;
442 
443 		if (num >= 3 &&
444 		    t3->tok == T_LPAREN &&
445 		    t2->tok == T_VAL &&
446 		    t1->tok == T_RPAREN) {
447 			/* (x) -> x */
448 			t2->place = t3->place;
449 			token_destroy(t1);
450 			token_destroy(t3);
451 			tokenarray_remove(&tokens, num-1);
452 			tokenarray_remove(&tokens, num-3);
453 			continue;
454 		}
455 
456 		if (num >= 2 &&
457 		    (num == 2 || isop(t3->tok) || t3->tok == T_LPAREN) &&
458 		    isuop(t2->tok) &&
459 		    t1->tok == T_VAL) {
460 			/* unary operator */
461 			t1->val = eval_uop(t2->tok, t1->val);
462 			t1->place = t2->place;
463 			token_destroy(t2);
464 			tokenarray_remove(&tokens, num-2);
465 			continue;
466 		}
467 		if (num >= 2 &&
468 		    (num == 2 || isop(t3->tok) || t3->tok == T_LPAREN) &&
469 		    t2->tok != T_LPAREN && t2->tok != T_VAL &&
470 		    t1->tok == T_VAL) {
471 			complain(&t2->place, "Invalid unary operator");
472 			complain_fail();
473 			token_destroy(t2);
474 			tokenarray_remove(&tokens, num-2);
475 			continue;
476 		}
477 
478 
479 		t4 = (num >= 4) ? tokenarray_get(&tokens, num-4) : NULL;
480 
481 		if (num >= 4 &&
482 		    t4->tok == T_VAL &&
483 		    isbop(t3->tok) &&
484 		    t2->tok == T_VAL) {
485 			/* binary operator */
486 			if (looser(t1->tok, t3->tok)) {
487 				t4->val = eval_bop(&t3->place,
488 						   t4->val, t3->tok, t2->val);
489 				token_destroy(t2);
490 				token_destroy(t3);
491 				tokenarray_remove(&tokens, num-2);
492 				tokenarray_remove(&tokens, num-3);
493 				continue;
494 			}
495 			break;
496 		}
497 
498 		t5 = (num >= 5) ? tokenarray_get(&tokens, num-5) : NULL;
499 		t6 = (num >= 6) ? tokenarray_get(&tokens, num-6) : NULL;
500 
501 		if (num >= 6 &&
502 		    t6->tok == T_VAL &&
503 		    t5->tok == T_QUES &&
504 		    t4->tok == T_VAL &&
505 		    t3->tok == T_COLON &&
506 		    t2->tok == T_VAL &&
507 		    !isop(t1->tok)) {
508 			/* conditional expression */
509 			t6->val = t6->val ? t4->val : t2->val;
510 			token_destroy(t2);
511 			token_destroy(t3);
512 			token_destroy(t4);
513 			token_destroy(t5);
514 			tokenarray_remove(&tokens, num-2);
515 			tokenarray_remove(&tokens, num-3);
516 			tokenarray_remove(&tokens, num-4);
517 			tokenarray_remove(&tokens, num-5);
518 			continue;
519 		}
520 
521 		if (num >= 2 &&
522 		    t2->tok == T_LPAREN &&
523 		    t1->tok == T_RPAREN) {
524 			complain(&t1->place, "Value expected within ()");
525 			complain_fail();
526 			t1->tok = T_VAL;
527 			t1->val = 0;
528 			token_destroy(t1);
529 			tokenarray_remove(&tokens, num-1);
530 			continue;
531 		}
532 
533 		if (num >= 2 &&
534 		    t2->tok == T_VAL &&
535 		    t1->tok == T_VAL) {
536 			complain(&t1->place, "Operator expected");
537 			complain_fail();
538 			token_destroy(t1);
539 			tokenarray_remove(&tokens, num-1);
540 			continue;
541 		}
542 
543 		if (num >= 2 &&
544 		    isop(t2->tok) &&
545 		    t1->tok == T_EOF) {
546 			complain(&t1->place, "Value expected after operator");
547 			complain_fail();
548 			token_destroy(t2);
549 			tokenarray_remove(&tokens, num-2);
550 			continue;
551 		}
552 
553 		if (num == 2 &&
554 		    t2->tok == T_VAL &&
555 		    t1->tok == T_RPAREN) {
556 			complain(&t1->place, "Excess right parenthesis");
557 			complain_fail();
558 			token_destroy(t1);
559 			tokenarray_remove(&tokens, num-1);
560 			continue;
561 		}
562 
563 		if (num == 3 &&
564 		    t3->tok == T_LPAREN &&
565 		    t2->tok == T_VAL &&
566 		    t1->tok == T_EOF) {
567 			complain(&t1->place, "Unclosed left parenthesis");
568 			complain_fail();
569 			token_destroy(t3);
570 			tokenarray_remove(&tokens, num-3);
571 			continue;
572 		}
573 
574 		if (num == 2 &&
575 		    t2->tok == T_VAL &&
576 		    t1->tok == T_EOF) {
577 			/* accepting state */
578 			break;
579 		}
580 
581 		if (num >= 1 &&
582 		    t1->tok == T_EOF) {
583 			/* any other configuration at eof is an error */
584 			complain(&t1->place, "Parse error");
585 			complain_fail();
586 			break;
587 		}
588 
589 		/* otherwise, wait for more input */
590 		break;
591 	}
592 }
593 
594 static
595 void
596 token(struct place *p, enum tokens tok, int val)
597 {
598 	struct token *t;
599 
600 	t = token_create(p, tok, val);
601 
602 	tokenarray_add(&tokens, t, NULL);
603 	tryreduce();
604 }
605 
606 static
607 int
608 wordval(struct place *p, char *word)
609 {
610 	unsigned long val;
611 	char *t;
612 
613 	if (word[0] >= '0' && word[0] <= '9') {
614 		errno = 0;
615 		val = strtoul(word, &t, 0);
616 		if (errno) {
617 			complain(p, "Invalid integer constant");
618 			complain_fail();
619 			return 0;
620 		}
621 		while (*t == 'U' || *t == 'L') {
622 			t++;
623 		}
624 		if (*t != '\0') {
625 			complain(p, "Trailing garbage after integer constant");
626 			complain_fail();
627 			return 0;
628 		}
629 		if (val > INT_MAX) {
630 			complain(p, "Integer constant too large");
631 			complain_fail();
632 			return INT_MAX;
633 		}
634 		return val;
635 	}
636 
637 	/* if it's a symbol, warn and substitute 0. */
638 	if (warns.undef) {
639 		complain(p, "Warning: value of undefined symbol %s is 0",
640 			 word);
641 		if (mode.werror) {
642 			complain_fail();
643 		}
644 	}
645 	return 0;
646 }
647 
648 static
649 bool
650 check_word(struct place *p, char *expr, size_t pos, size_t *len_ret)
651 {
652 	size_t len;
653 	int val;
654 	char tmp;
655 
656 	if (!strchr(alnum, expr[pos])) {
657 		return false;
658 	}
659 	len = strspn(expr + pos, alnum);
660 	tmp = expr[pos + len];
661 	expr[pos + len] = '\0';
662 	val = wordval(p, expr + pos);
663 	expr[pos + len] = tmp;
664 	token(p, T_VAL, val);
665 	*len_ret = len;
666 	return true;
667 }
668 
669 static
670 bool
671 check_tokens_2(struct place *p, char *expr, size_t pos)
672 {
673 	unsigned i;
674 
675 	for (i=0; i<num_tokens_2; i++) {
676 		if (expr[pos] == tokens_2[i].c1 &&
677 		    expr[pos+1] == tokens_2[i].c2) {
678 			token(p, tokens_2[i].tok, 0);
679 			return true;
680 		}
681 	}
682 	return false;
683 }
684 
685 static
686 bool
687 check_tokens_1(struct place *p, char *expr, size_t pos)
688 {
689 	unsigned i;
690 
691 	for (i=0; i<num_tokens_1; i++) {
692 		if (expr[pos] == tokens_1[i].c1) {
693 			token(p, tokens_1[i].tok, 0);
694 			return true;
695 		}
696 	}
697 	return false;
698 }
699 
700 static
701 void
702 tokenize(struct place *p, char *expr)
703 {
704 	size_t pos, len;
705 
706 	pos = 0;
707 	while (expr[pos] != '\0') {
708 		len = strspn(expr+pos, ws);
709 		pos += len;
710 		p->column += len;
711 		/* trailing whitespace is supposed to have been pruned */
712 		assert(expr[pos] != '\0');
713 		if (check_word(p, expr, pos, &len)) {
714 			pos += len;
715 			p->column += len;
716 			continue;
717 		}
718 		if (check_tokens_2(p, expr, pos)) {
719 			pos += 2;
720 			p->column += 2;
721 			continue;
722 		}
723 		if (check_tokens_1(p, expr, pos)) {
724 			pos++;
725 			p->column++;
726 			continue;
727 		}
728 		complain(p, "Invalid character %u in #if-expression",
729 			 (unsigned char)expr[pos]);
730 		complain_fail();
731 		pos++;
732 		p->column++;
733 	}
734 	token(p, T_EOF, 0);
735 }
736 
737 bool
738 eval(struct place *p, char *expr)
739 {
740 	struct token *t1, *t2;
741 	unsigned num;
742 	bool result;
743 
744 #ifdef DEBUG
745 	fprintf(stderr, "eval: %s\n", expr);
746 #endif
747 
748 	tokenarray_init(&tokens);
749 	tokenize(p, expr);
750 
751 	result = false;
752 	num = tokenarray_num(&tokens);
753 	if (num == 2) {
754 		t1 = tokenarray_get(&tokens, num-1);
755 		t2 = tokenarray_get(&tokens, num-2);
756 		if (t2->tok == T_VAL &&
757 		    t1->tok == T_EOF) {
758 			result = t2->val != 0;
759 		}
760 	}
761 
762 	tokenarray_destroyall(&tokens);
763 	tokenarray_cleanup(&tokens);
764 	return result;
765 }
766