1179404Sobrien/*	$NetBSD: gsp_eval.c,v 1.3 1998/04/09 00:32:40 tv Exp $	*/
2179404Sobrien/*
3208737Sjmallett * GSP assembler - expression evaluation
4179404Sobrien *
5179404Sobrien * Copyright (c) 1993 Paul Mackerras.
6179404Sobrien * All rights reserved.
7179404Sobrien *
8179404Sobrien * Redistribution and use in source and binary forms, with or without
9179404Sobrien * modification, are permitted provided that the following conditions
10179404Sobrien * are met:
11179404Sobrien * 1. Redistributions of source code must retain the above copyright
12179404Sobrien *    notice, this list of conditions and the following disclaimer.
13179404Sobrien * 2. Redistributions in binary form must reproduce the above copyright
14179404Sobrien *    notice, this list of conditions and the following disclaimer in the
15179404Sobrien *    documentation and/or other materials provided with the distribution.
16179404Sobrien * 3. All advertising materials mentioning features or use of this software
17179404Sobrien *    must display the following acknowledgement:
18179404Sobrien *      This product includes software developed by Paul Mackerras.
19179404Sobrien * 4. The name of the author may not be used to endorse or promote products
20179404Sobrien *    derived from this software without specific prior written permission
21179404Sobrien *
22179404Sobrien * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
23179404Sobrien * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24208737Sjmallett * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25179404Sobrien * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
26179404Sobrien * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
27179404Sobrien * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28179404Sobrien * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29179404Sobrien * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30179404Sobrien * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
31179404Sobrien * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32179404Sobrien */
33179404Sobrien
34179404Sobrien#include <sys/cdefs.h>
35179404Sobrien#ifndef lint
36179404Sobrien__RCSID("$NetBSD: gsp_eval.c,v 1.3 1998/04/09 00:32:40 tv Exp $");
37179404Sobrien#endif
38179404Sobrien
39179404Sobrien#include <stdlib.h>
40179404Sobrien#include "gsp_ass.h"
41179404Sobrien#include "gsp_gram.h"
42179404Sobrien
43179404Sobrienint32_t eval_op(int, int32_t, int32_t);
44179404Sobrienint32_t eval_subtree(expr, unsigned *);
45179404Sobrien
46179404Sobrienexpr
47179404Sobrienfold(expr x)
48179404Sobrien{
49179404Sobrien	int32_t l;
50179404Sobrien	expr lp, rp;
51179404Sobrien
52179404Sobrien	switch( x->e_op ){
53179404Sobrien	case SYM:
54179404Sobrien	case CONST:
55179404Sobrien	case '.':
56179404Sobrien		return x;
57179404Sobrien	}
58179404Sobrien	x->e_left = lp = fold(x->e_left);
59179404Sobrien	if( x->e_right != NULL )
60179404Sobrien		x->e_right = rp = fold(x->e_right);
61179404Sobrien	else
62179404Sobrien		rp = NULL;
63179404Sobrien	if( lp->e_op == CONST && (rp == NULL || rp->e_op == CONST) ){
64179404Sobrien		/* operator with constant subtree(s) */
65179404Sobrien		if( rp != NULL ){
66179404Sobrien			l = eval_op(x->e_op, lp->e_val, rp->e_val);
67179404Sobrien			free(rp);
68179404Sobrien		} else
69179404Sobrien			l = eval_op(x->e_op, lp->e_val, 0);
70179404Sobrien		free(lp);
71179404Sobrien		x->e_op = CONST;
72179404Sobrien		x->e_val = l;
73179404Sobrien	}
74179404Sobrien	return x;
75179404Sobrien}
76179404Sobrien
77179404Sobrienint32_t
78179404Sobrieneval_op(int op, int32_t l, int32_t r)
79208737Sjmallett{
80208737Sjmallett	switch( op ){
81179404Sobrien	case NEG:	l = -l;		break;
82179404Sobrien	case '~':	l = ~l;		break;
83179404Sobrien	case '+':	l += r;		break;
84179404Sobrien	case '-':	l -= r;		break;
85179404Sobrien	case '*':	l *= r;		break;
86179404Sobrien	case '&':	l &= r;		break;
87179404Sobrien	case '|':	l |= r;		break;
88179404Sobrien	case '^':	l ^= r;		break;
89179404Sobrien	case '/':
90179404Sobrien		if( r == 0 )
91179404Sobrien			perr("Divide by zero");
92208737Sjmallett		else
93208737Sjmallett			l /= r;
94208737Sjmallett		break;
95218822Sdim	case ':':
96179404Sobrien		l = (l << 16) | (r & 0xFFFF);
97179404Sobrien		break;
98179404Sobrien	case LEFT_SHIFT:
99179404Sobrien		l <<= r;
100179404Sobrien		break;
101218822Sdim	case RIGHT_SHIFT:
102218822Sdim		l >>= r;
103218822Sdim		break;
104179404Sobrien	}
105179404Sobrien	return l;
106179404Sobrien}
107179404Sobrien
108179404Sobrienint
109179404Sobrieneval_expr(expr e, int32_t *vp, unsigned *lp)
110179404Sobrien{
111179404Sobrien	e = fold(e);
112179404Sobrien	*vp = eval_subtree(e, lp);
113179404Sobrien	return (*lp < NOT_YET);
114179404Sobrien}
115179404Sobrien
116179404Sobrienint32_t
117179404Sobrieneval_subtree(expr e, unsigned *lp)
118179404Sobrien{
119179404Sobrien	symbol s;
120179404Sobrien	int32_t v1, v2;
121179404Sobrien	unsigned l2;
122179404Sobrien
123179404Sobrien	switch( e->e_op ){
124179404Sobrien	case SYM:
125179404Sobrien		s = e->e_sym;
126179404Sobrien		*lp = s->lineno;
127179404Sobrien		if( (s->flags & DEFINED) != 0 )
128208737Sjmallett			return s->value;
129208737Sjmallett		perr("Undefined symbol %s", s->name);
130208737Sjmallett		return 0;
131208737Sjmallett	case CONST:
132208737Sjmallett		*lp = 0;
133208737Sjmallett		return e->e_val;
134218822Sdim	case '.':
135208737Sjmallett		*lp = lineno;
136208737Sjmallett		return pc;
137208737Sjmallett	default:
138218822Sdim		v1 = eval_subtree(e->e_left, lp);
139208737Sjmallett		if( e->e_right == NULL )
140208737Sjmallett			return eval_op(e->e_op, v1, 0);
141208737Sjmallett		v2 = eval_subtree(e->e_right, &l2);
142208737Sjmallett		if( l2 > *lp )
143218822Sdim			*lp = l2;
144208737Sjmallett		return eval_op(e->e_op, v1, v2);
145208737Sjmallett	}
146208737Sjmallett}
147218822Sdim