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