File: | src/libexec/tradcpp/eval.c |
Warning: | line 335, column 25 The result of the left shift is undefined due to shifting by '32', which is greater or equal to the width of type 'unsigned int' |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
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(*__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)(sizeof(tokens_2)/sizeof((tokens_2)[0])); | |||
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)(sizeof(tokens_1)/sizeof((tokens_1)[0])); | |||
129 | ||||
130 | struct token { | |||
131 | struct place place; | |||
132 | enum tokens tok; | |||
133 | int val; | |||
134 | }; | |||
135 | DECLARRAY(token, static UNUSED)struct tokenarray { struct array arr; }; static __attribute__ ((__unused__)) struct tokenarray *tokenarray_create(void); static __attribute__((__unused__)) void tokenarray_destroy(struct tokenarray *a); static __attribute__((__unused__)) void tokenarray_init (struct tokenarray *a); static __attribute__((__unused__)) void tokenarray_cleanup(struct tokenarray *a); static __attribute__ ((__unused__)) unsigned tokenarray_num(const struct tokenarray *a); static __attribute__((__unused__)) struct token *tokenarray_get (const struct tokenarray *a, unsigned index_); static __attribute__ ((__unused__)) void tokenarray_set(struct tokenarray *a, unsigned index_, struct token *val); static __attribute__((__unused__ )) void tokenarray_setsize(struct tokenarray *a, unsigned num ); static __attribute__((__unused__)) void tokenarray_add(struct tokenarray *a, struct token *val, unsigned *index_ret); static __attribute__((__unused__)) void tokenarray_insert(struct tokenarray *a, unsigned index_); static __attribute__((__unused__)) void tokenarray_remove(struct tokenarray *a, unsigned index_); | |||
136 | DEFARRAY(token, static)static void tokenarray_init(struct tokenarray *a) { array_init (&a->arr); } static void tokenarray_cleanup(struct tokenarray *a) { array_cleanup(&a->arr); } static struct tokenarray *tokenarray_create(void) { struct tokenarray *a; a = domalloc (sizeof(*a)); tokenarray_init(a); return a; } static void tokenarray_destroy (struct tokenarray *a) { tokenarray_cleanup(a); dofree(a, sizeof (*a)); } static unsigned tokenarray_num(const struct tokenarray *a) { return array_num(&a->arr); } static struct token * tokenarray_get(const struct tokenarray *a, unsigned index_ ) { return (struct token *)array_get(&a->arr, index_); } static void tokenarray_set(struct tokenarray *a, unsigned index_ , struct token *val) { array_set(&a->arr, index_, (void *)val); } static void tokenarray_setsize(struct tokenarray * a, unsigned num) { array_setsize(&a->arr, num); } static void tokenarray_add(struct tokenarray *a, struct token *val, unsigned *ret) { array_add(&a->arr, (void *)val, ret) ; } static void tokenarray_insert(struct tokenarray *a, unsigned index_) { array_insert(&a->arr, index_); } static void tokenarray_remove(struct tokenarray *a, unsigned index_) { array_remove (&a->arr, index_); }; | |||
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, )void tokenarray_destroyall(struct tokenarray *arr); void tokenarray_destroyall (struct tokenarray *arr) { unsigned i, num; struct token *t; num = tokenarray_num(arr); for (i=0; i<num; i++) { t = tokenarray_get (arr, i); token_destroy(t); } tokenarray_setsize(arr, 0); }; | |||
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 true1; | |||
217 | default: | |||
218 | break; | |||
219 | } | |||
220 | return false0; | |||
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 false0; | |||
237 | default: | |||
238 | break; | |||
239 | } | |||
240 | return true1; | |||
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 false0; | |||
253 | default: | |||
254 | break; | |||
255 | } | |||
256 | return true1; | |||
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)((0) ? (void)0 : __assert2("/usr/src/libexec/tradcpp/eval.c", 296, __func__, "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_BIT8 * sizeof(unsigned)) { | |||
328 | complain(p, "Bit-shift farther than type width"); | |||
329 | complain_fail(); | |||
330 | rv = 0; | |||
331 | } | |||
332 | if (op
| |||
333 | return (int)((unsigned)lv << (unsigned)rv); | |||
334 | } | |||
335 | mask = ((unsigned)-1) << (CHAR_BIT8 * sizeof(unsigned) - rv); | |||
| ||||
336 | lv = (int)(((unsigned)lv >> (unsigned)rv) | mask); | |||
337 | return lv; | |||
338 | ||||
339 | case T_MINUS: | |||
340 | if (rv == INT_MIN(-0x7fffffff-1)) { | |||
341 | if (lv == INT_MIN(-0x7fffffff-1)) { | |||
342 | return 0; | |||
343 | } | |||
344 | lv--; | |||
345 | rv++; | |||
346 | } | |||
347 | rv = -rv; | |||
348 | /* FALLTHROUGH */ | |||
349 | case T_PLUS: | |||
350 | if (rv > 0 && lv > (INT_MAX0x7fffffff - rv)) { | |||
351 | complain(p, "Integer overflow"); | |||
352 | complain_fail(); | |||
353 | return INT_MAX0x7fffffff; | |||
354 | } | |||
355 | if (rv < 0 && lv < (INT_MIN(-0x7fffffff-1) - rv)) { | |||
356 | complain(p, "Integer underflow"); | |||
357 | complain_fail(); | |||
358 | return INT_MIN(-0x7fffffff-1); | |||
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(-0x7fffffff-1)) { | |||
370 | lv++; | |||
371 | lv = -lv; | |||
372 | if (lv == INT_MAX0x7fffffff) { | |||
373 | complain(p, "Integer overflow"); | |||
374 | complain_fail(); | |||
375 | return INT_MAX0x7fffffff; | |||
376 | } | |||
377 | lv++; | |||
378 | return lv; | |||
379 | } | |||
380 | if (lv == INT_MIN(-0x7fffffff-1) && rv < 0) { | |||
381 | complain(p, "Integer overflow"); | |||
382 | complain_fail(); | |||
383 | return INT_MAX0x7fffffff; | |||
384 | } | |||
385 | if (lv == INT_MIN(-0x7fffffff-1) && rv > 0) { | |||
386 | complain(p, "Integer underflow"); | |||
387 | complain_fail(); | |||
388 | return INT_MIN(-0x7fffffff-1); | |||
389 | } | |||
390 | if (rv < 0) { | |||
391 | rv = -rv; | |||
392 | lv = -lv; | |||
393 | } | |||
394 | if (lv > 0 && lv > INT_MAX0x7fffffff / rv) { | |||
395 | complain(p, "Integer overflow"); | |||
396 | complain_fail(); | |||
397 | return INT_MAX0x7fffffff; | |||
398 | } | |||
399 | if (lv < 0 && lv < INT_MIN(-0x7fffffff-1) / rv) { | |||
400 | complain(p, "Integer underflow"); | |||
401 | complain_fail(); | |||
402 | return INT_MIN(-0x7fffffff-1); | |||
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)((0) ? (void)0 : __assert2("/usr/src/libexec/tradcpp/eval.c", 422, __func__, "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((void *)0); | |||
440 | t2 = (num >= 2) ? tokenarray_get(&tokens, num-2) : NULL((void *)0); | |||
441 | t3 = (num >= 3) ? tokenarray_get(&tokens, num-3) : NULL((void *)0); | |||
442 | ||||
443 | if (num
| |||
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
| |||
457 | (num
| |||
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
| |||
468 | (num
| |||
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((void *)0); | |||
480 | ||||
481 | if (num
| |||
482 | t4->tok == T_VAL && | |||
483 | isbop(t3->tok) && | |||
484 | t2->tok
| |||
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((void *)0); | |||
499 | t6 = (num >= 6) ? tokenarray_get(&tokens, num-6) : NULL((void *)0); | |||
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((void *)0)); | |||
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(*__errno()) = 0; | |||
615 | val = strtoul(word, &t, 0); | |||
616 | if (errno(*__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_MAX0x7fffffff) { | |||
630 | complain(p, "Integer constant too large"); | |||
631 | complain_fail(); | |||
632 | return INT_MAX0x7fffffff; | |||
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 | debuglog(p, "Undefined symbol %s; substituting 0", word); | |||
646 | return 0; | |||
647 | } | |||
648 | ||||
649 | static | |||
650 | bool | |||
651 | check_word(struct place *p, char *expr, size_t pos, size_t *len_ret) | |||
652 | { | |||
653 | size_t len; | |||
654 | int val; | |||
655 | char tmp; | |||
656 | ||||
657 | if (!strchr(alnum, expr[pos])) { | |||
658 | return false0; | |||
659 | } | |||
660 | len = strspn(expr + pos, alnum); | |||
661 | tmp = expr[pos + len]; | |||
662 | expr[pos + len] = '\0'; | |||
663 | val = wordval(p, expr + pos); | |||
664 | expr[pos + len] = tmp; | |||
665 | token(p, T_VAL, val); | |||
666 | *len_ret = len; | |||
667 | return true1; | |||
668 | } | |||
669 | ||||
670 | static | |||
671 | bool | |||
672 | check_tokens_2(struct place *p, char *expr, size_t pos) | |||
673 | { | |||
674 | unsigned i; | |||
675 | ||||
676 | for (i=0; i<num_tokens_2; i++) { | |||
677 | if (expr[pos] == tokens_2[i].c1 && | |||
678 | expr[pos+1] == tokens_2[i].c2) { | |||
679 | token(p, tokens_2[i].tok, 0); | |||
680 | return true1; | |||
681 | } | |||
682 | } | |||
683 | return false0; | |||
684 | } | |||
685 | ||||
686 | static | |||
687 | bool | |||
688 | check_tokens_1(struct place *p, char *expr, size_t pos) | |||
689 | { | |||
690 | unsigned i; | |||
691 | ||||
692 | for (i=0; i<num_tokens_1; i++) { | |||
693 | if (expr[pos] == tokens_1[i].c1) { | |||
694 | token(p, tokens_1[i].tok, 0); | |||
695 | return true1; | |||
696 | } | |||
697 | } | |||
698 | return false0; | |||
699 | } | |||
700 | ||||
701 | static | |||
702 | void | |||
703 | tokenize(struct place *p, char *expr) | |||
704 | { | |||
705 | size_t pos, len; | |||
706 | ||||
707 | pos = 0; | |||
708 | while (expr[pos] != '\0') { | |||
709 | len = strspn(expr+pos, ws); | |||
710 | pos += len; | |||
711 | place_addcolumns(p, len); | |||
712 | /* trailing whitespace is supposed to have been pruned */ | |||
713 | assert(expr[pos] != '\0')((expr[pos] != '\0') ? (void)0 : __assert2("/usr/src/libexec/tradcpp/eval.c" , 713, __func__, "expr[pos] != '\\0'")); | |||
714 | if (check_word(p, expr, pos, &len)) { | |||
715 | pos += len; | |||
716 | place_addcolumns(p, len); | |||
717 | continue; | |||
718 | } | |||
719 | if (check_tokens_2(p, expr, pos)) { | |||
720 | pos += 2; | |||
721 | place_addcolumns(p, 2); | |||
722 | continue; | |||
723 | } | |||
724 | if (check_tokens_1(p, expr, pos)) { | |||
725 | pos++; | |||
726 | place_addcolumns(p, 1); | |||
727 | continue; | |||
728 | } | |||
729 | complain(p, "Invalid character %u in #if-expression", | |||
730 | (unsigned char)expr[pos]); | |||
731 | complain_fail(); | |||
732 | pos++; | |||
733 | place_addcolumns(p, 1); | |||
734 | } | |||
735 | token(p, T_EOF, 0); | |||
736 | } | |||
737 | ||||
738 | bool | |||
739 | eval(struct place *p, char *expr) | |||
740 | { | |||
741 | struct token *t1, *t2; | |||
742 | unsigned num; | |||
743 | bool result; | |||
744 | ||||
745 | #ifdef DEBUG | |||
746 | fprintf(stderr, "eval: %s\n", expr); | |||
747 | #endif | |||
748 | debuglog(p, "eval: %s", expr); | |||
749 | ||||
750 | tokenarray_init(&tokens); | |||
751 | tokenize(p, expr); | |||
| ||||
752 | ||||
753 | result = false0; | |||
754 | num = tokenarray_num(&tokens); | |||
755 | if (num == 2) { | |||
756 | t1 = tokenarray_get(&tokens, num-1); | |||
757 | t2 = tokenarray_get(&tokens, num-2); | |||
758 | if (t2->tok == T_VAL && | |||
759 | t1->tok == T_EOF) { | |||
760 | result = t2->val != 0; | |||
761 | } | |||
762 | } | |||
763 | ||||
764 | tokenarray_destroyall(&tokens); | |||
765 | tokenarray_cleanup(&tokens); | |||
766 | return result; | |||
767 | } |