On Tue, Mar 09, 2010 at 12:38:54AM +0100, Jilles Tjoelker wrote:
>
> Noncommutative operators break more easily, for example
> Input:
> echo $((3 - 3 * 3 - 3))
> Expected result:
> -9
> Actual result:
> -3
This should fix it:
commit 9655c1ac5646bde1007ecba7c6271d3aa98f294b
Author: Herbert Xu <herbert@xxxxxxxxxxxxxxxxxxx>
Date: Tue Mar 9 12:52:30 2010 +0800
[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@xxxxxxxxxxxxxxxxxxx>
diff --git a/ChangeLog b/ChangeLog
index 3e68917..8dfd747 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,7 @@
+2010-03-09 Herbert Xu <herbert@xxxxxxxxxxxxxxxxxxx>
+
+ * Fix binary operator parsing.
+
2009-11-26 Herbert Xu <herbert@xxxxxxxxxxxxxxxxxxx>
* 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)
> Another change I'm making to the arith code is making || return 0 or 1
> only, matching C, POSIX and other shells.
Please send a patch.
Thanks,
--
Visit Openswan at http://www.openswan.org/
Email: Herbert Xu ~{PmV>HI~} <herbert@xxxxxxxxxxxxxxxxxxx>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
--
To unsubscribe from this list: send the line "unsubscribe dash" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
[LARTC]
[Bugtraq]
[Yosemite Forum]
[Photo]