mirror of https://github.com/mirror/busybox.git
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>master
parent
ea6dcbe283
commit
38f423cc9c
35
shell/math.c
35
shell/math.c
|
@ -133,7 +133,10 @@ typedef unsigned char operator;
|
||||||
#define tok_decl(prec,id) (((id)<<5) | (prec))
|
#define tok_decl(prec,id) (((id)<<5) | (prec))
|
||||||
#define PREC(op) ((op) & 0x1F)
|
#define PREC(op) ((op) & 0x1F)
|
||||||
|
|
||||||
|
#define PREC_LPAREN 0
|
||||||
#define TOK_LPAREN tok_decl(0,0)
|
#define TOK_LPAREN tok_decl(0,0)
|
||||||
|
/* Precedence value of RPAREN is used only to distinguish it from LPAREN */
|
||||||
|
#define TOK_RPAREN tok_decl(1,1)
|
||||||
|
|
||||||
#define TOK_COMMA tok_decl(1,0)
|
#define TOK_COMMA tok_decl(1,0)
|
||||||
|
|
||||||
|
@ -223,7 +226,6 @@ typedef unsigned char operator;
|
||||||
#define SPEC_PREC (UNARYPREC+4)
|
#define SPEC_PREC (UNARYPREC+4)
|
||||||
|
|
||||||
#define TOK_NUM tok_decl(SPEC_PREC, 0)
|
#define TOK_NUM tok_decl(SPEC_PREC, 0)
|
||||||
#define TOK_RPAREN tok_decl(SPEC_PREC, 1)
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
is_assign_op(operator op)
|
is_assign_op(operator op)
|
||||||
|
@ -789,19 +791,32 @@ evaluate_string(arith_state_t *math_state, const char *expr)
|
||||||
* stack until we find an operator with a lesser priority than the
|
* stack until we find an operator with a lesser priority than the
|
||||||
* one we have just extracted. If op is right-associative,
|
* one we have just extracted. If op is right-associative,
|
||||||
* then stop "applying" on the equal priority too.
|
* then stop "applying" on the equal priority too.
|
||||||
* Left paren is given the lowest priority so it will never be
|
* Left paren will never be "applied" in this way.
|
||||||
* "applied" in this way.
|
|
||||||
*/
|
*/
|
||||||
prec = PREC(op);
|
prec = PREC(op);
|
||||||
if ((prec > 0 && prec < UNARYPREC) || prec == SPEC_PREC) {
|
if (prec != PREC_LPAREN && prec < UNARYPREC) {
|
||||||
/* not left paren or unary */
|
/* binary, ternary or RPAREN */
|
||||||
if (lasttok != TOK_NUM) {
|
if (lasttok != TOK_NUM) {
|
||||||
/* binary op must be preceded by a num */
|
/* must be preceded by a num */
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
/* The algorithm employed here is simple: while we don't
|
/* if op is RPAREN:
|
||||||
* hit an open paren nor the bottom of the stack, pop
|
* while opstack is not empty:
|
||||||
* tokens and apply them */
|
* pop prev_op
|
||||||
|
* if prev_op is LPAREN (finished evaluating (EXPR)):
|
||||||
|
* goto N
|
||||||
|
* evaluate prev_op on top of numstack
|
||||||
|
* BUG (unpaired RPAREN)
|
||||||
|
* else (op is not RPAREN):
|
||||||
|
* while opstack is not empty:
|
||||||
|
* pop prev_op
|
||||||
|
* if can't evaluate prev_op (it is lower precedence than op):
|
||||||
|
* push prev_op back
|
||||||
|
* goto P
|
||||||
|
* evaluate prev_op on top of numstack
|
||||||
|
* P: push op
|
||||||
|
* N: loop to parse the rest of string
|
||||||
|
*/
|
||||||
while (opstackptr != opstack) {
|
while (opstackptr != opstack) {
|
||||||
operator prev_op = *--opstackptr;
|
operator prev_op = *--opstackptr;
|
||||||
if (op == TOK_RPAREN) {
|
if (op == TOK_RPAREN) {
|
||||||
|
@ -821,7 +836,7 @@ evaluate_string(arith_state_t *math_state, const char *expr)
|
||||||
if (prev_prec < prec
|
if (prev_prec < prec
|
||||||
|| (prev_prec == prec && is_right_associative(prec))
|
|| (prev_prec == prec && is_right_associative(prec))
|
||||||
) {
|
) {
|
||||||
/* ...x~y@: push @ on opstack */
|
/* ...x~y@. push @ on opstack */
|
||||||
opstackptr++; /* undo removal of ~ op */
|
opstackptr++; /* undo removal of ~ op */
|
||||||
goto push_op;
|
goto push_op;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue