diff options
author | Denys Vlasenko <vda.linux@googlemail.com> | 2023-06-17 11:03:02 +0200 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2023-06-17 11:03:02 +0200 |
commit | 19a74a54ded98b28c672d38b79ea9f313f2d89db (patch) | |
tree | 41898bf80b1518438979d5e7c64787c73f766ba9 | |
parent | 6221832bc15d9037360e3bdc9405df08ed801cc1 (diff) | |
download | busybox-w32-19a74a54ded98b28c672d38b79ea9f313f2d89db.tar.gz busybox-w32-19a74a54ded98b28c672d38b79ea9f313f2d89db.tar.bz2 busybox-w32-19a74a54ded98b28c672d38b79ea9f313f2d89db.zip |
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>
-rw-r--r-- | shell/math.c | 33 | ||||
-rw-r--r-- | shell/math.h | 2 |
2 files changed, 21 insertions, 14 deletions
diff --git a/shell/math.c b/shell/math.c index 6196a6ad9..3e339a5ec 100644 --- a/shell/math.c +++ b/shell/math.c | |||
@@ -599,8 +599,6 @@ static arith_t strto_arith_t(const char *nptr, char **endptr) | |||
599 | static arith_t | 599 | static arith_t |
600 | evaluate_string(arith_state_t *math_state, const char *expr) | 600 | evaluate_string(arith_state_t *math_state, const char *expr) |
601 | { | 601 | { |
602 | #define EVAL_DISABLED ((unsigned long long)math_state->evaluation_disabled) | ||
603 | #define TOP_BIT_ULL ((unsigned long long)LLONG_MAX + 1) | ||
604 | operator lasttok; | 602 | operator lasttok; |
605 | const char *errmsg = NULL; | 603 | const char *errmsg = NULL; |
606 | const char *start_expr = expr = skip_whitespace(expr); | 604 | const char *start_expr = expr = skip_whitespace(expr); |
@@ -617,6 +615,7 @@ evaluate_string(arith_state_t *math_state, const char *expr) | |||
617 | operator *const opstack = alloca(expr_len * sizeof(opstack[0])); | 615 | operator *const opstack = alloca(expr_len * sizeof(opstack[0])); |
618 | operator *opstackptr = opstack; | 616 | operator *opstackptr = opstack; |
619 | operator insert_op = 0xff; | 617 | operator insert_op = 0xff; |
618 | unsigned ternary_level = 0; | ||
620 | 619 | ||
621 | /* Start with a left paren */ | 620 | /* Start with a left paren */ |
622 | dbg("(%d) op:TOK_LPAREN", (int)(opstackptr - opstack)); | 621 | dbg("(%d) op:TOK_LPAREN", (int)(opstackptr - opstack)); |
@@ -875,8 +874,11 @@ dbg(" numstack:%d val:%lld '%s'", (int)(numstackptr - numstack), numstackptr[ | |||
875 | /* Example: a=1?2:3,a. We just executed ":". | 874 | /* Example: a=1?2:3,a. We just executed ":". |
876 | * Prevent assignment from being still disabled. | 875 | * Prevent assignment from being still disabled. |
877 | */ | 876 | */ |
878 | math_state->evaluation_disabled >>= 1; | 877 | if (ternary_level == math_state->evaluation_disabled) { |
879 | dbg("':' executed: evaluation_disabled=%llx (restored)", EVAL_DISABLED); | 878 | math_state->evaluation_disabled = 0; |
879 | dbg("':' executed: evaluation_disabled=CLEAR"); | ||
880 | } | ||
881 | ternary_level--; | ||
880 | } | 882 | } |
881 | } /* while (opstack not empty) */ | 883 | } /* while (opstack not empty) */ |
882 | 884 | ||
@@ -887,12 +889,11 @@ dbg(" numstack:%d val:%lld '%s'", (int)(numstackptr - numstack), numstackptr[ | |||
887 | /* We just now evaluated EXPR before "?". | 889 | /* We just now evaluated EXPR before "?". |
888 | * Should we disable evaluation now? | 890 | * Should we disable evaluation now? |
889 | */ | 891 | */ |
890 | if (math_state->evaluation_disabled & TOP_BIT_ULL) | 892 | ternary_level++; |
891 | goto err; /* >63 levels of ?: nesting not supported */ | 893 | if (numstackptr[-1].val == 0 && !math_state->evaluation_disabled) { |
892 | math_state->evaluation_disabled = | 894 | math_state->evaluation_disabled = ternary_level; |
893 | (math_state->evaluation_disabled << 1) | 895 | dbg("'?' entered: evaluation_disabled=%u", math_state->evaluation_disabled); |
894 | | (numstackptr[-1].val == 0); | 896 | } |
895 | dbg("'?' entered: evaluation_disabled=%llx", EVAL_DISABLED); | ||
896 | } | 897 | } |
897 | } /* if */ | 898 | } /* if */ |
898 | /* else: LPAREN or UNARY: push it on opstack */ | 899 | /* else: LPAREN or UNARY: push it on opstack */ |
@@ -906,9 +907,15 @@ dbg(" numstack:%d val:%lld '%s'", (int)(numstackptr - numstack), numstackptr[ | |||
906 | insert_op = 0xff; | 907 | insert_op = 0xff; |
907 | dbg("inserting %02x", op); | 908 | dbg("inserting %02x", op); |
908 | if (op == TOK_CONDITIONAL_SEP) { | 909 | if (op == TOK_CONDITIONAL_SEP) { |
909 | /* The next token is ":". Toggle "do not evaluate" bit */ | 910 | /* The next token is ":". Toggle "do not evaluate" state */ |
910 | math_state->evaluation_disabled ^= 1; | 911 | if (!math_state->evaluation_disabled) { |
911 | dbg("':' entered: evaluation_disabled=%llx (negated)", EVAL_DISABLED); | 912 | math_state->evaluation_disabled = ternary_level; |
913 | dbg("':' entered: evaluation_disabled=%u", math_state->evaluation_disabled); | ||
914 | } else if (ternary_level == math_state->evaluation_disabled) { | ||
915 | math_state->evaluation_disabled = 0; | ||
916 | dbg("':' entered: evaluation_disabled=CLEAR"); | ||
917 | } /* else: ternary_level > nonzero evaluation_disabled: we are in nested ?:, in its disabled branch */ | ||
918 | /* do nothing */ | ||
912 | } | 919 | } |
913 | goto tok_found1; | 920 | goto tok_found1; |
914 | } | 921 | } |
diff --git a/shell/math.h b/shell/math.h index 9812184f1..439031828 100644 --- a/shell/math.h +++ b/shell/math.h | |||
@@ -57,7 +57,7 @@ typedef const char* FAST_FUNC (*arith_var_lookup_t)(const char *name); | |||
57 | typedef void FAST_FUNC (*arith_var_set_t)(const char *name, const char *val); | 57 | typedef void FAST_FUNC (*arith_var_set_t)(const char *name, const char *val); |
58 | 58 | ||
59 | typedef struct arith_state_t { | 59 | typedef struct arith_state_t { |
60 | uint64_t evaluation_disabled; | 60 | unsigned evaluation_disabled; |
61 | const char *errmsg; | 61 | const char *errmsg; |
62 | void *list_of_recursed_names; | 62 | void *list_of_recursed_names; |
63 | arith_var_lookup_t lookupvar; | 63 | arith_var_lookup_t lookupvar; |