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