182 lines
		
	
	
	
		
			3.7 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			182 lines
		
	
	
	
		
			3.7 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /* $Header$ */
 | |
| 
 | |
| #include <alloc.h>
 | |
| #include <assert.h>
 | |
| 
 | |
| #include "position.h"
 | |
| #include "scope.h"
 | |
| #include "idf.h"
 | |
| #include "symbol.h"
 | |
| #include "type.h"
 | |
| #include "message.h"
 | |
| #include "langdep.h"
 | |
| #include "expr.h"
 | |
| 
 | |
| int stack_offset;		/* for up and down commands */
 | |
| 
 | |
| extern long pointer_size;
 | |
| extern t_addr *get_EM_regs();
 | |
| extern char *memcpy();
 | |
| 
 | |
| /* Get the address of the object indicated by sym.
 | |
|    Return 0 on failure,
 | |
| 	  address on success.
 | |
|    *psize will contain size of object.
 | |
| */
 | |
| 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;
 | |
| }
 | |
| 
 | |
| /* Get the value of the symbol indicated by sym.
 | |
|    Return 0 on failure,
 | |
| 	  1 on success.
 | |
|    On success, 'buf' contains the value, and 'size' contains the size.
 | |
|    For 'buf', 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).
 | |
| */
 | |
| int
 | |
| get_value(sym, buf, psize)
 | |
|   register p_symbol	sym;
 | |
|   char	**buf;
 | |
|   long	*psize;
 | |
| {
 | |
|   p_type	tp = sym->sy_type;
 | |
|   int		retval = 0;
 | |
|   t_addr	a;
 | |
|   long		size = tp->ty_size;
 | |
| 
 | |
|   *buf = 0;
 | |
|   switch(sym->sy_class) {
 | |
|   case CONST:
 | |
| 	*buf = malloc((unsigned) size);
 | |
| 	if (! *buf) {
 | |
| 		error("could not allocate enough memory");
 | |
| 		break;
 | |
| 	}
 | |
| 	switch(tp->ty_class) {
 | |
| 	case T_REAL:
 | |
| 		put_real(*buf, size, sym->sy_const.co_rval);
 | |
| 		break;
 | |
| 	case T_INTEGER:
 | |
| 	case T_SUBRANGE:
 | |
| 	case T_UNSIGNED:
 | |
| 	case T_ENUM:
 | |
| 		put_int(*buf, size, sym->sy_const.co_ival);
 | |
| 		break;
 | |
| 	case T_SET:
 | |
| 		memcpy(*buf, sym->sy_const.co_setval, (int) size);
 | |
| 		break;
 | |
| 	case T_STRING:
 | |
| 		memcpy(*buf, 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);
 | |
| 	if (a) {
 | |
| 		size = *psize;
 | |
| 		*buf = malloc((unsigned) size);
 | |
| 		if (! *buf) {
 | |
| 			error("could not allocate enough memory");
 | |
| 			break;
 | |
| 		}
 | |
| 		if (get_bytes(size, a, *buf)) {
 | |
| 			retval = 1;
 | |
| 		}
 | |
| 	}
 | |
| 	break;
 | |
|   }
 | |
| 
 | |
|   if (retval == 0) {
 | |
| 	if (*buf) free(*buf);
 | |
| 	*buf = 0;
 | |
| 	*psize = 0;
 | |
|   }
 | |
|   else *psize = size;
 | |
| 
 | |
|   return retval;
 | |
| }
 |