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 SCREENSHOT filename.bmp Save video window to the specified file
SET ENV Name=Value Set Environment variable SET ENV Name=Value Set Environment variable
SET ENV -p "Prompt" Name=Default Gather User input into an 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 ASYNCH Enable Asynchronous I/O
SET NOASYNCH Disable Asynchronous I/O SET NOASYNCH Disable Asynchronous I/O
SET VERIFY Enable command display while processing DO command files 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 NOOP A no-op command
ON Establish or cancel an ON condition dispatch ON Establish or cancel an ON condition dispatch
IF Test some simulator state and conditionally execute commands 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 CD Change working directory
SET DEFAULT Change working directory SET DEFAULT Change working directory
PWD Show 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); void fprint_sep (FILE *st, int32 *tokens);
REG *find_reg_glob (CONST char *ptr, CONST char **optr, DEVICE **gdptr); 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); 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 */ /* Forward references */
@ -671,6 +672,7 @@ const struct scp_error {
{"EXPECT", "Expect matched"}, {"EXPECT", "Expect matched"},
{"AMBREG", "Ambiguous register name"}, {"AMBREG", "Ambiguous register name"},
{"REMOTE", "remote console command"}, {"REMOTE", "remote console command"},
{"INVEXPR", "invalid expression"},
}; };
const size_t size_map[] = { sizeof (int8), const size_t size_map[] = { sizeof (int8),
@ -1231,9 +1233,42 @@ static const char simh_help[] =
"+SET NOASYNCH disable asynchronous I/O\n" "+SET NOASYNCH disable asynchronous I/O\n"
#define HLP_SET_ENVIRON "*Commands SET Environment" #define HLP_SET_ENVIRON "*Commands SET Environment"
"3Environment\n" "3Environment\n"
"4Explicitily Changing A Variable\n" "4Explicitily Changing a Variable\n"
"+SET ENVIRONMENT name=val set environment variable\n" "+SET ENVIRONMENT name=val set environment variable\n"
"+SET ENVIRONMENT name clear 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" "4Gathering Input From A User\n"
" Input from a user can be obtained by:\n\n" " Input from a user can be obtained by:\n\n"
"+set environment -P \"Prompt String\" name=default\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" " failed\" message. Otherwise, the command file will continue to bring up\n"
" the operating system.\n" " the operating system.\n"
"4Conditional Expressions\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" " 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" "5Simulator State Expressions\n"
" The values of simulator registers can be evaluated with:\n\n" " The values of simulator registers can be evaluated with:\n\n"
"++{NOT} {<dev>} <reg>|<addr>{<logical-op><value>}<conditional-op><value>\n\n" "++{NOT} {<dev>} <reg>|<addr>{<logical-op><value>}<conditional-op><value>\n\n"
@ -3961,6 +4030,15 @@ if (Exist || (*gbuf == '"') || (*gbuf == '\'')) { /* quoted string compari
} }
} }
else { 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 */ cptr = get_glyph (cptr, gbuf, 0); /* get register */
rptr = find_reg (gbuf, &gptr, sim_dfdev); /* parse register */ rptr = find_reg (gbuf, &gptr, sim_dfdev); /* parse register */
if (rptr) { /* got register? */ if (rptr) { /* got register? */
@ -4016,6 +4094,7 @@ else {
result = test_search (sim_eval, &sim_staba); /* test condition */ result = test_search (sim_eval, &sim_staba); /* test condition */
} }
} }
}
if (Not ^ result) { if (Not ^ result) {
if (!flag) if (!flag)
sim_brk_setact (cptr); /* set up IF actions */ sim_brk_setact (cptr); /* set up IF actions */
@ -4605,6 +4684,20 @@ else {
return sim_messagef (SCPE_ARG, "Invalid quoted string: %s\n", cbuf); return sim_messagef (SCPE_ARG, "Invalid quoted string: %s\n", cbuf);
cbuf[str_size] = '\0'; 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); setenv(varname, cptr, 1);
return SCPE_OK; return SCPE_OK;
@ -13122,3 +13215,543 @@ va_end (ap);
return r; return r;
} }
#endif #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_EXPECT (SCPE_BASE + 45) /* expect matched */
#define SCPE_AMBREG (SCPE_BASE + 46) /* ambiguous register */ #define SCPE_AMBREG (SCPE_BASE + 46) /* ambiguous register */
#define SCPE_REMOTE (SCPE_BASE + 47) /* remote console command */ #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_KFLAG 0x10000000 /* tti data flag */
#define SCPE_BREAK 0x20000000 /* tti break flag */ #define SCPE_BREAK 0x20000000 /* tti break flag */
#define SCPE_NOMESSAGE 0x40000000 /* message display supression 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_PRI(d,m) (sim_deb && (d.dctrl & (m)))
#define DEBUG_PRJ(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_EVENT 0x010000
#define SIM_DBG_ACTIVATE 0x20000 #define SIM_DBG_ACTIVATE 0x020000
#define SIM_DBG_AIO_QUEUE 0x40000 #define SIM_DBG_AIO_QUEUE 0x040000
#define SIM_DBG_EXP_STACK 0x080000
#define SIM_DBG_EXP_EVAL 0x100000
/* Open File Reference */ /* Open File Reference */
struct FILEREF { struct FILEREF {