]> git.ipfire.org Git - thirdparty/nftables.git/commitdiff
binop: take care of operator precedence when printing binop arguments
authorPatrick McHardy <kaber@trash.net>
Sun, 16 Feb 2014 20:35:37 +0000 (20:35 +0000)
committerPatrick McHardy <kaber@trash.net>
Mon, 17 Feb 2014 17:17:18 +0000 (17:17 +0000)
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>
include/expression.h
src/expression.c

index 0633102e30e00683949d03ab4f7155a8e113b812..5128a5bb78d30d936f91821455ee7156d21b591b 100644 (file)
@@ -80,7 +80,9 @@ enum ops {
        OP_FLAGCMP,
        /* Set lookup */
        OP_LOOKUP,
+       __OP_MAX
 };
+#define OP_MAX         (__OP_MAX - 1)
 
 extern const char *expr_op_symbols[];
 
index c856622436ebe2790059172992ec1cbccde440c8..6cc79b2e7ff183f3d8c9f066b9c99e8e4f622086 100644 (file)
@@ -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)