diff options
author | Denys Vlasenko <vda.linux@googlemail.com> | 2023-06-15 16:46:31 +0200 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2023-06-15 16:46:31 +0200 |
commit | 38f423cc9c6419f86e8ab602f195a9035a879001 (patch) | |
tree | 56dff563b158a58bc9c4280212114c954ed541ee | |
parent | ea6dcbe2839fb21049baadd0d5da903ae11661ec (diff) | |
download | busybox-w32-38f423cc9c6419f86e8ab602f195a9035a879001.tar.gz busybox-w32-38f423cc9c6419f86e8ab602f195a9035a879001.tar.bz2 busybox-w32-38f423cc9c6419f86e8ab602f195a9035a879001.zip |
shell/math: explain the logic, small tweak to make code smaller
function old new delta
evaluate_string 1258 1257 -1
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r-- | shell/math.c | 35 |
1 files changed, 25 insertions, 10 deletions
diff --git a/shell/math.c b/shell/math.c index 7e2bf5ea5..4623c979e 100644 --- a/shell/math.c +++ b/shell/math.c | |||
@@ -133,7 +133,10 @@ typedef unsigned char operator; | |||
133 | #define tok_decl(prec,id) (((id)<<5) | (prec)) | 133 | #define tok_decl(prec,id) (((id)<<5) | (prec)) |
134 | #define PREC(op) ((op) & 0x1F) | 134 | #define PREC(op) ((op) & 0x1F) |
135 | 135 | ||
136 | #define PREC_LPAREN 0 | ||
136 | #define TOK_LPAREN tok_decl(0,0) | 137 | #define TOK_LPAREN tok_decl(0,0) |
138 | /* Precedence value of RPAREN is used only to distinguish it from LPAREN */ | ||
139 | #define TOK_RPAREN tok_decl(1,1) | ||
137 | 140 | ||
138 | #define TOK_COMMA tok_decl(1,0) | 141 | #define TOK_COMMA tok_decl(1,0) |
139 | 142 | ||
@@ -223,7 +226,6 @@ typedef unsigned char operator; | |||
223 | #define SPEC_PREC (UNARYPREC+4) | 226 | #define SPEC_PREC (UNARYPREC+4) |
224 | 227 | ||
225 | #define TOK_NUM tok_decl(SPEC_PREC, 0) | 228 | #define TOK_NUM tok_decl(SPEC_PREC, 0) |
226 | #define TOK_RPAREN tok_decl(SPEC_PREC, 1) | ||
227 | 229 | ||
228 | static int | 230 | static int |
229 | is_assign_op(operator op) | 231 | is_assign_op(operator op) |
@@ -789,19 +791,32 @@ evaluate_string(arith_state_t *math_state, const char *expr) | |||
789 | * stack until we find an operator with a lesser priority than the | 791 | * stack until we find an operator with a lesser priority than the |
790 | * one we have just extracted. If op is right-associative, | 792 | * one we have just extracted. If op is right-associative, |
791 | * then stop "applying" on the equal priority too. | 793 | * then stop "applying" on the equal priority too. |
792 | * Left paren is given the lowest priority so it will never be | 794 | * Left paren will never be "applied" in this way. |
793 | * "applied" in this way. | ||
794 | */ | 795 | */ |
795 | prec = PREC(op); | 796 | prec = PREC(op); |
796 | if ((prec > 0 && prec < UNARYPREC) || prec == SPEC_PREC) { | 797 | if (prec != PREC_LPAREN && prec < UNARYPREC) { |
797 | /* not left paren or unary */ | 798 | /* binary, ternary or RPAREN */ |
798 | if (lasttok != TOK_NUM) { | 799 | if (lasttok != TOK_NUM) { |
799 | /* binary op must be preceded by a num */ | 800 | /* must be preceded by a num */ |
800 | goto err; | 801 | goto err; |
801 | } | 802 | } |
802 | /* The algorithm employed here is simple: while we don't | 803 | /* if op is RPAREN: |
803 | * hit an open paren nor the bottom of the stack, pop | 804 | * while opstack is not empty: |
804 | * tokens and apply them */ | 805 | * pop prev_op |
806 | * if prev_op is LPAREN (finished evaluating (EXPR)): | ||
807 | * goto N | ||
808 | * evaluate prev_op on top of numstack | ||
809 | * BUG (unpaired RPAREN) | ||
810 | * else (op is not RPAREN): | ||
811 | * while opstack is not empty: | ||
812 | * pop prev_op | ||
813 | * if can't evaluate prev_op (it is lower precedence than op): | ||
814 | * push prev_op back | ||
815 | * goto P | ||
816 | * evaluate prev_op on top of numstack | ||
817 | * P: push op | ||
818 | * N: loop to parse the rest of string | ||
819 | */ | ||
805 | while (opstackptr != opstack) { | 820 | while (opstackptr != opstack) { |
806 | operator prev_op = *--opstackptr; | 821 | operator prev_op = *--opstackptr; |
807 | if (op == TOK_RPAREN) { | 822 | if (op == TOK_RPAREN) { |
@@ -821,7 +836,7 @@ evaluate_string(arith_state_t *math_state, const char *expr) | |||
821 | if (prev_prec < prec | 836 | if (prev_prec < prec |
822 | || (prev_prec == prec && is_right_associative(prec)) | 837 | || (prev_prec == prec && is_right_associative(prec)) |
823 | ) { | 838 | ) { |
824 | /* ...x~y@: push @ on opstack */ | 839 | /* ...x~y@. push @ on opstack */ |
825 | opstackptr++; /* undo removal of ~ op */ | 840 | opstackptr++; /* undo removal of ~ op */ |
826 | goto push_op; | 841 | goto push_op; |
827 | } | 842 | } |