diff options
author | Denys Vlasenko <vda.linux@googlemail.com> | 2023-06-15 13:56:12 +0200 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2023-06-15 13:56:12 +0200 |
commit | ea6dcbe2839fb21049baadd0d5da903ae11661ec (patch) | |
tree | 66408551d3fdb6957e1ced4951c23b5f24226965 | |
parent | 22cb0d573a5cabd24fa648f1a13c22acf661a4a3 (diff) | |
download | busybox-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.right | 2 | ||||
-rwxr-xr-x | shell/hush_test/hush-arith/arith-assign-in-varexp1.tests | 9 | ||||
-rw-r--r-- | shell/math.c | 49 |
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 @@ | |||
1 | 7:7 | ||
2 | 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 @@ | |||
1 | exec 2>&1 | ||
2 | a='x=1' | ||
3 | b='x=2' | ||
4 | c='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: | ||
8 | echo 7:$((a+b*c)) | ||
9 | 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_ | |||
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; |