/* l2xidbug.c Interactive SLD debugging routines for LTX2X interpreter */
/* 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 "l2xiexec.h"
#include "l2xiidbg.h"
#define MAX_BREAKS 16
#define MAX_WATCHES 16
#define COMMAND_QUERY "Command? "
/* EXTERNALS */
extern int level;
extern SYMTAB_NODE_PTR symtab_display[];
extern STACK_ITEM_PTR tos;
extern int line_number;
extern int buffer_offset;
extern BOOLEAN print_flag;
extern ICT *code_segmentp;
extern ICT *statement_startp;
extern int ctoken;
extern int exec_line_number;
extern int isynt_error_count;
extern char *bufferp;
extern int ch;
extern char source_buffer[];
extern char word_string[];
extern int token;
extern LITERAL literal;
extern BOOLEAN block_flag;
extern ICT *code_buffer;
extern ICT *code_bufferp;
extern ICT *code_segmentp;
extern BOOLEAN is_value_undef();
/* GLOBALS */
FILE *console;
BOOLEAN debugger_command_flag, /* TRUE during debug command */
halt_flag, /* TRUE to pause for debug command */
trace_flag, /* TRUE to trace statement */
step_flag, /* TRUE to single-step */
entry_flag, /* TRUE to trace routine entry */
exit_flag, /* TRUE to trace routine exit */
traceall_flag, /* TRUE to trace everything */
stack_flag; /* TRUE to watch the stack */
int break_count; /* count of breakpoints */
int break_list[MAX_BREAKS]; /* list of breakpoints */
int watch_count; /* count of watches */
SYMTAB_NODE_PTR watch_list[MAX_WATCHES]; /* list of watches */
typedef struct { /* watch structure */
SYMTAB_NODE_PTR watch_idp; /* id node watched variable */
BOOLEAN store_flag; /* TRUE to trace stores */
BOOLEAN fetch_flag; /* TRUE to trace fetches */
} WATCH_STRUCT, *WATCH_STRUCT_PTR;
/* char *symbol_strings[EOTC]; */
/* array of the strings which form tokens */
char *symbol_strings[] = {
#define sctc(a, b, c) c,
#include "l2xisctc.h"
#undef sctc
};
/* array of strings which corresponding to form types */
char *form2str[] = {
#define fotc(a, b, c, d) d,
#define sotc(a, b, c, d)
#define sftc(a, b, c, d) d,
#include "l2xisftc.h"
#undef fotc
#undef sotc
#undef sftc
};
/* array of strings which corresponding to stack types */
char *stack2str[] = {
#define fotc(a, b, c, d)
#define sotc(a, b, c, d) b,
#define sftc(a, b, c, d) b,
#include "l2xisftc.h"
#undef fotc
#undef sotc
#undef sftc
};
/********************************************************************/
/* init_debugger() Initialise interactive debugger */
init_debugger()
{
int i;
if (SLD_OFF) return;
/* initialise the globals */
/* console = fopen("CON", "r"); */
console = stdin;
/* init_symbol_strings(); */
/* code_buffer = alloc_bytes(MAX_SOURCE_LINE_LENGTH + 1); */
print_flag = FALSE;
halt_flag = block_flag = TRUE;
debugger_command_flag = trace_flag = step_flag
= entry_flag = exit_flag
= FALSE;
traceall_flag = stack_flag = FALSE;
break_count = 0;
for (i = 0; i <MAX_BREAKS; i++) break_list[i] = 0;
watch_count = 0;
for (i = 0; i <MAX_WATCHES; i++) watch_list[i] = NULL;
} /* end init_debugger */
/********************************************************************/
/********************************************************************/
/* read_debugger_command() Read and process a user's debug command */
read_debugger_command()
{
BOOLEAN done = FALSE;
entry_debug("read_debugger_command");
do {
printf("\n%s", COMMAND_QUERY);
/* read in comand and replace final \nEOS with ;;EOS */
bufferp = fgets(source_buffer, MAX_SOURCE_LINE_LENGTH, console);
strcpy(&source_buffer[strlen(source_buffer) - 1], ";;\0");
buffer_offset = 0;
ch = *bufferp++;
buffer_offset++;
code_bufferp = code_buffer;
isynt_error_count = 0;
get_token();
/* process the command */
switch (token) {
case SEMICOLON: {
done = TRUE;
break;
}
case IDENTIFIER: {
execute_debugger_command();
break;
}
}
if (token != SEMICOLON) {
error(UNEXPECTED_TOKEN);
}
} while (!done); /* end do */
debugger_command_flag = FALSE;
exit_debug("read_debugger_command");
} /* end read_debugger_command */
/********************************************************************/
/********************************************************************/
/* execute_debugger_command() Execute a debugger command */
execute_debugger_command()
{
WATCH_STRUCT_PTR wp;
WATCH_STRUCT_PTR allocate_watch();
if (strcmp(word_string, "trace") == 0) {
trace_flag = TRUE;
step_flag = FALSE;
get_token();
}
else if (strcmp(word_string, "untrace") == 0) {
trace_flag = FALSE;
get_token();
}
else if (strcmp(word_string, "step") == 0) {
step_flag = TRUE;
trace_flag = FALSE;
get_token();
}
else if (strcmp(word_string, "unstep") == 0) {
step_flag = FALSE;
get_token();
}
else if (strcmp(word_string, "break") == 0) {
set_breakpoint();
}
else if (strcmp(word_string, "unbreak") == 0) {
remove_breakpoint();
}
else if (strcmp(word_string, "entry") == 0) {
entry_flag = TRUE;
get_token();
}
else if (strcmp(word_string, "unentry") == 0) {
entry_flag = FALSE;
get_token();
}
else if (strcmp(word_string, "exit") == 0) {
exit_flag = TRUE;
get_token();
}
else if (strcmp(word_string, "unexit") == 0) {
exit_flag = FALSE;
get_token();
}
else if (strcmp(word_string, "watch") == 0) {
wp = allocate_watch();
if (wp != NULL) {
wp->store_flag = TRUE;
wp->fetch_flag = TRUE;
}
}
else if (strcmp(word_string, "unwatch") == 0) {
remove_watch();
}
else if (strcmp(word_string, "store") == 0) {
wp = allocate_watch();
if (wp != NULL) {
wp->store_flag = TRUE;
}
}
else if (strcmp(word_string, "fetch") == 0) {
wp = allocate_watch();
if (wp != NULL) {
wp->fetch_flag = TRUE;
}
}
else if (strcmp(word_string, "show") == 0) {
show_value();
}
else if (strcmp(word_string, "assign") == 0) {
assign_variable();
}
else if (strcmp(word_string, "where") == 0) {
print_statement();
get_token();
}
else if (strcmp(word_string, "kill") == 0) {
printf("Program killed.\n");
exit(0);
}
else if (strcmp(word_string, "traceall") == 0) {
traceall_flag = TRUE;
get_token();
}
else if (strcmp(word_string, "untraceall") == 0) {
traceall_flag = FALSE;
get_token();
}
else if (strcmp(word_string, "stack") == 0) {
stack_flag = TRUE;
stack_debug();
get_token();
}
else if (strcmp(word_string, "unstack") == 0) {
stack_flag = FALSE;
get_token();
}
return;
} /* end execute_debugger_command */
/********************************************************************/
/* TRACING ROUTINES */
/********************************************************************/
/* trace_statement_execution() Called just before the execution */
/* of each statement */
trace_statement_execution()
{
if (SLD_OFF) return;
if (traceall_flag) {
sprintf(dbuffer, ">> Stmt %d\n", exec_line_number);
log_print(dbuffer);
}
if (break_count > 0) {
int i;
/* check if this statement is a breakpoint */
for (i = 0; i < break_count; i++) {
if (exec_line_number == break_list[i]) {
printf("\nBreakpoint");
print_statement();
halt_flag = TRUE;
break;
}
}
}
/* pause to read debugger command */
if (halt_flag) {
read_debugger_command();
halt_flag = step_flag;
}
/* if single stepping, print the current statement */
/* if tracing, print the current line number */
if (step_flag) print_statement();
if (trace_flag && !traceall_flag) print_line_number();
} /* end trace_statement_execution */
/********************************************************************/
/********************************************************************/
/* trace_routine_entry(idp) Called at entry to a routine */
trace_routine_entry(idp)
SYMTAB_NODE_PTR idp; /* routine id */
{
if (SLD_OFF) return;
if (traceall_flag) {
sprintf(dbuffer, ">> Entering routine %s\n", idp->name);
log_print(dbuffer);
}
else if (entry_flag) {
printf("\nEntering %s\n", idp->name);
}
} /* end trace_routine_entry */
/********************************************************************/
/********************************************************************/
/* trace_routine_exit(idp) Called at exit from a routine */
trace_routine_exit(idp)
SYMTAB_NODE_PTR idp; /* routine id */
{
if (SLD_OFF) return;
if (traceall_flag) {
sprintf(dbuffer, ">> Exiting routine %s\n", idp->name);
log_print(dbuffer);
}
else if (exit_flag) {
printf("\nExiting %s\n", idp->name);
}
} /* end trace_routine_exit */
/********************************************************************/
/********************************************************************/
/* trace_data_store(idp, idp_tp, targetp, target_tp) Called just */
/* before storing data in a variable */
trace_data_store(idp, idp_tp, targetp, target_tp)
SYMTAB_NODE_PTR idp; /* id of target variable */
TYPE_STRUCT_PTR idp_tp; /* ptr to idp's type */
STACK_ITEM_PTR targetp; /* ptr to target location */
TYPE_STRUCT_PTR target_tp; /* ptr to target's type */
{
if (SLD_OFF) return;
if (traceall_flag) {
sprintf(dbuffer, ">> %s", idp->name);
log_print(dbuffer);
if (idp_tp->form == ARRAY_FORM ||
idp_tp->form == BAG_FORM ||
idp_tp->form == LIST_FORM ||
idp_tp->form == SET_FORM ) {
log_print("[*]");
}
else if (idp_tp->form == ENTITY_FORM) {
log_print(".*");
}
print_data_value_debug(targetp, target_tp, ":=");
}
/* check if variable is being watched for stores */
else if ((idp->info != NULL) && ((WATCH_STRUCT_PTR) idp->info)->store_flag) {
printf("\nAt %d: Store %s", exec_line_number, idp->name);
if (idp_tp->form == ARRAY_FORM ||
idp_tp->form == BAG_FORM ||
idp_tp->form == LIST_FORM ||
idp_tp->form == SET_FORM ) {
printf("[*]");
}
else if (idp_tp->form == ENTITY_FORM) {
printf(".*");
}
print_data_value(targetp, target_tp, ":=");
}
return;
} /* end trace_data_store */
/********************************************************************/
/********************************************************************/
/* trace_data_fetch(idp, tp, datap) Called just */
/* before fetching data from a variable */
trace_data_fetch(idp, tp, datap)
SYMTAB_NODE_PTR idp; /* id of target variable */
TYPE_STRUCT_PTR tp; /* ptr to idp's type */
STACK_ITEM_PTR datap; /* ptr to data */
{
TYPE_STRUCT_PTR idp_tp = idp->typep;
if (SLD_OFF) return;
if (traceall_flag) {
sprintf(dbuffer, ">> %s", idp->name);
log_print(dbuffer);
if (idp_tp->form == ARRAY_FORM ||
idp_tp->form == BAG_FORM ||
idp_tp->form == LIST_FORM ||
idp_tp->form == SET_FORM ) {
log_print("[*]");
}
else if (idp_tp->form == ENTITY_FORM) {
log_print(".*");
}
print_data_value_debug(datap, tp, "=");
}
/* check if variable is being watched for fetches */
else if ((idp->info != NULL) && ((WATCH_STRUCT_PTR) idp->info)->fetch_flag) {
printf("\nAt %d: Fetch %s", exec_line_number, idp->name);
if (idp_tp->form == ARRAY_FORM ||
idp_tp->form == BAG_FORM ||
idp_tp->form == LIST_FORM ||
idp_tp->form == SET_FORM ) {
printf("[*]");
}
else if (idp_tp->form == ENTITY_FORM) {
printf(".*");
}
print_data_value(datap, tp, "=");
}
return;
} /* end trace_data_fetch */
/********************************************************************/
/* PRINTING ROUTINES */
/********************************************************************/
/* print_statement() Uncrunch and print a statement */
print_statement()
{
int tk; /* token code */
BOOLEAN done = FALSE;
ICT *csp = statement_startp;
/* entry_debug("print_statement"); */
printf("\nAt %3d:", exec_line_number);
do {
switch (tk = *csp++) {
case SEMICOLON:
case END:
case ELSE:
case THEN:
case UNTIL:
case BEGIN:
case OF:
case STATEMENT_MARKER: {
done = TRUE;
break;
}
default: {
done = FALSE;
switch(tk) {
case ADDRESS_MARKER: {
csp++;
break;
}
case IDENTIFIER:
case NUMBER_LITERAL:
case STRING_LITERAL: {
SYMTAB_NODE_PTR np = *((SYMTAB_NODE_PTR *) csp);
printf(" %s", np->name);
csp++;
break;
}
default: {
printf(" %s", symbol_strings[tk]);
break;
}
} /* end switch */
}
} /* end switch */
} while (!done); /* end do */
printf("\n");
/* exit_debug("print_statement"); */
} /* end print_statement */
/********************************************************************/
/********************************************************************/
/* print_line_number() Print the current line number */
print_line_number()
{
printf("<%d>", exec_line_number);
} /* end print_line_number */
/********************************************************************/
/********************************************************************/
/* print_data_value(datap, tp, str) Print a data value */
print_data_value(datap, tp, str)
STACK_ITEM_PTR datap; /* ptr to data value */
TYPE_STRUCT_PTR tp; /* ptr to type of stack item */
char *str; /* " = " or " := " */
{
STACK_TYPE stype;
LOGICAL_REP log;
TYPE_FORM form;
form = tp->form;
if (form == ARRAY_FORM ||
form == BAG_FORM ||
form == LIST_FORM ||
form == SET_FORM ||
form == ENTITY_FORM ) {
printf(" %s <%s>\n", str, form2str[form]);
return;
}
stype = get_stackval_type(datap);
if (stype == STKUDF) {
printf(" %s %c\n", str, get_undef(datap));
}
else if (stype == STKINT) {
printf(" %s %d\n", str, get_integer(datap));
}
else if (stype == STKREA) {
printf(" %s %0.6g\n", str, get_real(datap));
}
else if (stype == STKLOG) {
log = get_logical(datap);
if (log == TRUE_REP) {
printf(" %s %s\n", str, "TRUE");
}
else if (log == FALSE_REP) {
printf(" %s %s\n", str, "FALSE");
}
else {
printf(" %s %s\n", str, "UNKNOWN");
}
}
else if (stype == STKSTR) {
printf(" %s %s\n", str, get_stacked_string(datap));
}
return;
} /* end print_data_value */
/********************************************************************/
/********************************************************************/
/* print_data_value_debug(datap, tp, str) Print a data value */
print_data_value_debug(datap, tp, str)
STACK_ITEM_PTR datap; /* ptr to data value */
TYPE_STRUCT_PTR tp; /* ptr to type of stack item */
char *str; /* " = " or " := " */
{
STACK_TYPE stype;
LOGICAL_REP log;
TYPE_FORM form;
form = tp->form;
if (form == ARRAY_FORM ||
form == BAG_FORM ||
form == LIST_FORM ||
form == SET_FORM ||
form == ENTITY_FORM ) {
sprintf(dbuffer, " %s <%s>\n", str, form2str[form]);
log_print(dbuffer);
return;
}
stype = get_stackval_type(datap);
if (stype == STKUDF) {
sprintf(dbuffer, " %s %c\n", str, get_undef(datap));
log_print(dbuffer);
}
else if (stype == STKINT) {
sprintf(dbuffer, " %s %d\n", str, get_integer(datap));
log_print(dbuffer);
}
else if (stype == STKREA) {
sprintf(dbuffer, " %s %0.6g\n", str, get_real(datap));
log_print(dbuffer);
}
else if (stype == STKLOG) {
log = get_logical(datap);
if (log == TRUE_REP) {
sprintf(dbuffer, " %s %s\n", str, "TRUE");
}
else if (log == FALSE_REP) {
sprintf(dbuffer, " %s %s\n", str, "FALSE");
}
else {
sprintf(dbuffer, " %s %s\n", str, "UNKNOWN");
}
log_print(dbuffer);
}
else if (stype == STKSTR) {
sprintf(dbuffer, " %s %s\n", str, get_stacked_string(datap));
log_print(dbuffer);
}
return;
} /* end print_data_value_debug */
/********************************************************************/
/* BREAKPOINTS AND WATCHES */
/********************************************************************/
/* set_breakpoint() Set a breakpoint, or print all breakpoints in */
/* the break list */
set_breakpoint()
{
int i, number;
get_token();
switch (token) {
case SEMICOLON: { /* no line number --- list all breakpoints */
printf("Statement breakpoints at:\n");
for (i = 0; i < break_count; i++) {
printf("%5d\n", break_list[i]);
}
break;
}
case NUMBER_LITERAL: { /* set breakpoint by appending to list */
if (literal.type == INTEGER_LIT) {
number = literal.value.integer;
if ((number > 0) && (number <= line_number)) {
if (break_count < MAX_BREAKS) {
break_list[break_count] = number;
++break_count;
}
else {
printf("Break list is full.\n");
}
}
else {
error(VALUE_OUT_OF_RANGE);
}
}
else {
error(UNEXPECTED_TOKEN);
}
get_token();
break;
}
} /* end switch */
} /* end set_breakpoint */
/********************************************************************/
/********************************************************************/
/* remove_breakpoint() Remove a specified breakpoint, or all */
remove_breakpoint()
{
int i, j, number;
get_token();
switch (token) {
case SEMICOLON: { /* no line number --- remove all breakpoints */
for (i = 0; i < break_count; i++) {
break_list[i] = 0;
}
break_count = 0;
break;
}
case NUMBER_LITERAL: { /* remove breakpoint from list, and move others up */
if (literal.type == INTEGER_LIT) {
number = literal.value.integer;
if (number > 0) {
for (i = 0; i < break_count; i++) {
if (break_list[i] == number) {
break_list[i] = 0;
--break_count;
for (j = i; j < break_count; j++) {
break_list[j] = break_list[j+1];
}
}
}
}
}
else {
error(VALUE_OUT_OF_RANGE);
}
get_token();
break;
}
} /* end switch */
} /* end remove_breakpoint */
/********************************************************************/
/********************************************************************/
/* allocate_watch() Return a pointer to a watch structure, */
/* or print all variables being watched */
WATCH_STRUCT_PTR allocate_watch()
{
int i;
SYMTAB_NODE_PTR idp;
WATCH_STRUCT_PTR wp;
get_token();
switch (token) {
case SEMICOLON: { /* no variable, print them all */
printf("Variables being watched:\n");
for (i = 0; i < watch_count; i++) {
idp = watch_list[i];
if (idp != NULL) {
wp = (WATCH_STRUCT_PTR) idp->info;
printf("%16s ", idp->name);
if (wp->store_flag) printf(" (store)");
if (wp->fetch_flag) printf(" (fetch)");
printf("\n");
}
}
return(NULL);
}
case IDENTIFIER: {
search_and_find_all_symtab(idp);
get_token();
switch (idp->defn.key) {
case UNDEFINED: {
return(NULL);
}
case CONST_DEFN:
case VAR_DEFN:
case ATTRIBUTE_DEFN:
case VALPARM_DEFN:
case VARPARM_DEFN: {
if (idp->info != NULL) { /* being watched, return ptr to structure */
return((WATCH_STRUCT_PTR) idp->info);
}
else if (watch_count < MAX_WATCHES) { /* a new structure */
wp = alloc_struct(WATCH_STRUCT);
wp->store_flag = FALSE;
wp->fetch_flag = FALSE;
idp->info = (char *) wp;
watch_list[watch_count] = idp;
watch_count++;
return(wp);
}
else {
printf("Watch list is full.\n");
return(NULL);
}
}
default: {
error(INVALID_IDENTIFIER_USAGE);
return(NULL);
}
} /* end switch */
break;
}
} /* end switch */
} /* end allocate_watch */
/********************************************************************/
/********************************************************************/
/* remove_watch() Remove a variable from the watch list, */
/* or remove all variables being watched */
remove_watch()
{
int i, j;
SYMTAB_NODE_PTR idp;
WATCH_STRUCT_PTR wp;
get_token();
switch (token) {
case SEMICOLON: { /* no variable, remove them all */
for (i = 0; i < watch_count; i++) {
if ((idp = watch_list[i]) != NULL) {
wp = (WATCH_STRUCT_PTR) idp->info;
watch_list[i] = NULL;
idp->info = NULL;
free(wp);
}
}
watch_count = 0;
break;
}
case IDENTIFIER: { /* remove it from the list and move other up */
search_and_find_all_symtab(idp);
get_token();
if ((idp != NULL) && (idp->info != NULL)) {
wp = (WATCH_STRUCT_PTR) idp->info;
for (i = 0; i < watch_count; i++) {
if (watch_list[i] == idp) {
watch_list[i] = NULL;
idp->info = NULL;
free(wp);
--watch_count;
for (j = i; j < watch_count; j++) {
watch_list[j] = watch_list[j + 1];
}
break;
}
}
}
break;
}
} /* end switch */
} /* end remove_watch */
/********************************************************************/
/* SHOW and ASSIGN */
/********************************************************************/
/* show-value() Print the value of an expression */
show_value()
{
get_token();
switch (token) {
case SEMICOLON: {
error(INVALID_EXPRESSION);
break;
}
default: { /* parse and execute expression from code buffer */
TYPE_STRUCT_PTR expression();
TYPE_STRUCT_PTR tp = expression(); /* parse */
ICT *save_code_segmentp = code_segmentp;
int save_ctoken = ctoken;
if (isynt_error_count > 0) break;
/* switch to the code buffer */
code_segmentp = code_buffer + 1;
get_ctoken();
exec_expression(); /* execute */
/* print and then pop the value */
if ((tp->form == ARRAY_FORM) ||
(tp->form == BAG_FORM) ||
(tp->form == LIST_FORM) ||
(tp->form == SET_FORM) ||
(tp->form == ENTITY_FORM)) {
print_data_value(get_address(tos), tp, " ");
}
else {
print_data_value(tos, tp, " ");
}
pop();
/* resume the code segment */
code_segmentp = save_code_segmentp;
ctoken = save_ctoken;
break;
}
} /* end switch */
} /* end show_value */
/********************************************************************/
/********************************************************************/
/* assign_variable() Exexcute an assignment statement */
assign_variable()
{
get_token();
switch (token) {
case SEMICOLON: {
error(MISSING_VARIABLE);
break;
}
case IDENTIFIER : { /* parse and execute the assignment statement from code buffer */
SYMTAB_NODE_PTR idp;
ICT *save_code_segmentp = code_segmentp;
int save_ctoken = ctoken;
search_and_find_all_symtab(idp);
assignment_statement(idp); /* parse */
if (isynt_error_count > 0) break;
/* switch to the code buffer */
code_segmentp = code_buffer + 1;
get_ctoken();
idp = get_symtab_cptr();
exec_assignment_statement(idp); /* execute */
/* resume the code segment */
code_segmentp = save_code_segmentp;
ctoken = save_ctoken;
break;
}
} /* end switch */
} /* end assign_variable */
/********************************************************************/
/* STACK */
/********************************************************************/
/* stack_debug() Print runtime stack */
extern STACK_ITEM *stack; /* runtime stack */
extern STACK_ITEM_PTR tos; /* top of stack */
extern STACK_ITEM_PTR stack_frame_basep; /* ptr to stack frame base */
extern STACK_ITEM_PTR maxtos; /* current max top of stack */
stack_debug()
{
STACK_ITEM_PTR basep = stack; /* base of stack */
STACK_ITEM_PTR i;
if (!stack_flag) return;
log_print("\n The runtime stack with: ");
stack_frame_debug();
for (i = basep; i <= tos; i++) {
stack_item_debug(i);
}
return;
} /* end stack_debug */
/********************************************************************/
/********************************************************************/
/* tos_debug() Print top of runtime stack */
tos_debug()
{
if (!stack_flag) return;
log_print(" Top of runtime stack.");
stack_item_debug(tos);
return;
} /* end tos_debug */
/********************************************************************/
/********************************************************************/
/* stack_access_debug(s, sptr) Print stack access kind */
stack_access_debug(s, sptr)
char s[]; /* access kind */
STACK_ITEM_PTR sptr; /* stack position */
{
if (!stack_flag) return;
sprintf(dbuffer, " %-7s ==>", s);
log_print(dbuffer);
stack_item_debug(sptr);
if (sptr > maxtos) { /* probably looking at data area */
log_print(" Accessed data area:\n");
data_item_debug(sptr);
}
return;
} /* end stack_access_debug */
/********************************************************************/
/********************************************************************/
/* stack_item_debug(sptr) Print a runtime stack item */
stack_item_debug(sptr)
STACK_ITEM_PTR sptr; /* ptr to stack item */
{
STACK_TYPE stype;
if (!stack_flag) return;
if ((sptr < stack) || (sptr > maxtos)) { /* out of stack range */
runtime_warning(INVALID_STACK_ACCESS);
}
stype = sptr->type;
switch (stype) {
case STKINT: {
sprintf(dbuffer, " (Entry %d : %s is %d)\n",
sptr, stack2str[stype], sptr->value.integer);
log_print(dbuffer);
break;
}
case STKREA: {
sprintf(dbuffer, " (Entry %d : %s is %f)\n",
sptr, stack2str[stype], sptr->value.real);
log_print(dbuffer);
break;
}
case STKLOG: {
sprintf(dbuffer, " (Entry %d : %s is ",
sptr, stack2str[stype]);
log_print(dbuffer);
if (sptr->value.integer == FALSE_REP) sprintf(dbuffer, "FALSE)\n");
else if (sptr->value.integer == TRUE_REP) sprintf(dbuffer, "TRUE)\n");
else sprintf(dbuffer, "UNKNOWN)\n");
log_print(dbuffer);
break;
}
case STKSTR: {
sprintf(dbuffer, " (Entry %d : %s is %d)\n",
sptr, stack2str[stype], sptr->value.string);
log_print(dbuffer);
break;
}
case STKARY:
case STKADD: {
sprintf(dbuffer, " (Entry %d : %s is %d)\n",
sptr, stack2str[stype], sptr->value.address);
log_print(dbuffer);
break;
}
case STKUDF: { /* undefined */
sprintf(dbuffer, " (Entry %d : %s is '%c')\n",
sptr, stack2str[stype], sptr->value.integer);
log_print(dbuffer);
break;
}
case STKBAG:
case STKLST:
case STKSET: {
sprintf(dbuffer, " (Entry %d : %s is %d)\n",
sptr, stack2str[stype], sptr->value.head);
log_print(dbuffer);
break;
}
case STKENT: {
sprintf(dbuffer, " (Entry %d : %s is %d)\n",
sptr, stack2str[stype], sptr->value.address);
log_print(dbuffer);
break;
}
default: {
sprintf(dbuffer, " (Entry %d : unknown type (%d))\n",
sptr, sptr->type);
log_print(dbuffer);
break;
}
}
return;
} /* end stack_item_debug */
/********************************************************************/
/********************************************************************/
/* data_item_debug(sptr) Print data of array/entity item */
data_item_debug(sptr)
STACK_ITEM_PTR sptr; /* ptr to 'start' of data item */
{
STACK_TYPE kind;
STACK_ITEM_PTR aptr = sptr;
int n = 1;
int maxn = 20; /* max number of elements to be printed */
if (!stack_flag) return;
kind = aptr->type;
while ( (kind >= STKINT) && (kind <= STKADD) && (n <= maxn) ) {
stack_item_debug(aptr);
aptr++;
n++;
kind = aptr->type;
}
return;
} /* end data_item_debug */
/********************************************************************/
/********************************************************************/
/* stack_frame_debug() print the stack frame base pointer */
stack_frame_debug()
{
if (!stack_flag) return;
sprintf(dbuffer, " (Stack frame base at %d)\n", stack_frame_basep);
log_print(dbuffer);
return;
} /* end stack_frame_debug */
/********************************************************************/
/********************************************************************/
/* expression_type_debug(tptr) print type of type */
extern TYPE_STRUCT_PTR integer_typep, real_typep,
boolean_typep;
extern TYPE_STRUCT_PTR logical_typep, string_typep, binary_typep,
generic_typep, any_typep;
expression_type_debug(tptr)
TYPE_STRUCT_PTR tptr; /* pointer to type structure */
{
if (!stack_flag) return;
if (tptr == integer_typep) {
log_print(" Type is: INTEGER TYPE\n");
return;
}
else if (tptr == real_typep) {
log_print(" Type is: REAL TYPE\n");
return;
}
else if (tptr == boolean_typep) {
log_print(" Type is: BOOLEAN TYPE\n");
return;
}
else if (tptr == logical_typep) {
log_print(" Type is: LOGICAL TYPE\n");
return;
}
else if (tptr == string_typep) {
log_print(" Type is: STRING TYPE\n");
return;
}
else if (tptr == binary_typep) {
log_print(" Type is: BINARY TYPE\n");
return;
}
else if (tptr == generic_typep) {
log_print(" Type is: GENERIC TYPE\n");
return;
}
else if (tptr == any_typep) {
log_print(" Type is: INDETERMINATE TYPE\n");
return;
}
switch (tptr->form) {
case NO_FORM: {
log_print(" Type is: NO FORM\n");
return;
}
case SCALAR_FORM: {
log_print(" Type is: SCALAR FORM\n");
return;
}
case ENUM_FORM: {
log_print(" Type is: ENUM FORM\n");
return;
}
case SUBRANGE_FORM: {
log_print(" Type is: SUBRANGE FORM\n");
return;
}
case ARRAY_FORM: {
log_print(" Type is: ARRAY of ");
expression_type_debug(tptr->info.array.elmt_typep);
return;
}
case BAG_FORM: {
log_print(" Type is: BAG of ");
expression_type_debug(tptr->info.dynagg.elmt_typep);
return;
}
case LIST_FORM: {
log_print(" Type is: LIST of ");
expression_type_debug(tptr->info.dynagg.elmt_typep);
return;
}
case SET_FORM: {
log_print(" Type is: SET of ");
expression_type_debug(tptr->info.dynagg.elmt_typep);
return;
}
case ENTITY_FORM: {
log_print(" Type is: ENTITY FORM\n");
return;
}
case STRING_FORM: {
log_print(" Type is: STRING FORM\n");
return;
}
default: {
log_print(" Type is: UNKNOWN\n");
return;
}
} /* end switch */
} /* end expression_type_debug */
/********************************************************************/