summaryrefslogtreecommitdiffstats
path: root/src/expression.c
diff options
context:
space:
mode:
authorPatrick McHardy <kaber@trash.net>2014-02-16 20:35:37 +0000
committerPatrick McHardy <kaber@trash.net>2014-02-17 17:17:18 +0000
commit5a140c9cf95724f971ec9cb40217bea8fc4d089f (patch)
tree19733bb86ac658978291abeb5139a8d1de156b90 /src/expression.c
parent6bad82aba5d304c7a2dd1b19fe57464dca327f4a (diff)
binop: take care of operator precedence when printing binop arguments
When the argument of a binop is a binop itself, we may need to add parens if the precedence of the argument is lower then the binop. Before: tcp flags & syn | ack == syn | ack tcp flags & syn | ack != syn | ack After: tcp flags & (syn | ack) == syn | ack tcp flags & (syn | ack) != syn | ack Signed-off-by: Patrick McHardy <kaber@trash.net>
Diffstat (limited to 'src/expression.c')
-rw-r--r--src/expression.c30
1 files changed, 28 insertions, 2 deletions
diff --git a/src/expression.c b/src/expression.c
index c8566224..6cc79b2e 100644
--- a/src/expression.c
+++ b/src/expression.c
@@ -404,16 +404,42 @@ struct expr *unary_expr_alloc(const struct location *loc,
return expr;
}
+static uint8_t expr_binop_precedence[OP_MAX + 1] = {
+ [OP_LSHIFT] = 1,
+ [OP_RSHIFT] = 1,
+ [OP_AND] = 2,
+ [OP_XOR] = 3,
+ [OP_OR] = 4,
+};
+
+static void binop_arg_print(const struct expr *op, const struct expr *arg)
+{
+ bool prec = false;
+
+ if (arg->ops->type == EXPR_BINOP &&
+ expr_binop_precedence[op->op] != 0 &&
+ expr_binop_precedence[op->op] < expr_binop_precedence[arg->op])
+ prec = 1;
+
+ if (prec)
+ printf("(");
+ expr_print(arg);
+ if (prec)
+ printf(")");
+}
+
static void binop_expr_print(const struct expr *expr)
{
- expr_print(expr->left);
+ binop_arg_print(expr, expr->left);
+
if (expr_op_symbols[expr->op] &&
(expr->op != OP_EQ ||
expr->left->ops->type == EXPR_BINOP))
printf(" %s ", expr_op_symbols[expr->op]);
else
printf(" ");
- expr_print(expr->right);
+
+ binop_arg_print(expr, expr->right);
}
static void binop_expr_clone(struct expr *new, const struct expr *expr)