xref: /netbsd/usr.sbin/gspa/gspa/gsp_eval.c (revision bf9ec67e)
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
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
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
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
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