From 32d17134cdac12feb949c4a0c73dbd84974c32d8 Mon Sep 17 00:00:00 2001 From: Bruno BELANYI Date: Fri, 30 Oct 2020 19:07:33 +0100 Subject: [PATCH] evalexpr: parse: parse operand more correctly I noted that the `right_prec` and `next_prec` functions taking a character only work because prefix operators come after infix operators in the table. We should compare the *actual* operator kind, which would probably need a single operator enum to make sure there are no collisions. --- src/parse/climbing_parse.c | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/src/parse/climbing_parse.c b/src/parse/climbing_parse.c index 4b4111a..351d2eb 100644 --- a/src/parse/climbing_parse.c +++ b/src/parse/climbing_parse.c @@ -91,6 +91,8 @@ static bool prec_between(char c, int min, int max) return false; } +// This function happen to work the way the code is setup, because of operator +// ordering static int right_prec(char c) { for (size_t i = 0; i < ARR_SIZE(ops); ++i) @@ -104,6 +106,8 @@ static int right_prec(char c) return INT_MIN; } +// This function happen to work the way the code is setup, because of operator +// ordering static int next_prec(char c) { for (size_t i = 0; i < ARR_SIZE(ops); ++i) @@ -202,6 +206,19 @@ static bool my_atoi(const char **input, int *val) return true; } +static int next_prec_prefix(int op) +{ + for (size_t i = 0; i < ARR_SIZE(ops); ++i) + if (ops[i].fix == OP_PREFIX && op == ops[i].kind) + { + if (ops[i].assoc != ASSOC_LEFT) + return ops[i].prio - 1; + return ops[i].prio; + } + + return INT_MIN; +} + static struct ast_node *parse_operand(const char **input) { skip_whitespace(input); // Whitespace is not significant @@ -214,7 +231,7 @@ static struct ast_node *parse_operand(const char **input) // Remove the parenthesis eat_char(input); - ast = climbing_parse_internal(input, 2); // FIXME: should be from table + ast = climbing_parse_internal(input, next_prec_prefix(op)); if (!ast) return NULL;