aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenys Vlasenko <vda.linux@googlemail.com>2023-06-15 13:56:12 +0200
committerDenys Vlasenko <vda.linux@googlemail.com>2023-06-15 13:56:12 +0200
commitea6dcbe2839fb21049baadd0d5da903ae11661ec (patch)
tree66408551d3fdb6957e1ced4951c23b5f24226965
parent22cb0d573a5cabd24fa648f1a13c22acf661a4a3 (diff)
downloadbusybox-w32-ea6dcbe2839fb21049baadd0d5da903ae11661ec.tar.gz
busybox-w32-ea6dcbe2839fb21049baadd0d5da903ae11661ec.tar.bz2
busybox-w32-ea6dcbe2839fb21049baadd0d5da903ae11661ec.zip
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 <vda.linux@googlemail.com>
-rw-r--r--shell/hush_test/hush-arith/arith-assign-in-varexp1.right2
-rwxr-xr-xshell/hush_test/hush-arith/arith-assign-in-varexp1.tests9
-rw-r--r--shell/math.c49
3 files changed, 26 insertions, 34 deletions
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 @@
17:7
2x=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 @@
1exec 2>&1
2a='x=1'
3b='x=2'
4c='x=3'
5# The variables should evaluate immediately when they encountered,
6# not when they go into an operation. Here, order of evaluation
7# of names to numbers should be a,b,c - not b,c,a:
8echo 7:$((a+b*c))
9echo "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_
310 310
311 var_or_num_t *top_of_stack; 311 var_or_num_t *top_of_stack;
312 arith_t rez; 312 arith_t rez;
313 const char *err;
314 313
315 /* There is no operator that can work without arguments */ 314 /* There is no operator that can work without arguments */
316 if (NUMPTR == numstack) 315 if (NUMPTR == numstack)
@@ -324,14 +323,8 @@ arith_apply(arith_state_t *math_state, operator op, var_or_num_t *numstack, var_
324 NUMPTR = expr1 + 1; 323 NUMPTR = expr1 + 1;
325 if (expr1 < numstack) /* Example: $((2:3)) */ 324 if (expr1 < numstack) /* Example: $((2:3)) */
326 return "malformed ?: operator"; 325 return "malformed ?: operator";
327 err = arith_lookup_val(math_state, expr1);
328 if (err)
329 return err;
330 if (expr1->val != 0) /* select expr2 or expr3 */ 326 if (expr1->val != 0) /* select expr2 or expr3 */
331 top_of_stack--; 327 top_of_stack--;
332 err = arith_lookup_val(math_state, top_of_stack);
333 if (err)
334 return err;
335 expr1->val = top_of_stack->val; 328 expr1->val = top_of_stack->val;
336 expr1->var_name = NULL; 329 expr1->var_name = NULL;
337 return NULL; 330 return NULL;
@@ -339,24 +332,6 @@ arith_apply(arith_state_t *math_state, operator op, var_or_num_t *numstack, var_
339 if (op == TOK_CONDITIONAL) /* Example: $((a ? b)) */ 332 if (op == TOK_CONDITIONAL) /* Example: $((a ? b)) */
340 return "malformed ?: operator"; 333 return "malformed ?: operator";
341 334
342 if (PREC(op) < UNARYPREC) {
343 /* In binops a ~ b, variables are resolved left-to-right,
344 * resolve top_of_stack[-1] _before_ resolving top_of_stack[0]
345 */
346 if (top_of_stack == numstack) /* need two arguments */
347 goto syntax_err;
348 /* Unless it is =, resolve top_of_stack[-1] name to value */
349 if (op != TOK_ASSIGN) {
350 err = arith_lookup_val(math_state, top_of_stack - 1);
351 if (err)
352 return err;
353 }
354 }
355 /* Resolve top_of_stack[0] name to value */
356 err = arith_lookup_val(math_state, top_of_stack);
357 if (err)
358 return err;
359
360 rez = top_of_stack->val; 335 rez = top_of_stack->val;
361 if (op == TOK_UMINUS) 336 if (op == TOK_UMINUS)
362 rez = -rez; 337 rez = -rez;
@@ -372,6 +347,9 @@ arith_apply(arith_state_t *math_state, operator op, var_or_num_t *numstack, var_
372 /* Binary operators */ 347 /* Binary operators */
373 arith_t right_side_val; 348 arith_t right_side_val;
374 349
350 if (top_of_stack == numstack) /* have two arguments? */
351 goto syntax_err; /* no */
352
375 /* Pop numstack */ 353 /* Pop numstack */
376 NUMPTR = top_of_stack; /* this decrements NUMPTR */ 354 NUMPTR = top_of_stack; /* this decrements NUMPTR */
377 top_of_stack--; /* now points to left side */ 355 top_of_stack--; /* now points to left side */
@@ -677,7 +655,16 @@ evaluate_string(arith_state_t *math_state, const char *expr)
677 numstackptr->var_name = alloca(var_name_size); 655 numstackptr->var_name = alloca(var_name_size);
678 safe_strncpy(numstackptr->var_name, expr, var_name_size); 656 safe_strncpy(numstackptr->var_name, expr, var_name_size);
679 dbg("[%d] var:'%s'", (int)(numstackptr - numstack), numstackptr->var_name); 657 dbg("[%d] var:'%s'", (int)(numstackptr - numstack), numstackptr->var_name);
680 expr = p; 658 expr = skip_whitespace(p);
659 /* If it is not followed by "=" operator... */
660 if (expr[0] != '=' /* not "=..." */
661 || expr[1] == '=' /* or "==..." */
662 ) {
663 /* Evaluate variable to value */
664 errmsg = arith_lookup_val(math_state, numstackptr);
665 if (errmsg)
666 goto err_with_custom_msg;
667 }
681 push_num: 668 push_num:
682 numstackptr++; 669 numstackptr++;
683 lasttok = TOK_NUM; 670 lasttok = TOK_NUM;
@@ -819,14 +806,8 @@ evaluate_string(arith_state_t *math_state, const char *expr)
819 operator prev_op = *--opstackptr; 806 operator prev_op = *--opstackptr;
820 if (op == TOK_RPAREN) { 807 if (op == TOK_RPAREN) {
821 if (prev_op == TOK_LPAREN) { 808 if (prev_op == TOK_LPAREN) {
822 if (VALID_NAME(numstackptr[-1].var_name)) { 809 /* Erase var name: (var) is just a number, for example, (var) = 1 is not valid */
823 /* Expression is (var), lookup now */ 810 numstackptr[-1].var_name = NULL;
824 errmsg = arith_lookup_val(math_state, &numstackptr[-1]);
825 if (errmsg)
826 goto err_with_custom_msg;
827 /* Erase var name: (var) is just a number, for example, (var) = 1 is not valid */
828 numstackptr[-1].var_name = NULL;
829 }
830 /* Any operator directly after a 811 /* Any operator directly after a
831 * close paren should consider itself binary */ 812 * close paren should consider itself binary */
832 lasttok = TOK_NUM; 813 lasttok = TOK_NUM;