SCP: Add string comparison support to C Style expression evaluation
- Fix operator precedence interpretation - Report expression parsing errors
This commit is contained in:
parent
96d3b5d26b
commit
a4b5160437
1 changed files with 133 additions and 59 deletions
192
scp.c
192
scp.c
|
@ -13270,12 +13270,16 @@ return r;
|
||||||
|
|
||||||
typedef t_svalue (*Operator_Function)(t_svalue, t_svalue);
|
typedef t_svalue (*Operator_Function)(t_svalue, t_svalue);
|
||||||
|
|
||||||
|
typedef t_svalue (*Operator_String_Function)(const char *, const char *);
|
||||||
|
|
||||||
typedef struct Operator {
|
typedef struct Operator {
|
||||||
const char *string;
|
const char *string;
|
||||||
int precedence;
|
int precedence;
|
||||||
int unary;
|
int unary;
|
||||||
Operator_Function
|
Operator_Function
|
||||||
function;
|
function;
|
||||||
|
Operator_String_Function
|
||||||
|
string_function;
|
||||||
const char *description;
|
const char *description;
|
||||||
} Operator;
|
} Operator;
|
||||||
|
|
||||||
|
@ -13351,7 +13355,7 @@ strcpy (data, this_Stack->elements[this_Stack->pointer-1].data);
|
||||||
--this_Stack->pointer;
|
--this_Stack->pointer;
|
||||||
|
|
||||||
if (*op)
|
if (*op)
|
||||||
sim_debug (SIM_DBG_EXP_STACK, sim_dflt_dev, "[Stack %d - Popping %s(%d)]\n",
|
sim_debug (SIM_DBG_EXP_STACK, sim_dflt_dev, "[Stack %d - Popping '%s'(precedence %d)]\n",
|
||||||
this_Stack->id, (*op)->string, (*op)->precedence);
|
this_Stack->id, (*op)->string, (*op)->precedence);
|
||||||
else
|
else
|
||||||
sim_debug (SIM_DBG_EXP_STACK, sim_dflt_dev, "[Stack %d - Popping %s]\n",
|
sim_debug (SIM_DBG_EXP_STACK, sim_dflt_dev, "[Stack %d - Popping %s]\n",
|
||||||
|
@ -13379,10 +13383,10 @@ strlcpy (this_Stack->elements[this_Stack->pointer].data, data, sizeof (this_Stac
|
||||||
++this_Stack->pointer;
|
++this_Stack->pointer;
|
||||||
|
|
||||||
if (op)
|
if (op)
|
||||||
sim_debug (SIM_DBG_EXP_STACK, sim_dflt_dev, "[Stack %d - Popping %s(%d)]\n",
|
sim_debug (SIM_DBG_EXP_STACK, sim_dflt_dev, "[Stack %d - Pushing '%s'(precedence %d)]\n",
|
||||||
this_Stack->id, op->string, op->precedence);
|
this_Stack->id, op->string, op->precedence);
|
||||||
else
|
else
|
||||||
sim_debug (SIM_DBG_EXP_STACK, sim_dflt_dev, "[Stack %d - Popping %s]\n",
|
sim_debug (SIM_DBG_EXP_STACK, sim_dflt_dev, "[Stack %d - Pushing %s]\n",
|
||||||
this_Stack->id, data);
|
this_Stack->id, data);
|
||||||
|
|
||||||
return TRUE; /* Success */
|
return TRUE; /* Success */
|
||||||
|
@ -13400,7 +13404,7 @@ strcpy (data, this_Stack->elements[this_Stack->pointer-1].data);
|
||||||
*op = this_Stack->elements[this_Stack->pointer-1].op;
|
*op = this_Stack->elements[this_Stack->pointer-1].op;
|
||||||
|
|
||||||
if (*op)
|
if (*op)
|
||||||
sim_debug (SIM_DBG_EXP_STACK, sim_dflt_dev, "[Stack %d - Topping %s(%d)]\n",
|
sim_debug (SIM_DBG_EXP_STACK, sim_dflt_dev, "[Stack %d - Topping '%s'(precedence %d)]\n",
|
||||||
this_Stack->id, (*op)->string, (*op)->precedence);
|
this_Stack->id, (*op)->string, (*op)->precedence);
|
||||||
else
|
else
|
||||||
sim_debug (SIM_DBG_EXP_STACK, sim_dflt_dev, "[Stack %d - Topping %s]\n",
|
sim_debug (SIM_DBG_EXP_STACK, sim_dflt_dev, "[Stack %d - Topping %s]\n",
|
||||||
|
@ -13511,6 +13515,36 @@ static t_svalue _op_gt (t_svalue data1, t_svalue data2)
|
||||||
return data1 > data2;
|
return data1 > data2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static t_svalue _op_str_eq (const char *str1, const char *str2)
|
||||||
|
{
|
||||||
|
return (0 == strcmp (str1, str2));
|
||||||
|
}
|
||||||
|
|
||||||
|
static t_svalue _op_str_ne (const char *str1, const char *str2)
|
||||||
|
{
|
||||||
|
return (0 != strcmp (str1, str2));
|
||||||
|
}
|
||||||
|
|
||||||
|
static t_svalue _op_str_le (const char *str1, const char *str2)
|
||||||
|
{
|
||||||
|
return (0 > strcmp (str1, str2));
|
||||||
|
}
|
||||||
|
|
||||||
|
static t_svalue _op_str_lt (const char *str1, const char *str2)
|
||||||
|
{
|
||||||
|
return (0 >= strcmp (str1, str2));
|
||||||
|
}
|
||||||
|
|
||||||
|
static t_svalue _op_str_ge (const char *str1, const char *str2)
|
||||||
|
{
|
||||||
|
return (0 < strcmp (str1, str2));
|
||||||
|
}
|
||||||
|
|
||||||
|
static t_svalue _op_str_gt (const char *str1, const char *str2)
|
||||||
|
{
|
||||||
|
return (0 <= strcmp (str1, str2));
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The order of elements in this array is significant.
|
* The order of elements in this array is significant.
|
||||||
* Care must be taken so that longer strings which have
|
* Care must be taken so that longer strings which have
|
||||||
|
@ -13522,28 +13556,28 @@ return data1 > data2;
|
||||||
* http://en.cppreference.com/w/c/language/operator_precedence
|
* http://en.cppreference.com/w/c/language/operator_precedence
|
||||||
*/
|
*/
|
||||||
static Operator operators[] = {
|
static Operator operators[] = {
|
||||||
{"(", 1, 0, NULL, "Open Parenthesis"},
|
{"(", 99, 0, NULL, NULL, "Open Parenthesis"},
|
||||||
{")", 1, 0, NULL, "Close Parenthesis"},
|
{")", 99, 0, NULL, NULL, "Close Parenthesis"},
|
||||||
{"+", 4, 0, _op_add, "Addition"},
|
{"+", 4, 0, _op_add, NULL, "Addition"},
|
||||||
{"-", 4, 0, _op_sub, "Subtraction"},
|
{"-", 4, 0, _op_sub, NULL, "Subtraction"},
|
||||||
{"*", 3, 0, _op_mult, "Multiplication"},
|
{"*", 3, 0, _op_mult, NULL, "Multiplication"},
|
||||||
{"/", 3, 0, _op_div, "Division"},
|
{"/", 3, 0, _op_div, NULL, "Division"},
|
||||||
{"%", 3, 0, _op_mod, "Modulus"},
|
{"%", 3, 0, _op_mod, NULL, "Modulus"},
|
||||||
{"&&", 11, 0, _op_log_and, "Logical AND"},
|
{"&&", 11, 0, _op_log_and, NULL, "Logical AND"},
|
||||||
{"||", 12, 0, _op_log_or, "Logical OR"},
|
{"||", 12, 0, _op_log_or, NULL, "Logical OR"},
|
||||||
{"&", 8, 0, _op_bit_and, "Bitwise AND"},
|
{"&", 8, 0, _op_bit_and, NULL, "Bitwise AND"},
|
||||||
{">>", 5, 0, _op_bit_rsh, "Bitwise Right Shift"},
|
{">>", 5, 0, _op_bit_rsh, NULL, "Bitwise Right Shift"},
|
||||||
{"<<", 5, 0, _op_bit_lsh, "Bitwise Left Shift"},
|
{"<<", 5, 0, _op_bit_lsh, NULL, "Bitwise Left Shift"},
|
||||||
{"|", 10, 0, _op_bit_or, "Bitwise Inclusive OR"},
|
{"|", 10, 0, _op_bit_or, NULL, "Bitwise Inclusive OR"},
|
||||||
{"^", 9, 0, _op_bit_xor, "Bitwise Exclusive OR"},
|
{"^", 9, 0, _op_bit_xor, NULL, "Bitwise Exclusive OR"},
|
||||||
{"==", 7, 0, _op_eq, "Equality"},
|
{"==", 7, 0, _op_eq, _op_str_eq, "Equality"},
|
||||||
{"!=", 7, 0, _op_ne, "Inequality"},
|
{"!=", 7, 0, _op_ne, _op_str_ne, "Inequality"},
|
||||||
{"<=", 6, 0, _op_le, "Less than or Equal"},
|
{"<=", 6, 0, _op_le, _op_str_le, "Less than or Equal"},
|
||||||
{"<", 6, 0, _op_lt, "Less than"},
|
{"<", 6, 0, _op_lt, _op_str_lt, "Less than"},
|
||||||
{">=", 6, 0, _op_ge, "Greater than or Equal"},
|
{">=", 6, 0, _op_ge, _op_str_ge, "Greater than or Equal"},
|
||||||
{">", 6, 0, _op_gt, "Greater than"},
|
{">", 6, 0, _op_gt, _op_str_gt, "Greater than"},
|
||||||
{"!", 2, 1, _op_log_not, "Logical Negation"},
|
{"!", 2, 1, _op_log_not, NULL, "Logical Negation"},
|
||||||
{"~", 2, 1, _op_comp, "Bitwise Compliment"},
|
{"~", 2, 1, _op_comp, NULL, "Bitwise Compliment"},
|
||||||
{NULL}};
|
{NULL}};
|
||||||
|
|
||||||
static const char *get_glyph_exp (const char *cptr, char *buf, Operator **oper, t_stat *stat)
|
static const char *get_glyph_exp (const char *cptr, char *buf, Operator **oper, t_stat *stat)
|
||||||
|
@ -13613,21 +13647,25 @@ else {
|
||||||
return cptr;
|
return cptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else { /* Special Characters (operators) */
|
||||||
{ /* Special Characters (operators) */
|
if ((*cptr == '"') || (*cptr == '\'')) {
|
||||||
Operator *op;
|
cptr = (CONST char *)get_glyph_gen (cptr, buf, 0, (sim_switches & SWMASK ('I')), TRUE, '\\');
|
||||||
|
|
||||||
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) {
|
else {
|
||||||
*stat = SCPE_INVEXPR;
|
Operator *op;
|
||||||
return cptr;
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -13647,7 +13685,7 @@ const char *start = cptr;
|
||||||
const char *last_cptr;
|
const char *last_cptr;
|
||||||
int parens = 0;
|
int parens = 0;
|
||||||
Operator *op = NULL, *last_op;
|
Operator *op = NULL, *last_op;
|
||||||
Stack *stack2 = new_Stack(); /* working stack */
|
Stack *stack2 = new_Stack(); /* operator stack */
|
||||||
char gbuf[CBUFSIZE];
|
char gbuf[CBUFSIZE];
|
||||||
|
|
||||||
while (isspace(*cptr)) /* skip leading whitespace */
|
while (isspace(*cptr)) /* skip leading whitespace */
|
||||||
|
@ -13670,24 +13708,31 @@ while (*cptr) {
|
||||||
gbuf[0] = '0';
|
gbuf[0] = '0';
|
||||||
cptr = last_cptr + 1;
|
cptr = last_cptr + 1;
|
||||||
}
|
}
|
||||||
|
sim_debug (SIM_DBG_EXP_EVAL, sim_dflt_dev, "[Glyph: %s]\n", op ? op->string : gbuf);
|
||||||
if (!op) {
|
if (!op) {
|
||||||
push_Stack (stack1, gbuf, op);
|
push_Stack (stack1, gbuf, op);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (!strcmp (op->string, "(")) {
|
if (0 == strcmp (op->string, "(")) {
|
||||||
++parens;
|
++parens;
|
||||||
push_Stack (stack2, gbuf, op);
|
push_Stack (stack2, gbuf, op);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (!strcmp (op->string, ")")) {
|
if (0 == strcmp (op->string, ")")) {
|
||||||
char temp_buf[CBUFSIZE];
|
char temp_buf[CBUFSIZE];
|
||||||
Operator *temp_op;
|
Operator *temp_op;
|
||||||
|
|
||||||
--parens;
|
--parens;
|
||||||
pop_Stack (stack2, temp_buf, &temp_op);
|
if ((!pop_Stack (stack2, temp_buf, &temp_op)) ||
|
||||||
while (!temp_op || strcmp (temp_op->string, "(")) {
|
(parens < 0)){
|
||||||
|
*stat = sim_messagef (SCPE_INVEXPR, "Invalid Parenthesis nesting\n");
|
||||||
|
delete_Stack (stack2);
|
||||||
|
return cptr;
|
||||||
|
}
|
||||||
|
while (0 != strcmp (temp_op->string, "(")) {
|
||||||
push_Stack (stack1, temp_buf, temp_op);
|
push_Stack (stack1, temp_buf, temp_op);
|
||||||
pop_Stack (stack2, temp_buf, &temp_op);
|
if (!pop_Stack (stack2, temp_buf, &temp_op))
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
if (parens_required && (parens == 0)) {
|
if (parens_required && (parens == 0)) {
|
||||||
delete_Stack (stack2);
|
delete_Stack (stack2);
|
||||||
|
@ -13700,35 +13745,44 @@ while (*cptr) {
|
||||||
Operator *top_op;
|
Operator *top_op;
|
||||||
|
|
||||||
top_Stack (stack2, top_buf, &top_op);
|
top_Stack (stack2, top_buf, &top_op);
|
||||||
if (op->precedence > top_op->precedence)
|
if (top_op->precedence > op->precedence)
|
||||||
break;
|
break;
|
||||||
pop_Stack (stack2, top_buf, &top_op);
|
pop_Stack (stack2, top_buf, &top_op);
|
||||||
push_Stack (stack1, top_buf, top_op);
|
push_Stack (stack1, top_buf, top_op);
|
||||||
}
|
}
|
||||||
push_Stack (stack2, gbuf, op);
|
push_Stack (stack2, gbuf, op);
|
||||||
}
|
}
|
||||||
|
if (parens != 0)
|
||||||
|
*stat = sim_messagef (SCPE_INVEXPR, "Invalid Parenthesis nesting\n");
|
||||||
/* migrate the rest of stack2 onto stack1 */
|
/* migrate the rest of stack2 onto stack1 */
|
||||||
while (!isempty_Stack (stack2)) {
|
while (!isempty_Stack (stack2)) {
|
||||||
pop_Stack (stack2, gbuf, &op);
|
pop_Stack (stack2, gbuf, &op);
|
||||||
push_Stack (stack1, gbuf, op);
|
push_Stack (stack1, gbuf, op);
|
||||||
}
|
}
|
||||||
|
|
||||||
delete_Stack (stack2); /* deletes the working stack */
|
delete_Stack (stack2); /* delete the working operator stack */
|
||||||
return cptr; /* return any unprocessed input */
|
return cptr; /* return any unprocessed input */
|
||||||
}
|
}
|
||||||
|
|
||||||
static t_svalue sim_value_of(const char *data)
|
static t_bool _value_of (const char *data, t_svalue *svalue, char *string, size_t string_size)
|
||||||
{
|
{
|
||||||
|
CONST char *gptr;
|
||||||
if (isalpha (*data)) {
|
if (isalpha (*data)) {
|
||||||
CONST char *gptr;
|
|
||||||
REG *rptr = find_reg (data, &gptr, sim_dfdev);
|
REG *rptr = find_reg (data, &gptr, sim_dfdev);
|
||||||
|
|
||||||
if (rptr)
|
if (rptr) {
|
||||||
return get_rval (rptr, 0);
|
*svalue = (t_svalue)get_rval (rptr, 0);
|
||||||
|
sprint_val (string + 1, *svalue, 10, string_size - 2, PV_LEFTSIGN);
|
||||||
|
*string = '"';
|
||||||
|
strlcpy (&string[strlen (string)], "\"", string_size - strlen (string));
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
gptr = getenv (data);
|
gptr = getenv (data);
|
||||||
data = gptr;
|
data = (gptr ? gptr : "");
|
||||||
}
|
}
|
||||||
return strtotsv(data, NULL, 0);
|
*svalue = strtotsv(data, &gptr, 0);
|
||||||
|
snprintf (string, string_size - 1, "\"%s\"", data);
|
||||||
|
return (*gptr == '\0');
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -13738,11 +13792,19 @@ static t_svalue sim_eval_postfix (Stack *stack1, t_stat *stat) {
|
||||||
Stack *stack2 = new_Stack(); /* local working stack2 which is holds the numbers operators */
|
Stack *stack2 = new_Stack(); /* local working stack2 which is holds the numbers operators */
|
||||||
char temp_data[CBUFSIZE]; /* Holds the items popped from the stack2 */
|
char temp_data[CBUFSIZE]; /* Holds the items popped from the stack2 */
|
||||||
Operator *temp_op;
|
Operator *temp_op;
|
||||||
|
t_svalue temp_val;
|
||||||
|
char temp_string[CBUFSIZE + 2];
|
||||||
|
|
||||||
*stat = SCPE_OK;
|
*stat = SCPE_OK;
|
||||||
/* Reverse stack1 onto stack2 leaving stack1 empty */
|
/* Reverse stack1 onto stack2 leaving stack1 empty */
|
||||||
while (!isempty_Stack(stack1)) {
|
while (!isempty_Stack(stack1)) {
|
||||||
pop_Stack (stack1, temp_data, &temp_op);
|
pop_Stack (stack1, temp_data, &temp_op);
|
||||||
|
if (temp_op)
|
||||||
|
sim_debug (SIM_DBG_EXP_EVAL, sim_dflt_dev, "[Expression element: %s (%d)\n",
|
||||||
|
temp_op->string, temp_op->precedence);
|
||||||
|
else
|
||||||
|
sim_debug (SIM_DBG_EXP_EVAL, sim_dflt_dev, "[Expression element: %s\n",
|
||||||
|
temp_data);
|
||||||
push_Stack (stack2, temp_data, temp_op);
|
push_Stack (stack2, temp_data, temp_op);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -13750,14 +13812,17 @@ while (!isempty_Stack(stack1)) {
|
||||||
while (!isempty_Stack(stack2)) {
|
while (!isempty_Stack(stack2)) {
|
||||||
pop_Stack (stack2, temp_data, &temp_op);
|
pop_Stack (stack2, temp_data, &temp_op);
|
||||||
if (temp_op) { /* operator? */
|
if (temp_op) { /* operator? */
|
||||||
char item1[CBUFSIZE];
|
t_bool num1;
|
||||||
|
t_svalue val1;
|
||||||
|
char item1[CBUFSIZE], string1[CBUFSIZE+2];
|
||||||
Operator *op1;
|
Operator *op1;
|
||||||
char item2[CBUFSIZE];
|
t_bool num2;
|
||||||
|
t_svalue val2;
|
||||||
|
char item2[CBUFSIZE], string2[CBUFSIZE+2];
|
||||||
Operator *op2;
|
Operator *op2;
|
||||||
|
|
||||||
if (!pop_Stack (stack1, item1, &op1)) {
|
if (!pop_Stack (stack1, item1, &op1)) {
|
||||||
*stat = SCPE_INVEXPR;
|
*stat = SCPE_INVEXPR;
|
||||||
delete_Stack (stack2);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if (temp_op->unary)
|
if (temp_op->unary)
|
||||||
|
@ -13771,7 +13836,12 @@ while (!isempty_Stack(stack2)) {
|
||||||
return 0;
|
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);
|
num1 = _value_of (item1, &val1, string1, sizeof (string1));
|
||||||
|
num2 = _value_of (item2, &val2, string2, sizeof (string2));
|
||||||
|
if ((!(num1 && num2)) && temp_op->string_function)
|
||||||
|
sprint_val (temp_data, (t_value)temp_op->string_function (string1, string2), 10, sizeof(temp_data) - 1, PV_LEFTSIGN);
|
||||||
|
else
|
||||||
|
sprint_val (temp_data, (t_value)temp_op->function (val1, val2), 10, sizeof(temp_data) - 1, PV_LEFTSIGN);
|
||||||
push_Stack (stack1, temp_data, NULL);
|
push_Stack (stack1, temp_data, NULL);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -13779,10 +13849,14 @@ while (!isempty_Stack(stack2)) {
|
||||||
}
|
}
|
||||||
if (!pop_Stack (stack1, temp_data, &temp_op)) {
|
if (!pop_Stack (stack1, temp_data, &temp_op)) {
|
||||||
*stat = SCPE_INVEXPR;
|
*stat = SCPE_INVEXPR;
|
||||||
|
delete_Stack (stack2);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
delete_Stack (stack2);
|
delete_Stack (stack2);
|
||||||
return sim_value_of (temp_data);
|
if (_value_of (temp_data, &temp_val, temp_string, sizeof (temp_string)))
|
||||||
|
return temp_val;
|
||||||
|
else
|
||||||
|
return (t_svalue)(strlen (temp_string) > 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *sim_eval_expression (const char *cptr, t_svalue *value, t_bool parens_required, t_stat *stat)
|
const char *sim_eval_expression (const char *cptr, t_svalue *value, t_bool parens_required, t_stat *stat)
|
||||||
|
|
Loading…
Add table
Reference in a new issue