#include <sys/cdefs.h>
#ifndef lint
__RCSID("$NetBSD: gsp_eval.c,v 1.5 2025/11/24 08:04:28 nia Exp $");
#endif
#include <stdlib.h>
#include "gsp_ass.h"
#include "gsp_gram.h"
int32_t eval_op(int, int32_t, int32_t);
int32_t eval_subtree(expr, unsigned *);
expr
fold(expr x)
{
int32_t l;
expr lp, rp;
switch( x->e_op ){
case SYM:
case CONST:
case '.':
return x;
}
x->e_left = lp = fold(x->e_left);
if( x->e_right != NULL )
x->e_right = rp = fold(x->e_right);
else
rp = NULL;
if( lp->e_op == CONST && (rp == NULL || rp->e_op == CONST) ){
if( rp != NULL ){
l = eval_op(x->e_op, lp->e_val, rp->e_val);
free(rp);
} else
l = eval_op(x->e_op, lp->e_val, 0);
free(lp);
x->e_op = CONST;
x->e_val = l;
}
return x;
}
int32_t
eval_op(int op, int32_t l, int32_t r)
{
switch( op ){
case NEG: l = -l; break;
case '~': l = ~l; break;
case '+': l += r; break;
case '-': l -= r; break;
case '*': l *= r; break;
case '&': l &= r; break;
case '|': l |= r; break;
case '^': l ^= r; break;
case '/':
if( r == 0 )
perr("Divide by zero");
else
l /= r;
break;
case ':':
l = (l << 16) | (r & 0xFFFF);
break;
case LEFT_SHIFT:
l <<= r;
break;
case RIGHT_SHIFT:
l >>= r;
break;
}
return l;
}
int
eval_expr(expr e, int32_t *vp, unsigned *lp)
{
e = fold(e);
*vp = eval_subtree(e, lp);
return (*lp < NOT_YET);
}
int32_t
eval_subtree(expr e, unsigned *lp)
{
symbol s;
int32_t v1, v2;
unsigned l2;
switch( e->e_op ){
case SYM:
s = e->e_sym;
*lp = s->lineno;
if( (s->flags & DEFINED) != 0 )
return s->value;
perr("Undefined symbol %s", s->name);
return 0;
case CONST:
*lp = 0;
return e->e_val;
case '.':
*lp = lineno;
return pc;
default:
v1 = eval_subtree(e->e_left, lp);
if( e->e_right == NULL )
return eval_op(e->e_op, v1, 0);
v2 = eval_subtree(e->e_right, &l2);
if( l2 > *lp )
*lp = l2;
return eval_op(e->e_op, v1, v2);
}
}