xref: /openbsd-src/libexec/tradcpp/eval.c (revision 88157d21ef4e0e7edfe65c55d80f66401a578afc)
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