/* l2xixxpr.c LTX2X interpreter expression executor routines */
/* Written by: Peter Wilson, CUA
[email protected] */
/* This code is partly based on algorithms presented by Ronald Mak in */
/* "Writing Compilers & Interpreters", John Wiley & Sons, 1991 */
#include <stdio.h>
#include <math.h>
#include "l2xicmon.h"
#include "l2xierr.h"
#include "l2xiscan.h"
#include "l2xisymt.h"
#include "l2xiprse.h"
#include "l2xiidbg.h"
#include "l2xiexec.h"
#include "listsetc.h"
/* EXTERNALS */
extern int level;
extern ICT *code_segmentp; /* code segment ptr */ /* used? */
extern TOKEN_CODE ctoken; /* token from code segment */
extern STACK_ITEM *stack; /* runtime stack */
extern STACK_ITEM_PTR tos; /* ptr to top of runtime stack */
extern STACK_ITEM_PTR stack_frame_basep; /* ptr to stack fame base */
extern BOOLEAN is_value_undef();
extern STRING get_stacked_string();
extern STACK_TYPE form2stack[]; /* map form type to stack type */
/* FORWARDS */
TYPE_STRUCT_PTR exec_expression(), exec_simple_expression(),
exec_term(), exec_factor(),
exec_constant(), exec_variable(),
exec_subscripts();
TYPE_STRUCT_PTR exec_simple_factor(), exec_attribute();
STRING concat_strings();
/* MACROS */
/* undef_types(tp1, tp2) TRUE if either type is undef, else FALSE */
#define undef_types(tp1, tp2) ((tp1 == any_typep) || (tp2 == any_typep))
/* undef_values(sp1, sp2) TRUE if either stack value is undef */
#define undef_values(sp1, sp2) (is_value_undef(sp1) || is_value_undef(sp2))
/* set_undef(tp1) Sets tp1 to undef type */
#define set_undef(tp1) (tp1 = any_typep)
/* is_undef(tp1) TRUE if tp1 is undef type, else FALSE */
#define is_undef(tp1) (tp1 == any_typep)
/* string_operands(tp1, tp2) TRUE iff tp1 and tp2 are string types */
#define string_operands(tp1, tp2) ((tp1)->form == STRING_FORM && (tp2)->form == STRING_FORM)
/***************************************************************************/
/* exec_expression() Execute an expression */
/* <sexp> [ <relop> <sexp> ] */
/* return a pointer to the type structure. */
TYPE_STRUCT_PTR exec_expression()
{
STACK_ITEM_PTR operandp1, operandp2; /* ptrs to operands */
TYPE_STRUCT_PTR result_tp, tp1, tp2; /* ptrs to types */
TOKEN_CODE op; /* operator token */
BOOLEAN result;
LOGICAL_REP log;
entry_debug("exec_expression");
tp1 = exec_simple_expression(); /* first simple expression */
result_tp = tp1;
/* process relop sexp, if any */
if ((ctoken == EQUAL) || (ctoken == LT) || (ctoken == GT) ||
(ctoken == NE) || (ctoken == LE) || (ctoken == GE) ||
(ctoken == COLONEQUALCOLON) || (ctoken == COLONNEQCOLON) ||
(ctoken == IN) || (ctoken == XLIKE) ) {
op = ctoken;
tp1 = base_type(tp1);
result_tp = logical_typep;
get_ctoken();
tp2 = base_type(exec_simple_expression()); /* second simple expression */
/* get operands */
operandp1 = tos - 1;
operandp2 = tos;
if (undef_types(tp1, tp2) || undef_values(operandp1, operandp2)) {
put_unknown(operandp1);
pop();
expression_type_debug(result_tp);
exit_debug("exec_expression");
return(result_tp);
}
log = do_relop(operandp1, tp1, op, operandp2, tp2);
/* replace the two operands on the stack by the result */
put_logical(operandp1, log);
pop();
} /* end if on relop */
expression_type_debug(result_tp);
exit_debug("exec_expression");
return(result_tp);
} /* end exec_expression */
/***************************************************************************/
/***************************************************************************/
/* do_relop() execute a relop expression */
LOGICAL_REP do_relop(operandp1, tp1, op, operandp2, tp2)
STACK_ITEM_PTR operandp1, operandp2; /* the operands */
TYPE_STRUCT_PTR tp1, tp2; /* their types */
TOKEN_CODE op; /* the relop */
{
int result;
LOGICAL_REP log;
entry_debug("do_relop (l2xixxpr.c)");
if (((tp1 == integer_typep) && (tp2 == integer_typep)) ||
(tp1->form == ENUM_FORM)) {
/* both operands are integer, bool or enum */
switch (op) {
case EQUAL:
case COLONEQUALCOLON: {
result = get_integer(operandp1) == get_integer(operandp2);
break;
}
case LT: {
result = get_integer(operandp1) < get_integer(operandp2);
break;
}
case GT: {
result = get_integer(operandp1) > get_integer(operandp2);
break;
}
case NE:
case COLONNEQCOLON: {
result = get_integer(operandp1) != get_integer(operandp2);
break;
}
case LE: {
result = get_integer(operandp1) <= get_integer(operandp2);
break;
}
case GE: {
result = get_integer(operandp1) >= get_integer(operandp2);
break;
}
} /* end switch on op */
}
else if ((tp1 == real_typep) || (tp2 == real_typep)) {
/* One operand real, t'other real or integer */
promote_operands_to_real(operandp1, tp1, operandp2, tp2);
switch (op) {
case EQUAL:
case COLONEQUALCOLON: {
result = get_real(operandp1) == get_real(operandp2);
break;
}
case LT: {
result = get_real(operandp1) < get_real(operandp2);
break;
}
case GT: {
result = get_real(operandp1) > get_real(operandp2);
break;
}
case NE:
case COLONNEQCOLON: {
result = get_real(operandp1) != get_real(operandp2);
break;
}
case LE: {
result = get_real(operandp1) <= get_real(operandp2);
break;
}
case GE: {
result = get_real(operandp1) >= get_real(operandp2);
break;
}
} /* end switch */
}
else if (string_operands(tp1, tp2)) { /* strings */
if (op == XLIKE) {
result = like_expr(get_stacked_string(operandp1),
get_stacked_string(operandp2));
if (result < 0) { /* invalid pattern */
runtime_error(INVALID_REGULAR_EXPRESSION);
log = UNKNOWN_REP;
}
else if (result == 0) {
log = FALSE_REP;
}
else {
log = TRUE_REP;
}
exit_debug("do_relop (at LIKE)");
return(log);
}
else { /* general relational operator */
int cmp = strncmp(get_stacked_string(operandp1),
get_stacked_string(operandp2));
result = (((cmp < 0) &&
((op == NE) || (op == COLONNEQCOLON) || (op == LE) || (op == LT)))
|| ((cmp == 0) &&
((op == EQUAL) || (op == COLONEQUALCOLON) || (op == LE) || (op == GE)))
|| ((cmp > 0) &&
((op == NE) || (op == COLONNEQCOLON) || (op == GE) || (op == GT))));
}
}
else if (is_dynagg(tp1) || is_dynagg(tp2)) { /* dynamic agg */
log = exec_dynagg_relop(tp1, operandp1, op, tp2, operandp2);
exit_debug("do_relop (at dynagg)");
return(log);
}
exit_debug("do_relop");
if (result == TRUE) return(TRUE_REP);
else return(FALSE_REP);
} /* end DO_RELOP */
/***************************************************************************/
/***************************************************************************/
/* exec_simple_expression() Execute a simple expression */
/* [ <unary-op> ] <term> <pmop> <term> { <pmop> <term> } */
/* return a pointer to the type structure. */
TYPE_STRUCT_PTR exec_simple_expression()
{
STACK_ITEM_PTR operandp1, operandp2; /* ptrs to operands */
TYPE_STRUCT_PTR result_tp, tp2; /* ptrs to types */
TOKEN_CODE op; /* operator token */
TOKEN_CODE unary_op = PLUS; /* unary op token */
XPRSAINT i1;
LOGICAL_REP b1, b2, br;
XPRSAREAL r1;
STRING str;
entry_debug("exec_simple_expression");
/* remember unary op */
if ((ctoken == PLUS) || (ctoken == MINUS)) {
unary_op = ctoken;
get_ctoken();
}
result_tp = exec_term(); /* first term */
/* if there was a unary MINUS, negate the top of the stack */
if (unary_op == MINUS) {
if (!is_value_undef(tos)) {
if (result_tp == integer_typep) put_integer(tos, -get_integer(tos));
else put_real(tos, -get_real(tos));
}
}
/* loop to process following terms (seperated by <op> ) */
while ((ctoken == PLUS) || (ctoken == MINUS) ||
(ctoken == OR) || (ctoken == XXOR) ) {
op = ctoken; /* operator */
result_tp = base_type(result_tp);
get_ctoken();
tp2 = base_type(exec_term()); /* term */
operandp1 = tos - 1;
operandp2 = tos;
if (undef_values(operandp1, operandp2)) {
put_undef(operandp1);
}
else if ((op == OR) || (op == XXOR)) {
b1 = get_logical(operandp1);
b2 = get_logical(operandp2);
br = FALSE_REP;
if (op == OR) { /* term OR term */
if (b1 == FALSE_REP && b2 == FALSE_REP) {
br = FALSE_REP;
}
else if (b1 == UNKNOWN_REP &&
(b2 == UNKNOWN_REP || b2 == FALSE_REP)) {
br = UNKNOWN_REP;
}
else if (b1 == FALSE_REP && b2 == UNKNOWN_REP) {
br = UNKNOWN_REP;
}
else {
br = TRUE_REP;
}
}
else { /* term XOR term */
if (b1 == TRUE_REP && b2 == TRUE_REP) {
br = FALSE_REP;
}
else if (b1 == TRUE_REP && b2 == FALSE_REP) {
br = TRUE_REP;
}
else if (b1 == FALSE_REP && b2 == TRUE_REP) {
br = TRUE_REP;
}
else if (b1 == FALSE_REP && b2 == FALSE_REP) {
br = FALSE_REP;
}
else {
br = UNKNOWN_REP;
}
}
put_logical(operandp1, br);
result_tp = logical_typep;
}
/* op is + or - */
else if ((result_tp == integer_typep) &&
(tp2 == integer_typep)) {
/* both operands are integer */
i1 = (op == PLUS)
? get_integer(operandp1) + get_integer(operandp2)
: get_integer(operandp1) - get_integer(operandp2);
put_integer(operandp1, i1);
result_tp = integer_typep;
}
else if ((result_tp == string_typep || result_tp->form == STRING_FORM) &&
(tp2 == string_typep || tp2->form == STRING_FORM)) {
/* two strings, plus is only operator */
if (op == PLUS) {
str = concat_strings(operandp1, operandp2);
free(get_stacked_string(operandp1));
put_string(operandp1, str);
result_tp = string_typep;
result_tp->form == STRING_FORM;
}
}
else {
/* mix of real and integer */
promote_operands_to_real(operandp1, result_tp, operandp2, tp2);
r1 = (op == PLUS)
? get_real(operandp1) + get_real(operandp2)
: get_real(operandp1) - get_real(operandp2);
put_real(operandp1, r1);
result_tp = real_typep;
}
/* pop off the second operand */
pop();
} /* end while over <op> <term> */
exit_debug("exec_simple_expression");
return(result_tp);
} /* end exec_simple_expression */
/***************************************************************************/
/***************************************************************************/
/* exec_term() Execute a term */
/* <factor> <multop> <factor> { <multop> <factor> } */
/* return a pointer to the type structure. */
TYPE_STRUCT_PTR exec_term()
{
STACK_ITEM_PTR operandp1, operandp2; /* ptrs to operands */
TYPE_STRUCT_PTR result_tp, tp2; /* ptrs to types */
TOKEN_CODE op; /* operator token */
XPRSAINT i1;
XPRSAREAL r1;
LOGICAL_REP b1, b2, br;
entry_debug("exec_term");
result_tp = exec_factor(); /* first factor */
/* loop to process following <multop> <factor> pairs */
while ((ctoken == STAR) || (ctoken == SLASH) || (ctoken == DIV) ||
(ctoken == MOD) || (ctoken == AND) || (ctoken == BARBAR)) {
op = ctoken;
result_tp = base_type(result_tp);
get_ctoken();
tp2 = exec_factor(); /* next factor */
operandp1 = tos - 1;
operandp2 = tos;
if (undef_values(operandp1, operandp2)) {
put_undef(operandp1);
}
else if (op == AND) {
b1 = get_logical(operandp1);
b2 = get_logical(operandp2);
if (b1 == TRUE_REP && b2 == TRUE_REP) {
br = TRUE_REP;
}
else if (b1 == TRUE_REP && b2 == UNKNOWN_REP) {
br = UNKNOWN_REP;
}
else if (b1 == UNKNOWN_REP && b2 == TRUE_REP) {
br = UNKNOWN_REP;
}
else if (b1 == UNKNOWN_REP && b2 == UNKNOWN_REP) {
br = UNKNOWN_REP;
}
else {
br = FALSE_REP;
}
put_logical(operandp1, br);
result_tp = logical_typep;
}
else if (op == BARBAR) {
runtime_error(UNIMPLEMENTED_RUNTIME_FEATURE);
/* result_tp = &dummy_typep; */
}
else {
/* *, /, DIV or MOD */
switch (op) {
case STAR: {
if ((result_tp == integer_typep) && (tp2 == integer_typep)) {
/* integer operands */
i1 = get_integer(operandp1) * get_integer(operandp2);
put_integer(operandp1, i1);
result_tp = integer_typep;
}
else {
/* at least one real */
promote_operands_to_real(operandp1, result_tp, operandp2, tp2);
r1 = get_real(operandp1) * get_real(operandp2);
put_real(operandp1, r1);
result_tp = real_typep;
}
break;
}
case SLASH: {
promote_operands_to_real(operandp1, result_tp, operandp2, tp2);
if (get_real(operandp2) == 0.0) {
runtime_error(DIVISION_BY_ZERO);
}
else {
r1 = get_real(operandp1) / get_real(operandp2);
put_real(operandp1, r1);
}
result_tp = real_typep;
break;
}
case DIV:
case MOD: {
/* both operands integer */
if (get_integer(operandp2) == 0) {
runtime_error(DIVISION_BY_ZERO);
}
else {
i1 = (op == DIV)
? get_integer(operandp1) / get_integer(operandp2)
: get_integer(operandp1) % get_integer(operandp2);
put_integer(operandp1, i1);
}
result_tp = integer_typep;
break;
}
} /* end switch */
}
/* pop off the second operand */
pop();
} /* end while over op/factor pairs */
exit_debug("exec_term");
return(result_tp);
} /* end exec_term */
/***************************************************************************/
/***************************************************************************/
/* exec_factor() Execute an EXPRESS factor */
/* <simple_factor> ** <simple_factor> */
/* return a pointer to the type structure */
TYPE_STRUCT_PTR exec_factor()
{
TYPE_STRUCT_PTR result_tp; /* ptr to type */
STACK_ITEM_PTR operand1, operand2; /* ptrs to operands */
TYPE_STRUCT_PTR tp2;
XPRSAINT i1, i2, i;
XPRSAREAL r1, r2, r;
entry_debug("exec_factor");
result_tp = exec_simple_factor(); /* first operand */
if (ctoken == STARSTAR) { /* have an operator */
result_tp = base_type(result_tp);
get_ctoken();
tp2 = base_type(exec_simple_factor());
operand1 = tos - 1;
operand2 = tos;
if (undef_values(operand1, operand2)) {
put_undef(operand1);
}
else if ((result_tp == integer_typep) && (tp2 == integer_typep)) {
/* integer operands */
i1 = get_integer(operand1);
i2 = get_integer(operand2);
if ((i1 == 0) && (i2 <= 0) ) {
runtime_error(INVALID_FUNCTION_ARGUMENT);
}
else {
i = (XPRSAINT) pow((double) i1, (double) i2);
sprintf(dbuffer, "i1= %d, i2= %d, pow(i1, i2)= %d\n", i1, i2, i);
debug_print(dbuffer);
put_integer(operand1, i);
result_tp = integer_typep;
}
}
else {
/* at least one real */
if ((tp2 == integer_typep)) { /* first real, second int */
r1 = get_real(operand1);
i2 = get_integer(operand2);
if ((r1 == 0.0) && (i2 <= 0)) {
runtime_error(INVALID_FUNCTION_ARGUMENT);
}
else {
r = (XPRSAREAL) pow((double) r1, (double) i2);
put_real(operand1, r);
result_tp = real_typep;
}
}
else if ((result_tp == real_typep) && (tp2 == real_typep)) {
r1 = get_real(operand1);
r2 = get_real(operand2);
if (((r1 == 0.0) && (r2 <= 0.0)) || (r1 < 0.0)) {
runtime_error(INVALID_FUNCTION_ARGUMENT);
}
else {
r = (XPRSAREAL) pow((double) r1, (double) r2);
put_real(operand1, r);
result_tp = real_typep;
}
}
else { /* first int, second real */
i1 = get_integer(operand1);
r2 = get_real(operand2);
if ((i1 == 0) && (r2 <= 0.0)) {
runtime_error(INVALID_FUNCTION_ARGUMENT);
}
else {
r = (XPRSAREAL) pow((double) i1, (double) r2);
put_real(operand1, r);
result_tp = real_typep;
}
}
}
pop(); /* pop off the second operand */
}
exit_debug("exec_factor");
return(result_tp);
} /* end EXEC_FACTOR */
/***************************************************************************/
/***************************************************************************/
/* exec_simple_factor() Execute a simple factor */
/* <variable> | <number> | NOT <simple_factor> | ( <expression> ) */
/* or an interval expression = {expr op expr op expr} */
/* return a pointer to the type structure. */
TYPE_STRUCT_PTR exec_simple_factor()
{
TYPE_STRUCT_PTR result_tp; /* ptr to type */
TYPE_STRUCT_PTR tp1, tp2, tp3;
LOGICAL_REP b1, br;
TOKEN_CODE op1, op2;
STACK_ITEM_PTR operandp1, operandp2, operandp3;
STACK_TYPE t1, t2, t3;
entry_debug("exec_simple_factor");
switch (ctoken) {
case IDENTIFIER: {
SYMTAB_NODE_PTR idp = get_symtab_cptr();
if (idp->defn.key == FUNC_DEFN) {
result_tp = exec_routine_call(idp);
}
else if (idp->defn.key == CONST_DEFN) {
result_tp = exec_constant(idp);
}
else {
result_tp = exec_variable(idp, EXPR_USE);
}
break;
}
case NUMBER_LITERAL: {
SYMTAB_NODE_PTR np = get_symtab_cptr();
/* get the number from the symbol table and push it on the stack */
if (np->typep == integer_typep) {
push_integer(np->defn.info.constant.value.integer);
result_tp = integer_typep;
}
else {
push_real(np->defn.info.constant.value.real);
result_tp = real_typep;
}
get_ctoken();
break;
}
case STRING_LITERAL: {
SYMTAB_NODE_PTR np = get_symtab_cptr();
int length = strlen(np->name);
push_string((STRING) np->info);
result_tp = np->typep;
get_ctoken();
break;
}
case NOT: {
get_ctoken();
result_tp = exec_simple_factor();
if (is_undef(result_tp) || is_value_undef(tos)) {
put_undef(tos);
}
else {
b1 = get_logical(tos);
if (b1 == TRUE_REP) {
br = FALSE_REP;
}
else if (b1 == FALSE_REP) {
br = TRUE_REP;
}
else {
br = UNKNOWN_REP;
}
put_logical(tos, br); /* TRUE -> FALSE, FALSE -> TRUE */
}
break;
}
case LPAREN: {
get_ctoken();
result_tp = exec_expression();
get_ctoken(); /* the token after the ) */
break;
}
case LBRACE: { /* interval expression */
result_tp = logical_typep;
get_ctoken();
tp1 = exec_simple_expression();
op1 = ctoken;
get_ctoken();
tp2 = exec_simple_expression();
op2 = ctoken;
get_ctoken();
tp3 = exec_simple_expression();
get_ctoken(); /* the token after the } */
operandp1 = tos - 2;
operandp2 = tos - 1;
operandp3 = tos;
pop();
pop();
/* check if anything is indeterminate */
t1 = get_stackval_type(operandp1);
if (t1 == STKUDF) {
put_unknown(operandp1);
break;
}
t2 = get_stackval_type(operandp2);
if (t2 == STKUDF) {
put_unknown(operandp1);
break;
}
t3 = get_stackval_type(operandp3);
if (t3 == STKUDF) {
put_unknown(operandp1);
break;
}
/* check first condition */
b1 = do_relop(operandp1, tp1, op1, operandp2, tp2);
if (b1 == FALSE_REP) {
put_false(operandp1);
break;
}
/* and the second */
br = do_relop(operandp2, tp2, op2, operandp3, tp3);
if (br == FALSE_REP) {
put_false(operandp1);
break;
}
if (b1 == TRUE_REP && br == TRUE_REP) {
put_true(operandp1);
}
else {
put_unknown(operandp1);
}
break;
}
} /* end switch */
expression_type_debug(result_tp);
exit_debug("exec_simple_factor");
return(result_tp);
} /* end exec_simple_factor */
/***************************************************************************/
/***************************************************************************/
/* exec_constant(idp) Push the value of a non-string constant id, */
/* or the address of a string constant id onto the stack */
/* return a pointer to the type structure. */
TYPE_STRUCT_PTR exec_constant(idp)
SYMTAB_NODE_PTR idp; /* constant id */
{
TYPE_STRUCT_PTR tp = idp->typep; /* ptrs to types */
entry_debug("exec_constant");
if (base_type(tp) == logical_typep) {
push_logical(idp->defn.info.constant.value.integer);
}
else if ((base_type(tp) == integer_typep) || (tp->form == ENUM_FORM)) {
push_integer(idp->defn.info.constant.value.integer);
}
else if (tp == real_typep) {
push_real(idp->defn.info.constant.value.real);
}
else if (tp->form == ARRAY_FORM) {
push_address((ADDRESS) idp->defn.info.constant.value.stringp);
}
else if (tp->form == STRING_FORM) {
push_string((STRING) idp->defn.info.constant.value.stringp);
}
else if (is_undef(tp)) {
push_undef();
}
trace_data_fetch(idp, tp, tos);
get_ctoken();
exit_debug("exec_constant");
return(tp);
} /* end exec_constant */
/***************************************************************************/
/***************************************************************************/
/* exec_variable(idp, use) Push either the variable's address or its */
/* value onto the stack */
/* return a pointer to the type structure. */
TYPE_STRUCT_PTR exec_variable(idp, use)
SYMTAB_NODE_PTR idp; /* variable id */
USE use; /* how variable is used */
{
int delta; /* difference in levels */
TYPE_STRUCT_PTR tp = idp->typep; /* ptrs to types */
TYPE_STRUCT_PTR base_tp; /* ptrs to types */
STACK_ITEM_PTR datap; /* ptr to data area */
STACK_ITEM_PTR hp;
STACK_TYPE stype;
entry_debug("exec_variable (l2xixxpr.c)");
/* point to the variable's stack item. If the variable's level */
/* is less than the current level, follow the static links to the */
/* appropriate stack frame base */
hp = (STACK_ITEM_PTR) stack_frame_basep;
delta = level - idp->level;
while (delta-- > 0) {
hp = (STACK_ITEM_PTR) get_static_link(hp);
}
datap = hp + idp->defn.info.data.offset;
/* If a scalar or enumeration VAR parm, that item points to the */
/* actual item */
if ((idp->defn.key == VARPARM_DEFN) &&
(tp->form != ARRAY_FORM) &&
(tp->form != ENTITY_FORM) &&
(tp->form != BAG_FORM) &&
(tp->form != LIST_FORM) &&
(tp->form != SET_FORM)) {
datap = (STACK_ITEM_PTR) get_address(datap);
}
/* push the address of the variables data area */
if ((tp->form == BAG_FORM) ||
(tp->form == LIST_FORM) ||
(tp->form == SET_FORM)) {
stype = form2stack[tp->form];
push_address_type(get_address_type(datap, stype), stype);
}
else if ((tp->form == ARRAY_FORM) ||
(tp->form == ENTITY_FORM)) {
push_address((ADDRESS) get_address(datap));
}
else {
push_address((ADDRESS) datap);
}
get_ctoken();
/* for a string, may be dealing with a substring only */
if (tp->form == STRING_FORM) {
if (ctoken == LBRACKET) {
exec_substring(use);
if (use != TARGET_USE && use != VARPARM_USE) {
exit_debug("exec_variable");
return(tp);
}
}
}
else {
/* if there are any subscripts or attribute designators, */
/* modify the address to point to the array element record field */
while ((ctoken == LBRACKET) || (ctoken == PERIOD)) {
if (ctoken == LBRACKET) tp = exec_subscripts(tp);
else if (ctoken == PERIOD) tp = exec_attribute();
}
}
base_tp = base_type(tp);
/* leave the modified address on top of the stack if it: */
/* is an assignment target */
/* represents a parameter passed by reference */
/* is the address of an array or entity */
/* Otherwise, replace the address with the value it points to */
if ((use != TARGET_USE) && (use != VARPARM_USE) &&
(tp->form != ARRAY_FORM) &&
(tp->form != ENTITY_FORM) &&
(tp->form != BAG_FORM) &&
(tp->form != LIST_FORM) &&
(tp->form != SET_FORM)) {
if (is_value_undef(get_address(tos))) {
put_undef(tos);
}
else if (base_tp == logical_typep) {
put_logical(tos, get_logical(get_address(tos)));
}
else if ((base_tp == integer_typep) || (tp->form == ENUM_FORM)) {
put_integer(tos, get_integer(get_address(tos)));
}
else if (tp->form == STRING_FORM) {
put_string(tos, get_stacked_string(get_address(tos)));
}
else if (tp->form == BAG_FORM ||
tp->form == LIST_FORM ||
tp->form == SET_FORM) {
stype = get_stackval_type(tos);
put_address_type(tos, get_address_type(tos, stype), stype);
}
else {
put_real(tos, get_real(get_address(tos)));
}
}
if ((use != TARGET_USE) && (use != VARPARM_USE)) {
stype = get_stackval_type(tos);
if ((tp->form == ARRAY_FORM) ||
(tp->form == ENTITY_FORM) ||
(tp->form == BAG_FORM) ||
(tp->form == LIST_FORM) ||
(tp->form == SET_FORM)) {
trace_data_fetch(idp, tp, get_address_type(tos, stype));
}
else {
trace_data_fetch(idp, tp, tos);
}
}
expression_type_debug(tp);
exit_debug("exec_variable");
return(tp);
} /* end exec_variable */
/***************************************************************************/
/***************************************************************************/
/* exec_substring() Execute subscripts to modify the string on top */
/* of the stack */
/* at entry: ctoken is the opening [ */
/* at exit: ctoken is after the closing ] */
exec_substring(usage)
USE usage; /* how the var is used */
{
XPRSAINT subscript1_value, subscript2_value;
STRING strorig;
STRING strnew;
int num, i, j;
entry_debug("exec_substring (l2xixxpr.c)");
/* save the current string */
strorig = get_stacked_string(get_address(tos));
/* do first expression */
get_ctoken();
exec_expression();
subscript1_value = get_integer(tos);
pop();
/* check value in range */
if ((subscript1_value < 1) ||
(subscript1_value > MAX_EXPRESS_STRING)) {
runtime_error(VALUE_OUT_OF_RANGE);
}
subscript2_value = subscript1_value;
if (ctoken == COLON) { /* do next expression */
get_ctoken();
exec_expression();
subscript2_value = get_integer(tos);
pop();
/* check value in range */
if ((subscript2_value < subscript1_value) ||
(subscript2_value > MAX_EXPRESS_STRING)) {
runtime_error(VALUE_OUT_OF_RANGE);
}
}
get_ctoken(); /* token after closing ] */
/* now do the substring stuff */
num = (subscript2_value - subscript1_value + 1); /* no of chars */
strnew = alloc_bytes(num+1);
j = 0;
for (i = subscript1_value - 1; i < subscript2_value; i++) {
strnew[j] = strorig[i];
j++;
}
strnew[j] = '\0';
/* replace strorig in the stack with strnew, unless a lhs */
if (usage != TARGET_USE && usage != VARPARM_USE) {
put_string(tos, strnew);
}
exit_debug("exec_substring");
return;
} /* end EXEC_SUBSTRING */
/***************************************************************************/
/***************************************************************************/
/* exec_subscripts(tp) Execute subscripts to modify the array data area */
/* address on the top of the stack */
/* return a pointer to the type of the array element */
TYPE_STRUCT_PTR exec_subscripts(tp)
TYPE_STRUCT_PTR tp; /* ptr to type structure */
{
XPRSAINT subscript_value;
STACK_ITEM_PTR adr, dat;
STACK_TYPE stype;
LBS_PTR lbs;
LBS_NODE_PTR node;
entry_debug("exec_subscripts");
/* loop to execute bracketed subscripts */
if (tp->form == ARRAY_FORM) {
while (ctoken == LBRACKET) {
/* loop to execute a subscript list */
do {
get_ctoken();
exec_expression();
subscript_value = get_integer(tos);
pop();
/* range check */
if ((subscript_value < tp->info.array.min_index) ||
(subscript_value > tp->info.array.max_index)) {
runtime_error(VALUE_OUT_OF_RANGE);
}
/* modify the data area address */
adr = (STACK_ITEM_PTR) get_address(tos);
adr = adr +
((subscript_value - tp->info.array.min_index) *
(tp->info.array.elmt_typep->size))/sizeof(STACK_ITEM);
put_address(tos, adr);
if (ctoken == COMMA) tp = tp->info.array.elmt_typep;
} while (ctoken == COMMA); /* end do */
get_ctoken();
if (ctoken == LBRACKET) tp = tp->info.array.elmt_typep;
} /* end while */
} /* end of array processing */
else if (tp->form == BAG_FORM ||
tp->form == LIST_FORM ||
tp->form == SET_FORM) { /* dynamic aggregate */
stype = form2stack[tp->form];
while (ctoken == LBRACKET) {
get_ctoken();
exec_expression();
subscript_value = get_integer(tos);
pop();
/* range check */
if ((subscript_value < tp->info.dynagg.min_index) ||
(subscript_value > tp->info.dynagg.max_index)) {
runtime_error(VALUE_OUT_OF_RANGE);
}
/* get the element from the aggregate */
lbs = (LBS_PTR) get_address_type(tos, stype);
/* outside element count? */
sprintf(dbuffer, "lbs = %d, el count = %d, subscript = %d\n",
lbs, NELS(lbs), subscript_value);
debug_print(dbuffer);
if (subscript_value > NELS(lbs)) runtime_error(VALUE_OUT_OF_RANGE);
node = lbs_get_nth(lbs, subscript_value);
sprintf(dbuffer, "node = %d\n", node);
debug_print(dbuffer);
/* put the element data on top of the stack */
dat = (STACK_ITEM_PTR) DATA(node);
sprintf(dbuffer, "data = %d\n", dat);
debug_print(dbuffer);
copy_value(tos, dat);
get_ctoken();
if (ctoken == LBRACKET) tp = tp->info.dynagg.elmt_typep;
} /* end while */
} /* end of dynamic aggregate processing */
exit_debug("exec_subscripts");
return(tp);
} /* end exec_subscripts */
/***************************************************************************/
/***************************************************************************/
/* exec_attribute() Execute an attribute designator to modify the */
/* entity data */
/* address area on the top of the stack */
/* return a pointer to the type of the attribute */
TYPE_STRUCT_PTR exec_attribute()
{
SYMTAB_NODE_PTR attr_idp;
ADDRESS adr;
entry_debug("exec_attribute (l2xixxpr.c)");
get_ctoken();
attr_idp = get_symtab_cptr();
adr = get_address(tos);
adr += attr_idp->defn.info.data.offset;
put_address(tos, adr);
get_ctoken();
exit_debug("exec_attribute");
return(attr_idp->typep);
} /* end EXEC_ATTRIBUTE */
/***************************************************************************/
/***************************************************************************/
/* promote_operands_to_real(operandp1, tp1, operandp2, tp2) If either */
/* operand is integer, convert it to real */
promote_operands_to_real(operandp1, tp1, operandp2, tp2)
STACK_ITEM_PTR operandp1, operandp2; /* ptrs to operands */
TYPE_STRUCT_PTR tp1, tp2; /* ptrs to types */
{
XPRSAINT i1;
entry_debug("promote_operands_to_real");
if (tp1 == integer_typep) {
if (!is_value_undef(operandp1)) {
i1 = get_integer(operandp1);
put_real(operandp1, (XPRSAREAL) i1);
}
}
if (tp2 == integer_typep) {
if (!is_value_undef(operandp2)) {
i1 = get_integer(operandp2);
put_real(operandp2, (XPRSAREAL) i1);
}
}
exit_debug("promote_operands_to_real");
return;
} /* end promote_operands_to_real */
/***************************************************************************/
/***************************************************************************/
/* concat_strings() Concatenate two strings */
STRING concat_strings(op1, op2)
STACK_ITEM_PTR op1; /* pos of first string in the stack */
STACK_ITEM_PTR op2; /* pos of second string in the stack */
{
int n1 = strlen(get_stacked_string(op1));
int n2 = strlen(get_stacked_string(op2));
int tot, i, j;
STRING str = NULL;
STRING two;
entry_debug("concat_strings (l2xixxpr.c)");
tot = n1 + n2;
if (tot <= MAX_EXPRESS_STRING) {
str = alloc_bytes(n1 + n2 + 1);
strcpy(str, get_stacked_string(op1));
strcat(str, get_stacked_string(op2));
}
else {
runtime_error(RUNTIME_STRING_TOO_LONG);
tot = MAX_EXPRESS_STRING;
str = alloc_bytes(tot + 1);
strcpy(str, get_stacked_string(op1));
two = get_stacked_string(op2);
j = n1;
for (i = 0; j <= tot; i++) {
str[j++] = two[i];
}
str[j] = '\0';
}
exit_debug("concat_strings");
return(str);
} /* end CONCAT_STRINGS */
/***************************************************************************/
/***************************************************************************/
/* exec_dynagg_relop(t1, p1, op, t2, p2) Execute a relop on dynamic */
/* aggregates */
/* p1 op p2 */
/* returns a logical result */
LOGICAL_REP exec_dynagg_relop(t1, p1, op, t2, p2)
TYPE_STRUCT_PTR t1; /* type of p1 */
STACK_ITEM_PTR p1; /* value of p1 */
TOKEN_CODE op; /* the operator */
TYPE_STRUCT_PTR t2; /* type of p2 */
STACK_ITEM_PTR p2; /* value of p2 */
{
LOGICAL_REP result;
STACK_ITEM_PTR agg;
LBS_NODE_PTR nod, nextnod;
STACK_TYPE agtp = get_stackval_type(p2);
LBS_PTR head;
entry_debug("exec_dynagg_relop (l2xixxpr.c)");
sprintf(dbuffer, "t1 = %d, p1 = %d, t2 = %d, p2 = %d\n", t1, p1, t2, p2);
debug_print(dbuffer);
if (op == IN) { /* element IN agg */
if (t1 != t2->info.dynagg.elmt_typep) { /* not an element */
exit_debug("exec_dynagg_relop");
return(FALSE_REP);
}
/* get first node */
head = (LBS_PTR) get_address_type(p2, agtp);
debug_print("Getting first node\n");
nod = lbs_get_next_el(head, NULL);
sprintf(dbuffer, "nod = %d\n", nod);
debug_print(dbuffer);
while (nod != NULL) { /* loop over all nodes */
debug_print("Testing for value equality\n");
sprintf(dbuffer, "data = %d\n", DATA(nod));
debug_print(dbuffer);
result = stack_value_equal(p1, DATA(nod));
if (result == UNKNOWN_REP || result == TRUE_REP) {
exit_debug("exec_dynagg_relop (p1 IN p2 not FALSE)");
return(result);
}
debug_print("Getting next node\n");
nod = lbs_get_next_el(head, nod);
sprintf(dbuffer, "nod = %d\n", nod);
debug_print(dbuffer);
}
exit_debug("exec_dynagg_relop (p1 IN p2 is FALSE");
return(FALSE_REP);
}
else {
runtime_error(UNIMPLEMENTED_RUNTIME_FEATURE);
exit_debug("exec_dynagg_relop");
return(UNKNOWN_REP);
}
} /* end EXEC_DYNAGG_RELOP */
/***************************************************************************/