From 60fe075c79589fa9fea16c1a6aba3997d694117f Mon Sep 17 00:00:00 2001 From: lixianjing Date: Wed, 29 May 2019 11:13:59 +0800 Subject: [PATCH] improve expr eval --- src/tkc/expr_eval.c | 74 +++++++++++++++++++++++++++++++++++++++++---- tests/expr_test.cc | 14 +++++++++ 2 files changed, 82 insertions(+), 6 deletions(-) diff --git a/src/tkc/expr_eval.c b/src/tkc/expr_eval.c index 402a9b1e8..8f79fa2a9 100644 --- a/src/tkc/expr_eval.c +++ b/src/tkc/expr_eval.c @@ -806,11 +806,7 @@ static EvalResult parse_product(EvalContext* ctx, ExprValue* output) { for (;;) { int type = ctx->token.type; - if (type == EVAL_TOKEN_TYPE_MULTIPLY || type == EVAL_TOKEN_TYPE_DIVIDE || - type == EVAL_TOKEN_TYPE_E || type == EVAL_TOKEN_TYPE_L || type == EVAL_TOKEN_TYPE_G || - type == EVAL_TOKEN_TYPE_NE || type == EVAL_TOKEN_TYPE_LE || type == EVAL_TOKEN_TYPE_GE || - type == EVAL_TOKEN_TYPE_OR || type == EVAL_TOKEN_TYPE_AND || - type == EVAL_TOKEN_TYPE_BITS_OR || type == EVAL_TOKEN_TYPE_BITS_AND) { + if (type == EVAL_TOKEN_TYPE_MULTIPLY || type == EVAL_TOKEN_TYPE_DIVIDE) { result = get_token(ctx); if (result != EVAL_RESULT_OK) return result; @@ -861,6 +857,72 @@ static EvalResult parse_sum(EvalContext* ctx, ExprValue* output) { return EVAL_RESULT_OK; } +static EvalResult parse_compare(EvalContext* ctx, ExprValue* output) { + ExprValue lhs; + ExprValue rhs; + EvalResult result; + + expr_value_init(&lhs); + expr_value_init(&rhs); + + result = parse_sum(ctx, &lhs); + if (result != EVAL_RESULT_OK) return result; + + for (;;) { + int type = ctx->token.type; + if (type == EVAL_TOKEN_TYPE_E || type == EVAL_TOKEN_TYPE_L || type == EVAL_TOKEN_TYPE_G || + type == EVAL_TOKEN_TYPE_NE || type == EVAL_TOKEN_TYPE_LE || type == EVAL_TOKEN_TYPE_GE) { + result = get_token(ctx); + if (result != EVAL_RESULT_OK) return result; + + result = parse_sum(ctx, &rhs); + if (result != EVAL_RESULT_OK) return result; + + expr_value_op(&lhs, &rhs, (EvalTokenType)type); + } else { + break; + } + } + + *output = lhs; + expr_value_clear(&rhs); + + return EVAL_RESULT_OK; +} + +static EvalResult parse_logic(EvalContext* ctx, ExprValue* output) { + ExprValue lhs; + ExprValue rhs; + EvalResult result; + + expr_value_init(&lhs); + expr_value_init(&rhs); + + result = parse_compare(ctx, &lhs); + if (result != EVAL_RESULT_OK) return result; + + for (;;) { + int type = ctx->token.type; + if (type == EVAL_TOKEN_TYPE_OR || type == EVAL_TOKEN_TYPE_AND || + type == EVAL_TOKEN_TYPE_BITS_OR || type == EVAL_TOKEN_TYPE_BITS_AND) { + result = get_token(ctx); + if (result != EVAL_RESULT_OK) return result; + + result = parse_compare(ctx, &rhs); + if (result != EVAL_RESULT_OK) return result; + + expr_value_op(&lhs, &rhs, (EvalTokenType)type); + } else { + break; + } + } + + *output = lhs; + expr_value_clear(&rhs); + + return EVAL_RESULT_OK; +} + static EvalResult parse_expr(EvalContext* ctx, ExprValue* output) { EvalResult result; @@ -869,7 +931,7 @@ static EvalResult parse_expr(EvalContext* ctx, ExprValue* output) { } ctx->stack_level++; - result = parse_sum(ctx, output); + result = parse_logic(ctx, output); ctx->stack_level--; return result; diff --git a/tests/expr_test.cc b/tests/expr_test.cc index ff1cbdf14..ac7738ade 100644 --- a/tests/expr_test.cc +++ b/tests/expr_test.cc @@ -2,6 +2,20 @@ #include "gtest/gtest.h" TEST(ExprEval, basic) { + ASSERT_EQ(0, tk_expr_eval("(2-2) && 3 + 2 * 2")); + ASSERT_EQ(0, tk_expr_eval("(2-2) && (3 + 2 * 2)")); + ASSERT_EQ(1, tk_expr_eval("(2-2) || 3 + 2 * 2")); + ASSERT_EQ(1, tk_expr_eval("(2-2) || (3 + 2 * 2)")); + ASSERT_EQ(0, tk_expr_eval("2-2 && 3 + 2 * 2")); + ASSERT_EQ(0, tk_expr_eval("2-2 && (3 + 2 * 2)")); + ASSERT_EQ(1, tk_expr_eval("2-2 || 3 + 2 * 2")); + ASSERT_EQ(1, tk_expr_eval("2-2 || (3 + 2 * 2)")); + ASSERT_EQ(1, tk_expr_eval("2*3 && 3 + 2 * 2")); + ASSERT_EQ(1, tk_expr_eval("2*3 && (3 + 2 * 2)")); + ASSERT_EQ(1, tk_expr_eval("2*3 || 3 + 2 * 2")); + ASSERT_EQ(1, tk_expr_eval("2*3 || (3 + 2 * 2)")); + ASSERT_EQ(0, tk_expr_eval("2*3 > 3 + 2 * 2")); + ASSERT_EQ(0, tk_expr_eval("2-3 > 3 + 2 * 2")); ASSERT_EQ(1, tk_expr_eval("1")); ASSERT_EQ(2, tk_expr_eval("1 + 1")); ASSERT_EQ(2, tk_expr_eval("1 * 2"));