Mercurial > ~dholland > hg > tradcpp > index.cgi
annotate eval.c @ 136:59680a727e9d
Improve previous.
Just in case we ever crash and reach cleanup() while processing an
-include foo option, take the array entry for it out of the array to
make sure it doesn't get freed twice. This case shouldn't be
reachable, but it's better to be safe.
author | David A. Holland |
---|---|
date | Tue, 09 Jul 2013 13:38:43 -0400 |
parents | 33954a07d013 |
children | 1d2bad7151f9 |
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 | |
92 | 35 //#define DEBUG |
36 #ifdef DEBUG | |
37 #include <stdio.h> | |
38 #endif | |
39 | |
16 | 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 }; | |
107 | 135 DECLARRAY(token, static UNUSED); |
47
2e25e55dba6b
Fix inline usage as per the version in dholland-make2.
David A. Holland
parents:
39
diff
changeset
|
136 DEFARRAY(token, static); |
16 | 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 { | |
39
337110e7240a
Pass the size to free; it makes debug checking easier.
David A. Holland
parents:
38
diff
changeset
|
157 dofree(t, sizeof(*t)); |
16 | 158 } |
159 | |
160 DESTROYALL_ARRAY(token, ); | |
161 | |
92 | 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 | |
16 | 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) { | |
92 | 264 case T_BANG: case T_TILDE: return -1; |
16 | 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 { | |
92 | 284 return getprec(t1) >= getprec(t2); |
16 | 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 | |
28 | 303 eval_bop(struct place *p, int lv, enum tokens op, int rv) |
16 | 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) { | |
92 | 435 #ifdef DEBUG |
436 printtokens(); | |
437 #endif | |
16 | 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 && | |
92 | 468 (num == 2 || isop(t3->tok) || t3->tok == T_LPAREN) && |
16 | 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) && | |
92 | 484 t2->tok == T_VAL) { |
16 | 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 | |
91
bd1b7a09da89
Don't expect the eval result to contain EOF *then* a value.
David A. Holland
parents:
63
diff
changeset
|
501 if (num >= 6 && |
16 | 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); | |
96 | 616 if (errno) { |
16 | 617 complain(p, "Invalid integer constant"); |
618 complain_fail(); | |
619 return 0; | |
620 } | |
96 | 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 } | |
16 | 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; | |
63 | 711 /* trailing whitespace is supposed to have been pruned */ |
712 assert(expr[pos] != '\0'); | |
16 | 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 | |
92 | 744 #ifdef DEBUG |
745 fprintf(stderr, "eval: %s\n", expr); | |
746 #endif | |
747 | |
16 | 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); | |
91
bd1b7a09da89
Don't expect the eval result to contain EOF *then* a value.
David A. Holland
parents:
63
diff
changeset
|
756 if (t2->tok == T_VAL && |
bd1b7a09da89
Don't expect the eval result to contain EOF *then* a value.
David A. Holland
parents:
63
diff
changeset
|
757 t1->tok == T_EOF) { |
bd1b7a09da89
Don't expect the eval result to contain EOF *then* a value.
David A. Holland
parents:
63
diff
changeset
|
758 result = t2->val != 0; |
16 | 759 } |
760 } | |
761 | |
762 tokenarray_destroyall(&tokens); | |
763 tokenarray_cleanup(&tokens); | |
764 return result; | |
765 } |