Mercurial > ~dholland > hg > tradcpp > index.cgi
annotate eval.c @ 64:f50b4ea6cbfe
Prune single-line comments from (most) directive lines.
Also, don't pass the string length to the directive processing
functions, as half of them weren't honoring it. Instead, ensure that
the directive line is terminated at the place the directive processing
functions should stop looking at it.
author | David A. Holland |
---|---|
date | Sun, 31 Mar 2013 02:04:56 -0400 |
parents | 5e24746d8335 |
children | bd1b7a09da89 |
rev | line source |
---|---|
30 | 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 | |
16 | 30 #include <stdlib.h> |
31 #include <string.h> | |
32 #include <limits.h> | |
33 #include <errno.h> | |
34 | |
35 #include "utils.h" | |
36 #include "array.h" | |
37 #include "mode.h" | |
38 #include "place.h" | |
39 #include "eval.h" | |
40 | |
41 /* | |
42 * e ::= | |
43 * e1 ? e2 : e3 | |
44 * e1 || e2 | |
45 * e1 && e2 | |
46 * e1 | e2 | |
47 * e1 ^ e2 | |
48 * e1 & e2 | |
49 * e1 == e2 | e1 != e2 | |
50 * e1 < e2 | e1 <= e2 | e1 > e2 | e1 >= e2 | |
51 * e1 << e2 | e1 >> e2 | |
52 * e1 + e2 | e1 - e2 | |
53 * e1 * e2 | e1 / e2 | e1 % e2 | |
54 * !e | ~e | -e | +e | |
55 * ( e ) | ident | |
56 */ | |
57 | |
58 enum tokens { | |
59 T_EOF, /* end of input */ | |
60 T_VAL, /* value */ | |
61 T_LPAREN, /* parens */ | |
62 T_RPAREN, | |
63 T_PIPEPIPE, /* operators */ | |
64 T_AMPAMP, | |
65 T_EQEQ, | |
66 T_BANGEQ, | |
67 T_LTEQ, | |
68 T_GTEQ, | |
69 T_LTLT, | |
70 T_GTGT, | |
71 T_QUES, | |
72 T_COLON, | |
73 T_PIPE, | |
74 T_CARET, | |
75 T_AMP, | |
76 T_LT, | |
77 T_GT, | |
78 T_PLUS, | |
79 T_MINUS, | |
80 T_STAR, | |
81 T_SLASH, | |
82 T_PCT, | |
83 T_BANG, | |
84 T_TILDE, | |
85 }; | |
86 | |
87 static const struct { | |
88 char c1, c2; | |
89 enum tokens tok; | |
90 } tokens_2[] = { | |
91 { '|', '|', T_PIPEPIPE }, | |
92 { '&', '&', T_AMPAMP }, | |
93 { '=', '=', T_EQEQ }, | |
94 { '!', '=', T_BANGEQ }, | |
95 { '<', '=', T_LTEQ }, | |
96 { '>', '=', T_GTEQ }, | |
97 { '<', '<', T_LTLT }, | |
98 { '>', '>', T_GTGT }, | |
99 }; | |
100 static const unsigned num_tokens_2 = HOWMANY(tokens_2); | |
101 | |
102 static const struct { | |
103 char c1; | |
104 enum tokens tok; | |
105 } tokens_1[] = { | |
106 { '?', T_QUES }, | |
107 { ':', T_COLON }, | |
108 { '|', T_PIPE }, | |
109 { '^', T_CARET }, | |
110 { '&', T_AMP }, | |
111 { '<', T_LT }, | |
112 { '>', T_GT }, | |
113 { '+', T_PLUS }, | |
114 { '-', T_MINUS }, | |
115 { '*', T_STAR }, | |
116 { '/', T_SLASH }, | |
117 { '%', T_PCT }, | |
118 { '!', T_BANG }, | |
119 { '~', T_TILDE }, | |
120 { '(', T_LPAREN }, | |
121 { ')', T_RPAREN }, | |
122 }; | |
123 static const unsigned num_tokens_1 = HOWMANY(tokens_1); | |
124 | |
125 struct token { | |
126 struct place place; | |
127 enum tokens tok; | |
128 int val; | |
129 }; | |
47
2e25e55dba6b
Fix inline usage as per the version in dholland-make2.
David A. Holland
parents:
39
diff
changeset
|
130 DECLARRAY(token, static __unused); |
2e25e55dba6b
Fix inline usage as per the version in dholland-make2.
David A. Holland
parents:
39
diff
changeset
|
131 DEFARRAY(token, static); |
16 | 132 |
133 static struct tokenarray tokens; | |
134 | |
135 static | |
136 struct token * | |
137 token_create(const struct place *p, enum tokens tok, int val) | |
138 { | |
139 struct token *t; | |
140 | |
141 t = domalloc(sizeof(*t)); | |
142 t->place = *p; | |
143 t->tok = tok; | |
144 t->val = val; | |
145 return t; | |
146 } | |
147 | |
148 static | |
149 void | |
150 token_destroy(struct token *t) | |
151 { | |
39
337110e7240a
Pass the size to free; it makes debug checking easier.
David A. Holland
parents:
38
diff
changeset
|
152 dofree(t, sizeof(*t)); |
16 | 153 } |
154 | |
155 DESTROYALL_ARRAY(token, ); | |
156 | |
157 static | |
158 bool | |
159 isuop(enum tokens tok) | |
160 { | |
161 switch (tok) { | |
162 case T_BANG: | |
163 case T_TILDE: | |
164 case T_MINUS: | |
165 case T_PLUS: | |
166 return true; | |
167 default: | |
168 break; | |
169 } | |
170 return false; | |
171 } | |
172 | |
173 static | |
174 bool | |
175 isbop(enum tokens tok) | |
176 { | |
177 switch (tok) { | |
178 case T_EOF: | |
179 case T_VAL: | |
180 case T_LPAREN: | |
181 case T_RPAREN: | |
182 case T_COLON: | |
183 case T_QUES: | |
184 case T_BANG: | |
185 case T_TILDE: | |
186 return false; | |
187 default: | |
188 break; | |
189 } | |
190 return true; | |
191 } | |
192 | |
193 static | |
194 bool | |
195 isop(enum tokens tok) | |
196 { | |
197 switch (tok) { | |
198 case T_EOF: | |
199 case T_VAL: | |
200 case T_LPAREN: | |
201 case T_RPAREN: | |
202 return false; | |
203 default: | |
204 break; | |
205 } | |
206 return true; | |
207 } | |
208 | |
209 static | |
210 int | |
211 getprec(enum tokens tok) | |
212 { | |
213 switch (tok) { | |
214 case T_STAR: case T_SLASH: case T_PCT: return 0; | |
215 case T_PLUS: case T_MINUS: return 1; | |
216 case T_LTLT: case T_GTGT: return 2; | |
217 case T_LT: case T_LTEQ: case T_GT: case T_GTEQ: return 3; | |
218 case T_EQEQ: case T_BANGEQ: return 4; | |
219 case T_AMP: return 5; | |
220 case T_CARET: return 6; | |
221 case T_PIPE: return 7; | |
222 case T_AMPAMP: return 8; | |
223 case T_PIPEPIPE: return 9; | |
224 default: break; | |
225 } | |
226 return 10; | |
227 } | |
228 | |
229 static | |
230 bool | |
231 looser(enum tokens t1, enum tokens t2) | |
232 { | |
233 return getprec(t1) > getprec(t2); | |
234 } | |
235 | |
236 static | |
237 int | |
238 eval_uop(enum tokens op, int val) | |
239 { | |
240 switch (op) { | |
241 case T_BANG: val = !val; break; | |
242 case T_TILDE: val = (int)~(unsigned)val; break; | |
243 case T_MINUS: val = -val; break; | |
244 case T_PLUS: break; | |
245 default: assert(0); break; | |
246 } | |
247 return val; | |
248 } | |
249 | |
250 static | |
251 int | |
28 | 252 eval_bop(struct place *p, int lv, enum tokens op, int rv) |
16 | 253 { |
254 unsigned mask; | |
255 | |
256 switch (op) { | |
257 case T_PIPEPIPE: return lv || rv; | |
258 case T_AMPAMP: return lv && rv; | |
259 case T_PIPE: return (int)((unsigned)lv | (unsigned)rv); | |
260 case T_CARET: return (int)((unsigned)lv ^ (unsigned)rv); | |
261 case T_AMP: return (int)((unsigned)lv & (unsigned)rv); | |
262 case T_EQEQ: return lv == rv; | |
263 case T_BANGEQ: return lv != rv; | |
264 case T_LT: return lv < rv; | |
265 case T_GT: return lv > rv; | |
266 case T_LTEQ: return lv <= rv; | |
267 case T_GTEQ: return lv >= rv; | |
268 | |
269 case T_LTLT: | |
270 case T_GTGT: | |
271 if (rv < 0) { | |
272 complain(p, "Negative bit-shift"); | |
273 complain_fail(); | |
274 rv = 0; | |
275 } | |
276 if ((unsigned)rv >= CHAR_BIT * sizeof(unsigned)) { | |
277 complain(p, "Bit-shift farther than type width"); | |
278 complain_fail(); | |
279 rv = 0; | |
280 } | |
281 if (op == T_LTLT) { | |
282 return (int)((unsigned)lv << (unsigned)rv); | |
283 } | |
284 mask = ((unsigned)-1) << (CHAR_BIT * sizeof(unsigned) - rv); | |
285 lv = (int)(((unsigned)lv >> (unsigned)rv) | mask); | |
286 return lv; | |
287 | |
288 case T_MINUS: | |
289 if (rv == INT_MIN) { | |
290 if (lv == INT_MIN) { | |
291 return 0; | |
292 } | |
293 lv--; | |
294 rv++; | |
295 } | |
296 rv = -rv; | |
297 /* FALLTHROUGH */ | |
298 case T_PLUS: | |
299 if (rv > 0 && lv > (INT_MAX - rv)) { | |
300 complain(p, "Integer overflow"); | |
301 complain_fail(); | |
302 return INT_MAX; | |
303 } | |
304 if (rv < 0 && lv < (INT_MIN - rv)) { | |
305 complain(p, "Integer underflow"); | |
306 complain_fail(); | |
307 return INT_MIN; | |
308 } | |
309 return lv + rv; | |
310 | |
311 case T_STAR: | |
312 if (rv == 0) { | |
313 return 0; | |
314 } | |
315 if (rv == 1) { | |
316 return lv; | |
317 } | |
318 if (rv == -1 && lv == INT_MIN) { | |
319 lv++; | |
320 lv = -lv; | |
321 if (lv == INT_MAX) { | |
322 complain(p, "Integer overflow"); | |
323 complain_fail(); | |
324 return INT_MAX; | |
325 } | |
326 lv++; | |
327 return lv; | |
328 } | |
329 if (lv == INT_MIN && rv < 0) { | |
330 complain(p, "Integer overflow"); | |
331 complain_fail(); | |
332 return INT_MAX; | |
333 } | |
334 if (lv == INT_MIN && rv > 0) { | |
335 complain(p, "Integer underflow"); | |
336 complain_fail(); | |
337 return INT_MIN; | |
338 } | |
339 if (rv < 0) { | |
340 rv = -rv; | |
341 lv = -lv; | |
342 } | |
343 if (lv > 0 && lv > INT_MAX / rv) { | |
344 complain(p, "Integer overflow"); | |
345 complain_fail(); | |
346 return INT_MAX; | |
347 } | |
348 if (lv < 0 && lv < INT_MIN / rv) { | |
349 complain(p, "Integer underflow"); | |
350 complain_fail(); | |
351 return INT_MIN; | |
352 } | |
353 return lv * rv; | |
354 | |
355 case T_SLASH: | |
356 if (rv == 0) { | |
357 complain(p, "Division by zero"); | |
358 complain_fail(); | |
359 return 0; | |
360 } | |
361 return lv / rv; | |
362 | |
363 case T_PCT: | |
364 if (rv == 0) { | |
365 complain(p, "Modulus by zero"); | |
366 complain_fail(); | |
367 return 0; | |
368 } | |
369 return lv % rv; | |
370 | |
371 default: assert(0); break; | |
372 } | |
373 return 0; | |
374 } | |
375 | |
376 static | |
377 void | |
378 tryreduce(void) | |
379 { | |
380 unsigned num; | |
381 struct token *t1, *t2, *t3, *t4, *t5, *t6; | |
382 | |
383 while (1) { | |
384 num = tokenarray_num(&tokens); | |
385 t1 = (num >= 1) ? tokenarray_get(&tokens, num-1) : NULL; | |
386 t2 = (num >= 2) ? tokenarray_get(&tokens, num-2) : NULL; | |
387 t3 = (num >= 3) ? tokenarray_get(&tokens, num-3) : NULL; | |
388 | |
389 if (num >= 3 && | |
390 t3->tok == T_LPAREN && | |
391 t2->tok == T_VAL && | |
392 t1->tok == T_RPAREN) { | |
393 /* (x) -> x */ | |
394 t2->place = t3->place; | |
395 token_destroy(t1); | |
396 token_destroy(t3); | |
397 tokenarray_remove(&tokens, num-1); | |
398 tokenarray_remove(&tokens, num-3); | |
399 continue; | |
400 } | |
401 | |
402 if (num >= 2 && | |
403 (num == 2 || isop(t3->tok) || t3->tok == T_LPAREN) && | |
404 isuop(t2->tok) && | |
405 t1->tok == T_VAL) { | |
406 /* unary operator */ | |
407 t1->val = eval_uop(t2->tok, t1->val); | |
408 t1->place = t2->place; | |
409 token_destroy(t2); | |
410 tokenarray_remove(&tokens, num-2); | |
411 continue; | |
412 } | |
413 if (num >= 2 && | |
414 (num == 2 || isop(t3->tok) || t3->tok == T_RPAREN) && | |
415 t2->tok != T_LPAREN && t2->tok != T_VAL && | |
416 t1->tok == T_VAL) { | |
417 complain(&t2->place, "Invalid unary operator"); | |
418 complain_fail(); | |
419 token_destroy(t2); | |
420 tokenarray_remove(&tokens, num-2); | |
421 continue; | |
422 } | |
423 | |
424 | |
425 t4 = (num >= 4) ? tokenarray_get(&tokens, num-4) : NULL; | |
426 | |
427 if (num >= 4 && | |
428 t4->tok == T_VAL && | |
429 isbop(t3->tok) && | |
430 t2->tok == T_VAL && | |
431 (isbop(t1->tok) || !isop(t1->tok))) { | |
432 /* binary operator */ | |
433 if (looser(t1->tok, t3->tok)) { | |
434 t4->val = eval_bop(&t3->place, | |
435 t4->val, t3->tok, t2->val); | |
436 token_destroy(t2); | |
437 token_destroy(t3); | |
438 tokenarray_remove(&tokens, num-2); | |
439 tokenarray_remove(&tokens, num-3); | |
440 continue; | |
441 } | |
442 break; | |
443 } | |
444 | |
445 t5 = (num >= 5) ? tokenarray_get(&tokens, num-5) : NULL; | |
446 t6 = (num >= 6) ? tokenarray_get(&tokens, num-6) : NULL; | |
447 | |
448 if (num >=6 && | |
449 t6->tok == T_VAL && | |
450 t5->tok == T_QUES && | |
451 t4->tok == T_VAL && | |
452 t3->tok == T_COLON && | |
453 t2->tok == T_VAL && | |
454 !isop(t1->tok)) { | |
455 /* conditional expression */ | |
456 t6->val = t6->val ? t4->val : t2->val; | |
457 token_destroy(t2); | |
458 token_destroy(t3); | |
459 token_destroy(t4); | |
460 token_destroy(t5); | |
461 tokenarray_remove(&tokens, num-2); | |
462 tokenarray_remove(&tokens, num-3); | |
463 tokenarray_remove(&tokens, num-4); | |
464 tokenarray_remove(&tokens, num-5); | |
465 continue; | |
466 } | |
467 | |
468 if (num >= 2 && | |
469 t2->tok == T_LPAREN && | |
470 t1->tok == T_RPAREN) { | |
471 complain(&t1->place, "Value expected within ()"); | |
472 complain_fail(); | |
473 t1->tok = T_VAL; | |
474 t1->val = 0; | |
475 token_destroy(t1); | |
476 tokenarray_remove(&tokens, num-1); | |
477 continue; | |
478 } | |
479 | |
480 if (num >= 2 && | |
481 t2->tok == T_VAL && | |
482 t1->tok == T_VAL) { | |
483 complain(&t1->place, "Operator expected"); | |
484 complain_fail(); | |
485 token_destroy(t1); | |
486 tokenarray_remove(&tokens, num-1); | |
487 continue; | |
488 } | |
489 | |
490 if (num >= 2 && | |
491 isop(t2->tok) && | |
492 t1->tok == T_EOF) { | |
493 complain(&t1->place, "Value expected after operator"); | |
494 complain_fail(); | |
495 token_destroy(t2); | |
496 tokenarray_remove(&tokens, num-2); | |
497 continue; | |
498 } | |
499 | |
500 if (num == 2 && | |
501 t2->tok == T_VAL && | |
502 t1->tok == T_RPAREN) { | |
503 complain(&t1->place, "Excess right parenthesis"); | |
504 complain_fail(); | |
505 token_destroy(t1); | |
506 tokenarray_remove(&tokens, num-1); | |
507 continue; | |
508 } | |
509 | |
510 if (num == 3 && | |
511 t3->tok == T_LPAREN && | |
512 t2->tok == T_VAL && | |
513 t1->tok == T_EOF) { | |
514 complain(&t1->place, "Unclosed left parenthesis"); | |
515 complain_fail(); | |
516 token_destroy(t3); | |
517 tokenarray_remove(&tokens, num-3); | |
518 continue; | |
519 } | |
520 | |
521 if (num == 2 && | |
522 t2->tok == T_VAL && | |
523 t1->tok == T_EOF) { | |
524 /* accepting state */ | |
525 break; | |
526 } | |
527 | |
528 if (num >= 1 && | |
529 t1->tok == T_EOF) { | |
530 /* any other configuration at eof is an error */ | |
531 complain(&t1->place, "Parse error"); | |
532 complain_fail(); | |
533 break; | |
534 } | |
535 | |
536 /* otherwise, wait for more input */ | |
537 break; | |
538 } | |
539 } | |
540 | |
541 static | |
542 void | |
543 token(struct place *p, enum tokens tok, int val) | |
544 { | |
545 struct token *t; | |
546 | |
547 t = token_create(p, tok, val); | |
548 | |
549 tokenarray_add(&tokens, t, NULL); | |
550 tryreduce(); | |
551 } | |
552 | |
553 static | |
554 int | |
555 wordval(struct place *p, char *word) | |
556 { | |
557 unsigned long val; | |
558 char *t; | |
559 | |
560 if (word[0] >= '0' && word[0] <= '9') { | |
561 errno = 0; | |
562 val = strtoul(word, &t, 0); | |
563 if (errno || *t != '\0') { | |
564 complain(p, "Invalid integer constant"); | |
565 complain_fail(); | |
566 return 0; | |
567 } | |
568 if (val > INT_MAX) { | |
569 complain(p, "Integer constant too large"); | |
570 complain_fail(); | |
571 return INT_MAX; | |
572 } | |
573 return val; | |
574 } | |
575 | |
576 /* if it's a symbol, warn and substitute 0. */ | |
577 if (warns.undef) { | |
578 complain(p, "Warning: value of undefined symbol %s is 0", | |
579 word); | |
580 if (mode.werror) { | |
581 complain_fail(); | |
582 } | |
583 } | |
584 return 0; | |
585 } | |
586 | |
587 static | |
588 bool | |
589 check_word(struct place *p, char *expr, size_t pos, size_t *len_ret) | |
590 { | |
591 size_t len; | |
592 int val; | |
593 char tmp; | |
594 | |
595 if (!strchr(alnum, expr[pos])) { | |
596 return false; | |
597 } | |
598 len = strspn(expr + pos, alnum); | |
599 tmp = expr[pos + len]; | |
600 expr[pos + len] = '\0'; | |
601 val = wordval(p, expr + pos); | |
602 expr[pos + len] = tmp; | |
603 token(p, T_VAL, val); | |
604 *len_ret = len; | |
605 return true; | |
606 } | |
607 | |
608 static | |
609 bool | |
610 check_tokens_2(struct place *p, char *expr, size_t pos) | |
611 { | |
612 unsigned i; | |
613 | |
614 for (i=0; i<num_tokens_2; i++) { | |
615 if (expr[pos] == tokens_2[i].c1 && | |
616 expr[pos+1] == tokens_2[i].c2) { | |
617 token(p, tokens_2[i].tok, 0); | |
618 return true; | |
619 } | |
620 } | |
621 return false; | |
622 } | |
623 | |
624 static | |
625 bool | |
626 check_tokens_1(struct place *p, char *expr, size_t pos) | |
627 { | |
628 unsigned i; | |
629 | |
630 for (i=0; i<num_tokens_1; i++) { | |
631 if (expr[pos] == tokens_1[i].c1) { | |
632 token(p, tokens_1[i].tok, 0); | |
633 return true; | |
634 } | |
635 } | |
636 return false; | |
637 } | |
638 | |
639 static | |
640 void | |
641 tokenize(struct place *p, char *expr) | |
642 { | |
643 size_t pos, len; | |
644 | |
645 pos = 0; | |
646 while (expr[pos] != '\0') { | |
647 len = strspn(expr+pos, ws); | |
648 pos += len; | |
649 p->column += len; | |
63 | 650 /* trailing whitespace is supposed to have been pruned */ |
651 assert(expr[pos] != '\0'); | |
16 | 652 if (check_word(p, expr, pos, &len)) { |
653 pos += len; | |
654 p->column += len; | |
655 continue; | |
656 } | |
657 if (check_tokens_2(p, expr, pos)) { | |
658 pos += 2; | |
659 p->column += 2; | |
660 continue; | |
661 } | |
662 if (check_tokens_1(p, expr, pos)) { | |
663 pos++; | |
664 p->column++; | |
665 continue; | |
666 } | |
667 complain(p, "Invalid character %u in #if-expression", | |
668 (unsigned char)expr[pos]); | |
669 complain_fail(); | |
670 pos++; | |
671 p->column++; | |
672 } | |
673 token(p, T_EOF, 0); | |
674 } | |
675 | |
676 bool | |
677 eval(struct place *p, char *expr) | |
678 { | |
679 struct token *t1, *t2; | |
680 unsigned num; | |
681 bool result; | |
682 | |
683 tokenarray_init(&tokens); | |
684 tokenize(p, expr); | |
685 | |
686 result = false; | |
687 num = tokenarray_num(&tokens); | |
688 if (num == 2) { | |
689 t1 = tokenarray_get(&tokens, num-1); | |
690 t2 = tokenarray_get(&tokens, num-2); | |
691 if (t1->tok == T_VAL && | |
692 t2->tok == T_EOF) { | |
693 result = t1->val != 0; | |
694 } | |
695 } | |
696 | |
697 tokenarray_destroyall(&tokens); | |
698 tokenarray_cleanup(&tokens); | |
699 return result; | |
700 } |