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