From ea6dcbe2839fb21049baadd0d5da903ae11661ec Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Thu, 15 Jun 2023 13:56:12 +0200 Subject: shell/math: fix order of expansion of variables to numbers This fixes arith-assign-in-varexp1.tests function old new delta evaluate_string 1132 1258 +126 arith_lookup_val 143 - -143 arith_apply 1132 977 -155 ------------------------------------------------------------------------------ (add/remove: 0/1 grow/shrink: 1/1 up/down: 126/-298) Total: -172 bytes Signed-off-by: Denys Vlasenko --- .../hush-arith/arith-assign-in-varexp1.right | 2 + .../hush-arith/arith-assign-in-varexp1.tests | 9 ++++ shell/math.c | 49 +++++++--------------- 3 files changed, 26 insertions(+), 34 deletions(-) create mode 100644 shell/hush_test/hush-arith/arith-assign-in-varexp1.right create mode 100755 shell/hush_test/hush-arith/arith-assign-in-varexp1.tests (limited to 'shell') diff --git a/shell/hush_test/hush-arith/arith-assign-in-varexp1.right b/shell/hush_test/hush-arith/arith-assign-in-varexp1.right new file mode 100644 index 000000000..1feb307d2 --- /dev/null +++ b/shell/hush_test/hush-arith/arith-assign-in-varexp1.right @@ -0,0 +1,2 @@ +7:7 +x=3 diff --git a/shell/hush_test/hush-arith/arith-assign-in-varexp1.tests b/shell/hush_test/hush-arith/arith-assign-in-varexp1.tests new file mode 100755 index 000000000..fc8ac9d97 --- /dev/null +++ b/shell/hush_test/hush-arith/arith-assign-in-varexp1.tests @@ -0,0 +1,9 @@ +exec 2>&1 +a='x=1' +b='x=2' +c='x=3' +# The variables should evaluate immediately when they encountered, +# not when they go into an operation. Here, order of evaluation +# of names to numbers should be a,b,c - not b,c,a: +echo 7:$((a+b*c)) +echo "x=$x" diff --git a/shell/math.c b/shell/math.c index 8d0c9dea7..7e2bf5ea5 100644 --- a/shell/math.c +++ b/shell/math.c @@ -310,7 +310,6 @@ arith_apply(arith_state_t *math_state, operator op, var_or_num_t *numstack, var_ var_or_num_t *top_of_stack; arith_t rez; - const char *err; /* There is no operator that can work without arguments */ if (NUMPTR == numstack) @@ -324,14 +323,8 @@ arith_apply(arith_state_t *math_state, operator op, var_or_num_t *numstack, var_ NUMPTR = expr1 + 1; if (expr1 < numstack) /* Example: $((2:3)) */ 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; expr1->val = top_of_stack->val; expr1->var_name = NULL; return NULL; @@ -339,24 +332,6 @@ arith_apply(arith_state_t *math_state, operator op, var_or_num_t *numstack, var_ if (op == TOK_CONDITIONAL) /* Example: $((a ? b)) */ return "malformed ?: operator"; - if (PREC(op) < UNARYPREC) { - /* In binops a ~ b, variables are resolved left-to-right, - * resolve top_of_stack[-1] _before_ resolving top_of_stack[0] - */ - if (top_of_stack == numstack) /* need two arguments */ - goto syntax_err; - /* Unless it is =, resolve top_of_stack[-1] name to value */ - if (op != TOK_ASSIGN) { - err = arith_lookup_val(math_state, top_of_stack - 1); - if (err) - return err; - } - } - /* Resolve top_of_stack[0] name to value */ - err = arith_lookup_val(math_state, top_of_stack); - if (err) - return err; - rez = top_of_stack->val; if (op == TOK_UMINUS) rez = -rez; @@ -372,6 +347,9 @@ arith_apply(arith_state_t *math_state, operator op, var_or_num_t *numstack, var_ /* Binary operators */ arith_t right_side_val; + if (top_of_stack == numstack) /* have two arguments? */ + goto syntax_err; /* no */ + /* Pop numstack */ NUMPTR = top_of_stack; /* this decrements NUMPTR */ top_of_stack--; /* now points to left side */ @@ -677,7 +655,16 @@ evaluate_string(arith_state_t *math_state, const char *expr) numstackptr->var_name = alloca(var_name_size); safe_strncpy(numstackptr->var_name, expr, var_name_size); dbg("[%d] var:'%s'", (int)(numstackptr - numstack), numstackptr->var_name); - expr = p; + expr = skip_whitespace(p); + /* If it is not followed by "=" operator... */ + if (expr[0] != '=' /* not "=..." */ + || expr[1] == '=' /* or "==..." */ + ) { + /* Evaluate variable to value */ + errmsg = arith_lookup_val(math_state, numstackptr); + if (errmsg) + goto err_with_custom_msg; + } push_num: numstackptr++; lasttok = TOK_NUM; @@ -819,14 +806,8 @@ evaluate_string(arith_state_t *math_state, const char *expr) operator prev_op = *--opstackptr; if (op == TOK_RPAREN) { if (prev_op == TOK_LPAREN) { - if (VALID_NAME(numstackptr[-1].var_name)) { - /* Expression is (var), lookup now */ - errmsg = arith_lookup_val(math_state, &numstackptr[-1]); - if (errmsg) - goto err_with_custom_msg; - /* Erase var name: (var) is just a number, for example, (var) = 1 is not valid */ - numstackptr[-1].var_name = NULL; - } + /* Erase var name: (var) is just a number, for example, (var) = 1 is not valid */ + numstackptr[-1].var_name = NULL; /* Any operator directly after a * close paren should consider itself binary */ lasttok = TOK_NUM; -- cgit v1.2.3