1444 lines
		
	
	
	
		
			28 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1444 lines
		
	
	
	
		
			28 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/* $Header$ */
 | 
						|
 | 
						|
/* This file contains the expression evaluator. It exports the following
 | 
						|
   routines:
 | 
						|
   - int eval_cond(p_tree p)
 | 
						|
	This routine evaluates the conditional expression indicated by p
 | 
						|
	and returns 1 if it evaluates to TRUE, or 0 if it could not be
 | 
						|
	evaluated for some reason or if it evalutes to FALSE.
 | 
						|
	If the expression cannot be evaluated, an error message is given.
 | 
						|
   - int eval_desig(p_tree p, t_addr *paddr, long **psize, p_type *ptp)
 | 
						|
	This routine evaluates the expression indicated by p, which should
 | 
						|
	result in a designator. The result of the expression is an address
 | 
						|
	which is to be found in *paddr. *psize will contain the size of the
 | 
						|
	designated object, and *ptp its type.
 | 
						|
	If the expression cannot be evaluated or does not result in a
 | 
						|
	designator, 0 is returned and an error message is given.
 | 
						|
	Otherwise, 1 is returned.
 | 
						|
   - int eval_expr(p_tree p, char **pbuf, long **psize, p_type *ptp)
 | 
						|
	This routine evaluates the expression indicated by p.
 | 
						|
	The result of the expression is left in *pbuf.
 | 
						|
	*psize will contain the size of the value, and *ptp its type.
 | 
						|
	If the expression cannot be evaluated, 0 is returned and an error
 | 
						|
	message is given.  Otherwise, 1 is returned.
 | 
						|
   - int convert(char **pbuf, long *psize, p_type *ptp, p_type tp, long size)
 | 
						|
	This routine tries to convert the value in pbuf of size psize
 | 
						|
	and type ptp to type tp with size size. It returns 0 if this fails,
 | 
						|
	while producing an error message. Otherwise, it returns 1 and
 | 
						|
	the resulting value, type and size are left in pbuf, ptp, and
 | 
						|
	psize, respectively.
 | 
						|
   - long get_int(char *buf, long size, int class)
 | 
						|
	Returns the value of size 'size', residing in 'buf', of 'class'
 | 
						|
	T_INTEGER, T_UNSIGNED, or T_ENUM.
 | 
						|
   - int put_int(char *buf, long size, long value)
 | 
						|
	Stores the value 'value' of size 'size' in 'buf'.
 | 
						|
   - double get_real(char *buf, long size)
 | 
						|
	Returns the real value of size 'size', residing in 'buf'.
 | 
						|
	T_INTEGER, T_UNSIGNED, or T_ENUM.
 | 
						|
   - int put_real(char *buf, long size, double value)
 | 
						|
	Stores the value 'value' of size 'size' in 'buf'.
 | 
						|
*/
 | 
						|
 | 
						|
#include <stdio.h>
 | 
						|
#include <alloc.h>
 | 
						|
#include <assert.h>
 | 
						|
 | 
						|
#include "position.h"
 | 
						|
#include "operator.h"
 | 
						|
#include "tree.h"
 | 
						|
#include "expr.h"
 | 
						|
#include "symbol.h"
 | 
						|
#include "type.h"
 | 
						|
#include "langdep.h"
 | 
						|
#include "scope.h"
 | 
						|
#include "idf.h"
 | 
						|
 | 
						|
extern FILE	*db_out;
 | 
						|
extern int	stack_offset;
 | 
						|
extern char	*strcpy();
 | 
						|
extern t_addr	*get_EM_regs();
 | 
						|
extern char	*memcpy();
 | 
						|
 | 
						|
#define	malloc_succeeded(p)	if (! (p)) {\
 | 
						|
					error("could not allocate enough memory");\
 | 
						|
					return 0;\
 | 
						|
				}
 | 
						|
 | 
						|
/* static t_addr	get_addr(p_symbol sym; long *psize);
 | 
						|
   Get the address of the object indicated by sym. Returns 0 on failure,
 | 
						|
   address on success. *psize will contain size of object.
 | 
						|
   For local variables or parameters, the 'stack_offset' variable is
 | 
						|
   used to determine from which stack frame the search must start.
 | 
						|
*/
 | 
						|
static t_addr
 | 
						|
get_addr(sym, psize)
 | 
						|
  register p_symbol	sym;
 | 
						|
  long			*psize;
 | 
						|
{
 | 
						|
  p_type	tp = sym->sy_type;
 | 
						|
  long		size = tp->ty_size;
 | 
						|
  t_addr	*EM_regs;
 | 
						|
  int		i;
 | 
						|
  p_scope	sc, symsc;
 | 
						|
 | 
						|
  *psize = size;
 | 
						|
  switch(sym->sy_class) {
 | 
						|
  case VAR:
 | 
						|
	/* exists if child exists; nm_value contains addres */
 | 
						|
	return (t_addr) sym->sy_name.nm_value;
 | 
						|
  case VARPAR:
 | 
						|
  case LOCVAR:
 | 
						|
	/* first find the stack frame in which it resides */
 | 
						|
	symsc = base_scope(sym->sy_scope);
 | 
						|
 | 
						|
	/* now symsc contains the scope where the storage for sym is
 | 
						|
	   allocated. Now find it on the stack of child.
 | 
						|
	*/
 | 
						|
	i = stack_offset;
 | 
						|
	for (;;) {
 | 
						|
		sc = 0;
 | 
						|
		if (! (EM_regs = get_EM_regs(i++))) {
 | 
						|
			return 0;
 | 
						|
		}
 | 
						|
		if (! EM_regs[1]) {
 | 
						|
			error("%s not available", sym->sy_idf->id_text);
 | 
						|
			return 0;
 | 
						|
		}
 | 
						|
		sc = base_scope(get_scope_from_addr(EM_regs[2]));
 | 
						|
		if (! sc || sc->sc_start > EM_regs[2]) {
 | 
						|
			error("%s not available", sym->sy_idf->id_text);
 | 
						|
			sc = 0;
 | 
						|
			return 0;
 | 
						|
		}
 | 
						|
		if (sc == symsc) break;		/* found it */
 | 
						|
	}
 | 
						|
 | 
						|
	if (sym->sy_class == LOCVAR) {
 | 
						|
		/* Either local variable or value parameter */
 | 
						|
		return EM_regs[sym->sy_name.nm_value < 0 ? 0 : 1] +
 | 
						|
				  (t_addr) sym->sy_name.nm_value;
 | 
						|
	}
 | 
						|
 | 
						|
	/* If we get here, we have a var parameter. Get the parameters
 | 
						|
	   of the current procedure invocation.
 | 
						|
	*/
 | 
						|
	{
 | 
						|
		p_type proctype = sc->sc_definedby->sy_type;
 | 
						|
		t_addr a;
 | 
						|
		char *AB;
 | 
						|
 | 
						|
		size = proctype->ty_nbparams;
 | 
						|
		if (has_static_link(sc)) size += pointer_size;
 | 
						|
		AB = malloc((unsigned) size);
 | 
						|
		if (! AB) {
 | 
						|
			error("could not allocate enough memory");
 | 
						|
			break;
 | 
						|
		}
 | 
						|
		if (! get_bytes(size, EM_regs[1], AB)) {
 | 
						|
			break;
 | 
						|
		}
 | 
						|
		if ((size = tp->ty_size) == 0) {
 | 
						|
			size = compute_size(tp, AB);
 | 
						|
			*psize = size;
 | 
						|
		}
 | 
						|
		a = (t_addr) get_int(AB+sym->sy_name.nm_value, pointer_size, T_UNSIGNED);
 | 
						|
		free(AB);
 | 
						|
		return a;
 | 
						|
	}
 | 
						|
  default:
 | 
						|
	error("%s is not a variable", sym->sy_idf->id_text);
 | 
						|
	break;
 | 
						|
  }
 | 
						|
  return 0;
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
get_v(a, pbuf, size)
 | 
						|
  t_addr	a;
 | 
						|
  char		**pbuf;
 | 
						|
  long		size;
 | 
						|
{
 | 
						|
  if (a) {
 | 
						|
	*pbuf = malloc((unsigned) size);
 | 
						|
	if (! *pbuf) {
 | 
						|
		error("could not allocate enough memory");
 | 
						|
		return 0;
 | 
						|
	}
 | 
						|
	if (! get_bytes(size, a, *pbuf)) return 0;
 | 
						|
  	return 1;
 | 
						|
  }
 | 
						|
  return 0;
 | 
						|
}
 | 
						|
 | 
						|
/* static int	get_value(p_symbol sym; char **pbuf; long *psize);
 | 
						|
   Get the value of the symbol indicated by sym.  Return 0 on failure,
 | 
						|
   1 on success. On success, 'pbuf' contains the value, and 'psize' contains
 | 
						|
   the size. For 'pbuf', storage is allocated by malloc; this storage must
 | 
						|
   be freed by caller (I don't like this any more than you do, but caller
 | 
						|
   does not know sizes).
 | 
						|
   For local variables or parameters, the 'stack_offset' variable is
 | 
						|
   used to determine from which stack frame the search must start.
 | 
						|
*/
 | 
						|
static int
 | 
						|
get_value(sym, pbuf, psize)
 | 
						|
  register p_symbol	sym;
 | 
						|
  char	**pbuf;
 | 
						|
  long	*psize;
 | 
						|
{
 | 
						|
  p_type	tp = sym->sy_type;
 | 
						|
  int		retval = 0;
 | 
						|
  t_addr	a;
 | 
						|
  long		size = tp->ty_size;
 | 
						|
 | 
						|
  *pbuf = 0;
 | 
						|
  switch(sym->sy_class) {
 | 
						|
  case CONST:
 | 
						|
	*pbuf = malloc((unsigned) size);
 | 
						|
	if (! *pbuf) {
 | 
						|
		error("could not allocate enough memory");
 | 
						|
		break;
 | 
						|
	}
 | 
						|
	switch(tp->ty_class) {
 | 
						|
	case T_REAL:
 | 
						|
		put_real(*pbuf, size, sym->sy_const.co_rval);
 | 
						|
		break;
 | 
						|
	case T_INTEGER:
 | 
						|
	case T_SUBRANGE:
 | 
						|
	case T_UNSIGNED:
 | 
						|
	case T_ENUM:
 | 
						|
		put_int(*pbuf, size, sym->sy_const.co_ival);
 | 
						|
		break;
 | 
						|
	case T_SET:
 | 
						|
		memcpy(*pbuf, sym->sy_const.co_setval, (int) size);
 | 
						|
		break;
 | 
						|
	case T_STRING:
 | 
						|
		memcpy(*pbuf, sym->sy_const.co_sval, (int) size);
 | 
						|
		break;
 | 
						|
	default:
 | 
						|
		fatal("strange constant");
 | 
						|
	}
 | 
						|
	retval = 1;
 | 
						|
	break;
 | 
						|
  case VAR:
 | 
						|
  case VARPAR:
 | 
						|
  case LOCVAR:
 | 
						|
	a = get_addr(sym, psize);
 | 
						|
	retval = get_v(a, pbuf, *psize);
 | 
						|
	size = *psize;
 | 
						|
	break;
 | 
						|
  case UBOUND:
 | 
						|
	a = get_addr(sym->sy_descr, psize);
 | 
						|
	retval = get_v(a, pbuf, *psize);
 | 
						|
	if (! retval) break;
 | 
						|
	size = get_int(*pbuf, *psize, T_INTEGER);
 | 
						|
	retval = get_v(a+*psize, pbuf, *psize);
 | 
						|
	if (! retval) break;
 | 
						|
	size += get_int(*pbuf, *psize, T_INTEGER);
 | 
						|
	put_int(*pbuf, *psize, size);
 | 
						|
	size = *psize;
 | 
						|
	break;
 | 
						|
  case LBOUND:
 | 
						|
	a = get_addr(sym->sy_descr, psize);
 | 
						|
	retval = get_v(a, pbuf, *psize);
 | 
						|
	break;
 | 
						|
  }
 | 
						|
 | 
						|
  if (retval == 0) {
 | 
						|
	if (*pbuf) free(*pbuf);
 | 
						|
	*pbuf = 0;
 | 
						|
	*psize = 0;
 | 
						|
  }
 | 
						|
  else *psize = size;
 | 
						|
 | 
						|
  return retval;
 | 
						|
}
 | 
						|
 | 
						|
/* buffer to integer and vice versa routines */
 | 
						|
 | 
						|
long
 | 
						|
get_int(buf, size, class)
 | 
						|
  char	*buf;
 | 
						|
  long	size;
 | 
						|
  int	class;
 | 
						|
{
 | 
						|
  register long l;
 | 
						|
 | 
						|
  switch((int)size) {
 | 
						|
  case sizeof(char):
 | 
						|
	l = *buf;
 | 
						|
	if (class == T_INTEGER && l >= 0x7F) l -= 256;
 | 
						|
	else if (class != T_INTEGER && l < 0) l += 256;
 | 
						|
	break;
 | 
						|
  case sizeof(short):
 | 
						|
	l = *((short *) buf);
 | 
						|
	if (class == T_INTEGER && l >= 0x7FFF) l -= 65536;
 | 
						|
	else if (class != T_INTEGER && l < 0) l += 65536;
 | 
						|
	break;
 | 
						|
  default:
 | 
						|
	l = *((long *) buf);
 | 
						|
  }
 | 
						|
  return l;
 | 
						|
}
 | 
						|
 | 
						|
put_int(buf, size, value)
 | 
						|
  char	*buf;
 | 
						|
  long	size;
 | 
						|
  long	value;
 | 
						|
{
 | 
						|
  switch((int)size) {
 | 
						|
  case sizeof(char):
 | 
						|
	*buf = value;
 | 
						|
	break;
 | 
						|
  case sizeof(short):
 | 
						|
	*((short *) buf) = value;
 | 
						|
	break;
 | 
						|
  default:
 | 
						|
	*((long *) buf) = value;
 | 
						|
	break;
 | 
						|
  }
 | 
						|
  /*NOTREACHED*/
 | 
						|
}
 | 
						|
 | 
						|
/* buffer to real and vice versa routines */
 | 
						|
 | 
						|
double
 | 
						|
get_real(buf, size)
 | 
						|
  char	*buf;
 | 
						|
  long	size;
 | 
						|
{
 | 
						|
  switch((int) size) {
 | 
						|
  case sizeof(float):
 | 
						|
	return *((float *) buf);
 | 
						|
  default:
 | 
						|
	return *((double *) buf);
 | 
						|
  }
 | 
						|
  /*NOTREACHED*/
 | 
						|
}
 | 
						|
 | 
						|
put_real(buf, size, value)
 | 
						|
  char	*buf;
 | 
						|
  long	size;
 | 
						|
  double value;
 | 
						|
{
 | 
						|
  switch((int)size) {
 | 
						|
  case sizeof(float):
 | 
						|
	*((float *) buf) = value;
 | 
						|
	break;
 | 
						|
  default:
 | 
						|
	*((double *) buf) = value;
 | 
						|
	break;
 | 
						|
  }
 | 
						|
  /* NOTREACHED */
 | 
						|
}
 | 
						|
 | 
						|
int
 | 
						|
convert(pbuf, psize, ptp, tp, size)
 | 
						|
  char	**pbuf;
 | 
						|
  long	*psize;
 | 
						|
  register p_type *ptp;
 | 
						|
  register p_type tp;
 | 
						|
  long size;
 | 
						|
{
 | 
						|
  /* Convert the value in pbuf, of size psize and type ptp, to type
 | 
						|
     tp and leave the resulting value in pbuf, the resulting size
 | 
						|
     in psize, and the resulting type in ptp.
 | 
						|
  */
 | 
						|
  long	l;
 | 
						|
  double d;
 | 
						|
 | 
						|
  if (*ptp == tp) return 1;
 | 
						|
  if (size > *psize) {
 | 
						|
	*pbuf = realloc(*pbuf, (unsigned int) size);
 | 
						|
	malloc_succeeded(*pbuf);
 | 
						|
  }
 | 
						|
  if ((*ptp)->ty_class == T_SUBRANGE) *ptp = (*ptp)->ty_base;
 | 
						|
  if (tp && *ptp) switch((*ptp)->ty_class) {
 | 
						|
  case T_INTEGER:
 | 
						|
  case T_UNSIGNED:
 | 
						|
  case T_POINTER:
 | 
						|
  case T_ENUM:
 | 
						|
	l = get_int(*pbuf, *psize, (*ptp)->ty_class);
 | 
						|
	if (tp == bool_type) l = l != 0;
 | 
						|
	switch(tp->ty_class) {
 | 
						|
  	case T_SUBRANGE:
 | 
						|
  	case T_INTEGER:
 | 
						|
  	case T_UNSIGNED:
 | 
						|
  	case T_POINTER:
 | 
						|
  	case T_ENUM:
 | 
						|
		put_int(*pbuf, size, l);
 | 
						|
		*psize = size;
 | 
						|
		*ptp = tp;
 | 
						|
		return 1;
 | 
						|
	case T_REAL:
 | 
						|
		put_real(*pbuf,
 | 
						|
			 size,
 | 
						|
			 (*ptp)->ty_class == T_INTEGER 
 | 
						|
				? (double) l
 | 
						|
				: (double) (unsigned long) l);
 | 
						|
		*psize = size;
 | 
						|
		*ptp = tp;
 | 
						|
		return 1;
 | 
						|
	default:
 | 
						|
		break;
 | 
						|
	}
 | 
						|
	break;
 | 
						|
  case T_REAL:
 | 
						|
	d = get_real(*pbuf, *psize);
 | 
						|
	switch(tp->ty_class) {
 | 
						|
  	case T_ENUM:
 | 
						|
  	case T_SUBRANGE:
 | 
						|
  	case T_INTEGER:
 | 
						|
  	case T_UNSIGNED:
 | 
						|
  	case T_POINTER:
 | 
						|
		if (tp == bool_type) put_int(*pbuf, size, (long) (d != 0));
 | 
						|
		else put_int(*pbuf, size, (long) d);
 | 
						|
		*psize = size;
 | 
						|
		*ptp = tp;
 | 
						|
		return 1;
 | 
						|
	case T_REAL:
 | 
						|
		put_real(*pbuf, size, d);
 | 
						|
		*psize = size;
 | 
						|
		*ptp = tp;
 | 
						|
		return 1;
 | 
						|
	default:
 | 
						|
		break;
 | 
						|
	}
 | 
						|
	break;
 | 
						|
  default:
 | 
						|
	break;
 | 
						|
  }
 | 
						|
  error("illegal conversion");
 | 
						|
  return 0;
 | 
						|
}
 | 
						|
 | 
						|
int
 | 
						|
eval_cond(p)
 | 
						|
  p_tree	p;
 | 
						|
{
 | 
						|
  char	*buf;
 | 
						|
  long	size;
 | 
						|
  p_type tp;
 | 
						|
  long val;
 | 
						|
  p_type target_tp = currlang->has_bool_type ? bool_type : int_type;
 | 
						|
 | 
						|
  if (eval_expr(p, &buf, &size, &tp)) {
 | 
						|
	if (convert(&buf, &size, &tp, target_tp, target_tp->ty_size)) {
 | 
						|
		val = get_int(buf, size, T_UNSIGNED);
 | 
						|
		free(buf);
 | 
						|
		return (int) (val != 0);
 | 
						|
	}
 | 
						|
	free(buf);
 | 
						|
  }
 | 
						|
  return 0;
 | 
						|
}
 | 
						|
 | 
						|
/* one routine for each unary operator */
 | 
						|
 | 
						|
static int
 | 
						|
not_op(p, pbuf, psize, ptp)
 | 
						|
  p_tree	p;
 | 
						|
  char		**pbuf;
 | 
						|
  long		*psize;
 | 
						|
  p_type	*ptp;
 | 
						|
{
 | 
						|
  p_type target_tp = currlang->has_bool_type ? bool_type : int_type;
 | 
						|
 | 
						|
  if (eval_expr(p->t_args[0], pbuf, psize, ptp) &&
 | 
						|
      convert(pbuf, psize, ptp, target_tp, target_tp->ty_size)) {
 | 
						|
	put_int(*pbuf, *psize, (long) !get_int(*pbuf, *psize, T_UNSIGNED));
 | 
						|
	return 1;
 | 
						|
  }
 | 
						|
  return 0;
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
bnot_op(p, pbuf, psize, ptp)
 | 
						|
  p_tree	p;
 | 
						|
  char		**pbuf;
 | 
						|
  long		*psize;
 | 
						|
  p_type	*ptp;
 | 
						|
{
 | 
						|
  if (eval_expr(p->t_args[0], pbuf, psize, ptp)) {
 | 
						|
	switch((*ptp)->ty_class) {
 | 
						|
	case T_INTEGER:
 | 
						|
	case T_ENUM:
 | 
						|
	case T_UNSIGNED:
 | 
						|
	case T_SUBRANGE:
 | 
						|
		put_int(*pbuf, *psize, ~get_int(*pbuf, *psize, T_UNSIGNED));
 | 
						|
		return 1;
 | 
						|
	default:
 | 
						|
		error("illegal operand type(s)");
 | 
						|
		break;
 | 
						|
	}
 | 
						|
  }
 | 
						|
  return 0;
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
ptr_addr(p, paddr, psize, ptp)
 | 
						|
  p_tree	p;
 | 
						|
  t_addr	*paddr;
 | 
						|
  long		*psize;
 | 
						|
  p_type	*ptp;
 | 
						|
{
 | 
						|
  char	*buf;
 | 
						|
 | 
						|
  if (eval_expr(p->t_args[0], &buf, psize, ptp)) {
 | 
						|
	switch((*ptp)->ty_class) {
 | 
						|
	case T_POINTER:
 | 
						|
		*ptp = (*ptp)->ty_ptrto;
 | 
						|
		*psize = (*ptp)->ty_size;
 | 
						|
		*paddr = get_int(buf, pointer_size, T_UNSIGNED);
 | 
						|
		free(buf);
 | 
						|
		return 1;
 | 
						|
  	default:
 | 
						|
		error("illegal operand of DEREF");
 | 
						|
		free(buf);
 | 
						|
		break;
 | 
						|
	}
 | 
						|
  }
 | 
						|
  return 0;
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
deref_op(p, pbuf, psize, ptp)
 | 
						|
  p_tree	p;
 | 
						|
  char		**pbuf;
 | 
						|
  long		*psize;
 | 
						|
  p_type	*ptp;
 | 
						|
{
 | 
						|
  t_addr addr;
 | 
						|
 | 
						|
  if (ptr_addr(p, &addr, psize, ptp)) {
 | 
						|
	*pbuf = malloc((unsigned) *psize);
 | 
						|
	malloc_succeeded(*pbuf);
 | 
						|
	if (! get_bytes(*psize, addr, *pbuf)) {
 | 
						|
		free(*pbuf);
 | 
						|
		*pbuf = 0;
 | 
						|
		return 0;
 | 
						|
	}
 | 
						|
	return 1;
 | 
						|
  }
 | 
						|
  return 0;
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
addr_op(p, pbuf, psize, ptp)
 | 
						|
  p_tree	p;
 | 
						|
  char		**pbuf;
 | 
						|
  long		*psize;
 | 
						|
  p_type	*ptp;
 | 
						|
{
 | 
						|
  t_addr addr;
 | 
						|
 | 
						|
  if (eval_desig(p->t_args[0], &addr, psize, ptp)) {
 | 
						|
	*pbuf = malloc((unsigned) pointer_size);
 | 
						|
	malloc_succeeded(*pbuf);
 | 
						|
	put_int(*pbuf, pointer_size, (long) addr);
 | 
						|
	address_type->ty_ptrto = *ptp;
 | 
						|
	*ptp = address_type;
 | 
						|
	return 1;
 | 
						|
  }
 | 
						|
  return 0;
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
unmin_op(p, pbuf, psize, ptp)
 | 
						|
  p_tree	p;
 | 
						|
  char		**pbuf;
 | 
						|
  long		*psize;
 | 
						|
  p_type	*ptp;
 | 
						|
{
 | 
						|
  if (eval_expr(p->t_args[0], pbuf, psize, ptp)) {
 | 
						|
  	switch((*ptp)->ty_class) {
 | 
						|
  	case T_SUBRANGE:
 | 
						|
  	case T_INTEGER:
 | 
						|
  	case T_ENUM:
 | 
						|
  	case T_UNSIGNED:
 | 
						|
		put_int(*pbuf, *psize, -get_int(*pbuf, *psize, (*ptp)->ty_class));
 | 
						|
		return 1;
 | 
						|
  	case T_REAL:
 | 
						|
		put_real(*pbuf, *psize, -get_real(*pbuf, *psize));
 | 
						|
		return 1;
 | 
						|
  	default:
 | 
						|
		error("illegal operand of unary -");
 | 
						|
		break;
 | 
						|
	}
 | 
						|
  }
 | 
						|
  return 0;
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
unplus_op(p, pbuf, psize, ptp)
 | 
						|
  p_tree	p;
 | 
						|
  char		**pbuf;
 | 
						|
  long		*psize;
 | 
						|
  p_type	*ptp;
 | 
						|
{
 | 
						|
  if (eval_expr(p->t_args[0], pbuf, psize, ptp)) {
 | 
						|
  	switch((*ptp)->ty_class) {
 | 
						|
  	case T_SUBRANGE:
 | 
						|
  	case T_INTEGER:
 | 
						|
  	case T_ENUM:
 | 
						|
  	case T_UNSIGNED:
 | 
						|
  	case T_REAL:
 | 
						|
		return 1;
 | 
						|
  	default:
 | 
						|
		error("illegal operand of unary +");
 | 
						|
		break;
 | 
						|
  	}
 | 
						|
  }
 | 
						|
  return 0;
 | 
						|
}
 | 
						|
 | 
						|
static int (*un_op[])() = {
 | 
						|
  0,
 | 
						|
  not_op,
 | 
						|
  deref_op,
 | 
						|
  0,
 | 
						|
  0,
 | 
						|
  0,
 | 
						|
  0,
 | 
						|
  0,
 | 
						|
  0,
 | 
						|
  0,
 | 
						|
  0,
 | 
						|
  unplus_op,
 | 
						|
  unmin_op,
 | 
						|
  0,
 | 
						|
  0,
 | 
						|
  0,
 | 
						|
  0,
 | 
						|
  0,
 | 
						|
  0,
 | 
						|
  0,
 | 
						|
  0,
 | 
						|
  0,
 | 
						|
  0,
 | 
						|
  0,
 | 
						|
  bnot_op,
 | 
						|
  0,
 | 
						|
  0,
 | 
						|
  0,
 | 
						|
  addr_op
 | 
						|
};
 | 
						|
 | 
						|
static p_type
 | 
						|
balance(tp1, tp2)
 | 
						|
  p_type	tp1, tp2;
 | 
						|
{
 | 
						|
 | 
						|
  if (tp1->ty_class == T_SUBRANGE) tp1 = tp1->ty_base;
 | 
						|
  if (tp2->ty_class == T_SUBRANGE) tp2 = tp2->ty_base;
 | 
						|
  if (tp1 == tp2) return tp2;
 | 
						|
  if (tp2->ty_class == T_REAL) {
 | 
						|
  	p_type tmp = tp1; tp1 = tp2; tp2 = tmp;
 | 
						|
  }
 | 
						|
  if (tp1->ty_class == T_REAL) {
 | 
						|
	switch(tp2->ty_class) {
 | 
						|
	case T_INTEGER:
 | 
						|
	case T_UNSIGNED:
 | 
						|
	case T_ENUM:
 | 
						|
		return tp1;
 | 
						|
	case T_REAL:
 | 
						|
		return tp1->ty_size > tp2->ty_size ? tp1 : tp2;
 | 
						|
	default:
 | 
						|
		error("illegal type combination");
 | 
						|
		return 0;
 | 
						|
	}
 | 
						|
  }
 | 
						|
  if (tp2->ty_class == T_POINTER) {
 | 
						|
  	p_type tmp = tp1; tp1 = tp2; tp2 = tmp;
 | 
						|
  }
 | 
						|
  if (tp1->ty_class == T_POINTER) {
 | 
						|
	switch(tp2->ty_class) {
 | 
						|
	case T_INTEGER:
 | 
						|
	case T_UNSIGNED:
 | 
						|
	case T_POINTER:
 | 
						|
	case T_ENUM:
 | 
						|
		return tp1;
 | 
						|
	default:
 | 
						|
		error("illegal type combination");
 | 
						|
		return 0;
 | 
						|
	}
 | 
						|
  }
 | 
						|
  if (tp2->ty_class == T_UNSIGNED) {
 | 
						|
  	p_type tmp = tp1; tp1 = tp2; tp2 = tmp;
 | 
						|
  }
 | 
						|
  if (tp1->ty_class == T_UNSIGNED) {
 | 
						|
	switch(tp2->ty_class) {
 | 
						|
	case T_INTEGER:
 | 
						|
	case T_UNSIGNED:
 | 
						|
		if (tp1->ty_size >= tp2->ty_size) return tp1;
 | 
						|
		return tp2;
 | 
						|
	case T_ENUM:
 | 
						|
		return tp1;
 | 
						|
	default:
 | 
						|
		error("illegal type combination");
 | 
						|
		return 0;
 | 
						|
	}
 | 
						|
  }
 | 
						|
  if (tp2->ty_class == T_INTEGER) {
 | 
						|
  	p_type tmp = tp1; tp1 = tp2; tp2 = tmp;
 | 
						|
  }
 | 
						|
  if (tp1->ty_class == T_INTEGER) {
 | 
						|
	switch(tp2->ty_class) {
 | 
						|
	case T_INTEGER:
 | 
						|
		if (tp1->ty_size >= tp2->ty_size) return tp1;
 | 
						|
		return tp2;
 | 
						|
	case T_ENUM:
 | 
						|
		return tp1;
 | 
						|
	default:
 | 
						|
		error("illegal type combination");
 | 
						|
		return 0;
 | 
						|
	}
 | 
						|
  }
 | 
						|
  error("illegal type combination");
 | 
						|
  return 0;
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
andor_op(p, pbuf, psize, ptp)
 | 
						|
  p_tree	p;
 | 
						|
  char		**pbuf;
 | 
						|
  long		*psize;
 | 
						|
  p_type	*ptp;
 | 
						|
{
 | 
						|
  long		l1, l2;
 | 
						|
  char		*buf = 0;
 | 
						|
  long		size;
 | 
						|
  p_type	tp;
 | 
						|
  p_type	target_tp = currlang->has_bool_type ? bool_type : int_type;
 | 
						|
 | 
						|
  if (eval_expr(p->t_args[0], pbuf, psize, ptp) &&
 | 
						|
      convert(pbuf, psize, ptp, target_tp, target_tp->ty_size) &&
 | 
						|
      eval_expr(p->t_args[1], &buf, &size, &tp) &&
 | 
						|
      convert(&buf, &size, &tp, target_tp, target_tp->ty_size)) {
 | 
						|
	l1 = get_int(*pbuf, *psize, T_UNSIGNED);
 | 
						|
	l2 = get_int(buf, size, T_UNSIGNED);
 | 
						|
	put_int(*pbuf,
 | 
						|
		*psize,
 | 
						|
		p->t_whichoper == E_AND 
 | 
						|
			? (long)(l1 && l2) 
 | 
						|
			: (long)(l1 || l2));
 | 
						|
	free(buf);
 | 
						|
	return 1;
 | 
						|
  }
 | 
						|
  if (buf) free(buf);
 | 
						|
  return 0;
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
arith_op(p, pbuf, psize, ptp)
 | 
						|
  p_tree	p;
 | 
						|
  char		**pbuf;
 | 
						|
  long		*psize;
 | 
						|
  p_type	*ptp;
 | 
						|
{
 | 
						|
  long		l1, l2;
 | 
						|
  double	d1, d2;
 | 
						|
  char		*buf = 0;
 | 
						|
  long		size;
 | 
						|
  p_type	tp, balance_tp;
 | 
						|
 | 
						|
  if (!(eval_expr(p->t_args[0], pbuf, psize, ptp) &&
 | 
						|
        eval_expr(p->t_args[1], &buf, &size, &tp))) {
 | 
						|
	return 0;
 | 
						|
  }
 | 
						|
  if ((*ptp)->ty_class == T_POINTER) {
 | 
						|
	if (currlang != c_dep ||
 | 
						|
	    (p->t_whichoper != E_PLUS && p->t_whichoper != E_MIN)) {
 | 
						|
		error("illegal operand type(s)");
 | 
						|
		free(buf);
 | 
						|
		return 0;
 | 
						|
	}
 | 
						|
	l1 = get_int(*pbuf, *psize, T_UNSIGNED);
 | 
						|
	if (tp->ty_class == T_POINTER) {
 | 
						|
		if (p->t_whichoper != E_MIN) {
 | 
						|
			error("illegal operand type(s)");
 | 
						|
			free(buf);
 | 
						|
			return 0;
 | 
						|
		}
 | 
						|
		l2 = get_int(buf, size, T_UNSIGNED);
 | 
						|
		free(buf);
 | 
						|
		*pbuf = Realloc(*pbuf, (unsigned) long_size);
 | 
						|
		put_int(*pbuf, long_size, (l1 - l2)/(*ptp)->ty_ptrto->ty_size);
 | 
						|
		*ptp = long_type;
 | 
						|
		return 1;
 | 
						|
	}
 | 
						|
	if (! convert(&buf, &size, &tp, long_type, long_size)) {
 | 
						|
		free(buf);
 | 
						|
		return 0;
 | 
						|
	}
 | 
						|
	l2 = get_int(buf, size, T_INTEGER) * (*ptp)->ty_ptrto->ty_size;
 | 
						|
	free(buf);
 | 
						|
	buf = 0;
 | 
						|
	if (p->t_whichoper == E_PLUS) l1 += l2;
 | 
						|
	else l1 -= l2;
 | 
						|
	put_int(*pbuf, *psize, l1);
 | 
						|
	return 1;
 | 
						|
  }
 | 
						|
  if ((balance_tp = balance(*ptp, tp)) &&
 | 
						|
      convert(pbuf, psize, ptp, balance_tp, balance_tp->ty_size) &&
 | 
						|
      convert(&buf, &size, &tp, balance_tp, balance_tp->ty_size)) {
 | 
						|
	switch(balance_tp->ty_class) {
 | 
						|
	case T_INTEGER:
 | 
						|
	case T_ENUM:
 | 
						|
	case T_UNSIGNED:
 | 
						|
		l1 = get_int(*pbuf, *psize, balance_tp->ty_class);
 | 
						|
		l2 = get_int(buf, size, balance_tp->ty_class);
 | 
						|
		free(buf);
 | 
						|
		buf = 0;
 | 
						|
		switch(p->t_whichoper) {
 | 
						|
		case E_BAND:
 | 
						|
			l1 &= l2;
 | 
						|
			break;
 | 
						|
		case E_BOR:
 | 
						|
			l1 |= l2;
 | 
						|
			break;
 | 
						|
		case E_BXOR:
 | 
						|
			l1 ^= l2;
 | 
						|
			break;
 | 
						|
		case E_PLUS:
 | 
						|
			l1 += l2;
 | 
						|
			break;
 | 
						|
		case E_MIN:
 | 
						|
			l1 -= l2;
 | 
						|
			break;
 | 
						|
		case E_MUL:
 | 
						|
			l1 *= l2;
 | 
						|
			break;
 | 
						|
		case E_DIV:
 | 
						|
		case E_ZDIV:
 | 
						|
			if (! l2) {
 | 
						|
				error("division by 0");
 | 
						|
				return 0;
 | 
						|
			}
 | 
						|
			if (balance_tp->ty_class == T_INTEGER) {
 | 
						|
				if ((l1 < 0) != (l2 < 0)) {
 | 
						|
					if (l1 < 0) l1 = - l1;
 | 
						|
					else l2 = -l2;
 | 
						|
					if (p->t_whichoper == E_DIV) {
 | 
						|
					    l1 = -((l1+l2-1)/l2);
 | 
						|
					}
 | 
						|
					else {
 | 
						|
					    l1 = -(l1/l2);
 | 
						|
					}
 | 
						|
				}
 | 
						|
				else l1 /= l2;
 | 
						|
			}
 | 
						|
			else l1 = (unsigned long) l1 /
 | 
						|
				  (unsigned long) l2;
 | 
						|
			break;
 | 
						|
		case E_MOD:
 | 
						|
		case E_ZMOD:
 | 
						|
			if (! l2) {
 | 
						|
				error("modulo by 0");
 | 
						|
				return 0;
 | 
						|
			}
 | 
						|
			if (balance_tp->ty_class == T_INTEGER) {
 | 
						|
				if ((l1 < 0) != (l2 < 0)) {
 | 
						|
					if (l1 < 0) l1 = - l1;
 | 
						|
					else l2 = -l2;
 | 
						|
					if (p->t_whichoper == E_MOD) {
 | 
						|
					    l1 = ((l1+l2-1)/l2)*l2 - l1;
 | 
						|
					}
 | 
						|
					else {
 | 
						|
					    l1 = (l1/l2)*l2 - l1;
 | 
						|
					}
 | 
						|
				}
 | 
						|
				else l1 %= l2;
 | 
						|
			}
 | 
						|
			else l1 = (unsigned long) l1 %
 | 
						|
				  (unsigned long) l2;
 | 
						|
			break;
 | 
						|
		}
 | 
						|
		put_int(*pbuf, *psize, l1);
 | 
						|
		break;
 | 
						|
	case T_REAL:
 | 
						|
		d1 = get_real(*pbuf, *psize);
 | 
						|
		d2 = get_real(buf, size);
 | 
						|
		free(buf);
 | 
						|
		buf = 0;
 | 
						|
		switch(p->t_whichoper) {
 | 
						|
		case E_DIV:
 | 
						|
		case E_ZDIV:
 | 
						|
			if (d2 == 0.0) {
 | 
						|
				error("division by 0.0");
 | 
						|
				return 0;
 | 
						|
			}
 | 
						|
			d1 /= d2;
 | 
						|
			break;
 | 
						|
		case E_PLUS:
 | 
						|
			d1 += d2;
 | 
						|
			break;
 | 
						|
		case E_MIN:
 | 
						|
			d1 -= d2;
 | 
						|
			break;
 | 
						|
		case E_MUL:
 | 
						|
			d1 *= d2;
 | 
						|
			break;
 | 
						|
		}
 | 
						|
		put_real(*pbuf, *psize, d1);
 | 
						|
		break;
 | 
						|
	default:
 | 
						|
		error("illegal operand type(s)");
 | 
						|
		free(buf);
 | 
						|
		return 0;
 | 
						|
	}
 | 
						|
	return 1;
 | 
						|
  }
 | 
						|
  if (buf) free(buf);
 | 
						|
  return 0;
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
sft_op(p, pbuf, psize, ptp)
 | 
						|
  p_tree	p;
 | 
						|
  char		**pbuf;
 | 
						|
  long		*psize;
 | 
						|
  p_type	*ptp;
 | 
						|
{
 | 
						|
  long		l1, l2;
 | 
						|
  char		*buf = 0;
 | 
						|
  long		size;
 | 
						|
  p_type	tp;
 | 
						|
 | 
						|
  if (eval_expr(p->t_args[0], pbuf, psize, ptp) &&
 | 
						|
      eval_expr(p->t_args[1], &buf, &size, &tp) &&
 | 
						|
      convert(&buf, &size, &tp, int_type, int_size)) {
 | 
						|
	tp = *ptp;
 | 
						|
	if (tp->ty_class == T_SUBRANGE) {
 | 
						|
		tp = tp->ty_base;
 | 
						|
	}
 | 
						|
	switch(tp->ty_class) {
 | 
						|
	case T_INTEGER:
 | 
						|
	case T_ENUM:
 | 
						|
	case T_UNSIGNED:
 | 
						|
		l1 = get_int(*pbuf, *psize, tp->ty_class);
 | 
						|
		l2 = get_int(buf, size, T_INTEGER);
 | 
						|
		free(buf);
 | 
						|
		buf = 0;
 | 
						|
		switch(p->t_whichoper) {
 | 
						|
		case E_LSFT:
 | 
						|
			l1 <<= (int) l2;
 | 
						|
			break;
 | 
						|
		case E_RSFT:
 | 
						|
			if (tp->ty_class == T_INTEGER) l1 >>= (int) l2;
 | 
						|
			else l1 = (unsigned long) l1 >> (int) l2;
 | 
						|
			break;
 | 
						|
		}
 | 
						|
		break;
 | 
						|
	default:
 | 
						|
		error("illegal operand type(s)");
 | 
						|
		free(buf);
 | 
						|
		return 0;
 | 
						|
	}
 | 
						|
	return 1;
 | 
						|
  }
 | 
						|
  if (buf) free(buf);
 | 
						|
  return 0;
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
cmp_op(p, pbuf, psize, ptp)
 | 
						|
  p_tree	p;
 | 
						|
  char		**pbuf;
 | 
						|
  long		*psize;
 | 
						|
  p_type	*ptp;
 | 
						|
{
 | 
						|
  long		l1, l2;
 | 
						|
  double	d1, d2;
 | 
						|
  char		*buf = 0;
 | 
						|
  long		size;
 | 
						|
  p_type	tp, balance_tp;
 | 
						|
 | 
						|
  if (eval_expr(p->t_args[0], pbuf, psize, ptp) &&
 | 
						|
      eval_expr(p->t_args[1], &buf, &size, &tp) &&
 | 
						|
      (balance_tp = balance(*ptp, tp)) &&
 | 
						|
      convert(pbuf, psize, ptp, balance_tp, balance_tp->ty_size) &&
 | 
						|
      convert(&buf, &size, &tp, balance_tp, balance_tp->ty_size)) {
 | 
						|
	switch(balance_tp->ty_class) {
 | 
						|
	case T_INTEGER:
 | 
						|
	case T_ENUM:
 | 
						|
	case T_UNSIGNED:
 | 
						|
	case T_POINTER:
 | 
						|
		l1 = get_int(*pbuf, *psize, balance_tp->ty_class);
 | 
						|
		l2 = get_int(buf, size, balance_tp->ty_class);
 | 
						|
		free(buf);
 | 
						|
		buf = 0;
 | 
						|
		switch(p->t_whichoper) {
 | 
						|
		case E_EQUAL:
 | 
						|
			l1 = l1 == l2;
 | 
						|
			break;
 | 
						|
		case E_NOTEQUAL:
 | 
						|
			l1 = l1 != l2;
 | 
						|
			break;
 | 
						|
		case E_LTEQUAL:
 | 
						|
			if (balance_tp->ty_class == T_INTEGER) {
 | 
						|
				l1 = l1 <= l2;
 | 
						|
			}
 | 
						|
			else	l1 = (unsigned long) l1 <=
 | 
						|
				     (unsigned long) l2;
 | 
						|
			break;
 | 
						|
		case E_LT:
 | 
						|
			if (balance_tp->ty_class == T_INTEGER) {
 | 
						|
				l1 = l1 < l2;
 | 
						|
			}
 | 
						|
			else	l1 = (unsigned long) l1 <
 | 
						|
				     (unsigned long) l2;
 | 
						|
			break;
 | 
						|
		case E_GTEQUAL:
 | 
						|
			if (balance_tp->ty_class == T_INTEGER) {
 | 
						|
				l1 = l1 >= l2;
 | 
						|
			}
 | 
						|
			else	l1 = (unsigned long) l1 >=
 | 
						|
				     (unsigned long) l2;
 | 
						|
			break;
 | 
						|
		case E_GT:
 | 
						|
			if (balance_tp->ty_class == T_INTEGER) {
 | 
						|
				l1 = l1 > l2;
 | 
						|
			}
 | 
						|
			else	l1 = (unsigned long) l1 >
 | 
						|
				     (unsigned long) l2;
 | 
						|
			break;
 | 
						|
		default:
 | 
						|
			l1 = 0;
 | 
						|
			assert(0);
 | 
						|
			break;
 | 
						|
		}
 | 
						|
		break;
 | 
						|
	case T_REAL:
 | 
						|
		d1 = get_real(*pbuf, *psize);
 | 
						|
		d2 = get_real(buf, size);
 | 
						|
		free(buf);
 | 
						|
		buf = 0;
 | 
						|
		switch(p->t_whichoper) {
 | 
						|
		case E_EQUAL:
 | 
						|
			l1 = d1 == d2;
 | 
						|
			break;
 | 
						|
		case E_NOTEQUAL:
 | 
						|
			l1 = d1 != d2;
 | 
						|
			break;
 | 
						|
		case E_LTEQUAL:
 | 
						|
			l1 = d1 <= d2;
 | 
						|
			break;
 | 
						|
		case E_LT:
 | 
						|
			l1 = d1 < d2;
 | 
						|
			break;
 | 
						|
		case E_GTEQUAL:
 | 
						|
			l1 = d1 >= d2;
 | 
						|
			break;
 | 
						|
		case E_GT:
 | 
						|
			l1 = d1 > d2;
 | 
						|
			break;
 | 
						|
		default:
 | 
						|
			l1 = 0;
 | 
						|
			assert(0);
 | 
						|
			break;
 | 
						|
		}
 | 
						|
		break;
 | 
						|
	default:
 | 
						|
		error("illegal operand type(s)");
 | 
						|
		free(buf);
 | 
						|
		return 0;
 | 
						|
	}
 | 
						|
	if (*psize < int_size) {
 | 
						|
		*psize = int_size;
 | 
						|
		*pbuf = realloc(*pbuf, (unsigned int) int_size);
 | 
						|
		malloc_succeeded(*pbuf);
 | 
						|
	}
 | 
						|
	else	*psize = int_size;
 | 
						|
	if (currlang->has_bool_type) {
 | 
						|
		*ptp = bool_type;
 | 
						|
	}
 | 
						|
	else	*ptp = int_type;
 | 
						|
	put_int(*pbuf, *psize, l1);
 | 
						|
	return 1;
 | 
						|
  }
 | 
						|
  if (buf) free(buf);
 | 
						|
  return 0;
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
in_op(p, pbuf, psize, ptp)
 | 
						|
  p_tree	p;
 | 
						|
  char		**pbuf;
 | 
						|
  long		*psize;
 | 
						|
  p_type	*ptp;
 | 
						|
{
 | 
						|
  long		l;
 | 
						|
  char		*buf = 0;
 | 
						|
  long		size;
 | 
						|
  p_type	tp;
 | 
						|
  int		sft = int_size == 2 ? 4 : 5;
 | 
						|
 | 
						|
  if (eval_expr(p->t_args[0], pbuf, psize, ptp) &&
 | 
						|
      eval_expr(p->t_args[1], &buf, &size, &tp)) {
 | 
						|
	if (tp->ty_class != T_SET) {
 | 
						|
		error("right-hand side of IN not a set");
 | 
						|
		free(buf);
 | 
						|
		return 0;
 | 
						|
	}
 | 
						|
	if (! convert(pbuf, psize, ptp, tp->ty_setbase, int_size)) {
 | 
						|
		free(buf);
 | 
						|
		return 0;
 | 
						|
	}
 | 
						|
	l = get_int(*pbuf, *psize, (*ptp)->ty_class) - tp->ty_setlow;
 | 
						|
	l = l >= 0 
 | 
						|
	    && l <= (size << 3) 
 | 
						|
	    && (((int *) buf)[(int)(l>>sft)] & (1 << (l & ((1 << sft)-1))));
 | 
						|
	free(buf);
 | 
						|
	*pbuf = realloc(*pbuf, (unsigned) int_size);
 | 
						|
	malloc_succeeded(*pbuf);
 | 
						|
	*psize = int_size;
 | 
						|
	*ptp = currlang->has_bool_type ? bool_type : int_type;
 | 
						|
	put_int(*pbuf, *psize, l);
 | 
						|
	return 1;
 | 
						|
  }
 | 
						|
  return 0;
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
array_addr(p, paddr, psize, ptp)
 | 
						|
  p_tree	p;
 | 
						|
  t_addr	*paddr;
 | 
						|
  long		*psize;
 | 
						|
  p_type	*ptp;
 | 
						|
{
 | 
						|
  long		l;
 | 
						|
  char		*buf = 0;
 | 
						|
  long		size;
 | 
						|
  p_type	tp;
 | 
						|
 | 
						|
  if (eval_desig(p->t_args[0], paddr, psize, ptp) &&
 | 
						|
      eval_expr(p->t_args[1], &buf, &size, &tp)) {
 | 
						|
	if ((*ptp)->ty_class != T_ARRAY && (*ptp)->ty_class != T_POINTER) {
 | 
						|
		error("illegal left-hand side of [");
 | 
						|
		free(buf);
 | 
						|
		return 0;
 | 
						|
	}
 | 
						|
	if ((*ptp)->ty_class == T_POINTER) {
 | 
						|
		if (! get_bytes(pointer_size, *paddr, (char *) paddr)) {
 | 
						|
			free(buf);
 | 
						|
			return 0;
 | 
						|
		}
 | 
						|
		*paddr = get_int((char *) paddr, pointer_size, T_UNSIGNED);
 | 
						|
	}
 | 
						|
	if (! convert(&buf, &size, &tp, int_type, int_size)) {
 | 
						|
		free(buf);
 | 
						|
		return 0;
 | 
						|
	}
 | 
						|
	l = get_int(buf, size, T_INTEGER);
 | 
						|
	free(buf);
 | 
						|
	buf = 0;
 | 
						|
	if ((*ptp)->ty_class == T_ARRAY) {
 | 
						|
	    	if (l < (*ptp)->ty_lb || l > (*ptp)->ty_hb) {
 | 
						|
			error("array bound error");
 | 
						|
			return 0;
 | 
						|
		}
 | 
						|
		l -= (*ptp)->ty_lb;
 | 
						|
		*ptp = (*ptp)->ty_elements;
 | 
						|
		l *= (*currlang->arrayelsize)((*ptp)->ty_size);
 | 
						|
	}
 | 
						|
	else {
 | 
						|
		*ptp = (*ptp)->ty_ptrto;
 | 
						|
		l *= (*ptp)->ty_size;
 | 
						|
	}
 | 
						|
	*psize = (*ptp)->ty_size;
 | 
						|
	*paddr += l;
 | 
						|
	return 1;
 | 
						|
  }
 | 
						|
  return 0;
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
array_op(p, pbuf, psize, ptp)
 | 
						|
  p_tree	p;
 | 
						|
  char		**pbuf;
 | 
						|
  long		*psize;
 | 
						|
  p_type	*ptp;
 | 
						|
{
 | 
						|
  t_addr	a;
 | 
						|
 | 
						|
  if (array_addr(p, &a, psize, ptp)) {
 | 
						|
	*pbuf = malloc((unsigned int) *psize);
 | 
						|
	malloc_succeeded(*pbuf);
 | 
						|
	if (! get_bytes(*psize, a, *pbuf)) {
 | 
						|
		return 0;
 | 
						|
	}
 | 
						|
	return 1;
 | 
						|
  }
 | 
						|
  return 0;
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
select_addr(p, paddr, psize, ptp)
 | 
						|
  p_tree	p;
 | 
						|
  t_addr	*paddr;
 | 
						|
  long		*psize;
 | 
						|
  p_type	*ptp;
 | 
						|
{
 | 
						|
  register p_type	tp;
 | 
						|
  register struct fields *f;
 | 
						|
  register int		nf;
 | 
						|
 | 
						|
  if (eval_desig(p->t_args[0], paddr, psize, ptp)) {
 | 
						|
	tp = *ptp;
 | 
						|
	if (tp->ty_class != T_STRUCT && tp->ty_class != T_UNION) {
 | 
						|
		error("SELECT on non-struct");
 | 
						|
		return 0;
 | 
						|
	}
 | 
						|
	if (p->t_args[1]->t_oper != OP_NAME) {
 | 
						|
		error("right-hand side of SELECT not a name");
 | 
						|
		return 0;
 | 
						|
	}
 | 
						|
	for (nf = tp->ty_nfields, f = tp->ty_fields; nf; nf--, f++) {
 | 
						|
		if (! strcmp(f->fld_name, p->t_args[1]->t_str)) break;
 | 
						|
	}
 | 
						|
	if (! nf) {
 | 
						|
		error("'%s' not found", p->t_args[1]->t_str);
 | 
						|
		return 0;
 | 
						|
	}
 | 
						|
	
 | 
						|
	/* ??? this needs some work for bitfields ??? */
 | 
						|
	*paddr += f->fld_pos>>3;
 | 
						|
	*psize = f->fld_bitsize >> 3;
 | 
						|
	*ptp = f->fld_type;
 | 
						|
	return 1;
 | 
						|
  }
 | 
						|
  return 0;
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
select_op(p, pbuf, psize, ptp)
 | 
						|
  p_tree	p;
 | 
						|
  char		**pbuf;
 | 
						|
  long		*psize;
 | 
						|
  p_type	*ptp;
 | 
						|
{
 | 
						|
  t_addr	a;
 | 
						|
  if (select_addr(p, &a, psize, ptp)) {
 | 
						|
	*pbuf = malloc((unsigned int) *psize);
 | 
						|
	malloc_succeeded(*pbuf);
 | 
						|
	if (! get_bytes(*psize, a, *pbuf)) {
 | 
						|
		free(*pbuf);
 | 
						|
		*pbuf = 0;
 | 
						|
		return 0;
 | 
						|
	}
 | 
						|
	return 1;
 | 
						|
  }
 | 
						|
  return 0;
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
derselect_op(p, pbuf, psize, ptp)
 | 
						|
  p_tree	p;
 | 
						|
  char		**pbuf;
 | 
						|
  long		*psize;
 | 
						|
  p_type	*ptp;
 | 
						|
{
 | 
						|
  int	retval;
 | 
						|
  t_tree	t;
 | 
						|
 | 
						|
  t.t_oper = OP_UNOP;
 | 
						|
  t.t_whichoper = E_DEREF;
 | 
						|
  t.t_args[0] = p->t_args[0];
 | 
						|
  p->t_args[0] = &t;
 | 
						|
  p->t_whichoper = E_SELECT;
 | 
						|
  retval = eval_expr(p, pbuf, psize, ptp);
 | 
						|
  p->t_args[0] = t.t_args[0];
 | 
						|
  p->t_whichoper = E_DERSELECT;
 | 
						|
  return retval;
 | 
						|
}
 | 
						|
 | 
						|
static int (*bin_op[])() = {
 | 
						|
  0,
 | 
						|
  0,
 | 
						|
  0,
 | 
						|
  andor_op,
 | 
						|
  andor_op,
 | 
						|
  arith_op,
 | 
						|
  arith_op,
 | 
						|
  arith_op,
 | 
						|
  arith_op,
 | 
						|
  in_op,
 | 
						|
  array_op,
 | 
						|
  arith_op,
 | 
						|
  arith_op,
 | 
						|
  arith_op,
 | 
						|
  cmp_op,
 | 
						|
  cmp_op,
 | 
						|
  cmp_op,
 | 
						|
  cmp_op,
 | 
						|
  cmp_op,
 | 
						|
  cmp_op,
 | 
						|
  select_op,
 | 
						|
  arith_op,
 | 
						|
  arith_op,
 | 
						|
  arith_op,
 | 
						|
  0,
 | 
						|
  derselect_op,
 | 
						|
  sft_op,
 | 
						|
  sft_op,
 | 
						|
  0
 | 
						|
};
 | 
						|
 | 
						|
int
 | 
						|
eval_expr(p, pbuf, psize, ptp)
 | 
						|
  p_tree	p;
 | 
						|
  char		**pbuf;
 | 
						|
  long		*psize;
 | 
						|
  p_type	*ptp;
 | 
						|
{
 | 
						|
  register p_symbol	sym;
 | 
						|
  int		retval = 0;
 | 
						|
 | 
						|
  *pbuf = 0;
 | 
						|
 | 
						|
  switch(p->t_oper) {
 | 
						|
  case OP_FORMAT:
 | 
						|
	if (eval_expr(p->t_args[0], pbuf, psize, ptp)) retval = 1;
 | 
						|
	break;
 | 
						|
  case OP_NAME:
 | 
						|
  case OP_SELECT:
 | 
						|
	sym = identify(p, VAR|REGVAR|LOCVAR|VARPAR|CONST|LBOUND|UBOUND);
 | 
						|
	if (! sym) return 0;
 | 
						|
	if (! get_value(sym, pbuf, psize)) {
 | 
						|
		break;
 | 
						|
	}
 | 
						|
	*ptp = sym->sy_type;
 | 
						|
	retval = 1;
 | 
						|
	break;
 | 
						|
 | 
						|
  case OP_INTEGER:
 | 
						|
	*pbuf = malloc((unsigned int) long_size);
 | 
						|
	malloc_succeeded(*pbuf);
 | 
						|
	*psize = long_size;
 | 
						|
	*ptp = long_type;
 | 
						|
	put_int(*pbuf, long_size, p->t_ival);
 | 
						|
	retval = 1;
 | 
						|
	break;
 | 
						|
 | 
						|
  case OP_REAL:
 | 
						|
	*pbuf = malloc((unsigned int) double_size);
 | 
						|
	malloc_succeeded(*pbuf);
 | 
						|
	*psize = double_size;
 | 
						|
	*ptp = double_type;
 | 
						|
	put_real(*pbuf, double_size, p->t_fval);
 | 
						|
	retval = 1;
 | 
						|
	break;
 | 
						|
 | 
						|
  case OP_STRING:
 | 
						|
	*psize = strlen(p->t_sval)+1;
 | 
						|
	*pbuf = malloc((unsigned int)*psize);
 | 
						|
	malloc_succeeded(*pbuf);
 | 
						|
	*ptp = string_type;
 | 
						|
	strcpy(*pbuf, p->t_sval);
 | 
						|
	retval = 1;
 | 
						|
	break;
 | 
						|
 | 
						|
  case OP_UNOP:
 | 
						|
	retval = (*un_op[p->t_whichoper])(p, pbuf, psize, ptp);
 | 
						|
	break;
 | 
						|
 | 
						|
  case OP_BINOP:
 | 
						|
	retval = (*bin_op[p->t_whichoper])(p, pbuf, psize, ptp);
 | 
						|
	break;
 | 
						|
  default:
 | 
						|
	assert(0);
 | 
						|
	break;
 | 
						|
  }
 | 
						|
  if (! retval) {
 | 
						|
	if (*pbuf) {
 | 
						|
		free(*pbuf);
 | 
						|
		*pbuf = 0;
 | 
						|
	}
 | 
						|
	*psize = 0;
 | 
						|
  }
 | 
						|
  else {
 | 
						|
	if ((*ptp)->ty_class == T_CROSS) {
 | 
						|
		*ptp = (*ptp)->ty_cross;
 | 
						|
		if (! *ptp) *ptp = void_type;
 | 
						|
	}
 | 
						|
  }
 | 
						|
  return retval;
 | 
						|
}
 | 
						|
 | 
						|
int
 | 
						|
eval_desig(p, paddr, psize, ptp)
 | 
						|
  p_tree	p;
 | 
						|
  t_addr	*paddr;
 | 
						|
  long		*psize;
 | 
						|
  p_type	*ptp;
 | 
						|
{
 | 
						|
  register p_symbol	sym;
 | 
						|
  int	retval = 0;
 | 
						|
  t_addr a;
 | 
						|
 | 
						|
  switch(p->t_oper) {
 | 
						|
  case OP_NAME:
 | 
						|
  case OP_SELECT:
 | 
						|
	sym = identify(p, VAR|REGVAR|LOCVAR|VARPAR);
 | 
						|
	if (! sym) return 0;
 | 
						|
	if (! (a = get_addr(sym, psize))) {
 | 
						|
		break;
 | 
						|
	}
 | 
						|
	*paddr = a;
 | 
						|
	*ptp = sym->sy_type;
 | 
						|
	retval = 1;
 | 
						|
	break;
 | 
						|
 | 
						|
  case OP_UNOP:
 | 
						|
	switch(p->t_whichoper) {
 | 
						|
	case E_DEREF:
 | 
						|
		if (ptr_addr(p, paddr, psize, ptp)) {
 | 
						|
			retval = 1;
 | 
						|
		}
 | 
						|
		break;
 | 
						|
	default:
 | 
						|
		print_node(db_out, p, 0);
 | 
						|
		fputs(" not a designator\n", db_out);
 | 
						|
		break;
 | 
						|
	}
 | 
						|
	break;
 | 
						|
 | 
						|
  case OP_BINOP:
 | 
						|
	switch(p->t_whichoper) {
 | 
						|
	case E_ARRAY:
 | 
						|
		if (array_addr(p, paddr, psize, ptp)) {
 | 
						|
			retval = 1;
 | 
						|
		}
 | 
						|
		break;
 | 
						|
	case E_SELECT:
 | 
						|
		if (select_addr(p, paddr, psize, ptp)) {
 | 
						|
			retval = 1;
 | 
						|
		}
 | 
						|
		break;
 | 
						|
	default:
 | 
						|
		print_node(db_out, p, 0);
 | 
						|
		fputs(" not a designator\n", db_out);
 | 
						|
		break;
 | 
						|
	}
 | 
						|
	break;
 | 
						|
  default:
 | 
						|
	error("illegal designator");
 | 
						|
	break;
 | 
						|
  }
 | 
						|
  if (! retval) {
 | 
						|
	*psize = 0;
 | 
						|
  }
 | 
						|
  else {
 | 
						|
	if ((*ptp)->ty_class == T_CROSS) {
 | 
						|
		*ptp = (*ptp)->ty_cross;
 | 
						|
		if (! *ptp) {
 | 
						|
			*ptp = void_type;
 | 
						|
			print_node(db_out, p, 0);
 | 
						|
			fputs(" designator has unknown type\n", db_out);
 | 
						|
			retval = 0;
 | 
						|
			*psize = 0;
 | 
						|
		}
 | 
						|
	}
 | 
						|
  }
 | 
						|
  return retval;
 | 
						|
}
 |