diff options
author | Herbert Xu <herbert@gondor.apana.org.au> | 2010-03-09 12:52:30 +0800 |
---|---|---|
committer | Herbert Xu <herbert@gondor.apana.org.au> | 2010-03-09 12:52:30 +0800 |
commit | 9655c1ac5646bde1007ecba7c6271d3aa98f294b (patch) | |
tree | 121775c10571f5291091e63de2dc1a48d11838e2 | |
parent | [BUILD] Fix changelog entry (diff) | |
download | dash-9655c1ac5646bde1007ecba7c6271d3aa98f294b.tar.gz dash-9655c1ac5646bde1007ecba7c6271d3aa98f294b.zip |
[ARITH] Fix binary operator parsing
Jilles Tjoelker reported that binary operator parsing doesn't respect operator precedence correctly in the case where a lower- precedence operator is followed by a higher-precedence operator, and then by a lower-precedence operator. This patch fixes this by stopping when we encounter a binary oeprator with a precedence lower than one that we have already encountered. Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
-rw-r--r-- | ChangeLog | 4 | ||||
-rw-r--r-- | src/arith_yacc.c | 30 |
2 files changed, 24 insertions, 10 deletions
diff --git a/ChangeLog b/ChangeLog index 3e68917..8dfd747 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2010-03-09 Herbert Xu <herbert@gondor.apana.org.au> + + * Fix binary operator parsing. + 2009-11-26 Herbert Xu <herbert@gondor.apana.org.au> * Fix off-by-one recordregion in readcmd. diff --git a/src/arith_yacc.c b/src/arith_yacc.c index f4857fe..74b95f8 100644 --- a/src/arith_yacc.c +++ b/src/arith_yacc.c @@ -74,6 +74,8 @@ static const char prec[ARITH_BINOP_MAX - ARITH_BINOP_MIN] = { ARITH_PRECEDENCE(ARITH_BOR, 7), }; +#define ARITH_MAX_PREC 8 + static void yyerror(const char *s) __attribute__ ((noreturn)); static void yyerror(const char *s) { @@ -81,9 +83,14 @@ static void yyerror(const char *s) /* NOTREACHED */ } +static inline int arith_prec(int op) +{ + return prec[op - ARITH_BINOP_MIN]; +} + static inline int higher_prec(int op1, int op2) { - return prec[op1 - ARITH_BINOP_MIN] < prec[op2 - ARITH_BINOP_MIN]; + return arith_prec(op1) < arith_prec(op2); } static intmax_t do_binop(int op, intmax_t a, intmax_t b) @@ -174,7 +181,7 @@ again: } } -static intmax_t binop2(intmax_t a, int op, int noeval) +static intmax_t binop2(intmax_t a, int op, int prec, int noeval) { for (;;) { union yystype val; @@ -188,15 +195,18 @@ static intmax_t binop2(intmax_t a, int op, int noeval) b = primary(token, &val, yylex(), noeval); op2 = last_token; - if (op2 < ARITH_BINOP_MIN || op2 >= ARITH_BINOP_MAX) - return noeval ? b : do_binop(op, a, b); - - if (higher_prec(op2, op)) { - b = binop2(b, op2, noeval); - return noeval ? b : do_binop(op, a, b); + if (op2 >= ARITH_BINOP_MIN && op2 < ARITH_BINOP_MAX && + higher_prec(op2, op)) { + b = binop2(b, op2, arith_prec(op), noeval); + op2 = last_token; } - a = do_binop(op, a, b); + a = noeval ? b : do_binop(op, a, b); + + if (op2 < ARITH_BINOP_MIN || op2 >= ARITH_BINOP_MAX || + arith_prec(op2) >= prec) + return a; + op = op2; } } @@ -209,7 +219,7 @@ static intmax_t binop(int token, union yystype *val, int op, int noeval) if (op < ARITH_BINOP_MIN || op >= ARITH_BINOP_MAX) return a; - return binop2(a, op, noeval); + return binop2(a, op, ARITH_MAX_PREC, noeval); } static intmax_t and(int token, union yystype *val, int op, int noeval) |