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 |
|
|
} |