From 7d798d0dec5f1c5294b5ed9258ef7abcfde6ea37 Mon Sep 17 00:00:00 2001 From: Arash Partow Date: Thu, 26 Jun 2014 04:24:20 +1000 Subject: [PATCH] C++ Mathematical Expression Library (ExprTk) http://www.partow.net/programming/exprtk/index.html --- exprtk.hpp | 107 +++++++++++++++++++++++++++++++++++++++++++++--- exprtk_test.cpp | 20 +++++++++ 2 files changed, 121 insertions(+), 6 deletions(-) diff --git a/exprtk.hpp b/exprtk.hpp index 128990c..4754765 100644 --- a/exprtk.hpp +++ b/exprtk.hpp @@ -3653,6 +3653,19 @@ namespace exprtk return node && (details::expression_node::e_function == node->type()); } + template class unary_node; + + template + inline bool is_negate_node(const expression_node* node) + { + if (node && is_unary_node(node)) + { + return (details::e_neg == static_cast*>(node)->operation()); + } + else + return false; + } + template inline bool branch_deletable(expression_node* node) { @@ -4059,6 +4072,11 @@ namespace exprtk return branch_; } + inline void release() + { + branch_deletable_ = false; + } + protected: operator_type operation_; @@ -13514,10 +13532,16 @@ namespace exprtk expression_node_ptr right_branch = parse_expression(current_state.right); expression_node_ptr new_expression = error_node(); + details::operator_type current_operation = current_state.operation; + if (right_branch) { + simplify_negation(current_operation, + expression, + right_branch); + new_expression = expression_generator_( - current_state.operation, + current_operation, expression, right_branch ); @@ -13553,6 +13577,77 @@ namespace exprtk return expression; } + bool simplify_negation_branch(expression_node_ptr& right) + { + if (is_unary_node(right)) + { + details::unary_node* un = static_cast*>(right); + if (details::e_neg == un->operation()) + { + expression_node_ptr un_r = un->branch(0); + un->release(); + free_node(node_allocator_,right); + right = un_r; + return true; + } + } + + return false; + } + + void simplify_negation(details::operator_type& current_operation, + expression_node_ptr& left, + expression_node_ptr& right) + { + bool simplified = false; + do + { + simplified = false; + // (x + - y) --> (x - y) + if (details::e_add == current_operation) + { + if (is_negate_node(right)) + { + if (simplify_negation_branch(right)) + { + current_operation = details::e_sub; + simplified = true; + } + } + } + // (x - - y) --> (x + y) + else if (details::e_sub == current_operation) + { + if (is_negate_node(right)) + { + if (simplify_negation_branch(right)) + { + current_operation = details::e_add; + simplified = true; + } + } + } + // -x * - y --> x * y + // -x / - y --> x / y + else if ( + (details::e_mul == current_operation) || + (details::e_div == current_operation) + ) + { + if ( + is_negate_node(left ) && + is_negate_node(right) + ) + { + simplify_negation_branch(left ); + simplify_negation_branch(right); + simplified = true; + } + } + } + while (simplified); + } + static inline expression_node_ptr error_node() { return reinterpret_cast(0); @@ -16017,7 +16112,7 @@ namespace exprtk !token_is(token_t::e_rsqrbracket,false) ) { - if (!token_is(token_t::e_eof)) + if (!token_is(token_t::e_eof,false)) { set_error( make_error(parser_error::e_syntax, @@ -18686,8 +18781,8 @@ namespace exprtk if (details::is_cob_node(branch[1])) { // Simplify expressions of the form: - // 1. (1 * (2 * (3 * (4 * (5 * (6 * (7 * (8 * (9 + x))))))))) ---> 40320 * (9 + x) - // 2. (1 + (2 + (3 + (4 + (5 + (6 + (7 + (8 + (9 + x))))))))) ---> 45 + x + // 1. (1 * (2 * (3 * (4 * (5 * (6 * (7 * (8 * (9 + x))))))))) --> 40320 * (9 + x) + // 2. (1 + (2 + (3 + (4 + (5 + (6 + (7 + (8 + (9 + x))))))))) --> 45 + x if ( (operation == details::e_mul) || (operation == details::e_add) @@ -18794,8 +18889,8 @@ namespace exprtk if (details::is_boc_node(branch[0])) { // Simplify expressions of the form: - // 1. (((((((((x + 9) * 8) * 7) * 6) * 5) * 4) * 3) * 2) * 1) ---> (x + 9) * 40320 - // 2. (((((((((x + 9) + 8) + 7) + 6) + 5) + 4) + 3) + 2) + 1) ---> x + 45 + // 1. (((((((((x + 9) * 8) * 7) * 6) * 5) * 4) * 3) * 2) * 1) --> (x + 9) * 40320 + // 2. (((((((((x + 9) + 8) + 7) + 6) + 5) + 4) + 3) + 2) + 1) --> x + 45 if ( (operation == details::e_mul) || (operation == details::e_add) diff --git a/exprtk_test.cpp b/exprtk_test.cpp index 4571910..0355c26 100644 --- a/exprtk_test.cpp +++ b/exprtk_test.cpp @@ -342,6 +342,10 @@ static const test_t test_list[] = test_t("+(1+2)",+3.0), test_t("+(1-2)",-1.0), test_t("-(1-2)",+1.0), + test_t("(-3*-6)",+18.0), + test_t("(-6*-3)",+18.0), + test_t("-(-3*-6)",-18.0), + test_t("-(-6*-3)",-18.0), test_t("1.1+2.2+3.3",+6.6), test_t("+1.1+2.2+3.3",+6.6), test_t("-1.1-2.2-3.3",-6.6), @@ -3277,6 +3281,22 @@ inline bool run_test10() { std::string expression_list[] = { + "var x := 3; var y := 6; x + -y == -3", + "var x := 3; var y := 6; x - -y == 9", + "var x := 3; var y := 6; -x + -y == -9", + "var x := 3; var y := 6; -x - -y == 3", + "var x := 3; var y := 6; -x * -y == 18", + "var x := 6; var y := 3; -x / -y == 2", + "var x := 3; var y := 6; -(-x * -y) == -18", + "var x := 6; var y := 3; -(-x / -y) == -2", + "var x:=3; var y:=6; -(-x)*-(-y) == 18", + "var x:=3; var y:=6; -(-x)*-(-(-y)) == -18", + "var x:=3; var y:=6; -(-(-x))*-(-y) == -18", + "var x:=3; var y:=6; -(-(-x))*-(-(-y)) == 18", + "var x:=3; var y:=6; -(-(x+y))*-(-(y+x)) == 81", + "var x:=3; var y:=6; -(-(-(x+y)))*-(-(y+x)) == -81", + "var x:=3; var y:=6; -(-(x+y))*-(-(-(y+x))) == -81", + "var x:=3; var y:=6; -(-(-(x+y)))*-(-(-(y+x))) == 81", "var x := 1; var y := 2; swap(x,y); (x == 2) and (y == 1)", "var x := 1; var y := 2; x <=> y ; (x == 2) and (y == 1)", "var v[2] := {1,2}; swap(v[0],v[1]); (v[0] == 2) and (v[1] == 1)",