From 3a684785a8edb7baab1ff94fc42c7fed7d7bb21a Mon Sep 17 00:00:00 2001 From: Arash Partow Date: Tue, 2 Aug 2016 15:41:21 +1000 Subject: [PATCH] C++ Mathematical Expression Library (ExprTk) http://www.partow.net/programming/exprtk/index.html --- exprtk.hpp | 343 +++++++++++++++++++++++++++++++---------------------- readme.txt | 130 ++++++++++++++++++-- 2 files changed, 322 insertions(+), 151 deletions(-) diff --git a/exprtk.hpp b/exprtk.hpp index a1d7366..9cd92ff 100644 --- a/exprtk.hpp +++ b/exprtk.hpp @@ -2256,7 +2256,9 @@ namespace exprtk inline void scan_token() { skip_whitespace(); + skip_comments(); + if (is_end(s_itr_)) { return; @@ -2391,14 +2393,20 @@ namespace exprtk { /* Attempt to match a valid numeric value in one of the following formats: - 1. 123456 - 2. 123.456 - 3. 123.456e3 - 4. 123.456E3 - 5. 123.456e+3 - 6. 123.456E+3 - 7. 123.456e-3 - 8. 123.456E-3 + 01. 123456 + 02. 123.456 + 03. 123.456e3 + 04. 123.456E3 + 05. 123.456e+3 + 06. 123.456E+3 + 07. 123.456e-3 + 08. 123.456E-3 + 09. .1234 + 10. .1234e3 + 11. .1234E+3 + 12. .1234e+3 + 13. .1234E-3 + 14. .1234e-3 */ const char* initial_itr = s_itr_; bool dot_found = false; @@ -2825,30 +2833,27 @@ namespace exprtk return changes; } - inline virtual int insert(const token&, token& ) - { - return -1; - } + #define token_inserter_empty_body \ + { \ + return -1; \ + } \ + + inline virtual int insert(const token&, token&) + token_inserter_empty_body inline virtual int insert(const token&, const token&, token&) - { - return -1; - } + token_inserter_empty_body inline virtual int insert(const token&, const token&, const token&, token&) - { - return -1; - } + token_inserter_empty_body inline virtual int insert(const token&, const token&, const token&, const token&, token&) - { - return -1; - } + token_inserter_empty_body inline virtual int insert(const token&, const token&, const token&, const token&, const token&, token&) - { - return -1; - } + token_inserter_empty_body + + #undef token_inserter_empty_body private: @@ -2888,7 +2893,7 @@ namespace exprtk std::size_t changes = 0; - for (std::size_t i = 0; i < g.token_list_.size() - 1; ++i) + for (std::size_t i = 0; i < (g.token_list_.size() - 1); ++i) { token t; @@ -2912,7 +2917,7 @@ namespace exprtk std::size_t changes = 0; - for (std::size_t i = 0; i < g.token_list_.size() - 2; ++i) + for (std::size_t i = 0; i < (g.token_list_.size() - 2); ++i) { token t; @@ -3023,6 +3028,7 @@ namespace exprtk t.type = lexer::token::e_assign; t.value = ":="; t.position = t0.position; + return true; } // '+ =' --> '+=' @@ -3031,6 +3037,7 @@ namespace exprtk t.type = lexer::token::e_addass; t.value = "+="; t.position = t0.position; + return true; } // '- =' --> '-=' @@ -3039,6 +3046,7 @@ namespace exprtk t.type = lexer::token::e_subass; t.value = "-="; t.position = t0.position; + return true; } // '* =' --> '*=' @@ -3047,6 +3055,7 @@ namespace exprtk t.type = lexer::token::e_mulass; t.value = "*="; t.position = t0.position; + return true; } // '/ =' --> '/=' @@ -3055,6 +3064,7 @@ namespace exprtk t.type = lexer::token::e_divass; t.value = "/="; t.position = t0.position; + return true; } // '% =' --> '%=' @@ -3063,6 +3073,7 @@ namespace exprtk t.type = lexer::token::e_modass; t.value = "%="; t.position = t0.position; + return true; } // '> =' --> '>=' @@ -3071,6 +3082,7 @@ namespace exprtk t.type = lexer::token::e_gte; t.value = ">="; t.position = t0.position; + return true; } // '< =' --> '<=' @@ -3079,6 +3091,7 @@ namespace exprtk t.type = lexer::token::e_lte; t.value = "<="; t.position = t0.position; + return true; } // '= =' --> '==' @@ -3087,6 +3100,7 @@ namespace exprtk t.type = lexer::token::e_eq; t.value = "=="; t.position = t0.position; + return true; } // '! =' --> '!=' @@ -3095,6 +3109,7 @@ namespace exprtk t.type = lexer::token::e_ne; t.value = "!="; t.position = t0.position; + return true; } // '< >' --> '<>' @@ -3103,6 +3118,7 @@ namespace exprtk t.type = lexer::token::e_ne; t.value = "<>"; t.position = t0.position; + return true; } // '<= >' --> '<=>' @@ -3111,6 +3127,7 @@ namespace exprtk t.type = lexer::token::e_swap; t.value = "<=>"; t.position = t0.position; + return true; } // '+ -' --> '-' @@ -3119,6 +3136,7 @@ namespace exprtk t.type = lexer::token::e_sub; t.value = "-"; t.position = t0.position; + return true; } // '- +' --> '-' @@ -3127,6 +3145,7 @@ namespace exprtk t.type = lexer::token::e_sub; t.value = "-"; t.position = t0.position; + return true; } // '- -' --> '-' @@ -3139,6 +3158,7 @@ namespace exprtk t.type = lexer::token::e_add; t.value = "+"; t.position = t0.position; + return true; } else @@ -3221,14 +3241,14 @@ namespace exprtk { if (stack_.empty()) { - state_ = false; + state_ = false; error_token_ = t; return false; } else if (c != stack_.top().first) { - state_ = false; + state_ = false; error_token_ = t; return false; @@ -3558,6 +3578,7 @@ namespace exprtk } token_scanner_list.push_back(scanner); + return true; } @@ -3571,6 +3592,7 @@ namespace exprtk } token_modifier_list.push_back(modifier); + return true; } @@ -3584,6 +3606,7 @@ namespace exprtk } token_joiner_list.push_back(joiner); + return true; } @@ -3597,13 +3620,13 @@ namespace exprtk } token_inserter_list.push_back(inserter); + return true; } inline bool run_modifiers(lexer::generator& g) { error_token_modifier = reinterpret_cast(0); - bool result = true; for (std::size_t i = 0; i < token_modifier_list.size(); ++i) { @@ -3615,17 +3638,17 @@ namespace exprtk if (!modifier.result()) { error_token_modifier = token_modifier_list[i]; + return false; } } - return result; + return true; } inline bool run_joiners(lexer::generator& g) { error_token_joiner = reinterpret_cast(0); - bool result = true; for (std::size_t i = 0; i < token_joiner_list.size(); ++i) { @@ -3637,17 +3660,17 @@ namespace exprtk if (!joiner.result()) { error_token_joiner = token_joiner_list[i]; + return false; } } - return result; + return true; } inline bool run_inserters(lexer::generator& g) { error_token_inserter = reinterpret_cast(0); - bool result = true; for (std::size_t i = 0; i < token_inserter_list.size(); ++i) { @@ -3659,17 +3682,17 @@ namespace exprtk if (!inserter.result()) { error_token_inserter = token_inserter_list[i]; + return false; } } - return result; + return true; } inline bool run_scanners(lexer::generator& g) { error_token_scanner = reinterpret_cast(0); - bool result = true; for (std::size_t i = 0; i < token_scanner_list.size(); ++i) { @@ -3681,11 +3704,12 @@ namespace exprtk if (!scanner.result()) { error_token_scanner = token_scanner_list[i]; + return false; } } - return result; + return true; } std::vector token_scanner_list; @@ -14235,120 +14259,85 @@ namespace exprtk virtual ~ifunction() {} + #define empty_method_body \ + { \ + return std::numeric_limits::quiet_NaN(); \ + } \ + inline virtual T operator()() - { - return std::numeric_limits::quiet_NaN(); - } + empty_method_body inline virtual T operator()(const T&) - { - return std::numeric_limits::quiet_NaN(); - } + empty_method_body inline virtual T operator()(const T&,const T&) - { - return std::numeric_limits::quiet_NaN(); - } + empty_method_body inline virtual T operator()(const T&, const T&, const T&) - { - return std::numeric_limits::quiet_NaN(); - } + empty_method_body inline virtual T operator()(const T&, const T&, const T&, const T&) - { - return std::numeric_limits::quiet_NaN(); - } + empty_method_body inline virtual T operator()(const T&, const T&, const T&, const T&, const T&) - { - return std::numeric_limits::quiet_NaN(); - } + empty_method_body inline virtual T operator()(const T&, const T&, const T&, const T&, const T&, const T&) - { - return std::numeric_limits::quiet_NaN(); - } + empty_method_body inline virtual T operator()(const T&, const T&, const T&, const T&, const T&, const T&, const T&) - { - return std::numeric_limits::quiet_NaN(); - } + empty_method_body inline virtual T operator()(const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&) - { - return std::numeric_limits::quiet_NaN(); - } + empty_method_body inline virtual T operator()(const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&) - { - return std::numeric_limits::quiet_NaN(); - } + empty_method_body inline virtual T operator()(const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&) - { - return std::numeric_limits::quiet_NaN(); - } + empty_method_body inline virtual T operator()(const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&) - { - return std::numeric_limits::quiet_NaN(); - } + empty_method_body inline virtual T operator()(const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&) - { - return std::numeric_limits::quiet_NaN(); - } + empty_method_body inline virtual T operator()(const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&) - { - return std::numeric_limits::quiet_NaN(); - } + empty_method_body inline virtual T operator()(const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&) - { - return std::numeric_limits::quiet_NaN(); - } + empty_method_body inline virtual T operator()(const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&) - { - return std::numeric_limits::quiet_NaN(); - } + empty_method_body inline virtual T operator()(const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&) - { - return std::numeric_limits::quiet_NaN(); - } + empty_method_body inline virtual T operator()(const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&) - { - return std::numeric_limits::quiet_NaN(); - } + empty_method_body inline virtual T operator()(const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&) - { - return std::numeric_limits::quiet_NaN(); - } + empty_method_body inline virtual T operator()(const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&) - { - return std::numeric_limits::quiet_NaN(); - } + empty_method_body inline virtual T operator()(const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&) - { - return std::numeric_limits::quiet_NaN(); - } + empty_method_body + + #undef empty_method_body std::size_t param_count; }; @@ -14391,33 +14380,27 @@ namespace exprtk virtual ~igeneric_function() {} + #define igeneric_function_empty_body(N) \ + { \ + exprtk_debug(("igeneric_function::operator() - Operator has not been overridden. ["#N"]\n")); \ + return std::numeric_limits::quiet_NaN(); \ + } \ + // f(i_0,i_1,....,i_N) --> Scalar inline virtual T operator()(parameter_list_t) - { - exprtk_debug(("igeneric_function::operator() - Operator has not been overridden. [1]\n")); - return std::numeric_limits::quiet_NaN(); - } + igeneric_function_empty_body(1) // f(i_0,i_1,....,i_N) --> String inline virtual T operator()(std::string&, parameter_list_t) - { - exprtk_debug(("igeneric_function::operator() - Operator has not been overridden. [2]\n")); - return std::numeric_limits::quiet_NaN(); - } + igeneric_function_empty_body(2) // f(psi,i_0,i_1,....,i_N) --> Scalar inline virtual T operator()(const std::size_t&, parameter_list_t) - { - exprtk_debug(("igeneric_function::operator() - Operator has not been overridden. [3]\n")); - return std::numeric_limits::quiet_NaN(); - } + igeneric_function_empty_body(3) // f(psi,i_0,i_1,....,i_N) --> String inline virtual T operator()(const std::size_t&, std::string&, parameter_list_t) - { - exprtk_debug(("igeneric_function::operator() - Operator has not been overridden. [4]\n")); - return std::numeric_limits::quiet_NaN(); - } + igeneric_function_empty_body(4) std::string parameter_sequence; return_type rtrn_type; @@ -14436,6 +14419,7 @@ namespace exprtk typedef T (*ff3_functor)(T,T,T); typedef T (*ff4_functor)(T,T,T,T); typedef T (*ff5_functor)(T,T,T,T,T); + typedef T (*ff6_functor)(T,T,T,T,T,T); protected: @@ -14479,6 +14463,14 @@ namespace exprtk ff5_functor f; }; + struct freefunc6 : public exprtk::ifunction + { + freefunc6(ff6_functor ff) : exprtk::ifunction(6), f(ff) {} + inline T operator()(const T& v0, const T& v1, const T& v2, const T& v3, const T& v4, const T& v5) + { return f(v0,v1,v2,v3,v4,v5); } + ff5_functor f; + }; + template struct type_store { @@ -14762,6 +14754,7 @@ namespace exprtk static RawType null_type = init_type::set(RawType()); tm_const_itr_t itr = map.find(symbol_name); + if (map.end() == itr) return null_type; else @@ -15372,6 +15365,22 @@ namespace exprtk return add_function(function_name,(*local_data().free_function_list_.back())); } + inline bool add_function(const std::string& function_name, ff6_functor function) + { + if (!valid()) + return false; + else if (!valid_symbol(function_name)) + return false; + else if (symbol_exists(function_name)) + return false; + + exprtk::ifunction* ifunc = new freefunc6(function); + + local_data().free_function_list_.push_back(ifunc); + + return add_function(function_name,(*local_data().free_function_list_.back())); + } + inline bool add_reserved_function(const std::string& function_name, function_t& function) { if (!valid()) @@ -25968,6 +25977,7 @@ namespace exprtk if (synthesize_sf4ext_expression::template compile_left(expr_gen,v,operation,branch[0],result)) { free_node(*expr_gen.node_allocator_,branch[0]); + return result; } } @@ -26247,6 +26257,7 @@ namespace exprtk if (details::e_pow == boc_opr) { bocnode->set_c(bocnode->c() * c); + return bocnode; } } @@ -26362,6 +26373,7 @@ namespace exprtk result = expr_gen.node_allocator_-> template allocate_tt > > (cobnode->c() / c,cobnode->move_branch(0)); + free_node(*expr_gen.node_allocator_,branch[0]); } } @@ -26415,6 +26427,7 @@ namespace exprtk result = expr_gen.node_allocator_-> template allocate_tt > > (c - cobnode->c(),cobnode->move_branch(0)); + free_node(*expr_gen.node_allocator_,branch[1]); } } @@ -26430,6 +26443,7 @@ namespace exprtk result = expr_gen.node_allocator_-> template allocate_tt > > (c - cobnode->c(),cobnode->move_branch(0)); + free_node(*expr_gen.node_allocator_,branch[1]); } } @@ -26445,6 +26459,7 @@ namespace exprtk result = expr_gen.node_allocator_-> template allocate_tt > > (c / cobnode->c(),cobnode->move_branch(0)); + free_node(*expr_gen.node_allocator_,branch[1]); } } @@ -26460,6 +26475,7 @@ namespace exprtk result = expr_gen.node_allocator_-> template allocate_tt > > (c / cobnode->c(),cobnode->move_branch(0)); + free_node(*expr_gen.node_allocator_,branch[1]); } } @@ -26517,6 +26533,7 @@ namespace exprtk result = expr_gen.node_allocator_-> template allocate_tt > > (bocnode->move_branch(0),c - bocnode->c()); + free_node(*expr_gen.node_allocator_,branch[0]); } else if (details::e_sub == operation) @@ -26561,6 +26578,7 @@ namespace exprtk result = expr_gen.node_allocator_-> template allocate_tt > > (c - bocnode->c(),bocnode->move_branch(0)); + free_node(*expr_gen.node_allocator_,branch[1]); } } @@ -26571,6 +26589,7 @@ namespace exprtk result = expr_gen.node_allocator_-> template allocate_tt > > (bocnode->move_branch(0),c - bocnode->c()); + free_node(*expr_gen.node_allocator_,branch[1]); } else if (details::e_sub == operation) @@ -26578,6 +26597,7 @@ namespace exprtk result = expr_gen.node_allocator_-> template allocate_tt > > (c + bocnode->c(),bocnode->move_branch(0)); + free_node(*expr_gen.node_allocator_,branch[1]); } } @@ -26593,6 +26613,7 @@ namespace exprtk result = expr_gen.node_allocator_-> template allocate_tt > > (c / bocnode->c(),bocnode->move_branch(0)); + free_node(*expr_gen.node_allocator_,branch[1]); } } @@ -26608,6 +26629,7 @@ namespace exprtk result = expr_gen.node_allocator_-> template allocate_tt > > (c * bocnode->c(),bocnode->move_branch(0)); + free_node(*expr_gen.node_allocator_,branch[1]); } } @@ -32504,66 +32526,71 @@ namespace exprtk virtual ~polynomial() {} + #define poly_rtrn(NN) \ + return (NN != N) ? std::numeric_limits::quiet_NaN() : + inline virtual T operator()(const T& x, const T& c1, const T& c0) { - return ((1 == N) ? poly_impl::evaluate(x,c1,c0) : std::numeric_limits::quiet_NaN()); + poly_rtrn(1) poly_impl::evaluate(x,c1,c0); } inline virtual T operator()(const T& x, const T& c2, const T& c1, const T& c0) { - return ((2 == N) ? poly_impl::evaluate(x,c2,c1,c0) : std::numeric_limits::quiet_NaN()); + poly_rtrn(2) poly_impl::evaluate(x,c2,c1,c0); } inline virtual T operator()(const T& x, const T& c3, const T& c2, const T& c1, const T& c0) { - return ((3 == N) ? poly_impl::evaluate(x,c3,c2,c1,c0) : std::numeric_limits::quiet_NaN()); + poly_rtrn(3) poly_impl::evaluate(x,c3,c2,c1,c0); } inline virtual T operator()(const T& x, const T& c4, const T& c3, const T& c2, const T& c1, const T& c0) { - return ((4 == N) ? poly_impl::evaluate(x,c4,c3,c2,c1,c0) : std::numeric_limits::quiet_NaN()); + poly_rtrn(4) poly_impl::evaluate(x,c4,c3,c2,c1,c0); } inline virtual T operator()(const T& x, const T& c5, const T& c4, const T& c3, const T& c2, const T& c1, const T& c0) { - return ((5 == N) ? poly_impl::evaluate(x,c5,c4,c3,c2,c1,c0) : std::numeric_limits::quiet_NaN()); + poly_rtrn(5) poly_impl::evaluate(x,c5,c4,c3,c2,c1,c0); } inline virtual T operator()(const T& x, const T& c6, const T& c5, const T& c4, const T& c3, const T& c2, const T& c1, const T& c0) { - return ((6 == N) ? poly_impl::evaluate(x,c6,c5,c4,c3,c2,c1,c0) : std::numeric_limits::quiet_NaN()); + poly_rtrn(6) poly_impl::evaluate(x,c6,c5,c4,c3,c2,c1,c0); } inline virtual T operator()(const T& x, const T& c7, const T& c6, const T& c5, const T& c4, const T& c3, const T& c2, const T& c1, const T& c0) { - return ((7 == N) ? poly_impl::evaluate(x,c7,c6,c5,c4,c3,c2,c1,c0) : std::numeric_limits::quiet_NaN()); + poly_rtrn(7) poly_impl::evaluate(x,c7,c6,c5,c4,c3,c2,c1,c0); } inline virtual T operator()(const T& x, const T& c8, const T& c7, const T& c6, const T& c5, const T& c4, const T& c3, const T& c2, const T& c1, const T& c0) { - return ((8 == N) ? poly_impl::evaluate(x,c8,c7,c6,c5,c4,c3,c2,c1,c0) : std::numeric_limits::quiet_NaN()); + poly_rtrn(8) poly_impl::evaluate(x,c8,c7,c6,c5,c4,c3,c2,c1,c0); } inline virtual T operator()(const T& x, const T& c9, const T& c8, const T& c7, const T& c6, const T& c5, const T& c4, const T& c3, const T& c2, const T& c1, const T& c0) { - return ((9 == N) ? poly_impl::evaluate(x,c9,c8,c7,c6,c5,c4,c3,c2,c1,c0) : std::numeric_limits::quiet_NaN()); + poly_rtrn(9) poly_impl::evaluate(x,c9,c8,c7,c6,c5,c4,c3,c2,c1,c0); } inline virtual T operator()(const T& x, const T& c10, const T& c9, const T& c8, const T& c7, const T& c6, const T& c5, const T& c4, const T& c3, const T& c2, const T& c1, const T& c0) { - return ((10 == N) ? poly_impl::evaluate(x,c10,c9,c8,c7,c6,c5,c4,c3,c2,c1,c0) : std::numeric_limits::quiet_NaN()); + poly_rtrn(10) poly_impl::evaluate(x,c10,c9,c8,c7,c6,c5,c4,c3,c2,c1,c0); } inline virtual T operator()(const T& x, const T& c11, const T& c10, const T& c9, const T& c8, const T& c7, const T& c6, const T& c5, const T& c4, const T& c3, const T& c2, const T& c1, const T& c0) { - return ((11 == N) ? poly_impl::evaluate(x,c11,c10,c9,c8,c7,c6,c5,c4,c3,c2,c1,c0) : std::numeric_limits::quiet_NaN()); + poly_rtrn(11) poly_impl::evaluate(x,c11,c10,c9,c8,c7,c6,c5,c4,c3,c2,c1,c0); } inline virtual T operator()(const T& x, const T& c12, const T& c11, const T& c10, const T& c9, const T& c8, const T& c7, const T& c6, const T& c5, const T& c4, const T& c3, const T& c2, const T& c1, const T& c0) { - return ((12 == N) ? poly_impl::evaluate(x,c12,c11,c10,c9,c8,c7,c6,c5,c4,c3,c2,c1,c0) : std::numeric_limits::quiet_NaN()); + poly_rtrn(12) poly_impl::evaluate(x,c12,c11,c10,c9,c8,c7,c6,c5,c4,c3,c2,c1,c0); } + #undef poly_rtrn + inline virtual T operator()() { return std::numeric_limits::quiet_NaN(); @@ -32645,6 +32672,19 @@ namespace exprtk v_.push_back(v2); v_.push_back(v3); } + function(const std::string& name, + const std::string& expression, + const std::string& v0, const std::string& v1, + const std::string& v2, const std::string& v3, + const std::string& v4) + : name_(name), + expression_(expression) + { + v_.push_back(v0); v_.push_back(v1); + v_.push_back(v2); v_.push_back(v3); + v_.push_back(v4); + } + inline function& name(const std::string& n) { name_ = n; @@ -32672,12 +32712,12 @@ namespace exprtk struct base_func : public exprtk::ifunction { - typedef const T& type; - typedef exprtk::ifunction function_t; - typedef std::vector varref_t; - typedef std::vector var_t; + typedef const T& type; + typedef exprtk::ifunction function_t; + typedef std::vector varref_t; + typedef std::vector var_t; typedef std::pair lvarref_t; - typedef std::vector lvr_vec_t; + typedef std::vector lvr_vec_t; base_func(const std::size_t& pc = 0) : exprtk::ifunction(pc), @@ -32893,16 +32933,30 @@ namespace exprtk typedef const T& type; + template + struct scoped_bft + { + scoped_bft(BaseFuncType& bft) : bft_(bft) { bft_.pre (); } + ~scoped_bft() { bft_.post(); } + + BaseFuncType& bft_; + + private: + + scoped_bft(scoped_bft&); + scoped_bft& operator=(scoped_bft&); + }; + struct func_1param : public base_func { func_1param() : base_func(1) {} inline T operator()(type v0) { - base_func::pre(); + scoped_bft sb(*this); base_func::update(v0); T result = this->value(base_func::expression); - base_func::post(); + return result; } }; @@ -32913,10 +32967,10 @@ namespace exprtk inline T operator()(type v0, type v1) { - base_func::pre(); + scoped_bft sb(*this); base_func::update(v0,v1); T result = this->value(base_func::expression); - base_func::post(); + return result; } }; @@ -32927,10 +32981,10 @@ namespace exprtk inline T operator()(type v0, type v1, type v2) { - base_func::pre(); + scoped_bft sb(*this); base_func::update(v0,v1,v2); T result = this->value(base_func::expression); - base_func::post(); + return result; } }; @@ -32941,10 +32995,10 @@ namespace exprtk inline T operator()(type v0, type v1, type v2, type v3) { - base_func::pre(); + scoped_bft sb(*this); base_func::update(v0,v1,v2,v3); T result = this->value(base_func::expression); - base_func::post(); + return result; } }; @@ -32955,10 +33009,10 @@ namespace exprtk inline T operator()(type v0, type v1, type v2, type v3, type v4) { - base_func::pre(); + scoped_bft sb(*this); base_func::update(v0,v1,v2,v3,v4); T result = this->value(base_func::expression); - base_func::post(); + return result; } }; @@ -32969,10 +33023,10 @@ namespace exprtk inline T operator()(type v0, type v1, type v2, type v3, type v4, type v5) { - base_func::pre(); + scoped_bft sb(*this); base_func::update(v0,v1,v2,v3,v4,v5); T result = this->value(base_func::expression); - base_func::post(); + return result; } }; @@ -33040,6 +33094,7 @@ namespace exprtk if (compile_expression(name,expression,var_list)) { fp_map_[n][name]->setup(expr_map_[name]); + return true; } else diff --git a/readme.txt b/readme.txt index 224da97..24f542b 100644 --- a/readme.txt +++ b/readme.txt @@ -94,6 +94,7 @@ locations: (a) Download: http://www.partow.net/programming/exprtk/index.html (b) Repository: https://github.com/ArashPartow/exprtk + https://github.com/ArashPartow/exprtk-extras ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -240,7 +241,7 @@ of C++ compilers: | ceil | Smallest integer that is greater than or equal to x. | +----------+---------------------------------------------------------+ | clamp | Clamp x in range between r0 and r1, where r0 < r1. | -| | (eg: clamp(r0,x,r1) | +| | (eg: clamp(r0,x,r1)) | +----------+---------------------------------------------------------+ | equal | Equality test between x and y using normalized epsilon | +----------+---------------------------------------------------------+ @@ -762,12 +763,12 @@ Expression: z := (x + y^-2.345) * sin(pi / min(w - 7.3,v)) Variable(z) [Multiplication] ____________/ \___________ / \ - / [Unary-Func(sin)] + / [Unary-Function(sin)] [Addition] | ____/ \____ [Division] / \ ___/ \___ Variable(x) [Exponentiation] / \ - ______/ \______ Constant(pi) [Binary-Func(min)] + ______/ \______ Constant(pi) [Binary-Function(min)] / \ ____/ \____ Variable(y) [Negation] / \ | / Variable(v) @@ -801,6 +802,118 @@ error status code, with a more detailed description of the error(s) and its location within the input provided by the 'get_error' interface. + +Note: The exprtk::expression and exprtk::symbol_table components are +reference counted entities. Copy constructing or assigning to or from +either component will result in a shallow copy and a reference count +increment, rather than a complete replication. Furthermore the +expression and symbol_table components being Default-Constructible, +Copy-Constructible and Copy-Assignable make them compatible with +various C++ standard library containers and adaptors such as +std::vector, std::map, std::stack etc. + +The following is an example of two unique expressions, after having +being instantiated and compiled, one expression is assigned to the +other. The diagrams depict their initial and post assignment states, +including which control block each expression references and their +associated reference counts. + + + exprtk::expression e0; // constructed expression, eg: x + 1 + exprtk::expression e1; // constructed expression, eg: 2z + y + + +-----[ e0 cntrl block]----+ +-----[ e1 cntrl block]-----+ + | 1. Expression Node 'x+1' | | 1. Expression Node '2z+y' | + | 2. Ref Count: 1 |<-+ | 2. Ref Count: 1 |<-+ + +--------------------------+ | +---------------------------+ | + | | + +--[ e0 expression]--+ | +--[ e1 expression]--+ | + | 1. Reference to ]------+ | 1. Reference to ]-------+ + | e0 Control Block | | e1 Control Block | + +--------------------+ +--------------------+ + + + e0 = e1; // e0 and e1 are now 2z+y + + +-----[ e1 cntrl block]-----+ + | 1. Expression Node '2z+y' | + +----------->| 2. Ref Count: 2 |<----------+ + | +---------------------------+ | + | | + | +--[ e0 expression]--+ +--[ e1 expression]--+ | + +---[ 1. Reference to | | 1. Reference to ]---+ + | e1 Control Block | | e1 Control Block | + +--------------------+ +--------------------+ + +The reason for the above complexity and restrictions of deep copies +for the expression and symbol_table components is because expressions +may include user defined variables or functions. These are embedded as +references into the expression's AST. When copying an expression, said +references need to also be copied. if the references are blindly +copied, then it will result in two or more identical expressions +utilizing the exact same references for variables. This obviously is +not the default assumed scenario and will give rise to non-obvious +behaviours when using the expressions in various contexts such as +muli-threading et al. + +The prescribed method for cloning an expression is to compile it from +its string form. Doing so will allow the one to properly consider the +exact source of user defined variables and functions. + +Note: The exprtk::parser is a non-copyable and non-thread safe +component, and should only be shared via either a reference, a shared +pointer or a std::ref mechanism, and considerations relating to +synchronisation taken into account where appropriate. The parser +represents an object factory, specifically a factory of expressions, +and generally should not be instantiated solely on a per expression +compilation basis. + +The following diagram and example depicts the flow of data and +operations for compiling multiple expressions via the parser and +inserting the newly minted exprtk::expression instances into a +std::vector. + + + +--[exprtk::parser]--+ + | expression factory | + +---->- compile(....) ->---+ + | +--------------------+ | + Expressions | | Expressions as + in string form A V exprtk::expression + | | instances + [s0:'x+1' ]-+ | | +-[e0: x+1] + | | | | + [s1:'2z+y']-----+--+ +-->+-[e1: 2z+y] + | | + [s2:'sin(k+w)']-+ +-[e2: sin(k+w)] + + + const std::string expression_str[3] + = { "x + 1", "2x + y", "sin(k + w)" }; + + std::vector expression_list; + + parser_t parser; + expression_t expression; + symbol_table_t symbol_table; + + expression.register_symbol_table(symbol_table); + + for (std::size_t i = 0; i < 3; ++i) + { + if (parser.compile(expression_str[i],expression)) + { + expression_list.push_back(expression); + } + else + std::cout << "Error in " << expression_str[i] << "\n"; + } + + for (auto e : expression_list) + { + e.value(); + } + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ [11 - COMPILATION OPTIONS] @@ -1060,9 +1173,9 @@ zero. The following are examples of vector definitions: (3) String Definition -Strings are a sequence of 8-bit characters. They can only be defined -with an explicit initialisation value. The following are examples of -string variable definitions: +Strings are sequences comprised of 8-bit characters. They can only be +defined with an explicit initialisation value. The following are +examples of string variable definitions: (a) Initialise to a string var x := 'abc'; @@ -1096,6 +1209,9 @@ variable definitions, the value to which the variable is initialised will be returned. Where as for vectors, the value of the first element (eg: v[0]) will be returned. + 8 == ((var x := 7;) + 1) + 4 == (var y[3] := {4, 5, 6};) + (5) Variable/Vector Assignment The value of a variable can be assigned to a vector and a vector or a @@ -1700,7 +1816,7 @@ the function can be disabled. { foo() : exprtk::ifunction(3) { - exprtk::disable_has_side_effects(*this); + exprtk::disable_has_side_effects(*this); } T operator()(const T& v1, const T& v2, const T& v3)