Home | History | Annotate | Line # | Download | only in gspa
      1 /*	$NetBSD: gsp_eval.c,v 1.5 2025/11/24 08:04:28 nia 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. The name of the author may not be used to endorse or promote products
     17  *    derived from this software without specific prior written permission
     18  *
     19  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     20  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     21  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     22  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     23  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     24  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     28  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     29  */
     30 
     31 #include <sys/cdefs.h>
     32 #ifndef lint
     33 __RCSID("$NetBSD: gsp_eval.c,v 1.5 2025/11/24 08:04:28 nia Exp $");
     34 #endif
     35 
     36 #include <stdlib.h>
     37 #include "gsp_ass.h"
     38 #include "gsp_gram.h"
     39 
     40 int32_t eval_op(int, int32_t, int32_t);
     41 int32_t eval_subtree(expr, unsigned *);
     42 
     43 expr
     44 fold(expr x)
     45 {
     46 	int32_t l;
     47 	expr lp, rp;
     48 
     49 	switch( x->e_op ){
     50 	case SYM:
     51 	case CONST:
     52 	case '.':
     53 		return x;
     54 	}
     55 	x->e_left = lp = fold(x->e_left);
     56 	if( x->e_right != NULL )
     57 		x->e_right = rp = fold(x->e_right);
     58 	else
     59 		rp = NULL;
     60 	if( lp->e_op == CONST && (rp == NULL || rp->e_op == CONST) ){
     61 		/* operator with constant subtree(s) */
     62 		if( rp != NULL ){
     63 			l = eval_op(x->e_op, lp->e_val, rp->e_val);
     64 			free(rp);
     65 		} else
     66 			l = eval_op(x->e_op, lp->e_val, 0);
     67 		free(lp);
     68 		x->e_op = CONST;
     69 		x->e_val = l;
     70 	}
     71 	return x;
     72 }
     73 
     74 int32_t
     75 eval_op(int op, int32_t l, int32_t r)
     76 {
     77 	switch( op ){
     78 	case NEG:	l = -l;		break;
     79 	case '~':	l = ~l;		break;
     80 	case '+':	l += r;		break;
     81 	case '-':	l -= r;		break;
     82 	case '*':	l *= r;		break;
     83 	case '&':	l &= r;		break;
     84 	case '|':	l |= r;		break;
     85 	case '^':	l ^= r;		break;
     86 	case '/':
     87 		if( r == 0 )
     88 			perr("Divide by zero");
     89 		else
     90 			l /= r;
     91 		break;
     92 	case ':':
     93 		l = (l << 16) | (r & 0xFFFF);
     94 		break;
     95 	case LEFT_SHIFT:
     96 		l <<= r;
     97 		break;
     98 	case RIGHT_SHIFT:
     99 		l >>= r;
    100 		break;
    101 	}
    102 	return l;
    103 }
    104 
    105 int
    106 eval_expr(expr e, int32_t *vp, unsigned *lp)
    107 {
    108 	e = fold(e);
    109 	*vp = eval_subtree(e, lp);
    110 	return (*lp < NOT_YET);
    111 }
    112 
    113 int32_t
    114 eval_subtree(expr e, unsigned *lp)
    115 {
    116 	symbol s;
    117 	int32_t v1, v2;
    118 	unsigned l2;
    119 
    120 	switch( e->e_op ){
    121 	case SYM:
    122 		s = e->e_sym;
    123 		*lp = s->lineno;
    124 		if( (s->flags & DEFINED) != 0 )
    125 			return s->value;
    126 		perr("Undefined symbol %s", s->name);
    127 		return 0;
    128 	case CONST:
    129 		*lp = 0;
    130 		return e->e_val;
    131 	case '.':
    132 		*lp = lineno;
    133 		return pc;
    134 	default:
    135 		v1 = eval_subtree(e->e_left, lp);
    136 		if( e->e_right == NULL )
    137 			return eval_op(e->e_op, v1, 0);
    138 		v2 = eval_subtree(e->e_right, &l2);
    139 		if( l2 > *lp )
    140 			*lp = l2;
    141 		return eval_op(e->e_op, v1, v2);
    142 	}
    143 }
    144