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