shell/math: change ?: nesting code to not have 63 level nesting limitation

function                                             old     new   delta
evaluate_string                                     1406    1432     +26
arith                                                 36      29      -7
arith_apply                                          998     990      -8
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 1/2 up/down: 26/-15)             Total: 11 bytes

Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
This commit is contained in:
Denys Vlasenko 2023-06-17 11:03:02 +02:00
parent 6221832bc1
commit 19a74a54de
2 changed files with 21 additions and 14 deletions

View file

@ -599,8 +599,6 @@ static arith_t strto_arith_t(const char *nptr, char **endptr)
static arith_t
evaluate_string(arith_state_t *math_state, const char *expr)
{
#define EVAL_DISABLED ((unsigned long long)math_state->evaluation_disabled)
#define TOP_BIT_ULL ((unsigned long long)LLONG_MAX + 1)
operator lasttok;
const char *errmsg = NULL;
const char *start_expr = expr = skip_whitespace(expr);
@ -617,6 +615,7 @@ evaluate_string(arith_state_t *math_state, const char *expr)
operator *const opstack = alloca(expr_len * sizeof(opstack[0]));
operator *opstackptr = opstack;
operator insert_op = 0xff;
unsigned ternary_level = 0;
/* Start with a left paren */
dbg("(%d) op:TOK_LPAREN", (int)(opstackptr - opstack));
@ -875,8 +874,11 @@ dbg(" numstack:%d val:%lld '%s'", (int)(numstackptr - numstack), numstackptr[
/* Example: a=1?2:3,a. We just executed ":".
* Prevent assignment from being still disabled.
*/
math_state->evaluation_disabled >>= 1;
dbg("':' executed: evaluation_disabled=%llx (restored)", EVAL_DISABLED);
if (ternary_level == math_state->evaluation_disabled) {
math_state->evaluation_disabled = 0;
dbg("':' executed: evaluation_disabled=CLEAR");
}
ternary_level--;
}
} /* while (opstack not empty) */
@ -887,12 +889,11 @@ dbg(" numstack:%d val:%lld '%s'", (int)(numstackptr - numstack), numstackptr[
/* We just now evaluated EXPR before "?".
* Should we disable evaluation now?
*/
if (math_state->evaluation_disabled & TOP_BIT_ULL)
goto err; /* >63 levels of ?: nesting not supported */
math_state->evaluation_disabled =
(math_state->evaluation_disabled << 1)
| (numstackptr[-1].val == 0);
dbg("'?' entered: evaluation_disabled=%llx", EVAL_DISABLED);
ternary_level++;
if (numstackptr[-1].val == 0 && !math_state->evaluation_disabled) {
math_state->evaluation_disabled = ternary_level;
dbg("'?' entered: evaluation_disabled=%u", math_state->evaluation_disabled);
}
}
} /* if */
/* else: LPAREN or UNARY: push it on opstack */
@ -906,9 +907,15 @@ dbg(" numstack:%d val:%lld '%s'", (int)(numstackptr - numstack), numstackptr[
insert_op = 0xff;
dbg("inserting %02x", op);
if (op == TOK_CONDITIONAL_SEP) {
/* The next token is ":". Toggle "do not evaluate" bit */
math_state->evaluation_disabled ^= 1;
dbg("':' entered: evaluation_disabled=%llx (negated)", EVAL_DISABLED);
/* The next token is ":". Toggle "do not evaluate" state */
if (!math_state->evaluation_disabled) {
math_state->evaluation_disabled = ternary_level;
dbg("':' entered: evaluation_disabled=%u", math_state->evaluation_disabled);
} else if (ternary_level == math_state->evaluation_disabled) {
math_state->evaluation_disabled = 0;
dbg("':' entered: evaluation_disabled=CLEAR");
} /* else: ternary_level > nonzero evaluation_disabled: we are in nested ?:, in its disabled branch */
/* do nothing */
}
goto tok_found1;
}

View file

@ -57,7 +57,7 @@ typedef const char* FAST_FUNC (*arith_var_lookup_t)(const char *name);
typedef void FAST_FUNC (*arith_var_set_t)(const char *name, const char *val);
typedef struct arith_state_t {
uint64_t evaluation_disabled;
unsigned evaluation_disabled;
const char *errmsg;
void *list_of_recursed_names;
arith_var_lookup_t lookupvar;