1 /* $NetBSD: gsp_eval.c,v 1.4 2001/06/13 10:46:06 wiz Exp $ */
2 /*
3 * GSP assembler - expression evaluation
4 *
5 * Copyright (c) 1993 Paul Mackerras.
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 * must display the following acknowledgement:
18 * This product includes software developed by Paul Mackerras.
19 * 4. The name of the author may not be used to endorse or promote products
20 * derived from this software without specific prior written permission
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
23 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
27 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
31 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 */
33
34 #include <sys/cdefs.h>
35 #ifndef lint
36 __RCSID("$NetBSD: gsp_eval.c,v 1.4 2001/06/13 10:46:06 wiz Exp $");
37 #endif
38
39 #include <stdlib.h>
40 #include "gsp_ass.h"
41 #include "gsp_gram.h"
42
43 int32_t eval_op(int, int32_t, int32_t);
44 int32_t eval_subtree(expr, unsigned *);
45
46 expr
fold(expr x)47 fold(expr x)
48 {
49 int32_t l;
50 expr lp, rp;
51
52 switch( x->e_op ){
53 case SYM:
54 case CONST:
55 case '.':
56 return x;
57 }
58 x->e_left = lp = fold(x->e_left);
59 if( x->e_right != NULL )
60 x->e_right = rp = fold(x->e_right);
61 else
62 rp = NULL;
63 if( lp->e_op == CONST && (rp == NULL || rp->e_op == CONST) ){
64 /* operator with constant subtree(s) */
65 if( rp != NULL ){
66 l = eval_op(x->e_op, lp->e_val, rp->e_val);
67 free(rp);
68 } else
69 l = eval_op(x->e_op, lp->e_val, 0);
70 free(lp);
71 x->e_op = CONST;
72 x->e_val = l;
73 }
74 return x;
75 }
76
77 int32_t
eval_op(int op,int32_t l,int32_t r)78 eval_op(int op, int32_t l, int32_t r)
79 {
80 switch( op ){
81 case NEG: l = -l; break;
82 case '~': l = ~l; break;
83 case '+': l += r; break;
84 case '-': l -= r; break;
85 case '*': l *= r; break;
86 case '&': l &= r; break;
87 case '|': l |= r; break;
88 case '^': l ^= r; break;
89 case '/':
90 if( r == 0 )
91 perr("Divide by zero");
92 else
93 l /= r;
94 break;
95 case ':':
96 l = (l << 16) | (r & 0xFFFF);
97 break;
98 case LEFT_SHIFT:
99 l <<= r;
100 break;
101 case RIGHT_SHIFT:
102 l >>= r;
103 break;
104 }
105 return l;
106 }
107
108 int
eval_expr(expr e,int32_t * vp,unsigned * lp)109 eval_expr(expr e, int32_t *vp, unsigned *lp)
110 {
111 e = fold(e);
112 *vp = eval_subtree(e, lp);
113 return (*lp < NOT_YET);
114 }
115
116 int32_t
eval_subtree(expr e,unsigned * lp)117 eval_subtree(expr e, unsigned *lp)
118 {
119 symbol s;
120 int32_t v1, v2;
121 unsigned l2;
122
123 switch( e->e_op ){
124 case SYM:
125 s = e->e_sym;
126 *lp = s->lineno;
127 if( (s->flags & DEFINED) != 0 )
128 return s->value;
129 perr("Undefined symbol %s", s->name);
130 return 0;
131 case CONST:
132 *lp = 0;
133 return e->e_val;
134 case '.':
135 *lp = lineno;
136 return pc;
137 default:
138 v1 = eval_subtree(e->e_left, lp);
139 if( e->e_right == NULL )
140 return eval_op(e->e_op, v1, 0);
141 v2 = eval_subtree(e->e_right, &l2);
142 if( l2 > *lp )
143 *lp = l2;
144 return eval_op(e->e_op, v1, v2);
145 }
146 }
147