Browse Source

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>
Denys Vlasenko 10 months ago
parent
commit
19a74a54de
2 changed files with 21 additions and 14 deletions
  1. 20 13
      shell/math.c
  2. 1 1
      shell/math.h

+ 20 - 13
shell/math.c

@@ -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;
 		}

+ 1 - 1
shell/math.h

@@ -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;