/* l2xixstd.c LTX2X interpreter standard procedure/function 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 <stdlib.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"
#define DEFAULT_NUMERIC_FIELD_WIDTH 10
#define DEFAULT_PRECISION 4
/* added for ltx2x */
#define MAX_LTX2X_BUFFER 2000
/* EXTERNALS */
extern int level;
extern int exec_line_number; /* no. of line executed */
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 STACK_ITEM_PTR stack_display[]; /* ????????? */
extern BOOLEAN is_value_undef();
extern STRING get_stacked_string();
extern STACK_TYPE form2stack[]; /* map form type to stack type */
extern TYPE_FORM stack2form[]; /* map stack type to form type */
extern STACK_ITEM_PTR create_copy_value();
/* FORWARDS */
TYPE_STRUCT_PTR exec_eof_eoln(), exec_abs_sqr(),
exec_arctan_cos_exp_ln_sin_sqrt(),
exec_odd(), exec_round_trunc();
TYPE_STRUCT_PTR exec_atan(), exec_exists_etc(), exec_nvl_etc();
TYPE_STRUCT_PTR exec_rexpr_etc(), exec_hibound_etc(), exec_length_etc();
/* GLOBALS */
BOOLEAN eof_flag = FALSE;
char acbuffer[MAX_LTX2X_BUFFER]; /* added for ltx2x */
/************************************************************************/
/* exec_standard_routine_call(rtn_idp) Execute a call to a standard */
/* procedure or function */
/* return a pointer to the type stucture of the call */
TYPE_STRUCT_PTR exec_standard_routine_call(rtn_idp)
SYMTAB_NODE_PTR rtn_idp; /* routine id */
{
entry_debug("exec_standard_routine_call");
switch (rtn_idp->defn.info.routine.key) {
case READ:
case READLN: {
exec_read_readln(rtn_idp);
exit_debug("exec_standard_routine_call");
return(NULL);
}
case WRITE:
case WRITELN: {
exec_write_writeln(rtn_idp);
exit_debug("exec_standard_routine_call");
return(NULL);
}
case EOFF:
case EOLN: {
exit_debug("exec_standard_routine_call");
return(exec_eof_eoln(rtn_idp));
}
case ABS: /* real or int -> real or int */
{
exit_debug("exec_standard_routine_call");
return(exec_abs_sqr(rtn_idp));
}
case COS: /* real or int -> real */
case EXP:
case SIN:
case SQRT:
case XACOS:
case XASIN:
case XLOG:
case XLOG2:
case XLOG10:
case XTAN: {
exit_debug("exec_standard_routine_call");
return(exec_arctan_cos_exp_ln_sin_sqrt(rtn_idp));
}
case XATAN: { /* extra for EXPRESS */
exit_debug("exec_standard_routine_call");
return(exec_atan(rtn_idp));
}
case ODD: { /* int -> boolean */
exit_debug("exec_standard_routine_call");
return(exec_odd());
}
case ROUND: /* real -> int */
case TRUNC: {
exit_debug("exec_standard_routine_call");
return(exec_round_trunc(rtn_idp));
}
case L2XPRINT:
case L2XPRINTLN: { /* added for ltx2x */
exec_print_println(rtn_idp);
exit_debug("exec_standard_routine_call");
return(NULL);
}
case L2XSYSTEM: { /* added for ltx2x */
exec_system_etc(rtn_idp);
exit_debug("exec_standard_routine_call");
return(NULL);
}
case L2XREXPR: { /* added for ltx2x */
exit_debug("exec_standard_routine_call");
return(exec_rexpr_etc(rtn_idp));
}
case XHIBOUND:
case XHIINDEX:
case XLOBOUND:
case XLOINDEX:
case XSIZEOF: {
exit_debug("exec_standard_routine_call");
return(exec_hibound_etc(rtn_idp));
}
case XLENGTH: {
exit_debug("exec_standard_routine_call");
return(exec_length_etc(rtn_idp));
}
case XEXISTS: {
exit_debug("exec_standard_routine_call");
return(exec_exists_etc(rtn_idp));
}
case XNVL: {
exit_debug("exec_standard_routine_call");
return(exec_nvl_etc(rtn_idp));
}
case XINSERT:
case XREMOVE: {
exec_insert_etc(rtn_idp);
exit_debug("exec_standard_routine_call");
return(NULL);
}
case XBLENGTH:
case XFORMAT:
case XROLESOF:
case XTYPEOF:
case XUSEDIN:
case XVALUE:
case XVALUE_IN:
case XVALUE_UNIQUE: { /* unimplemented EXPRESS stuff */
runtime_error(UNIMPLEMENTED_RUNTIME_FEATURE);
exit_debug("exec_standard_routine_call");
return(NULL);
}
default: {
runtime_error(UNIMPLEMENTED_RUNTIME_FEATURE);
break;
}
} /* end switch */
exit_debug("exec_standard_routine_call");
return(NULL);
} /* end exec_standard_routine_call */
/************************************************************************/
/************************************************************************/
/* exec_read_readln(rtn_idp) Execute a call to READ or READLN */
exec_read_readln(rtn_idp)
SYMTAB_NODE_PTR rtn_idp; /* routine id */
{
SYMTAB_NODE_PTR parm_idp; /* param id */
TYPE_STRUCT_PTR parm_tp; /* param type */
STACK_ITEM_PTR targetp; /* ptr to read target */
XPRSAINT i1;
XPRSAREAL r1;
int len;
char ch;
char tbuff[MAX_LTX2X_BUFFER];
STRING lhs;
entry_debug("exec_read_readln");
/* params are optional for readln */
get_ctoken();
if (ctoken == LPAREN) { /* id list */
do {
get_ctoken();
parm_idp = get_symtab_cptr();
parm_tp = base_type(exec_variable(parm_idp, VARPARM_USE));
targetp = (STACK_ITEM_PTR) get_address(tos);
pop(); /* pop off address */
if (parm_tp == integer_typep) {
scanf("%d", &i1);
put_integer(targetp, i1);
}
else if (parm_tp == real_typep) {
scanf("%g", &r1);
put_real(targetp, r1);
}
else { /* a string or a logical */
scanf("%sMAX_LTX2X_BUFFER", tbuff);
len = strlen(tbuff);
sprintf(dbuffer, "strlen(str) = %d, str = %s\n", len, tbuff);
debug_print(dbuffer);
if (parm_tp == logical_typep) { /* check which one */
if (len == 4 && (tbuff[0] == 't' || tbuff[0] == 'T')) { /* TRUE */
put_true(targetp);
}
else if (len == 5 && (tbuff[0] == 'f' || tbuff[0] == 'F')) { /* FALSE */
put_false(targetp);
}
else if (len == 7 && (tbuff[0] == 'u' || tbuff[0] == 'U')) { /* UNKNOWN */
put_unknown(targetp);
}
else { /* an error */
runtime_error(INVALID_FUNCTION_ARGUMENT);
put_unknown(targetp);
}
}
else { /* a string */
free(targetp->value.string);
lhs = alloc_bytes(len+1);
sprintf(dbuffer, "lhs = %d", lhs);
debug_print(dbuffer);
strcpy(lhs, tbuff);
sprintf(dbuffer, ", str = %s\n", lhs);
debug_print(dbuffer);
put_string(targetp, lhs);
}
}
trace_data_store(parm_idp, parm_idp->typep, targetp, parm_tp);
} while (ctoken == COMMA); /* end do */
get_ctoken(); /* token after RPAREN */
}
if (rtn_idp->defn.info.routine.key == READLN) {
do {
ch = getchar();
} while(!eof_flag && (ch != '\n'));
}
exit_debug("exec_read_readln");
return;
} /* end exec_read_readln */
/************************************************************************/
/************************************************************************/
/* exec_write_writeln(rtn_idp) Execute a call to WRITE or WRITELN */
/* Each actual parameter can be: <expr> */
/* or <expr> : <expr> */
/* or <expr> : <expr> : <expr> */
exec_write_writeln(rtn_idp)
SYMTAB_NODE_PTR rtn_idp; /* routine id */
{
TYPE_STRUCT_PTR parm_tp; /* parameter type */
STACK_TYPE stype;
XPRSAINT field_width;
XPRSAINT precision;
entry_debug("exec_write_writeln");
/* parameters are optional for writeln */
get_ctoken();
if (ctoken == LPAREN) {
do {
/* push value */
get_ctoken();
parm_tp = base_type(exec_expression());
/* check if dynamic agg */
if (is_dynagg(parm_tp)) parm_tp = parm_tp->info.dynagg.elmt_typep;
field_width = DEFAULT_NUMERIC_FIELD_WIDTH;
precision = DEFAULT_PRECISION;
/* optional field width expresion */
if (ctoken == COLON) {
get_ctoken();
exec_expression();
if (!is_value_undef(tos)) {
field_width = get_integer(tos);
}
pop(); /* field width */
/* optional decimal places expresion */
if (ctoken == COLON) {
get_ctoken();
exec_expression();
if (!is_value_undef(tos)) {
precision = get_integer(tos);
}
pop(); /* precision */
}
}
if (parm_tp->form == ARRAY_FORM) { /* array, address on top of stack */
if (get_stackval_type(tos) == STKADD) {
copy_value(tos, get_address(tos));
}
}
stype = get_stackval_type(tos);
/* write value */
if (is_value_undef(tos)) {
printf("%*c", field_width, get_undef(tos));
}
else if (stype == STKINT) {
printf("%*d", field_width, get_integer(tos));
}
else if (stype == STKREA) {
printf("%*.*g", field_width, precision, get_real(tos));
}
else if (stype == STKLOG) {
field_width = 0;
switch (get_logical(tos)) {
case TRUE_REP: {
printf("%*s", -field_width, "TRUE");
break;
}
case FALSE_REP: {
printf("%*s", -field_width, "FALSE");
break;
}
case UNKNOWN_REP: {
printf("%*s", -field_width, "UNKNOWN");
break;
}
default: {
printf("%*s", -field_width, "??UNKNOWN??");
break;
}
} /* end switch */
}
else if (parm_tp == string_typep || parm_tp->form == STRING_FORM) {
field_width = 0;
printf("%*s", -field_width, get_stacked_string(tos) );
}
pop(); /* value */
} while (ctoken == COMMA); /* end do */
get_ctoken(); /* token after RPAREN */
} /* end of if over parameters */
if (rtn_idp->defn.info.routine.key == WRITELN) putchar('\n');
exit_debug("exec_write_writeln");
return;
} /* end exec_write_writeln */
/************************************************************************/
/************************************************************************/
/* exec_print_println(rtn_idp) Execute a call to PRINT or PRINTLN */
/* Each actual parameter can be: <expr> */
/* or <expr> : <expr> */
/* or <expr> : <expr> : <expr> */
/* Identical to exec_write_writeln, except output is to ltx2x myprint */
exec_print_println(rtn_idp)
SYMTAB_NODE_PTR rtn_idp; /* routine id */
{
TYPE_STRUCT_PTR parm_tp; /* parameter type */
STACK_TYPE stype;
XPRSAINT field_width;
XPRSAINT precision;
entry_debug("exec_print_println");
/* parameters are optional for println */
get_ctoken();
if (ctoken == LPAREN) {
do {
/* push value */
get_ctoken();
parm_tp = base_type(exec_expression());
/* check if dynamic agg */
if (is_dynagg(parm_tp)) {
parm_tp = parm_tp->info.dynagg.elmt_typep;
}
field_width = DEFAULT_NUMERIC_FIELD_WIDTH;
precision = DEFAULT_PRECISION;
/* optional field width expresion */
if (ctoken == COLON) {
get_ctoken();
exec_expression();
if (!is_value_undef(tos)) {
field_width = get_integer(tos);
}
pop(); /* field width */
/* optional decimal places expresion */
if (ctoken == COLON) {
get_ctoken();
exec_expression();
if (!is_value_undef(tos)) {
precision = get_integer(tos);
}
pop(); /* precision */
}
}
if (parm_tp->form == ARRAY_FORM) { /* array, address on top of stack */
if (get_stackval_type(tos) == STKADD) {
copy_value(tos, get_address(tos));
}
}
stype = get_stackval_type(tos);
/* write value */
if (is_value_undef(tos)) {
sprintf(acbuffer, "%*c", field_width, get_undef(tos));
}
else if (stype == STKINT) {
sprintf(acbuffer, "%*d", field_width, get_integer(tos));
}
else if (stype == STKREA) {
sprintf(acbuffer, "%*.*g", field_width, precision, get_real(tos));
}
else if (stype == STKLOG) {
field_width = 0;
switch (get_logical(tos)) {
case TRUE_REP: {
sprintf(acbuffer, "%*s", -field_width, "TRUE");
break;
}
case FALSE_REP: {
sprintf(acbuffer, "%*s", -field_width, "FALSE");
break;
}
case UNKNOWN_REP: {
sprintf(acbuffer, "%*s", -field_width, "UNKNOWN");
break;
}
default: {
sprintf(acbuffer, "%*s", -field_width, "??UNKNOWN??");
break;
}
} /* end switch */
}
else if (parm_tp == string_typep || parm_tp->form == STRING_FORM) {
field_width = 0;
sprintf(acbuffer, "%*s", -field_width, get_stacked_string(tos) );
}
myprint(acbuffer);
pop(); /* value */
} while (ctoken == COMMA); /* end do */
get_ctoken(); /* token after RPAREN */
} /* end of if over parameters */
if (rtn_idp->defn.info.routine.key == L2XPRINTLN) myprint("\n");
exit_debug("exec_print_println");
return;
} /* end exec_print_println */
/************************************************************************/
/************************************************************************/
/* exec_insert_etc(rtn_idp) Execute a call to procedure INSERT, etc */
/* INSERT(<list>, <item>, <posn>) */
/* REMOVE(<list>, <posn>) */
/* at entry: ctoken is `proc' */
/* at exit: ctoken is the token after the closing ) */
exec_insert_etc(rtn_idp)
SYMTAB_NODE_PTR rtn_idp; /* routine id */
{
TYPE_STRUCT_PTR parm_tp; /* parameter type */
LBS_PTR list;
LBS_NODE_PTR nod;
STACK_ITEM_PTR pitem;
XPRSAINT pos;
int code = rtn_idp->defn.info.routine.key;
entry_debug("exec_insert_etc (l2xixstd.c)");
/* first parameter */
get_ctoken(); /* should be ( */
get_ctoken(); /* should be param 1 */
parm_tp = base_type(exec_expression());
if (parm_tp->form != LIST_FORM) {
runtime_error(INVALID_FUNCTION_ARGUMENT);
}
list = (LBS_PTR) get_address_type(tos, STKLST);
sprintf(dbuffer, "list = %d\n", list);
debug_print(dbuffer);
pop(); /* first parm */
get_ctoken(); /* start of next parameter */
if (code == XINSERT) { /* do INSERT second param */
exec_expression();
pitem = create_copy_value(tos);
sprintf(dbuffer, "pitem = %d\n", pitem);
debug_print(dbuffer);
get_ctoken(); /* start of next parameter */
}
/* final parameter */
parm_tp = base_type(exec_expression());
pos = get_integer(tos);
pop(); /* last parm */
get_ctoken(); /* token after closing ) */
switch (code) {
case XINSERT: {
nod = lbs_insert(list, (genptr) pitem, pos);
sprintf(dbuffer, "inserted node = %d, with data = %d, at pos = %d, into list = %d\n",
nod, pitem, pos, list);
debug_print(dbuffer);
pop(); /* middle parm */
break;
}
case XREMOVE: {
nod = lbs_remove(list, pos);
sprintf(dbuffer, "removed node = %d\n", nod);
debug_print(dbuffer);
break;
}
} /* end switch */
exit_debug("exec_insert_etc");
return;
} /* end EXEC_INSERT_ETC */
/************************************************************************/
/************************************************************************/
/* exec_eof_eoln(rtn_idp) Execute a call to EOF or EOLN */
/* No parameters => boolean result */
/* return a pointer to the type stucture of the call */
TYPE_STRUCT_PTR exec_eof_eoln(rtn_idp)
SYMTAB_NODE_PTR rtn_idp; /* routine id */
{
char ch = getchar();
entry_debug("exec_eof_eoln");
switch (rtn_idp->defn.info.routine.key) {
case EOFF: {
if (eof_flag || feof(stdin)) {
eof_flag = TRUE;
push_true();
}
else {
push_false();
ungetc(ch, stdin);
}
break;
}
case EOLN: {
if (eof_flag || feof(stdin)) {
eof_flag = TRUE;
push_true();
}
else {
push_logical(ch == '\n' ? TRUE_REP : FALSE_REP);
ungetc(ch, stdin);
}
break;
}
} /* end switch */
get_ctoken(); /* token after function name */
exit_debug("exec_eof_eoln");
return(logical_typep);
} /* end exec_eof_eoln */
/************************************************************************/
/************************************************************************/
/* exec_system_etc(rtn_idp) Execute a call to system, etc */
/* fun('string') */
/* String parameter, no result */
/* at entry, ctoken is `fun' */
/* at exit, ctoken is token after closing ) */
exec_system_etc(rtn_idp)
SYMTAB_NODE_PTR rtn_idp; /* routine id */
{
TYPE_STRUCT_PTR parm_tp; /* actual param type */
entry_debug("exec_system_etc");
get_ctoken(); /* should be ( */
get_ctoken(); /* start of param */
parm_tp = base_type(exec_expression());
if (parm_tp->form != STRING_FORM) {
runtime_error(INVALID_FUNCTION_ARGUMENT);
}
else {
switch (rtn_idp->defn.info.routine.key) {
case L2XSYSTEM : {
system(get_stacked_string(tos));
break;
}
default : {
runtime_error(UNIMPLEMENTED_RUNTIME_FEATURE);
break;
}
} /* end switch */
}
get_ctoken(); /* token after closing ) */
exit_debug("exec_system_etc");
return;
} /* end EXEC_SYSTEM_ETC */
/************************************************************************/
/************************************************************************/
/* exec_rexpr_etc(rtn_idp) Execute a call to REXPR, etc */
/* In general, any function fun(p1, p2) that: */
/* p1 and p2 are strings --> boolean result */
/* return a pointer to the type stucture of the call */
TYPE_STRUCT_PTR exec_rexpr_etc(rtn_idp)
SYMTAB_NODE_PTR rtn_idp; /* routine id */
{
TYPE_STRUCT_PTR parm1_tp, parm2_tp; /* actual param types */
TYPE_STRUCT_PTR result_tp = logical_typep;
STRING parm1, parm2; /* parameters */
BOOLEAN undef_parm = FALSE;
int code = rtn_idp->defn.info.routine.key;
int result;
entry_debug("exec_rexpr_etc (l2xixstd.c)");
get_ctoken(); /* LPAREN */
get_ctoken(); /* start of first parameter */
parm1_tp = base_type(exec_expression());
if (is_value_undef(tos)) {
undef_parm = TRUE;
}
else {
parm1 = get_stacked_string(tos);
}
/* get_ctoken(); COMMA */
get_ctoken(); /* start of second parameter */
parm2_tp = base_type(exec_expression());
if (is_value_undef(tos)) {
undef_parm = TRUE;
}
else {
parm2 = get_stacked_string(tos);
}
pop();
if (code == L2XREXPR) { /* parm1 = string, parm2 = pattern */
if (undef_parm) {
put_undef(tos);
}
else {
result = rexpr(parm1, parm2);
if (result < 0) {
runtime_error(INVALID_REGULAR_EXPRESSION);
put_undef(tos);
}
else if (result == 0) {
put_false(tos);
}
else {
put_true(tos);
}
}
}
get_ctoken(); /* token after RPAREN */
exit_debug("exec_rexpr_etc");
return(result_tp);
} /* end EXEC_REXPR_ETC */
/************************************************************************/
/************************************************************************/
/* exec_hibound_etc(rtn_idp) Execute a call to HIBOUND, etc */
/* agg type -> integer */
/* return a pointer to the type stucture of the call */
TYPE_STRUCT_PTR exec_hibound_etc(rtn_idp)
SYMTAB_NODE_PTR rtn_idp; /* routine id */
{
TYPE_STRUCT_PTR parm_tp; /* actual param type */
TYPE_STRUCT_PTR result_tp = integer_typep; /* result type */
XPRSAINT result = 0;
STACK_TYPE stype;
TYPE_FORM ftype;
int code = rtn_idp->defn.info.routine.key;
entry_debug("exec_hibound_etc");
get_ctoken(); /* LPAREN */
get_ctoken();
parm_tp = base_type(exec_expression());
if (is_value_undef(tos)) {
put_undef(tos);
get_ctoken(); /* token after RPAREN */
exit_debug("exec_hibound_etc");
return(result_tp);
}
ftype = parm_tp->form;
if ((ftype != ARRAY_FORM) &&
(ftype != BAG_FORM) &&
(ftype != LIST_FORM) &&
(ftype != SET_FORM) ) {
runtime_error(INVALID_FUNCTION_ARGUMENT);
put_undef(tos);
get_ctoken(); /* token after RPAREN */
exit_debug("exec_hibound_etc");
return(result_tp);
}
stype = get_stackval_type(tos);
if (stype != form2stack[ftype] &&
stype != STKADD) {
stack_warning(form2stack[ftype], stype);
}
switch (code) {
case XHIBOUND: { /* declared upper bound */
if (parm_tp->form == ARRAY_FORM) {
result = parm_tp->info.array.max_index;
}
else {
result = parm_tp->info.dynagg.max_index;
}
break;
}
case XHIINDEX: { /* declared array upper bound, or # of elements */
if (parm_tp->form == ARRAY_FORM) {
result = parm_tp->info.array.max_index;
}
else {
result = NELS((LBS_PTR) get_address_type(tos, stype));
}
break;
}
case XLOBOUND: { /* declared lower bound */
if (parm_tp->form == ARRAY_FORM) {
result = parm_tp->info.array.min_index;
}
else {
result = parm_tp->info.dynagg.min_index;
}
break;
}
case XLOINDEX: { /* declared array lower bound, or 1 */
if (parm_tp->form == ARRAY_FORM) {
result = parm_tp->info.array.min_index;
}
else {
result = 1;
}
break;
}
case XSIZEOF: { /* # of actual elements */
if (parm_tp->form == ARRAY_FORM) {
result = parm_tp->info.array.max_index - parm_tp->info.array.min_index + 1;
}
else {
result = NELS((LBS_PTR) get_address_type(tos, stype));
}
break;
}
default: { /* should not be here */
runtime_error(UNIMPLEMENTED_RUNTIME_FEATURE);
get_ctoken();
put_undef(tos);
exit_debug("exec_hibound_etc");
return(result_tp);
}
} /* end switch */
get_ctoken(); /* token after RPAREN */
put_integer(tos, result);
exit_debug("exec_hibound_etc");
return(result_tp);
} /* end EXEC_HIBOUND_ETC */
/************************************************************************/
/************************************************************************/
/* exec_length_etc(rtn_idp) Execute a call to LENGTH, etc */
/* fun('string') */
/* String parameter, integer result */
/* at entry, ctoken is `fun' */
/* at exit, ctoken is token after closing ) */
TYPE_STRUCT_PTR exec_length_etc(rtn_idp)
SYMTAB_NODE_PTR rtn_idp; /* routine id */
{
TYPE_STRUCT_PTR parm_tp; /* actual param type */
TYPE_STRUCT_PTR result_tp; /* returned type */
XPRSAINT result = 0;
entry_debug("exec_length_etc (l2xixstd.c)");
get_ctoken(); /* should be ( */
get_ctoken(); /* start of param */
parm_tp = base_type(exec_expression());
if (parm_tp->form != STRING_FORM) {
runtime_error(INVALID_FUNCTION_ARGUMENT);
}
else {
switch (rtn_idp->defn.info.routine.key) {
case XLENGTH : { /* # of chars in a string */
result = (XPRSAINT) strlen(get_stacked_string(tos));
break;
}
default : {
runtime_error(UNIMPLEMENTED_RUNTIME_FEATURE);
break;
}
} /* end switch */
}
get_ctoken(); /* token after closing ) */
put_integer(tos, result);
exit_debug("exec_length_etc");
return(result_tp);
} /* end EXEC_LENGTH_ETC */
/************************************************************************/
/************************************************************************/
/* exec_exists_etc(rtn_idp) Execute a call to EXISTS, etc */
/* any type -> boolean */
/* return a pointer to the type stucture of the call */
TYPE_STRUCT_PTR exec_exists_etc(rtn_idp)
SYMTAB_NODE_PTR rtn_idp; /* routine id */
{
TYPE_STRUCT_PTR parm_tp; /* actual param type */
TYPE_STRUCT_PTR result_tp; /* result type */
int code = rtn_idp->defn.info.routine.key;
entry_debug("exec_exists_etc");
get_ctoken(); /* LPAREN */
get_ctoken();
parm_tp = base_type(exec_expression());
if (code == XEXISTS) {
if (is_value_undef(tos)) {
put_true(tos);
}
else {
put_false(tos);
}
}
get_ctoken(); /* token after RPAREN */
exit_debug("exec_exists_etc");
return(logical_typep);
} /* end EXEC_EXISTS_ETC */
/************************************************************************/
/************************************************************************/
/* exec_nvl_etc(rtn_idp) Execute a call to NVL, etc */
/* In general, any function fun(p1, p2) that: */
/* any compatible params --> compatible result */
/* return a pointer to the type stucture of the call */
TYPE_STRUCT_PTR exec_nvl_etc(rtn_idp)
SYMTAB_NODE_PTR rtn_idp; /* routine id */
{
TYPE_STRUCT_PTR parm1_tp, parm2_tp; /* actual param types */
TYPE_STRUCT_PTR result_tp;
STACK_ITEM_PTR parm1, parm2; /* parameters */
int code = rtn_idp->defn.info.routine.key;
entry_debug("exec_nvl_etc");
get_ctoken(); /* LPAREN */
get_ctoken(); /* start of first parameter */
parm1_tp = base_type(exec_expression());
parm1 = tos;
get_ctoken(); /* COMMA */
get_ctoken(); /* start of second parameter */
parm2_tp = base_type(exec_expression());
parm2 = tos;
if (code == XNVL) {
if (is_value_undef(parm1)) {
copy_value(parm1, parm2);
result_tp = parm2_tp;
}
else {
result_tp = parm1_tp;
}
}
get_ctoken(); /* token after RPAREN */
exit_debug("exec_nvl_etc");
return(result_tp);
} /* end EXEC_NVL_ETC */
/************************************************************************/
/************************************************************************/
/* exec_abs_sqr(rtn_idp) Execute a call to ABS or SQR */
/* Integer --> integer result */
/* real --> real result */
/* return a pointer to the type stucture of the call */
TYPE_STRUCT_PTR exec_abs_sqr(rtn_idp)
SYMTAB_NODE_PTR rtn_idp; /* routine id */
{
TYPE_STRUCT_PTR parm_tp; /* actual param type */
TYPE_STRUCT_PTR result_tp; /* result type */
XPRSAINT i1;
XPRSAREAL r1;
int code = rtn_idp->defn.info.routine.key;
entry_debug("exec_abs_sqr");
get_ctoken(); /* LPAREN */
get_ctoken();
parm_tp = base_type(exec_expression());
if (is_value_undef(tos)) {
;
}
if (code == ABS) {
if (parm_tp == integer_typep) {
i1 = get_integer(tos);
if (i1 >= 0) {
put_integer(tos, i1);
}
else {
put_integer(tos, -i1);
}
}
else {
r1 = (XPRSAREAL) fabs((double) get_real(tos));
put_real(tos, r1);
}
}
get_ctoken(); /* token after RPAREN */
exit_debug("exec_abs_sqr");
return(parm_tp);
} /* end exec_abs_sqr */
/************************************************************************/
/************************************************************************/
/* exec_arctan_cos_exp_ln_sin_sqrt(rtn_idp) Execute a call to ARCTAN, */
/* COS, EXP, LN, SIN or SQRT */
/* In general, any function fun(p1) that: */
/* integer or real param --> real result */
/* return a pointer to the type stucture of the call */
/* NOTE calling C library routines acos() and asin() give wierd interp error */
TYPE_STRUCT_PTR exec_arctan_cos_exp_ln_sin_sqrt(rtn_idp)
SYMTAB_NODE_PTR rtn_idp; /* routine id */
{
TYPE_STRUCT_PTR parm_tp; /* actual param type */
int code = rtn_idp->defn.info.routine.key;
XPRSAREAL r1, r2;
entry_debug("exec_arctan_cos_exp_ln_sin_sqrt");
get_ctoken(); /* LPAREN */
get_ctoken();
parm_tp = base_type(exec_expression());
if (is_value_undef(tos)) {
get_ctoken(); /* token after RPAREN */
exit_debug("exec_arctan_cos_exp_ln_sin_sqrt");
return(real_typep);
}
if (parm_tp == integer_typep) {
put_real(tos, (XPRSAREAL) get_integer(tos));
}
r1 = (double) get_real(tos);
/* check input value */
if (((code == SQRT) && (r1 < 0.0)) ||
((code == XACOS) && (r1 < -1.0 || r1 > 1.0)) ||
((code == XASIN) && (r1 < -1.0 || r1 > 1.0)) ||
((code == XLOG) && (r1 <= 0.0)) ||
((code == XLOG2) && (r1 <= 0.0)) ||
((code == XLOG10) && (r1 <= 0.0)) ) {
runtime_error(INVALID_FUNCTION_ARGUMENT);
exit_debug("exec_arctan_cos_exp_ln_sin_sqrt");
}
else {
switch (rtn_idp->defn.info.routine.key) {
case COS: {
put_real(tos, (XPRSAREAL) cos(r1));
exit_debug("exec_arctan_cos_exp_ln_sin_sqrt (COS)");
break;
}
case EXP: {
put_real(tos, (XPRSAREAL) exp(r1));
exit_debug("exec_arctan_cos_exp_ln_sin_sqrt (EXP)");
break;
}
case SIN: {
put_real(tos, (XPRSAREAL) sin(r1));
exit_debug("exec_arctan_cos_exp_ln_sin_sqrt (SIN)");
break;
}
case SQRT: {
put_real(tos, (XPRSAREAL) sqrt(r1));
exit_debug("exec_arctan_cos_exp_ln_sin_sqrt (SQRT)");
break;
}
case XACOS: {
put_real(tos, (XPRSAREAL) acos(r1));
exit_debug("exec_arctan_cos_exp_ln_sin_sqrt (ACOS)");
break;
}
case XASIN: {
put_real(tos, (XPRSAREAL) asin(r1));
exit_debug("exec_arctan_cos_exp_ln_sin_sqrt (ASIN)");
break;
}
case XLOG: {
put_real(tos, (XPRSAREAL) log(r1));
exit_debug("exec_arctan_cos_exp_ln_sin_sqrt (LOG)");
break;
}
case XLOG2: { /* log_a(x) = ln(x)/ln(a) : ln(2) = 0.6931 47180 55994 */
put_real(tos, (1.442695 * ((XPRSAREAL) log(r1))));
exit_debug("exec_arctan_cos_exp_ln_sin_sqrt (LOG2)");
break;
}
case XLOG10: {
put_real(tos, (XPRSAREAL) log10(r1));
exit_debug("exec_arctan_cos_exp_ln_sin_sqrt (LOG10)");
break;
}
case XTAN: {
put_real(tos, (XPRSAREAL) tan(r1));
exit_debug("exec_arctan_cos_exp_ln_sin_sqrt (TAN)");
break;
}
} /* end switch */
}
get_ctoken(); /* token after RPAREN */
return(real_typep);
} /* end exec_arctan_cos_exp_ln_sin_sqrt */
/************************************************************************/
/************************************************************************/
/* exec_atan(rtn_idp) Execute a call to ATAN, */
/* In general, any function fun(p1, p2) that: */
/* integer or real param --> real result */
/* return a pointer to the type stucture of the call */
/* NOTE: Calling C library function atan2() gives wierd interp. error */
TYPE_STRUCT_PTR exec_atan(rtn_idp)
SYMTAB_NODE_PTR rtn_idp; /* routine id */
{
TYPE_STRUCT_PTR parm1_tp, parm2_tp; /* actual param type */
TYPE_STRUCT_PTR result_tp;
STACK_ITEM_PTR parm1, parm2;
int code = rtn_idp->defn.info.routine.key;
XPRSAREAL r1;
XPRSAREAL r2;
entry_debug("exec_atan");
get_ctoken(); /* LPAREN */
get_ctoken(); /* start of first parameter */
parm1_tp = base_type(exec_expression());
parm1 = tos;
get_ctoken(); /* COMMA */
get_ctoken(); /* start of second parameter */
parm2_tp = base_type(exec_expression());
parm2 = tos;
if (code == XATAN) {
if (is_value_undef(parm1) || is_value_undef(parm2)) {
put_undef(parm1);
}
else {
if (parm1_tp == integer_typep) {
put_real(parm1, (XPRSAREAL) get_integer(parm1));
}
r1 = get_real(parm1);
if (parm2_tp == integer_typep) {
put_real(parm2, (XPRSAREAL) get_integer(parm2));
}
r2 = get_real(parm2);
if (r1 == 0.0 && r2 == 0.0) {
runtime_error(INVALID_FUNCTION_ARGUMENT);
}
else {
r1 = (double) r1;
r2 = (double) r2;
put_real(parm1, (XPRSAREAL) atan2(r1, r2));
}
}
}
pop();
get_ctoken(); /* token after RPAREN */
exit_debug("exec_atan");
return(real_typep);
} /* end EXEC_ATAN */
/************************************************************************/
/************************************************************************/
/* exec_odd() Execute a call to ODD */
/* integer param --> boolean result */
/* return a pointer to the type stucture of the call */
TYPE_STRUCT_PTR exec_odd()
{
XPRSAINT i1;
entry_debug("exec_odd");
get_ctoken(); /* LPAREN */
get_ctoken();
exec_expression();
if (!is_value_undef(tos)) {
i1 = get_integer(tos);
i1 &= 1;
if (i1 == 0) {
put_false(tos);
}
else {
put_true(tos);
}
}
get_ctoken(); /* after RPAREN */
exit_debug("exec_odd");
return(logical_typep);
} /* end exec_odd */
/************************************************************************/
/************************************************************************/
/* exec_round_trunc(rtn_idp) Execute a call to ROUND or TRUNC */
/* real param --> integer result */
/* return a pointer to the type stucture of the call */
TYPE_STRUCT_PTR exec_round_trunc(rtn_idp)
SYMTAB_NODE_PTR rtn_idp; /* routine id */
{
XPRSAREAL r1;
XPRSAINT i1;
entry_debug("exec_round_trunc");
get_ctoken(); /* LPAREN */
get_ctoken();
exec_expression();
if (!is_value_undef(tos)) {
r1 = get_real(tos);
if (rtn_idp->defn.info.routine.key == ROUND) {
i1 = r1 > 0.0
? (XPRSAINT) (r1 + 0.5)
: (XPRSAINT) (r1 - 0.5);
}
else {
i1 = (XPRSAINT) r1;
}
put_integer(tos, i1);
}
get_ctoken(); /* after RPAREN */
exit_debug("exec_round_trunc");
return(integer_typep);
} /* end exec_round_trunc */
/************************************************************************/