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:
parent
6221832bc1
commit
19a74a54de
2 changed files with 21 additions and 14 deletions
33
shell/math.c
33
shell/math.c
|
@ -599,8 +599,6 @@ static arith_t strto_arith_t(const char *nptr, char **endptr)
|
||||||
static arith_t
|
static arith_t
|
||||||
evaluate_string(arith_state_t *math_state, const char *expr)
|
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;
|
operator lasttok;
|
||||||
const char *errmsg = NULL;
|
const char *errmsg = NULL;
|
||||||
const char *start_expr = expr = skip_whitespace(expr);
|
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 *const opstack = alloca(expr_len * sizeof(opstack[0]));
|
||||||
operator *opstackptr = opstack;
|
operator *opstackptr = opstack;
|
||||||
operator insert_op = 0xff;
|
operator insert_op = 0xff;
|
||||||
|
unsigned ternary_level = 0;
|
||||||
|
|
||||||
/* Start with a left paren */
|
/* Start with a left paren */
|
||||||
dbg("(%d) op:TOK_LPAREN", (int)(opstackptr - opstack));
|
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 ":".
|
/* Example: a=1?2:3,a. We just executed ":".
|
||||||
* Prevent assignment from being still disabled.
|
* Prevent assignment from being still disabled.
|
||||||
*/
|
*/
|
||||||
math_state->evaluation_disabled >>= 1;
|
if (ternary_level == math_state->evaluation_disabled) {
|
||||||
dbg("':' executed: evaluation_disabled=%llx (restored)", EVAL_DISABLED);
|
math_state->evaluation_disabled = 0;
|
||||||
|
dbg("':' executed: evaluation_disabled=CLEAR");
|
||||||
|
}
|
||||||
|
ternary_level--;
|
||||||
}
|
}
|
||||||
} /* while (opstack not empty) */
|
} /* while (opstack not empty) */
|
||||||
|
|
||||||
|
@ -887,12 +889,11 @@ dbg(" numstack:%d val:%lld '%s'", (int)(numstackptr - numstack), numstackptr[
|
||||||
/* We just now evaluated EXPR before "?".
|
/* We just now evaluated EXPR before "?".
|
||||||
* Should we disable evaluation now?
|
* Should we disable evaluation now?
|
||||||
*/
|
*/
|
||||||
if (math_state->evaluation_disabled & TOP_BIT_ULL)
|
ternary_level++;
|
||||||
goto err; /* >63 levels of ?: nesting not supported */
|
if (numstackptr[-1].val == 0 && !math_state->evaluation_disabled) {
|
||||||
math_state->evaluation_disabled =
|
math_state->evaluation_disabled = ternary_level;
|
||||||
(math_state->evaluation_disabled << 1)
|
dbg("'?' entered: evaluation_disabled=%u", math_state->evaluation_disabled);
|
||||||
| (numstackptr[-1].val == 0);
|
}
|
||||||
dbg("'?' entered: evaluation_disabled=%llx", EVAL_DISABLED);
|
|
||||||
}
|
}
|
||||||
} /* if */
|
} /* if */
|
||||||
/* else: LPAREN or UNARY: push it on opstack */
|
/* 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;
|
insert_op = 0xff;
|
||||||
dbg("inserting %02x", op);
|
dbg("inserting %02x", op);
|
||||||
if (op == TOK_CONDITIONAL_SEP) {
|
if (op == TOK_CONDITIONAL_SEP) {
|
||||||
/* The next token is ":". Toggle "do not evaluate" bit */
|
/* The next token is ":". Toggle "do not evaluate" state */
|
||||||
math_state->evaluation_disabled ^= 1;
|
if (!math_state->evaluation_disabled) {
|
||||||
dbg("':' entered: evaluation_disabled=%llx (negated)", EVAL_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;
|
goto tok_found1;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 void FAST_FUNC (*arith_var_set_t)(const char *name, const char *val);
|
||||||
|
|
||||||
typedef struct arith_state_t {
|
typedef struct arith_state_t {
|
||||||
uint64_t evaluation_disabled;
|
unsigned evaluation_disabled;
|
||||||
const char *errmsg;
|
const char *errmsg;
|
||||||
void *list_of_recursed_names;
|
void *list_of_recursed_names;
|
||||||
arith_var_lookup_t lookupvar;
|
arith_var_lookup_t lookupvar;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue