diff options
author | Denys Vlasenko | 2023-06-13 13:55:13 +0200 |
---|---|---|
committer | Denys Vlasenko | 2023-06-13 13:55:13 +0200 |
commit | a4f30f3c70550ee6ceea6768864bfb2e3a99a887 (patch) | |
tree | d9499d794557290984bdc785356e7417ddbfd6f4 /shell | |
parent | d417193cf37ca1005830d7e16f5fa7e1d8a44209 (diff) | |
download | busybox-a4f30f3c70550ee6ceea6768864bfb2e3a99a887.zip busybox-a4f30f3c70550ee6ceea6768864bfb2e3a99a887.tar.gz |
shell/math: reduce stack usage
function old new delta
arith_apply 1123 1134 +11
arith_lookup_val 140 145 +5
evaluate_string 1053 1047 -6
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 2/1 up/down: 16/-6) Total: 10 bytes
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
Diffstat (limited to 'shell')
-rw-r--r-- | shell/math.c | 66 |
1 files changed, 36 insertions, 30 deletions
diff --git a/shell/math.c b/shell/math.c index 727c294..af8e691 100644 --- a/shell/math.c +++ b/shell/math.c @@ -236,14 +236,19 @@ typedef struct { * then '?' selects one of them based on its left side. */ arith_t second_val; - char second_val_present; - /* If NULL then it's just a number, else it's a named variable */ - char *var; +#define SECOND_VAL_VALID ((char*)(intptr_t)-1) + /* If NULL then it's just a number, if SECOND_VAL_VALID, + * it's a result of "expr : expr", else it's a named variable. + * (We use SECOND_VAL_VALID instead of a bit flag to keep + * var_or_num_t smaller, we allocate a lot of them on stack). + */ + char *var_name; } var_or_num_t; + typedef struct remembered_name { struct remembered_name *next; - const char *var; + const char *var_name; } remembered_name; @@ -253,17 +258,17 @@ evaluate_string(arith_state_t *math_state, const char *expr); static const char* arith_lookup_val(arith_state_t *math_state, var_or_num_t *t) { - if (t->var) { - const char *p = math_state->lookupvar(t->var); + if (t->var_name && t->var_name != SECOND_VAL_VALID) { + const char *p = math_state->lookupvar(t->var_name); if (p) { remembered_name *cur; - remembered_name cur_save; + remembered_name remember; /* did we already see this name? * testcase: a=b; b=a; echo $((a)) */ for (cur = math_state->list_of_recursed_names; cur; cur = cur->next) { - if (strcmp(cur->var, t->var) == 0) { + if (strcmp(cur->var_name, t->var_name) == 0) { /* Yes */ return "expression recursion loop detected"; } @@ -271,9 +276,9 @@ arith_lookup_val(arith_state_t *math_state, var_or_num_t *t) /* push current var name */ cur = math_state->list_of_recursed_names; - cur_save.var = t->var; - cur_save.next = cur; - math_state->list_of_recursed_names = &cur_save; + remember.var_name = t->var_name; + remember.next = cur; + math_state->list_of_recursed_names = &remember; /* recursively evaluate p as expression */ t->val = evaluate_string(math_state, p); @@ -286,7 +291,7 @@ arith_lookup_val(arith_state_t *math_state, var_or_num_t *t) /* treat undefined var as 0 */ t->val = 0; } - return 0; + return NULL; } /* "Applying" a token means performing it on the top elements on the integer @@ -303,7 +308,7 @@ arith_apply(arith_state_t *math_state, operator op, var_or_num_t *numstack, var_ /* There is no operator that can work without arguments */ if (NUMPTR == numstack) - goto err; + goto syntax_err; top_of_stack = NUMPTR - 1; @@ -326,15 +331,15 @@ arith_apply(arith_state_t *math_state, operator op, var_or_num_t *numstack, var_ else if (op != TOK_UPLUS) { /* Binary operators */ arith_t right_side_val; - char bad_second_val; + int bad_second_val; /* Binary operators need two arguments */ if (top_of_stack == numstack) - goto err; + goto syntax_err; /* ...and they pop one */ NUMPTR = top_of_stack; /* this decrements NUMPTR */ - bad_second_val = top_of_stack->second_val_present; + bad_second_val = (top_of_stack->var_name == SECOND_VAL_VALID); if (op == TOK_CONDITIONAL) { /* ? operation */ /* Make next if (...) protect against * $((expr1 ? expr2)) - that is, missing ": expr" */ @@ -363,8 +368,10 @@ arith_apply(arith_state_t *math_state, operator op, var_or_num_t *numstack, var_ /* Protect against $((expr : expr)) */ return "malformed ?: operator"; } - top_of_stack->second_val_present = op; + top_of_stack->val = rez; top_of_stack->second_val = right_side_val; + top_of_stack->var_name = SECOND_VAL_VALID; + return NULL; } else if (op == TOK_BOR || op == TOK_OR_ASSIGN) rez |= right_side_val; @@ -439,13 +446,13 @@ arith_apply(arith_state_t *math_state, operator op, var_or_num_t *numstack, var_ if (is_assign_op(op)) { char buf[sizeof(arith_t)*3 + 2]; - if (top_of_stack->var == NULL) { + if (!top_of_stack->var_name || top_of_stack->var_name == SECOND_VAL_VALID) { /* Hmm, 1=2 ? */ - goto err; + goto syntax_err; } /* Save to shell variable */ sprintf(buf, ARITH_FMT, rez); - math_state->setvar(top_of_stack->var, buf); + math_state->setvar(top_of_stack->var_name, buf); /* After saving, make previous value for v++ or v-- */ if (op == TOK_POST_INC) rez--; @@ -455,9 +462,9 @@ arith_apply(arith_state_t *math_state, operator op, var_or_num_t *numstack, var_ top_of_stack->val = rez; /* Erase var name, it is just a number now */ - top_of_stack->var = NULL; + top_of_stack->var_name = NULL; return NULL; - err: + syntax_err: return "arithmetic syntax error"; #undef NUMPTR } @@ -660,12 +667,11 @@ evaluate_string(arith_state_t *math_state, const char *expr) if (p != expr) { /* Name */ size_t var_name_size = (p - expr) + 1; /* +1 for NUL */ - numstackptr->var = alloca(var_name_size); - safe_strncpy(numstackptr->var, expr, var_name_size); + numstackptr->var_name = alloca(var_name_size); + safe_strncpy(numstackptr->var_name, expr, var_name_size); //bb_error_msg("var:'%s'", numstackptr->var); expr = p; num: - numstackptr->second_val_present = 0; numstackptr++; lasttok = TOK_NUM; continue; @@ -673,7 +679,7 @@ evaluate_string(arith_state_t *math_state, const char *expr) if (isdigit(*expr)) { /* Number */ - numstackptr->var = NULL; + numstackptr->var_name = NULL; errno = 0; numstackptr->val = strto_arith_t(expr, (char**) &expr); /* A number can't be followed by another number, or a variable name. @@ -702,7 +708,7 @@ evaluate_string(arith_state_t *math_state, const char *expr) if ((expr[0] == '+' || expr[0] == '-') && (expr[1] == expr[0]) ) { - if (numstackptr == numstack || !numstackptr[-1].var) { /* not a VAR++ */ + if (numstackptr == numstack || !numstackptr[-1].var_name) { /* not a VAR++ */ char next = skip_whitespace(expr + 2)[0]; if (!(isalpha(next) || next == '_')) { /* not a ++VAR */ //bb_error_msg("special %c%c", expr[0], expr[0]); @@ -795,14 +801,14 @@ evaluate_string(arith_state_t *math_state, const char *expr) //bb_error_msg("op == TOK_RPAREN"); if (prev_op == TOK_LPAREN) { //bb_error_msg("prev_op == TOK_LPAREN"); -//bb_error_msg(" %p %p numstackptr[-1].var:'%s'", numstack, numstackptr-1, numstackptr[-1].var); - if (numstackptr[-1].var) { +//bb_error_msg(" %p %p numstackptr[-1].var_name:'%s'", numstack, numstackptr-1, numstackptr[-1].var_name); + if (numstackptr[-1].var_name && numstackptr[-1].var_name != SECOND_VAL_VALID) { /* 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 = NULL; + numstackptr[-1].var_name = NULL; } /* Any operator directly after a * close paren should consider itself binary */ |