SCP: Add C style expression support for IF conditions and SET ENV -A

Expression evaluation code provided by Gabriel Pizzolato.
This commit is contained in:
Mark Pizzolato 2018-05-01 22:08:06 -07:00
parent 8fe02ad6d1
commit 4e508cfc29
4 changed files with 696 additions and 58 deletions

View file

@ -328,6 +328,7 @@ Device simulator authors can easily schedule their device polling activities to
SCREENSHOT filename.bmp Save video window to the specified file
SET ENV Name=Value Set Environment variable
SET ENV -p "Prompt" Name=Default Gather User input into an Environment Variable
SET ENV -a Name=Expression Evaluate an expression and store result in an Environment Variable
SET ASYNCH Enable Asynchronous I/O
SET NOASYNCH Disable Asynchronous I/O
SET VERIFY Enable command display while processing DO command files
@ -358,6 +359,7 @@ Device simulator authors can easily schedule their device polling activities to
NOOP A no-op command
ON Establish or cancel an ON condition dispatch
IF Test some simulator state and conditionally execute commands
IF (C-style-expression) Test some simulator state and conditionally execute commands
CD Change working directory
SET DEFAULT Change working directory
PWD Show working directory

Binary file not shown.

637
scp.c
View file

@ -481,6 +481,7 @@ void fprint_capac (FILE *st, DEVICE *dptr, UNIT *uptr);
void fprint_sep (FILE *st, int32 *tokens);
REG *find_reg_glob (CONST char *ptr, CONST char **optr, DEVICE **gdptr);
REG *find_reg_glob_reason (CONST char *cptr, CONST char **optr, DEVICE **gdptr, t_stat *stat);
const char *sim_eval_expression (const char *cptr, t_svalue *value, t_bool parens_required, t_stat *stat);
/* Forward references */
@ -671,6 +672,7 @@ const struct scp_error {
{"EXPECT", "Expect matched"},
{"AMBREG", "Ambiguous register name"},
{"REMOTE", "remote console command"},
{"INVEXPR", "invalid expression"},
};
const size_t size_map[] = { sizeof (int8),
@ -1231,9 +1233,42 @@ static const char simh_help[] =
"+SET NOASYNCH disable asynchronous I/O\n"
#define HLP_SET_ENVIRON "*Commands SET Environment"
"3Environment\n"
"4Explicitily Changing A Variable\n"
"4Explicitily Changing a Variable\n"
"+SET ENVIRONMENT name=val set environment variable\n"
"+SET ENVIRONMENT name clear environment variable\n"
"4Arithmetic Computations into a Variable\n\n"
"+SET ENVIRONMENT -A name=expression\n\n"
" Expression can contain any of these C language operators:\n\n"
"++ ( Open Parenthesis\n"
"++ ) Close Parenthesis\n"
"++ - Subtraction\n"
"++ + Addition\n"
"++ * Multiplication\n"
"++ / Division\n"
"++ %% Modulus\n"
"++ && Logical AND\n"
"++ || Logical OR\n"
"++ & Bitwise AND\n"
"++ | Bitwise Inclusive OR\n"
"++ ^ Bitwise Exclusive OR\n"
"++ >> Bitwise Right Shift\n"
"++ << Bitwise Left Shift\n"
"++ == Equality\n"
"++ != Inequality\n"
"++ <= Less than or Equal\n"
"++ < Less than\n"
"++ >= Greater than or Equal\n"
"++ > Greater than\n"
"++ ! Logical Negation\n"
"++ ~ Bitwise Compliment\n\n"
" Operator precedence is consistent with C language precedence.\n\n"
" Expression can contain arbitrary combinations of constant\n"
" values, simulator registers and environment variables \n"
"5Examples:\n"
"++SET ENV -A A=7+2\n"
"++SET ENV -A A=A-1\n"
"++ECHO A=%%A%%\n"
"++A=8\n"
"4Gathering Input From A User\n"
" Input from a user can be obtained by:\n\n"
"+set environment -P \"Prompt String\" name=default\n\n"
@ -1975,8 +2010,42 @@ static const char simh_help[] =
" failed\" message. Otherwise, the command file will continue to bring up\n"
" the operating system.\n"
"4Conditional Expressions\n"
" The IF and ASSERT commands evaluate three different forms of conditional\n"
" The IF and ASSERT commands evaluate five different forms of conditional\n"
" expressions.:\n\n"
"5C Style Simulator State Expressions\n"
" Comparisons can optionally be done with complete C style computational\n"
" expressions which leverage the C operations in the below table and can\n"
" optionally reference any combination of values that are constants or\n"
" contained in environment variables or simulator registers. C style\n"
" expression evaluation is initiated by enclosing the expression in\n"
" parenthesis.\n\n"
" Expression can contain any of these C language operators:\n\n"
"++ ( Open Parenthesis\n"
"++ ) Close Parenthesis\n"
"++ - Subtraction\n"
"++ + Addition\n"
"++ * Multiplication\n"
"++ / Division\n"
"++ %% Modulus\n"
"++ && Logical AND\n"
"++ || Logical OR\n"
"++ & Bitwise AND\n"
"++ | Bitwise Inclusive OR\n"
"++ ^ Bitwise Exclusive OR\n"
"++ >> Bitwise Right Shift\n"
"++ << Bitwise Left Shift\n"
"++ == Equality\n"
"++ != Inequality\n"
"++ <= Less than or Equal\n"
"++ < Less than\n"
"++ >= Greater than or Equal\n"
"++ > Greater than\n"
"++ ! Logical Negation\n"
"++ ~ Bitwise Compliment\n\n"
" Operator precedence is consistent with C language precedence.\n\n"
" Expression can contain arbitrary combinations of constant\n"
" values, simulator registers and environment variables \n"
"5Simulator State Expressions\n"
" The values of simulator registers can be evaluated with:\n\n"
"++{NOT} {<dev>} <reg>|<addr>{<logical-op><value>}<conditional-op><value>\n\n"
@ -3960,6 +4029,15 @@ if (Exist || (*gbuf == '"') || (*gbuf == '\'')) { /* quoted string compari
result = (f != NULL);
}
}
else {
while (sim_isspace (*cptr)) /* skip spaces */
++cptr;
if (*cptr == '(') {
t_svalue value;
cptr = sim_eval_expression (cptr, &value, TRUE, &r);
result = (value != 0);
}
else {
cptr = get_glyph (cptr, gbuf, 0); /* get register */
rptr = find_reg (gbuf, &gptr, sim_dfdev); /* parse register */
@ -4016,6 +4094,7 @@ else {
result = test_search (sim_eval, &sim_staba); /* test condition */
}
}
}
if (Not ^ result) {
if (!flag)
sim_brk_setact (cptr); /* set up IF actions */
@ -4605,6 +4684,20 @@ else {
return sim_messagef (SCPE_ARG, "Invalid quoted string: %s\n", cbuf);
cbuf[str_size] = '\0';
}
else {
if (sim_switches & SWMASK ('A')) { /* Arithmentic Expression Evaluation argument? */
t_svalue val;
t_stat stat;
cptr = sim_eval_expression (cptr, &val, FALSE, &stat);
if (stat == SCPE_OK) {
sprintf (cbuf, "%ld", (long)val);
cptr = cbuf;
}
else
return stat;
}
}
}
setenv(varname, cptr, 1);
return SCPE_OK;
@ -13122,3 +13215,543 @@ va_end (ap);
return r;
}
#endif
/*
* Expression evaluation package
*
* Derived from code provided by Gabriel Pizzolato
*/
typedef t_svalue (*Operator_Function)(t_svalue, t_svalue);
typedef struct Operator {
const char *string;
int precedence;
int unary;
Operator_Function
function;
const char *description;
} Operator;
typedef struct Stack_Element {
Operator *op;
char data[72];
} Stack_Element;
typedef struct Stack {
int size;
int pointer;
int id;
Stack_Element *elements;
} Stack;
#define STACK_GROW_AMOUNT 5 /* Number of elements to add to stack when needed */
/* static variable allocation */
static int stack_counter = 0; /* number of stacks current allocated */
/* start of true stack code */
/*-----------------------------------------------------------------------------
* Delete the given stack and free all memory associated with it.
-----------------------------------------------------------------------------*/
void delete_Stack (Stack *sp)
{
if (sp == NULL)
return;
sim_debug (SIM_DBG_EXP_STACK, sim_dflt_dev, "[Stack %d has been deallocated]\n", sp->id);
/* Free the data that the stack was pointing at */
free (sp->elements);
free (sp);
stack_counter--;
}
/*-----------------------------------------------------------------------------
* Check to see if a stack is empty
-----------------------------------------------------------------------------*/
static t_bool isempty_Stack (Stack *this_Stack)
{
return (this_Stack->pointer == 0);
}
/*-----------------------------------------------------------------------------
* Create a new stack.
-----------------------------------------------------------------------------*/
static Stack *new_Stack (void)
{
/* Stack variable to return */
Stack *this_Stack = (Stack *)calloc(1, sizeof(*this_Stack));
this_Stack->id = ++stack_counter;
sim_debug (SIM_DBG_EXP_STACK, sim_dflt_dev, "[Stack %d has been allocated]\n", this_Stack->id);
return this_Stack; /* Returns created stack */
}
/*-----------------------------------------------------------------------------
* Remove the top element from the specified stack
-----------------------------------------------------------------------------*/
static t_bool pop_Stack (Stack * this_Stack, char *data, Operator **op)
{
*op = NULL;
*data = '\0';
if (isempty_Stack(this_Stack))
return FALSE;
strcpy (data, this_Stack->elements[this_Stack->pointer-1].data);
*op = this_Stack->elements[this_Stack->pointer-1].op;
--this_Stack->pointer;
if (*op)
sim_debug (SIM_DBG_EXP_STACK, sim_dflt_dev, "[Stack %d - Popping %s(%d)]\n",
this_Stack->id, (*op)->string, (*op)->precedence);
else
sim_debug (SIM_DBG_EXP_STACK, sim_dflt_dev, "[Stack %d - Popping %s]\n",
this_Stack->id, data);
return TRUE; /* Success */
}
/*-----------------------------------------------------------------------------
* Add an element to the specified stack.
-----------------------------------------------------------------------------*/
static t_bool push_Stack (Stack * this_Stack, char *data, Operator *op)
{
if (this_Stack == NULL)
return FALSE;
if (this_Stack->pointer == this_Stack->size) { /* If necessary, grow stack */
this_Stack->size += STACK_GROW_AMOUNT;
this_Stack->elements = (Stack_Element *)realloc (this_Stack->elements, this_Stack->size * sizeof(*this_Stack->elements));
memset (&this_Stack->elements[this_Stack->size - STACK_GROW_AMOUNT], 0, STACK_GROW_AMOUNT * sizeof(*this_Stack->elements));
}
this_Stack->elements[this_Stack->pointer].op = op;
strlcpy (this_Stack->elements[this_Stack->pointer].data, data, sizeof (this_Stack->elements[this_Stack->pointer].data));
++this_Stack->pointer;
if (op)
sim_debug (SIM_DBG_EXP_STACK, sim_dflt_dev, "[Stack %d - Popping %s(%d)]\n",
this_Stack->id, op->string, op->precedence);
else
sim_debug (SIM_DBG_EXP_STACK, sim_dflt_dev, "[Stack %d - Popping %s]\n",
this_Stack->id, data);
return TRUE; /* Success */
}
/*-----------------------------------------------------------------------------
* Return the element at the top of the stack.
-----------------------------------------------------------------------------*/
static t_bool top_Stack (Stack * this_Stack, char *data, Operator **op)
{
if (isempty_Stack(this_Stack))
return FALSE;
strcpy (data, this_Stack->elements[this_Stack->pointer-1].data);
*op = this_Stack->elements[this_Stack->pointer-1].op;
if (*op)
sim_debug (SIM_DBG_EXP_STACK, sim_dflt_dev, "[Stack %d - Topping %s(%d)]\n",
this_Stack->id, (*op)->string, (*op)->precedence);
else
sim_debug (SIM_DBG_EXP_STACK, sim_dflt_dev, "[Stack %d - Topping %s]\n",
this_Stack->id, data);
return TRUE; /* Success */
}
/* All Functions implementing operations */
static t_svalue _op_add (t_svalue augend, t_svalue addend)
{
return augend + addend;
}
static t_svalue _op_sub (t_svalue subtrahend, t_svalue minuend)
{
return minuend - subtrahend;
}
static t_svalue _op_mult (t_svalue factorx, t_svalue factory)
{
return factorx * factory;
}
static t_svalue _op_div (t_svalue divisor, t_svalue dividend)
{
return dividend / divisor;
}
static t_svalue _op_mod (t_svalue divisor, t_svalue dividend)
{
return dividend % divisor;
}
static t_svalue _op_comp (t_svalue data, t_svalue unused)
{
return ~data;
}
static t_svalue _op_log_not (t_svalue data, t_svalue unused)
{
return !data;
}
static t_svalue _op_log_and (t_svalue data1, t_svalue data2)
{
return data1 && data2;
}
static t_svalue _op_log_or (t_svalue data1, t_svalue data2)
{
return data1 || data2;
}
static t_svalue _op_bit_and (t_svalue data1, t_svalue data2)
{
return data1 & data2;
}
static t_svalue _op_bit_rsh (t_svalue shift, t_svalue data)
{
return data >> shift;
}
static t_svalue _op_bit_lsh (t_svalue shift, t_svalue data)
{
return data << shift;
}
static t_svalue _op_bit_or (t_svalue data1, t_svalue data2)
{
return data1 | data2;
}
static t_svalue _op_bit_xor (t_svalue data1, t_svalue data2)
{
return data1 ^ data2;
}
static t_svalue _op_eq (t_svalue data1, t_svalue data2)
{
return data1 == data2;
}
static t_svalue _op_ne (t_svalue data1, t_svalue data2)
{
return data1 != data2;
}
static t_svalue _op_le (t_svalue data1, t_svalue data2)
{
return data1 <= data2;
}
static t_svalue _op_lt (t_svalue data1, t_svalue data2)
{
return data1 < data2;
}
static t_svalue _op_ge (t_svalue data1, t_svalue data2)
{
return data1 >= data2;
}
static t_svalue _op_gt (t_svalue data1, t_svalue data2)
{
return data1 > data2;
}
/*
* The order of elements in this array is significant.
* Care must be taken so that longer strings which have
* shorter strings contained in them must come first.
* For example "!=" must come before "!".
*
* These operators implement C language operator precedence
* as described in:
* http://en.cppreference.com/w/c/language/operator_precedence
*/
static Operator operators[] = {
{"(", 1, 0, NULL, "Open Parenthesis"},
{")", 1, 0, NULL, "Close Parenthesis"},
{"+", 4, 0, _op_add, "Addition"},
{"-", 4, 0, _op_sub, "Subtraction"},
{"*", 3, 0, _op_mult, "Multiplication"},
{"/", 3, 0, _op_div, "Division"},
{"%", 3, 0, _op_mod, "Modulus"},
{"&&", 11, 0, _op_log_and, "Logical AND"},
{"||", 12, 0, _op_log_or, "Logical OR"},
{"&", 8, 0, _op_bit_and, "Bitwise AND"},
{">>", 5, 0, _op_bit_rsh, "Bitwise Right Shift"},
{"<<", 5, 0, _op_bit_lsh, "Bitwise Left Shift"},
{"|", 10, 0, _op_bit_or, "Bitwise Inclusive OR"},
{"^", 9, 0, _op_bit_xor, "Bitwise Exclusive OR"},
{"==", 7, 0, _op_eq, "Equality"},
{"!=", 7, 0, _op_ne, "Inequality"},
{"<=", 6, 0, _op_le, "Less than or Equal"},
{"<", 6, 0, _op_lt, "Less than"},
{">=", 6, 0, _op_ge, "Greater than or Equal"},
{">", 6, 0, _op_gt, "Greater than"},
{"!", 2, 1, _op_log_not, "Logical Negation"},
{"~", 2, 1, _op_comp, "Bitwise Compliment"},
{NULL}};
static const char *get_glyph_exp (const char *cptr, char *buf, Operator **oper, t_stat *stat)
{
static const char HexDigits[] = "0123456789abcdefABCDEF";
static const char OctalDigits[] = "01234567";
static const char BinaryDigits[] = "01";
*stat = SCPE_OK; /* Assume Success */
*buf = '\0';
*oper = NULL;
while (isspace (*cptr))
++cptr;
if (isalpha (*cptr)) {
while (isalnum (*cptr))
*buf++ = *cptr++;
*buf = '\0';
}
else {
if (isdigit (*cptr)) {
if ((!memcmp (cptr, "0x", 2)) || /* Hex Number */
(!memcmp (cptr, "0X", 2))) {
memcpy (buf, cptr, 2);
cptr += 2;
buf += 2;
while (strchr (HexDigits, *cptr))
*buf++ = *cptr++;
*buf = '\0';
}
else {
if ((!memcmp (cptr, "0b", 2)) ||/* Binary Number */
(!memcmp (cptr, "0B", 2))) {
memcpy (buf, cptr, 2);
cptr += 2;
buf += 2;
while (strchr (BinaryDigits, *cptr))
*buf++ = *cptr++;
*buf = '\0';
}
else {
if (*cptr == '0') { /* Octal Number */
while (strchr (OctalDigits, *cptr))
*buf++ = *cptr++;
*buf = '\0';
}
else { /* Decimal Number */
while (isdigit (*cptr))
*buf++ = *cptr++;
*buf = '\0';
}
}
}
if (isalpha (*cptr)) { /* Numbers can't be followed by alpha character */
*stat = SCPE_INVEXPR;
return cptr;
}
}
else {
if (((cptr[0] == '-') || (cptr[0] == '+')) &&
(isdigit (cptr[1]))) { /* Signed Decimal Number */
*buf++ = *cptr++;
while (isdigit (*cptr))
*buf++ = *cptr++;
*buf = '\0';
if (isalpha (*cptr)) { /* Numbers can't be followed by alpha character */
*stat = SCPE_INVEXPR;
return cptr;
}
}
else
{ /* Special Characters (operators) */
Operator *op;
for (op = operators; op->string; op++) {
if (!memcmp (cptr, op->string, strlen (op->string))) {
strcpy (buf, op->string);
cptr += strlen (op->string);
*oper = op;
break;
}
}
if (!op->string) {
*stat = SCPE_INVEXPR;
return cptr;
}
}
}
}
while (isspace (*cptr))
++cptr;
return cptr;
}
/*
* Translate a string containing an infix ordered expression
* into a stack containing that expression in postfix order
*/
static const char *sim_into_postfix (Stack *stack1, const char *cptr, t_stat *stat, t_bool parens_required)
{
const char *start = cptr;
const char *last_cptr;
int parens = 0;
Operator *op = NULL, *last_op;
Stack *stack2 = new_Stack(); /* working stack */
char gbuf[CBUFSIZE];
while (isspace(*cptr)) /* skip leading whitespace */
++cptr;
if (parens_required && (*cptr != '(')) {
delete_Stack (stack2);
*stat = SCPE_INVEXPR;
return cptr;
}
while (*cptr) {
last_cptr = cptr;
last_op = op;
cptr = get_glyph_exp (cptr, gbuf, &op, stat);
if (*stat != SCPE_OK) {
delete_Stack (stack2);
return cptr;
}
if (!last_op && !op && ((gbuf[0] == '-') || (gbuf[0] == '+'))) {
for (op = operators; gbuf[0] != op->string[0]; op++);
gbuf[0] = '0';
cptr = last_cptr + 1;
}
if (!op) {
push_Stack (stack1, gbuf, op);
continue;
}
if (!strcmp (op->string, "(")) {
++parens;
push_Stack (stack2, gbuf, op);
continue;
}
if (!strcmp (op->string, ")")) {
char temp_buf[CBUFSIZE];
Operator *temp_op;
--parens;
pop_Stack (stack2, temp_buf, &temp_op);
while (!temp_op || strcmp (temp_op->string, "(")) {
push_Stack (stack1, temp_buf, temp_op);
pop_Stack (stack2, temp_buf, &temp_op);
}
if (parens_required && (parens == 0)) {
delete_Stack (stack2);
return cptr;
}
continue;
}
while (!isempty_Stack(stack2)) {
char top_buf[CBUFSIZE];
Operator *top_op;
top_Stack (stack2, top_buf, &top_op);
if (op->precedence > top_op->precedence)
break;
pop_Stack (stack2, top_buf, &top_op);
push_Stack (stack1, top_buf, top_op);
}
push_Stack (stack2, gbuf, op);
}
/* migrate the rest of stack2 onto stack1 */
while (!isempty_Stack (stack2)) {
pop_Stack (stack2, gbuf, &op);
push_Stack (stack1, gbuf, op);
}
delete_Stack (stack2); /* deletes the working stack */
return cptr; /* return any unprocessed input */
}
static t_svalue sim_value_of(const char *data)
{
if (isalpha (*data)) {
CONST char *gptr;
REG *rptr = find_reg (data, &gptr, sim_dfdev);
if (rptr)
return get_rval (rptr, 0);
gptr = getenv (data);
data = gptr;
}
return strtotsv(data, NULL, 0);
}
/*
* Evaluate a given stack1 containing a postfix expression
*/
static t_svalue sim_eval_postfix (Stack *stack1, t_stat *stat) {
Stack *stack2 = new_Stack(); /* local working stack2 which is holds the numbers operators */
char temp_data[CBUFSIZE]; /* Holds the items popped from the stack2 */
Operator *temp_op;
*stat = SCPE_OK;
/* Reverse stack1 onto stack2 leaving stack1 empty */
while (!isempty_Stack(stack1)) {
pop_Stack (stack1, temp_data, &temp_op);
push_Stack (stack2, temp_data, temp_op);
}
/* Loop through the postfix expression in stack2 evaluating until stack2 is empty */
while (!isempty_Stack(stack2)) {
pop_Stack (stack2, temp_data, &temp_op);
if (temp_op) { /* operator? */
char item1[CBUFSIZE];
Operator *op1;
char item2[CBUFSIZE];
Operator *op2;
if (!pop_Stack (stack1, item1, &op1)) {
*stat = SCPE_INVEXPR;
return 0;
}
if (temp_op->unary)
strlcpy (item2, "0", sizeof (item2));
else {
if ((!pop_Stack (stack1, item2, &op2)) &&
(temp_op->string[0] != '-') &&
(temp_op->string[0] != '+')) {
*stat = SCPE_INVEXPR;
return 0;
}
}
sprint_val (temp_data, (t_value)temp_op->function (sim_value_of (item1), sim_value_of (item2)), 10, sizeof(temp_data) - 1, PV_LEFTSIGN);
push_Stack (stack1, temp_data, NULL);
}
else
push_Stack (stack1, temp_data, temp_op);
}
if (!pop_Stack (stack1, temp_data, &temp_op)) {
*stat = SCPE_INVEXPR;
return 0;
}
delete_Stack (stack2);
return sim_value_of (temp_data);
}
const char *sim_eval_expression (const char *cptr, t_svalue *value, t_bool parens_required, t_stat *stat)
{
const char *iptr = cptr;
Stack *postfix = new_Stack (); /* for the postfix expression */
*value = 0;
cptr = sim_into_postfix (postfix, cptr, stat, parens_required);
if (*stat != SCPE_OK) {
delete_Stack (postfix);
*stat = sim_messagef (SCPE_ARG, "Invalid Expression Element:\n%s\n%*s^\n", iptr, (int)(cptr-iptr), "");
return cptr;
}
*value = sim_eval_postfix (postfix, stat);
delete_Stack (postfix);
return cptr;
}

View file

@ -405,8 +405,9 @@ typedef uint32 t_addr;
#define SCPE_EXPECT (SCPE_BASE + 45) /* expect matched */
#define SCPE_AMBREG (SCPE_BASE + 46) /* ambiguous register */
#define SCPE_REMOTE (SCPE_BASE + 47) /* remote console command */
#define SCPE_INVEXPR (SCPE_BASE + 48) /* invalid expression */
#define SCPE_MAX_ERR (SCPE_BASE + 47) /* Maximum SCPE Error Value */
#define SCPE_MAX_ERR (SCPE_BASE + 48) /* Maximum SCPE Error Value */
#define SCPE_KFLAG 0x10000000 /* tti data flag */
#define SCPE_BREAK 0x20000000 /* tti break flag */
#define SCPE_NOMESSAGE 0x40000000 /* message display supression flag */
@ -843,9 +844,11 @@ struct DEBTAB {
#define DEBUG_PRI(d,m) (sim_deb && (d.dctrl & (m)))
#define DEBUG_PRJ(d,m) (sim_deb && ((d)->dctrl & (m)))
#define SIM_DBG_EVENT 0x10000
#define SIM_DBG_ACTIVATE 0x20000
#define SIM_DBG_AIO_QUEUE 0x40000
#define SIM_DBG_EVENT 0x010000
#define SIM_DBG_ACTIVATE 0x020000
#define SIM_DBG_AIO_QUEUE 0x040000
#define SIM_DBG_EXP_STACK 0x080000
#define SIM_DBG_EXP_EVAL 0x100000
/* Open File Reference */
struct FILEREF {