/* l2xixutl.c LTX2X Executor utility 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 "l2xicmon.h"
#include "l2xierr.h"
#include "l2xiscan.h"
#include "l2xisymt.h"
#include "l2xiidbg.h"
#include "l2xiexec.h"
#include "listsetc.h"
/* EXTERNALS */
extern TOKEN_CODE token;
extern int line_number;;
extern int level;
extern BOOLEAN executed_return; /* TRUE iff return statement executed */
/* GLOBALS */
ICT *code_buffer; /* code buffer */
ICT *code_bufferp; /* code buffer ptr */
ICT *code_segmentp; /* code segment ptr */
ICT *code_segment_limit; /* end of code segment */
ICT *statement_startp; /* ptr to start of statement */
TOKEN_CODE ctoken; /* token from code segment */
int exec_line_number; /* no. of line executed */
long exec_stmt_count = 0; /* count of executed statements */
STACK_ITEM *stack; /* runtime stack */
STACK_ITEM_PTR tos; /* ptr to top of runtime stack */
STACK_ITEM_PTR stack_frame_basep; /* ptr to stack fame base */
STACK_ITEM_PTR maxtos; /* current max top of runtime stack */
/* map from form type to stack type */
STACK_TYPE form2stack[] = {
#define fotc(a, b, c, d) a,
#define sotc(a, b, c, d)
#define sftc(a, b, c, d) a,
#include "l2xisftc.h"
#undef fotc
#undef sotc
#undef sftc
};
/* map from stack type to form type */
TYPE_FORM stack2form[] = {
#define fotc(a, b, c, d)
#define sotc(a, b, c, d) c,
#define sftc(a, b, c, d) c,
#include "l2xisftc.h"
#undef fotc
#undef sotc
#undef sftc
};
/* FORWARDS */
ADDRESS get_static_link();
ADDRESS get_dynamic_link();
ADDRESS get_return_address();
STACK_TYPE get_stackval_type();
/* CODE SEGMENT ROUTINES */
/***************************************************************************/
/* create_code_segment() Create a code segment and copy in the contents */
/* of the code buffer. Reset the code buffer pointer */
/* return a pointer to the segment */
ICT *create_code_segment()
{
ICT *code_segment = alloc_array(ICT, (code_bufferp - code_buffer));
entry_debug("create_code_segment");
code_segment_limit = code_segment + (code_bufferp - code_buffer);
code_bufferp = code_buffer;
code_segmentp = code_segment;
/* copy in the contents of the code buffer */
while (code_segmentp != code_segment_limit) {
*code_segmentp++ = *code_bufferp++;
}
/* reset the code buffer pointer */
code_bufferp = code_buffer;
code_segment_debug(code_segment, code_segment_limit);
exit_debug("create_code_segment");
return(code_segment);
} /* end create_code_segment */
/***************************************************************************/
/***************************************************************************/
/* crunch_token() Append the token code to the code buffer. */
/* Called by the scanner routine only while parsing a block */
crunch_token()
{
int token_code = token; /* integer sized token code */
entry_debug("crunch_token");
if ((code_bufferp - code_buffer) >= MAX_CODE_BUFFER_SIZE - sizeof(token_code)) {
error(CODE_SEGMENT_OVERFLOW);
exit(-CODE_SEGMENT_OVERFLOW);
}
*code_bufferp++ = (ICT) token_code;
exit_debug("crunch_token");
return;
} /* end crunch_token */
/***************************************************************************/
/***************************************************************************/
/* crunch_extra_token() Append the token code to the code buffer. */
crunch_extra_token(tok)
TOKEN_CODE tok;
{
entry_debug("crunch_extra_token (l2xixutl.c)");
if ((code_bufferp - code_buffer) >= MAX_CODE_BUFFER_SIZE - sizeof(tok)) {
error(CODE_SEGMENT_OVERFLOW);
exit(-CODE_SEGMENT_OVERFLOW);
}
*code_bufferp++ = (ICT) tok;
exit_debug("crunch_extra_token");
return;
} /* end CRUNCH_EXTRA_TOKEN */
/***************************************************************************/
/***************************************************************************/
/* get_ctoken() Gets next crunched token */
TOKEN_CODE get_ctoken()
{
entry_debug("get_ctoken (l2xixutl.c)");
code_segment_entry_debug(code_segmentp);
ctoken = *code_segmentp++;
exit_debug("get_ctoken");
return(ctoken);
} /* end GET_CTOKEN */
/***************************************************************************/
/***************************************************************************/
/* change_crunched_token(newtok) Replace the last token in the code */
/* segment by newtok */
change_crunched_token(newtok)
int newtok; /* integer sized new token code */
{
ICT *bp;
entry_debug("change_crunched_token");
bp = code_bufferp;
bp--;
*bp = (ICT) newtok;
exit_debug("change_crunched_token");
return;
} /* end CHANGE_CRUNCHED_TOKEN */
/***************************************************************************/
/***************************************************************************/
/* backup_crunched() prepare to write over last code entry */
/* */
backup_crunched()
{
entry_debug("backup_crunched");
code_bufferp--;
exit_debug("backup_crunched");
return;
} /* end BACKUP_CRUNCHED */
/***************************************************************************/
/***************************************************************************/
/* crunch_symtab_node_ptr(np) Append a symbol table node pointer to the */
/* code buffer */
crunch_symtab_node_ptr(np)
SYMTAB_NODE_PTR np; /* pointer to append */
{
/* SYMTAB_NODE_PTR *npp = (SYMTAB_NODE_PTR *) code_bufferp; */
ICT *npp = code_bufferp;
entry_debug("crunch_symtab_node_ptr");
if ((code_bufferp - code_buffer) >=
(MAX_CODE_BUFFER_SIZE - sizeof(SYMTAB_NODE_PTR))) {
error(CODE_SEGMENT_OVERFLOW);
exit(-CODE_SEGMENT_OVERFLOW);
}
else {
*npp = (ICT) np;
code_bufferp++;
}
exit_debug("crunch_symtab_node_ptr");
return;
} /* end crunch_symtab_node_ptr */
/***************************************************************************/
/***************************************************************************/
/* get_symtab_cptr() Extract a symbol table node pointer from the current */
/* code segment */
/* return the symbol table node pointer */
SYMTAB_NODE_PTR get_symtab_cptr()
{
SYMTAB_NODE_PTR np;
ICT *npp = code_segmentp;
np = (SYMTAB_NODE_PTR) *npp;
/* code_segmentp += sizeof(SYMTAB_NODE_PTR); */
code_segmentp++;
return(np);
} /* end get_symtab_cptr */
/***************************************************************************/
/***************************************************************************/
/* crunch_statement_marker() Append a statement marker to the code buffer */
/* */
crunch_statement_marker()
{
entry_debug("crunch_statement_marker");
if ((code_bufferp - code_buffer) >= MAX_CODE_BUFFER_SIZE) {
error(CODE_SEGMENT_OVERFLOW);
exit(-CODE_SEGMENT_OVERFLOW);
}
else {
ICT save_code = *(--code_bufferp);
*code_bufferp++ = STATEMENT_MARKER;
*((int *) code_bufferp) = line_number;
code_bufferp++;
*code_bufferp++ = save_code;
}
exit_debug("crunch_statement_marker");
return;
} /* end crunch_statement_marker */
/***************************************************************************/
/***************************************************************************/
/* get_statement_cmarker() Extract a statement marker from the current */
/* code segment. */
/* return its line number. */
int get_statement_cmarker()
{
int line_num;
entry_debug("get_statement_cmarker");
if (ctoken == STATEMENT_MARKER) {
line_num = *((int *) code_segmentp);
code_segmentp++;
}
exit_debug("get_statement_cmarker");
return(line_num);
} /* end get_statement_cmarker */
/***************************************************************************/
/***************************************************************************/
/* crunch_address_marker(address) Append a code address to the code */
/* buffer */
/* return the address of the address */
ICT *crunch_address_marker(address)
ADDRESS address;
{
ICT *save_code_bufferp;
if ((code_bufferp - code_buffer) >= MAX_CODE_BUFFER_SIZE - sizeof(ADDRESS)) {
error(CODE_SEGMENT_OVERFLOW);
exit(-CODE_SEGMENT_OVERFLOW);
}
else {
ICT save_code = *(--code_bufferp);
*code_bufferp++ = (ICT) ADDRESS_MARKER;
save_code_bufferp = code_bufferp;
*((ADDRESS *) code_bufferp) = address;
code_bufferp++;
*code_bufferp++ = save_code;
}
return(save_code_bufferp);
} /* end crunch_address_marker */
/***************************************************************************/
/***************************************************************************/
/* get_address_cmarker Extract an address marker from current code */
/* segment. Add its offset value to the code segment */
/* address. */
/* return new address */
ADDRESS get_address_cmarker()
{
ADDRESS address; /* address to be returned */
if (ctoken == ADDRESS_MARKER) {
address = *((int *) code_segmentp) + code_segmentp - 1;
code_segmentp++;
}
return(address);
} /* end get_address_cmarker */
/***************************************************************************/
/***************************************************************************/
/* fixup_address_marker(address) Fix up an address marker with the offset */
/* from the address marker to the current */
/* code buffer address. */
/* return the old value of the address marker */
ADDRESS fixup_address_marker(address)
ADDRESS address; /* address of marker to be fixed up */
{
/* ADDRESS old_address = address; */
/* int *old_address = *((ADDRESS *) address); */
ADDRESS old_address = *((ADDRESS *) address);
*((int *) address) = code_bufferp - address;
return(old_address);
} /* end fixup_address_marker */
/***************************************************************************/
/***************************************************************************/
/* crunch_integer(value) Append an integer value to the code buffer */
crunch_integer(value)
XPRSAINT value;
{
if ((code_bufferp - code_buffer) >= MAX_CODE_BUFFER_SIZE - sizeof(XPRSAINT)) {
error(CODE_SEGMENT_OVERFLOW);
exit(-CODE_SEGMENT_OVERFLOW);
}
else {
*code_bufferp++ = (ICT) value;
}
} /* end crunch_integer */
/***************************************************************************/
/***************************************************************************/
/* get_cinteger Extract an integer from the current code segment */
/* return the value */
XPRSAINT get_cinteger()
{
XPRSAINT value;
value = (XPRSAINT) *code_segmentp++;
return(value);
} /* end get_cinteger */
/***************************************************************************/
/***************************************************************************/
/* crunch_offset(address) Append an integer value to the code that */
/* represents the offset from the given address */
/* to the current code buffer address */
crunch_offset(address)
ADDRESS address;
{
ICT *temp;
if ((code_bufferp - code_buffer) >= MAX_CODE_BUFFER_SIZE - sizeof(int)) {
error(CODE_SEGMENT_OVERFLOW);
exit(-CODE_SEGMENT_OVERFLOW);
}
else {
temp = code_bufferp;
*code_bufferp++ = address - temp;
}
} /* end crunch_offset */
/***************************************************************************/
/***************************************************************************/
/* get_caddress() Extract an offset from the current code segment and */
/* add it to the code segment address. */
/* return the new address */
ADDRESS get_caddress()
{
ADDRESS address;
address = *((int *) code_segmentp) + code_segmentp - 1;
code_segmentp++;
return(address);
} /* end get_caddress */
/***************************************************************************/
/* EXECUTOR UTILITIES */
/***************************************************************************/
/* get_element_type(tp) Given an aggregate type, return the element type */
TYPE_STRUCT_PTR get_element_type(agg_tp)
TYPE_STRUCT_PTR agg_tp; /* the aggregate type */
{
TYPE_STRUCT_PTR et;
if (is_array(agg_tp)) return(agg_tp->info.array.elmt_typep);
else if (is_dynagg(agg_tp)) return(agg_tp->info.dynagg.elmt_typep);
else return(agg_tp);
} /* end GET_ELEMENT_TYPE */
/***************************************************************************/
/***************************************************************************/
/* push_integer(item_value) Push an integer onto the runtime stack */
push_integer(item_value)
XPRSAINT item_value;
{
STACK_ITEM_PTR itemp = ++tos;
entry_debug("push_integer");
maxtos = tos > maxtos ? tos : maxtos;
if (itemp >= &stack[MAX_STACK_SIZE]) {
runtime_error(RUNTIME_STACK_OVERFLOW);
}
itemp->type = STKINT;
itemp->value.integer = item_value;
stack_access_debug("Pushed", tos);
exit_debug("push_integer");
return;
} /* end push_integer */
/***************************************************************************/
/***************************************************************************/
/* put_integer(sptr, item_value) Put an integer into the runtime stack */
put_integer(sptr, item_value)
STACK_ITEM_PTR sptr;
XPRSAINT item_value;
{
STACK_ITEM_PTR itemp = sptr;
entry_debug("put_integer");
itemp->type = STKINT;
itemp->value.integer = item_value;
stack_access_debug("Put", itemp);
if (itemp > maxtos) {
runtime_warning(INVALID_STACK_ACCESS);
}
exit_debug("put_integer");
return;
} /* end put_integer */
/***************************************************************************/
/***************************************************************************/
/* int get_integer(sptr) Get an integer from the runtime stack */
XPRSAINT get_integer(sptr)
STACK_ITEM_PTR sptr;
{
int item_value = 0;
XPRSAREAL r1;
STACK_ITEM_PTR itemp = sptr;
STACK_TYPE stype;
entry_debug("get_integer");
stack_access_debug("Got", itemp);
if (itemp == NULL) {
runtime_warning(INVALID_STACK_ACCESS);
return(item_value);
}
stype = itemp->type;
if (stype == STKINT) {
item_value = itemp->value.integer;
}
else if (stype == STKREA) { /* real value, return nearest integer */
r1 = itemp->value.real;
item_value = r1 > 0.0 ? (XPRSAINT) (r1 + 0.5)
: (XPRSAINT) (r1 - 0.5);
}
else {
stack_warning(STKINT, stype);
}
exit_debug("get_integer");
return(item_value);
} /* end get_integer */
/***************************************************************************/
/***************************************************************************/
/* push_real(item_value) Push a real onto the runtime stack */
push_real(item_value)
XPRSAREAL item_value;
{
STACK_ITEM_PTR itemp = ++tos;
entry_debug("push_real");
maxtos = tos > maxtos ? tos : maxtos;
if (itemp >= &stack[MAX_STACK_SIZE]) {
runtime_error(RUNTIME_STACK_OVERFLOW);
}
itemp->type = STKREA;
itemp->value.real = item_value;
stack_access_debug("Pushed", tos);
exit_debug("push_real");
return;
} /* end push_real */
/***************************************************************************/
/***************************************************************************/
/* put_real(sptr, item_value) Put a real into the runtime stack */
put_real(sptr, item_value)
STACK_ITEM_PTR sptr;
XPRSAREAL item_value;
{
STACK_ITEM_PTR itemp = sptr;
entry_debug("put_real");
itemp->type = STKREA;
itemp->value.real = item_value;
stack_access_debug("Put",itemp);
if (itemp > maxtos) {
runtime_warning(INVALID_STACK_ACCESS);
}
exit_debug("put_real");
return;
} /* end put_real */
/***************************************************************************/
/***************************************************************************/
/* float get_real(sptr) Get a real from the runtime stack */
XPRSAREAL get_real(sptr)
STACK_ITEM_PTR sptr;
{
XPRSAREAL item_value = 0.0;
STACK_ITEM_PTR itemp = sptr;
STACK_TYPE stype;
entry_debug("get_real");
stack_access_debug("Got", itemp);
if (itemp == NULL) {
runtime_warning(INVALID_STACK_ACCESS);
return(item_value);
}
stype = itemp->type;
if (stype == STKREA) {
item_value = itemp->value.real;
}
else if (stype == STKINT) { /* convert integer to float */
item_value = (XPRSAREAL) itemp->value.integer;
}
else {
stack_warning(STKREA, stype);
}
exit_debug("get_real");
return(item_value);
} /* end get_real */
/***************************************************************************/
/***************************************************************************/
/* push_address(item_value) Push an address onto the runtime stack */
push_address(address)
ADDRESS address;
{
STACK_ITEM_PTR itemp = ++tos;
entry_debug("push_address");
maxtos = tos > maxtos ? tos : maxtos;
if (itemp >= &stack[MAX_STACK_SIZE]) {
runtime_error(RUNTIME_STACK_OVERFLOW);
}
itemp->type = STKADD;
itemp->value.address = address;
stack_access_debug("Pushed", tos);
exit_debug("push_address");
return;
} /* end push_address */
/***************************************************************************/
/***************************************************************************/
/* put_address(sptr, item_value) Put an address into the runtime stack */
put_address(sptr, address)
STACK_ITEM_PTR sptr;
ADDRESS address;
{
STACK_ITEM_PTR itemp = sptr;
entry_debug("put_address");
itemp->type = STKADD;
itemp->value.address = address;
stack_access_debug("Put", itemp);
if (itemp > maxtos) {
runtime_warning(INVALID_STACK_ACCESS);
}
exit_debug("put_address");
return;
} /* end put_address */
/***************************************************************************/
/***************************************************************************/
/* ADDRESS get_address(sptr) Get an address from the runtime stack */
ADDRESS get_address(sptr)
STACK_ITEM_PTR sptr;
{
STACK_ITEM_PTR itemp = sptr;
ADDRESS address = NULL;
STACK_TYPE stype;
entry_debug("get_address");
stack_access_debug("Got", itemp);
if (itemp == NULL) {
runtime_warning(INVALID_STACK_ACCESS);
return(address);
}
stype = get_stackval_type(itemp);
if (stype == STKINT ||
stype == STKREA ||
stype == STKLOG ||
stype == STKSTR ||
stype == STKBAG ||
stype == STKLST ||
stype == STKSET ||
stype == STKUDF) {
stack_warning(STKADD, stype);
}
else {
address = itemp->value.address;
}
exit_debug("get_address");
return(address);
} /* end get_address */
/***************************************************************************/
/***************************************************************************/
/* push_address_type(item_value, type) Push an address onto the runtime */
/* stack */
push_address_type(address, type)
ADDRESS address;
STACK_TYPE type;
{
STACK_ITEM_PTR itemp = ++tos;
entry_debug("push_address_type (l2xixutl.c)");
maxtos = tos > maxtos ? tos : maxtos;
if (itemp >= &stack[MAX_STACK_SIZE]) {
runtime_error(RUNTIME_STACK_OVERFLOW);
}
switch (type) {
case STKBAG:
case STKLST:
case STKSET: {
itemp->type = type;
itemp->value.head = (LBS_PTR) address;
break;
}
case STKSTR: {
itemp->type = type;
itemp->value.string = (STRING) address;
break;
}
default : {
itemp->type = type;
itemp->value.address = address;
break;
}
}
stack_access_debug("Pushed", tos);
exit_debug("push_address_type");
return;
} /* end push_address_type */
/***************************************************************************/
/***************************************************************************/
/* put_address_type(sptr, item_value, type) Put an address into the runtime stack */
put_address_type(sptr, address, type)
STACK_ITEM_PTR sptr;
ADDRESS address;
STACK_TYPE type;
{
STACK_ITEM_PTR itemp = sptr;
entry_debug("put_address_type (l2xixutl.c)");
switch (type) {
case STKBAG:
case STKLST:
case STKSET: {
itemp->type = type;
itemp->value.head = (LBS_PTR) address;
break;
}
case STKSTR: {
itemp->type = type;
itemp->value.string = (STRING) address;
break;
}
default : {
itemp->type = type;
itemp->value.address = address;
break;
}
}
stack_access_debug("Put", itemp);
if (itemp > maxtos) {
runtime_warning(INVALID_STACK_ACCESS);
}
exit_debug("put_address_type");
return;
} /* end put_address_type */
/***************************************************************************/
/***************************************************************************/
/* ADDRESS get_address_type(sptr, type) Get an address from the runtime stack */
ADDRESS get_address_type(sptr, type)
STACK_ITEM_PTR sptr;
STACK_TYPE type;
{
STACK_ITEM_PTR itemp = sptr;
ADDRESS address = NULL;
STACK_TYPE ftype;
entry_debug("get_address_type (l2xixutl.c)");
stack_access_debug("Got", itemp);
if (itemp == NULL) {
runtime_warning(INVALID_STACK_ACCESS);
return(NULL);
}
ftype = get_stackval_type(itemp);
if (type != ftype) stack_warning(type, ftype);
switch (ftype) {
case STKBAG:
case STKLST:
case STKSET: {
address = (ADDRESS) itemp->value.head;
break;
}
case STKSTR: {
address = (ADDRESS) itemp->value.string;
break;
}
case STKADD:
case STKARY:
case STKENT: {
address = itemp->value.address;
break;
}
}
exit_debug("get_address_type");
return(address);
} /* end get_address_type */
/***************************************************************************/
/***************************************************************************/
/* get_stackval_type(sptr) Returns the type of value in the stack */
STACK_TYPE get_stackval_type(sptr)
STACK_ITEM_PTR sptr;
{
entry_debug("get_stackval_type (l2xixutl.c)");
if (sptr == NULL) {
runtime_warning(INVALID_STACK_ACCESS);
}
exit_debug("get_stackval_type");
return(sptr->type);
} /* end GET_STACKVAL_TYPE */
/***************************************************************************/
/***************************************************************************/
/* push_false() Push false onto runtime stack */
push_false()
{
STACK_ITEM_PTR itemp = ++tos;
entry_debug("push_false");
maxtos = tos > maxtos ? tos : maxtos;
if (itemp >= &stack[MAX_STACK_SIZE]) {
runtime_error(RUNTIME_STACK_OVERFLOW);
}
itemp->type = STKLOG;
itemp->value.integer = FALSE_REP;
stack_access_debug("Pushed", tos);
exit_debug("push_false");
return;
} /* end PUSH_FALSE */
/***************************************************************************/
/***************************************************************************/
/* push_unknown() Push unknown onto runtime stack */
push_unknown()
{
STACK_ITEM_PTR itemp = ++tos;
entry_debug("push_unknown");
maxtos = tos > maxtos ? tos : maxtos;
if (itemp >= &stack[MAX_STACK_SIZE]) {
runtime_error(RUNTIME_STACK_OVERFLOW);
}
itemp->type = STKLOG;
itemp->value.integer = UNKNOWN_REP;
stack_access_debug("Pushed", tos);
exit_debug("push_unknown");
return;
} /* end PUSH_UNKNOWN */
/***************************************************************************/
/***************************************************************************/
/* push_true() Push true onto runtime stack */
push_true()
{
STACK_ITEM_PTR itemp = ++tos;
entry_debug("push_true");
maxtos = tos > maxtos ? tos : maxtos;
if (itemp >= &stack[MAX_STACK_SIZE]) {
runtime_error(RUNTIME_STACK_OVERFLOW);
}
itemp->type = STKLOG;
itemp->value.integer = TRUE_REP;
stack_access_debug("Pushed", tos);
exit_debug("push_true");
return;
} /* end PUSH_TRUE */
/***************************************************************************/
/***************************************************************************/
/* put_false() Put false onto runtime stack */
put_false(sptr)
STACK_ITEM_PTR sptr;
{
STACK_ITEM_PTR itemp = sptr;
entry_debug("put_false");
itemp->type = STKLOG;
itemp->value.integer = FALSE_REP;
stack_access_debug("Put", itemp);
if (itemp > maxtos) {
runtime_warning(INVALID_STACK_ACCESS);
}
exit_debug("put_false");
return;
} /* end PUT_FALSE */
/***************************************************************************/
/***************************************************************************/
/* put_unknown() Put unknown onto runtime stack */
put_unknown(sptr)
STACK_ITEM_PTR sptr;
{
STACK_ITEM_PTR itemp = sptr;
entry_debug("put_unknown");
itemp->type = STKLOG;
itemp->value.integer = UNKNOWN_REP;
stack_access_debug("Put", itemp);
if (itemp > maxtos) {
runtime_warning(INVALID_STACK_ACCESS);
}
exit_debug("put_unknown");
return;
} /* end PUT_UNKNOWN */
/***************************************************************************/
/***************************************************************************/
/* put_true() Put true onto runtime stack */
put_true(sptr)
STACK_ITEM_PTR sptr;
{
STACK_ITEM_PTR itemp = sptr;
entry_debug("put_true");
itemp->type = STKLOG;
itemp->value.integer = TRUE_REP;
stack_access_debug("Put", itemp);
if (itemp > maxtos) {
runtime_warning(INVALID_STACK_ACCESS);
}
exit_debug("put_true");
return;
} /* end PUT_TRUE */
/***************************************************************************/
/***************************************************************************/
/* push_logical() Push logical value onto runtime stack */
push_logical(item_value)
LOGICAL_REP item_value;
{
STACK_ITEM_PTR itemp = ++tos;
entry_debug("push_logical");
maxtos = tos > maxtos ? tos : maxtos;
if (itemp >= &stack[MAX_STACK_SIZE]) {
runtime_error(RUNTIME_STACK_OVERFLOW);
}
itemp->type = STKLOG;
itemp->value.integer = item_value;
stack_access_debug("Pushed", tos);
exit_debug("push_logical");
return;
} /* end PUSH_LOGICAL */
/***************************************************************************/
/***************************************************************************/
/* put_logical() Put logical value onto runtime stack */
put_logical(sptr, item_value)
STACK_ITEM_PTR sptr;
LOGICAL_REP item_value;
{
STACK_ITEM_PTR itemp = sptr;
entry_debug("put_logical");
itemp->type = STKLOG;
itemp->value.integer = item_value;
stack_access_debug("Put", itemp);
if (itemp > maxtos) {
runtime_warning(INVALID_STACK_ACCESS);
}
exit_debug("put_logical");
return;
} /* end PUT_LOGICAL */
/***************************************************************************/
/***************************************************************************/
/* get_logical(sptr) Get a boolean/logical from the runtime stack */
LOGICAL_REP get_logical(sptr)
STACK_ITEM_PTR sptr;
{
STACK_ITEM_PTR itemp = sptr;
LOGICAL_REP item_value = UNKNOWN_REP;
entry_debug("get_logical");
stack_access_debug("Got", itemp);
if (itemp == NULL) {
runtime_warning(INVALID_STACK_ACCESS);
}
if (itemp->type != STKLOG) {
stack_warning(STKLOG, itemp->type);
}
else {
item_value = itemp->value.integer;
}
exit_debug("get_logical");
return(item_value);
} /* end GET_LOGICAL */
/***************************************************************************/
/***************************************************************************/
/* push_string(item_value) Push a string onto the stack */
STRING push_string(item_value)
STRING item_value;
{
STACK_ITEM_PTR itemp = ++tos;
entry_debug("push_string");
maxtos = tos > maxtos ? tos : maxtos;
if (itemp >= &stack[MAX_STACK_SIZE]) {
runtime_error(RUNTIME_STACK_OVERFLOW);
}
itemp->type = STKSTR;
itemp->value.string = item_value;
stack_access_debug("Pushed", tos);
exit_debug("push_string");
return;
} /* end PUSH_STRING */
/***************************************************************************/
/***************************************************************************/
/* put_string(sptr, item_value) Put a string into the stack */
STRING put_string(sptr, item_value)
STACK_ITEM_PTR sptr;
STRING item_value;
{
STACK_ITEM_PTR itemp = sptr;
entry_debug("put_string");
itemp->type = STKSTR;
itemp->value.string = item_value;
stack_access_debug("Put", itemp);
if (itemp > tos) {
runtime_warning(INVALID_STACK_ACCESS);
}
exit_debug("put_string");
return;
} /* end PUT_STRING */
/***************************************************************************/
/***************************************************************************/
/* get_stacked_string(sptr) Get a string from the stack */
STRING get_stacked_string(sptr)
STACK_ITEM_PTR sptr;
{
STACK_ITEM_PTR itemp = sptr;
STRING item_value = "";
entry_debug("get_stacked_string");
stack_access_debug("Got", itemp);
if (itemp == NULL) {
runtime_warning(INVALID_STACK_ACCESS);
}
if (itemp->type != STKSTR) {
stack_warning(STKSTR, itemp->type);
}
else {
item_value = itemp->value.string;
}
exit_debug("get_stacked_string");
return(item_value);
} /* end GET_STACKED_STRING */
/***************************************************************************/
/***************************************************************************/
/* push_undef() Push undefined `?' onto runtime stack */
push_undef()
{
STACK_ITEM_PTR itemp = ++tos;
entry_debug("push_undef");
maxtos = tos > maxtos ? tos : maxtos;
if (itemp >= &stack[MAX_STACK_SIZE]) {
runtime_error(RUNTIME_STACK_OVERFLOW);
}
itemp->type = STKUDF;
itemp->value.integer = '\?';
stack_access_debug("Pushed", tos);
exit_debug("push_undef");
return;
} /* end PUSH_UNDEF */
/***************************************************************************/
/***************************************************************************/
/* put_undef(sptr) Put undefined `?' into runtime stack */
put_undef(sptr)
STACK_ITEM_PTR sptr;
{
STACK_ITEM_PTR itemp = sptr;
entry_debug("put_undef");
itemp->type = STKUDF;
itemp->value.integer = '\?';
stack_access_debug("Put", itemp);
if (itemp > maxtos) {
runtime_warning(INVALID_STACK_ACCESS);
}
exit_debug("put_undef");
return;
} /* end PUT_UNDEF */
/***************************************************************************/
/***************************************************************************/
/* get_undef() Get undefined `?' from runtime stack */
char get_undef(sptr)
STACK_ITEM_PTR sptr;
{
char item_value = ' ';
STACK_ITEM_PTR itemp = sptr;
entry_debug("get_undef");
stack_access_debug("Got", itemp);
if (itemp == NULL) {
runtime_warning(INVALID_STACK_ACCESS);
}
if (itemp->type != STKUDF) {
item_value = ' ';
runtime_warning(STKUDF, itemp->type);
}
else {
item_value = itemp->value.integer;
}
exit_debug("get_undef");
return(item_value);
} /* end GET_UNDEF */
/***************************************************************************/
/***************************************************************************/
/* is_value_undef(sptr) TRUE iff value on stack at sptr is undef */
BOOLEAN is_value_undef(sptr)
STACK_ITEM_PTR sptr;
{
BOOLEAN result = FALSE;
if (sptr == NULL) {
runtime_warning(INVALID_STACK_ACCESS);
}
else {
result = (sptr->type == STKUDF);
}
return(result);
} /* end IS_VALUE_UNDEF */
/***************************************************************************/
/***************************************************************************/
/* copy_value(to, from) Copies stack value */
copy_value(top, fromp)
STACK_ITEM_PTR top;
STACK_ITEM_PTR fromp;
{
STACK_TYPE type;
entry_debug("copy_value (l2xixutl.c)");
if (top == NULL || fromp == NULL) {
runtime_warning(INVALID_STACK_ACCESS);
exit_debug("copy_value");
return;
}
stack_access_debug("Copy -- replacing: ", top);
stack_access_debug(" with: ", fromp);
type = fromp->type;
switch (type) {
case STKINT: {
top->type = type;
top->value.integer = fromp->value.integer;
break;
}
case STKREA: {
top->type = type;
top->value.real = fromp->value.real;
break;
}
case STKADD:
case STKARY:
case STKBAG:
case STKLST:
case STKSET:
case STKENT: {
top->type = type;
top->value.address = fromp->value.address;
break;
}
case STKUDF: {
put_undef(top);
break;
}
default: {
break;
}
} /* end switch */
exit_debug("copy_value");
return;
} /* end COPY_VALUE */
/***************************************************************************/
/***************************************************************************/
/* create_copy_value(fromp) Copies a stack value to a new value */
/* returns pointer to the new copied value */
STACK_ITEM_PTR create_copy_value(fromp)
STACK_ITEM_PTR fromp;
{
STACK_TYPE type;
STACK_ITEM_PTR top;
entry_debug("create_copy_value (l2xixutl.c)");
/* get the memory required */
top = alloc_struct(STACK_ITEM);
if (top == NULL) {
runtime_error(RUNTIME_STACK_OVERFLOW);
exit_debug("create_copy_value");
return(NULL);
}
type = fromp->type;
switch (type) {
case STKINT: {
top->type = type;
top->value.integer = fromp->value.integer;
break;
}
case STKREA: {
top->type = type;
top->value.real = fromp->value.real;
break;
}
case STKADD:
case STKARY:
case STKBAG:
case STKLST:
case STKSET:
case STKENT: {
top->type = type;
top->value.address = fromp->value.address;
break;
}
case STKUDF: {
put_undef(top);
break;
}
default: {
break;
}
} /* end switch */
stack_access_debug("Created copy of: ", fromp);
stack_access_debug(" as: ", top);
exit_debug("create_copy_value");
return(top);
} /* end CREATE_COPY_VALUE */
/***************************************************************************/
/***************************************************************************/
/* execute(rtn_idp) Execute a routine's code segment */
/* */
execute(rtn_idp)
SYMTAB_NODE_PTR rtn_idp;
{
entry_debug("execute");
routine_entry(rtn_idp);
get_ctoken();
exec_statement();
routine_exit(rtn_idp);
exit_debug("execute");
return;
} /* end execute */
/***************************************************************************/
/***************************************************************************/
/* routine_entry(rtn_idp) Point to the new routine's code segment */
/* and allocate its locals */
routine_entry(rtn_idp)
SYMTAB_NODE_PTR rtn_idp; /* new routine's id */
{
SYMTAB_NODE_PTR var_idp; /* local variable id */
entry_debug("routine_entry");
stack_debug();
trace_routine_entry(rtn_idp);
/* switch to new code segment */
code_segmentp = rtn_idp->defn.info.routine.code_segment;
/* allocate local variables */
for (var_idp = rtn_idp->defn.info.routine.locals;
var_idp != NULL;
var_idp = var_idp->next) {
alloc_local(var_idp->typep);
}
stack_debug();
exit_debug("routine_entry");
return;
} /* end routine_entry */
/***************************************************************************/
/***************************************************************************/
/* routine_exit(rtn_idp) Deallocate the routine's parameters and locals. */
/* Cut off its stack frame and return to the */
/* caller's code segment. */
routine_exit(rtn_idp)
SYMTAB_NODE_PTR rtn_idp; /* exiting routine's id */
{
SYMTAB_NODE_PTR idp; /* local variable or param id */
STACK_FRAME_HEADER_PTR hp; /* ptr to stack frame header */
TYPE_STRUCT_PTR target_tp; /* ptr to return type of routine */
TYPE_STRUCT_PTR expr_tp; /* ptr to type of RETURN expression */
entry_debug("routine_exit");
stack_debug();
trace_routine_exit(rtn_idp);
/* Treat a RETURN expression as an assignment to the routine's id */
if (ctoken == LPAREN) {
target_tp = rtn_idp->typep;
expr_tp = exec_expression();
exec_the_assign(stack_frame_basep, target_tp, expr_tp);
}
/* Deallocate parameters and local variables */
for (idp = rtn_idp->defn.info.routine.parms;
idp != NULL;
idp = idp->next) {
free_data(idp);
}
for (idp = rtn_idp->defn.info.routine.locals;
idp != NULL;
idp = idp->next) {
free_data(idp);
}
/* pop off the stack frame and return to caller's code segmnent */
entry_debug("routine_exit: pop the frame stack");
stack_debug();
hp = (STACK_FRAME_HEADER_PTR) stack_frame_basep;
code_segmentp = get_return_address(hp);
tos = (rtn_idp->defn.key == PROC_DEFN)
? stack_frame_basep - 1
: stack_frame_basep;
stack_frame_basep = (STACK_ITEM_PTR) get_dynamic_link(hp);
exit_debug("routine_exit: pop the frame stack");
stack_debug();
exit_debug("routine_exit");
return;
} /* end routine_exit */
/***************************************************************************/
/***************************************************************************/
/* push_stack_frame_header(old_level, new_level) Allocate the callee */
/* routine's stack frame */
push_stack_frame_header(old_level, new_level)
int old_level; /* level of caller */
int new_level; /* level of callee */
{
STACK_FRAME_HEADER_PTR hp;
STACK_ITEM_PTR newbasep; /* pointer to base of new frame */
entry_debug("push_stack_frame_header");
stack_debug();
/* push_integer(0); return value */
hp = (STACK_FRAME_HEADER_PTR) stack_frame_basep;
newbasep = tos + 1;
push_frame_data(0, NULL, NULL, NULL);
/* static link */
if (new_level == (old_level + 1)) {
/* calling a routine nested in the caller */
/* push pointer to caller's stack frame */
put_static_link(newbasep, (ADDRESS) hp);
}
else if (new_level == old_level) {
/* calling routine at the same level */
/* push pointer to stack of common parent */
put_static_link(newbasep, get_static_link(hp));
}
else {
/* calling a routine at a lesser level (nested less deeply ) */
/* push pointer to stack of nearest common ancestor */
int delta = (old_level - new_level);
while (delta-- >= 0) {
hp = (STACK_FRAME_HEADER_PTR) get_static_link(hp);
}
put_static_link(newbasep, hp);
}
put_dynamic_link(newbasep, stack_frame_basep);
stack_debug();
exit_debug("push_stack_frame_header");
return;
} /* end push_stack_frame_header */
/***************************************************************************/
/***************************************************************************/
/* alloc_local(tp) Allocate a local variable on the stack */
/* */
alloc_local(tp)
TYPE_STRUCT_PTR tp; /* ptr to type of variable */
{
LBS_PTR lbs; /* pointer to dynamic agg */
STACK_TYPE stktyp;
entry_debug("alloc_local");
if (tp == integer_typep) {
push_integer(0);
}
else if (tp == real_typep) {
push_real(0.0);
}
else if (tp == boolean_typep) {
push_false(); /* FALSE */
}
else if (tp == string_typep || tp->form == STRING_FORM) {
push_string(NULL);
}
else if (tp == logical_typep) {
push_unknown();
}
else {
switch (tp->form) {
case ENUM_FORM: {
push_integer(0);
break;
}
case SUBRANGE_FORM: {
alloc_local(tp->info.subrange.range_typep);
break;
}
case ARRAY_FORM: {
ADDRESS ptr = (ADDRESS) alloc_array(STACK_ITEM_PTR, tp->size);
sprintf(dbuffer, "Allocated %d bytes for array at %d\n",
tp->size, ptr);
debug_print(dbuffer);
push_address((ADDRESS) ptr);
break;
}
case ENTITY_FORM: {
ADDRESS ptr = (ADDRESS) alloc_array(STACK_ITEM_PTR, tp->size);
sprintf(dbuffer, "Allocated %d bytes for entity at %d\n",
tp->size, ptr);
debug_print(dbuffer);
push_address_type((ADDRESS) ptr, STKENT);
break;
}
case BAG_FORM:
case LIST_FORM:
case SET_FORM: {
lbs = lbs_init();
push_address_type(lbs, form2stack[tp->form]);
break;
}
} /* end switch */
}
exit_debug("alloc_local");
return;
} /* end alloc_local */
/***************************************************************************/
/***************************************************************************/
/* free_data(idp) Deallocate the data area of an array or record local */
/* variable or value parameter */
free_data(idp)
SYMTAB_NODE_PTR idp; /* parm or variable id */
{
STACK_ITEM_PTR itemp; /* ptr to stack item */
TYPE_STRUCT_PTR tp = idp->typep; /* ptr to id's type */
entry_debug("free_data");
if (((tp->form == ARRAY_FORM) || (tp->form == ENTITY_FORM)) &&
(idp->defn.key != VARPARM_DEFN)) {
stack_frame_debug();
itemp = stack_frame_basep + idp->defn.info.data.offset;
stack_item_debug(itemp);
free(get_address(itemp));
}
exit_debug("free_data");
return;
} /* end free_data */
/***************************************************************************/
/***************************************************************************/
/* push_frame_data(int, add, add, add) Push frame data onto runtime stack */
push_frame_data(ifrv, asl, adl, ara)
int ifrv; /* function return value */
ADDRESS asl; /* static link */
ADDRESS adl; /* dynamic link */
ADDRESS ara; /* return address */
{
entry_debug("push_frame_data");
stack_debug();
push_integer(ifrv);
push_address(asl);
push_address(adl);
push_address(ara);
stack_debug();
exit_debug("push_frame_data");
return;
} /* end push_frame_data */
/***************************************************************************/
/***************************************************************************/
/* put_static_link(framep, address) Put static link data into frame */
put_static_link(framep, address)
STACK_ITEM_PTR framep; /* pointer to frame */
ADDRESS address; /* static link */
{
entry_debug("put_static_link");
put_address((framep+1), address);
exit_debug("put_static_link");
} /* end put_static_link */
/***************************************************************************/
/***************************************************************************/
/* ADDRESS get_static_link(framep) Get static link data from frame */
ADDRESS get_static_link(framep)
STACK_ITEM_PTR framep; /* pointer to frame */
{
ADDRESS result;
entry_debug("get_static_link");
result = get_address(framep + 1);
exit_debug("get_static_link");
return(result);
} /* end get_static_link */
/***************************************************************************/
/***************************************************************************/
/* put_dynamic_link(framep, address) Put dynamic link data into frame */
put_dynamic_link(framep, address)
STACK_ITEM_PTR framep; /* pointer to frame */
ADDRESS address; /* dynamic link */
{
entry_debug("put_dynamic_link");
put_address((framep+2), address);
exit_debug("put_dynamic_link");
} /* end put_dynamic_link */
/***************************************************************************/
/***************************************************************************/
/* ADDRESS get_dynamic_link(framep) Get dynamic link data from frame */
ADDRESS get_dynamic_link(framep)
STACK_ITEM_PTR framep; /* pointer to base of frame */
{
ADDRESS result;
entry_debug("get_dynamic_link");
result = get_address(framep + 2);
exit_debug("get_dynamic_link");
return(result);
} /* end get_dynamic_link */
/***************************************************************************/
/***************************************************************************/
/* put_return_address(framep, address) Put return address data into frame */
put_return_address(framep, address)
STACK_ITEM_PTR framep; /* pointer to frame */
ADDRESS address; /* return link */
{
entry_debug("put_return_address");
put_address((framep+3), address);
exit_debug("put_return_address");
} /* end put_return_address */
/***************************************************************************/
/***************************************************************************/
/* ADDRESS get_return_address(framep) Get return address data from frame */
ADDRESS get_return_address(framep)
STACK_ITEM_PTR framep; /* pointer to frame */
{
ADDRESS result;
entry_debug("get_return_address");
result = get_address(framep + 3);
exit_debug("get_return_address");
return(result);
} /* end get_return_address */
/***************************************************************************/
/***************************************************************************/
/* stack_value_equal(a, b) Tests whether two stack items have the same */
/* data value. */
/* returns: UNKNOWN_REP if either arg is indeterminate */
/* otherwise TRUE_REP or FALSE_REP as appropriate */
LOGICAL_REP stack_value_equal(a, b)
STACK_ITEM_PTR a;
STACK_ITEM_PTR b;
{
STACK_TYPE atype, btype;
int ans;
XPRSAINT i1, i2;
XPRSAREAL r1, r2;
LOGICAL_REP b1, b2;
LOGICAL_REP log = FALSE_REP;
entry_debug("stack_value_equal (l2xixutl.c)");
/* check for indeterminate values */
atype = get_stackval_type(a);
if (atype == STKUDF) log = UNKNOWN_REP;
btype = get_stackval_type(b);
if (btype == STKUDF) log = UNKNOWN_REP;
if (log == UNKNOWN_REP) {
exit_debug("stack_value_equal (indeterminate UNKNOWN_REP)");
return(log);
}
/* check type equality */
if (atype != btype) {
exit_debug("stack_value_equal (different types FALSE_REP)");
return(FALSE_REP);
}
switch (atype) {
case STKINT: {
i2 = get_integer(b);
i1 = get_integer(a);
sprintf(dbuffer, "Checking %d == %d\n",
i1, i2);
debug_print(dbuffer);
ans = (i1 == i2);
sprintf(dbuffer, "Checked %d == %d, with result = ",
i1, i2);
debug_print(dbuffer);
if (ans) sprintf(dbuffer, "TRUE\n");
else sprintf(dbuffer, "FALSE\n");
debug_print(dbuffer);
break;
}
case STKREA: {
ans = (get_real(a) == get_real(b));
break;
}
case STKLOG: {
ans = (get_logical(a) == get_logical(b));
break;
}
case STKSTR: {
ans = strcmp(get_stacked_string(a), get_stacked_string(b));
if (ans == 0) ans = TRUE;
else ans = FALSE;
break;
}
default: { /* for now, only test on simple types */
exit_debug("stack_value_equal (default UNKNOWN_REP)");
return(UNKNOWN_REP);
break;
}
} /* end switch */
if (ans) {
exit_debug("stack_value_equal (end switch TRUE_REP)");
return(TRUE_REP);
}
else {
exit_debug("stack_value_equal (end switch FALSE_REP)");
return(FALSE_REP);
}
} /* end STACK_VALUE_EQUAL */
/***************************************************************************/