|
|
|
@ -331,6 +331,28 @@ arith_apply(arith_state_t *math_state, operator op, var_or_num_t *numstack, var_
|
|
|
|
|
|
|
|
|
|
top_of_stack = NUMPTR - 1;
|
|
|
|
|
|
|
|
|
|
if (op == TOK_CONDITIONAL_SEP) {
|
|
|
|
|
/* "expr1 ? expr2 : expr3" operation */
|
|
|
|
|
var_or_num_t *expr1 = &top_of_stack[-2];
|
|
|
|
|
if (expr1 < numstack) {
|
|
|
|
|
return "malformed ?: operator";
|
|
|
|
|
}
|
|
|
|
|
err = arith_lookup_val(math_state, expr1);
|
|
|
|
|
if (err)
|
|
|
|
|
return err;
|
|
|
|
|
if (expr1->val != 0) /* select expr2 or expr3 */
|
|
|
|
|
top_of_stack--;
|
|
|
|
|
err = arith_lookup_val(math_state, top_of_stack);
|
|
|
|
|
if (err)
|
|
|
|
|
return err;
|
|
|
|
|
NUMPTR = expr1 + 1;
|
|
|
|
|
expr1->val = top_of_stack->val;
|
|
|
|
|
expr1->var_name = NULL;
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
if (op == TOK_CONDITIONAL) /* Example: $((a ? b)) */
|
|
|
|
|
return "malformed ?: operator";
|
|
|
|
|
|
|
|
|
|
/* Resolve name to value, if needed */
|
|
|
|
|
err = arith_lookup_val(math_state, top_of_stack);
|
|
|
|
|
if (err)
|
|
|
|
@ -350,25 +372,12 @@ arith_apply(arith_state_t *math_state, operator op, var_or_num_t *numstack, var_
|
|
|
|
|
else if (op != TOK_UPLUS) {
|
|
|
|
|
/* Binary operators */
|
|
|
|
|
arith_t right_side_val;
|
|
|
|
|
int bad_second_val;
|
|
|
|
|
|
|
|
|
|
/* Binary operators need two arguments */
|
|
|
|
|
if (top_of_stack == numstack)
|
|
|
|
|
goto syntax_err;
|
|
|
|
|
/* ...and they pop one */
|
|
|
|
|
NUMPTR = top_of_stack; /* this decrements NUMPTR */
|
|
|
|
|
|
|
|
|
|
bad_second_val = (top_of_stack->var_name == SECOND_VAL_VALID);
|
|
|
|
|
if (op == TOK_CONDITIONAL) { /* ? operation */
|
|
|
|
|
/* Make next if (...) protect against
|
|
|
|
|
* $((expr1 ? expr2)) - that is, missing ": expr" */
|
|
|
|
|
bad_second_val = !bad_second_val;
|
|
|
|
|
}
|
|
|
|
|
if (bad_second_val) {
|
|
|
|
|
/* Protect against $((expr <not_?_op> expr1 : expr2)) */
|
|
|
|
|
return "malformed ?: operator";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
top_of_stack--; /* now points to left side */
|
|
|
|
|
|
|
|
|
|
if (op != TOK_ASSIGN) {
|
|
|
|
@ -380,19 +389,7 @@ arith_apply(arith_state_t *math_state, operator op, var_or_num_t *numstack, var_
|
|
|
|
|
|
|
|
|
|
right_side_val = rez;
|
|
|
|
|
rez = top_of_stack->val;
|
|
|
|
|
if (op == TOK_CONDITIONAL) /* ? operation */
|
|
|
|
|
rez = (rez ? right_side_val : top_of_stack[1].second_val);
|
|
|
|
|
else if (op == TOK_CONDITIONAL_SEP) { /* : operation */
|
|
|
|
|
if (top_of_stack == numstack) {
|
|
|
|
|
/* Protect against $((expr : expr)) */
|
|
|
|
|
return "malformed ?: operator";
|
|
|
|
|
}
|
|
|
|
|
top_of_stack->val = rez;
|
|
|
|
|
top_of_stack->second_val = right_side_val;
|
|
|
|
|
top_of_stack->var_name = SECOND_VAL_VALID;
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
else if (op == TOK_BOR || op == TOK_OR_ASSIGN)
|
|
|
|
|
if (op == TOK_BOR || op == TOK_OR_ASSIGN)
|
|
|
|
|
rez |= right_side_val;
|
|
|
|
|
else if (op == TOK_OR)
|
|
|
|
|
rez = right_side_val || rez;
|
|
|
|
@ -833,7 +830,7 @@ evaluate_string(arith_state_t *math_state, const char *expr)
|
|
|
|
|
lasttok = TOK_NUM;
|
|
|
|
|
goto next;
|
|
|
|
|
}
|
|
|
|
|
/* Not (y), but ...x~y): fall through to evaluate x~y */
|
|
|
|
|
/* Not (y), but ...x~y). Fall through to evaluate x~y */
|
|
|
|
|
} else {
|
|
|
|
|
operator prev_prec = PREC(prev_op);
|
|
|
|
|
fix_assignment_prec(prec);
|
|
|
|
@ -841,11 +838,17 @@ evaluate_string(arith_state_t *math_state, const char *expr)
|
|
|
|
|
if (prev_prec < prec
|
|
|
|
|
|| (prev_prec == prec && is_right_associative(prec))
|
|
|
|
|
) {
|
|
|
|
|
/* ...x~y@: push @ on opstack */
|
|
|
|
|
opstackptr++; /* undo removal of ~ op */
|
|
|
|
|
goto push_op;
|
|
|
|
|
/* Unless a?b?c:d:... and we are at the second : */
|
|
|
|
|
if (op != TOK_CONDITIONAL_SEP
|
|
|
|
|
|| prev_op != TOK_CONDITIONAL_SEP
|
|
|
|
|
) {
|
|
|
|
|
/* ...x~y@: push @ on opstack */
|
|
|
|
|
opstackptr++; /* undo removal of ~ op */
|
|
|
|
|
goto push_op;
|
|
|
|
|
}
|
|
|
|
|
/* else: a?b?c:d:. Evaluate b?c:d, replace it on stack with result. Then repeat */
|
|
|
|
|
}
|
|
|
|
|
/* ...x~y@: evaluate x~y, replace it on stack with result. Then repeat */
|
|
|
|
|
/* else: ...x~y@. Evaluate x~y, replace it on stack with result. Then repeat */
|
|
|
|
|
}
|
|
|
|
|
dbg("arith_apply(prev_op:%02x, numstack:%d)", prev_op, (int)(numstackptr - numstack));
|
|
|
|
|
errmsg = arith_apply(math_state, prev_op, numstack, &numstackptr);
|
|
|
|
@ -856,6 +859,21 @@ dbg(" numstack:%d val:%lld %lld %p", (int)(numstackptr - numstack),
|
|
|
|
|
numstackptr[-1].var_name == SECOND_VAL_VALID ? numstackptr[-1].second_val : 0,
|
|
|
|
|
numstackptr[-1].var_name
|
|
|
|
|
);
|
|
|
|
|
/* For ternary ?: we need to remove ? from opstack too, not just : */
|
|
|
|
|
if (prev_op == TOK_CONDITIONAL_SEP) {
|
|
|
|
|
// This is caught in arith_apply()
|
|
|
|
|
//if (opstackptr == opstack) {
|
|
|
|
|
// /* Example: $((2:3)) */
|
|
|
|
|
// errmsg = "where is your ? in ?:";
|
|
|
|
|
// goto err_with_custom_msg;
|
|
|
|
|
//}
|
|
|
|
|
opstackptr--;
|
|
|
|
|
if (*opstackptr != TOK_CONDITIONAL) {
|
|
|
|
|
/* Example: $((1,2:3)) */
|
|
|
|
|
errmsg = "malformed ?: operator";
|
|
|
|
|
goto err_with_custom_msg;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} /* while (opstack not empty) */
|
|
|
|
|
if (op == TOK_RPAREN) /* unpaired RPAREN? */
|
|
|
|
|
goto err;
|
|
|
|
|