From f46bffcd6966d38a09023fb37ba9335214c9b959 Mon Sep 17 00:00:00 2001 From: ArashPartow Date: Sun, 1 Jan 2023 02:18:35 +0000 Subject: [PATCH] C++ Mathematical Expression Library (ExprTk) https://www.partow.net/programming/exprtk/index.html --- .circleci/config.yml | 12 +- Makefile | 4 +- exprtk.hpp | 1582 ++++++++++++++++++++-------------- exprtk_benchmark.cpp | 8 +- exprtk_functional_test.txt | 6 +- exprtk_simple_example_01.cpp | 6 +- exprtk_simple_example_02.cpp | 6 +- exprtk_simple_example_03.cpp | 6 +- exprtk_simple_example_04.cpp | 6 +- exprtk_simple_example_05.cpp | 6 +- exprtk_simple_example_06.cpp | 6 +- exprtk_simple_example_07.cpp | 6 +- exprtk_simple_example_08.cpp | 6 +- exprtk_simple_example_09.cpp | 6 +- exprtk_simple_example_10.cpp | 6 +- exprtk_simple_example_11.cpp | 6 +- exprtk_simple_example_12.cpp | 6 +- exprtk_simple_example_13.cpp | 6 +- exprtk_simple_example_14.cpp | 6 +- exprtk_simple_example_15.cpp | 6 +- exprtk_simple_example_16.cpp | 6 +- exprtk_simple_example_17.cpp | 6 +- exprtk_simple_example_18.cpp | 6 +- exprtk_simple_example_19.cpp | 6 +- exprtk_test.cpp | 130 ++- readme.txt | 166 +++- 26 files changed, 1235 insertions(+), 787 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index a0cba13..14a17a8 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -1,18 +1,18 @@ version: 2.1 jobs: - build_gcc_6: + build_gcc_09: docker: - - image: gcc:6 + - image: gcc:9 steps: - checkout - run: c++ --version - run: make all -j 2 - run: ./exprtk_test - build_gcc_7: + build_gcc_10: docker: - - image: gcc:7 + - image: gcc:10 steps: - checkout - run: c++ --version @@ -32,6 +32,6 @@ workflows: version: 2 build_and_test: jobs: - - build_gcc_6 - - build_gcc_7 + - build_gcc_09 + - build_gcc_10 - build_gcc_latest diff --git a/Makefile b/Makefile index dbb7697..54c776c 100644 --- a/Makefile +++ b/Makefile @@ -2,8 +2,8 @@ # ************************************************************** # * C++ Mathematical Expression Toolkit Library * # * * -# * Author: Arash Partow (1999-2022) * -# * URL: http://www.partow.net/programming/exprtk/index.html * +# * Author: Arash Partow (1999-2023) * +# * URL: https://www.partow.net/programming/exprtk/index.html * # * * # * Copyright notice: * # * Free use of the Mathematical Expression Toolkit Library is * diff --git a/exprtk.hpp b/exprtk.hpp index 4a4db54..b4530ba 100644 --- a/exprtk.hpp +++ b/exprtk.hpp @@ -2,7 +2,7 @@ ****************************************************************** * C++ Mathematical Expression Toolkit Library * * * - * Author: Arash Partow (1999-2022) * + * Author: Arash Partow (1999-2023) * * URL: https://www.partow.net/programming/exprtk/index.html * * * * Copyright notice: * @@ -38,7 +38,6 @@ #include #include #include -#include #include #include #include @@ -298,7 +297,6 @@ namespace exprtk std::reverse(result.begin(), result.end()); - return result; } @@ -401,7 +399,7 @@ namespace exprtk { public: - build_string(const std::size_t& initial_size = 64) + explicit build_string(const std::size_t& initial_size = 64) { data_.reserve(initial_size); } @@ -605,6 +603,8 @@ namespace exprtk const typename std::iterator_traits::value_type& zero_or_more, const typename std::iterator_traits::value_type& exactly_one ) { + typedef typename std::iterator_traits::value_type type; + const Iterator null_itr(0); Iterator p_itr = pattern_begin; @@ -614,39 +614,45 @@ namespace exprtk for ( ; ; ) { - const bool pvalid = p_itr != pattern_end; - const bool dvalid = d_itr != data_end; - - if (!pvalid && !dvalid) - break; - - if (pvalid) + if (p_itr != pattern_end) { - const typename std::iterator_traits::value_type c = *(p_itr); + const type c = *(p_itr); - if (zero_or_more == c) + if ((data_end != d_itr) && (Compare::cmp(c,*(d_itr)) || (exactly_one == c))) { - np_itr = p_itr; - nd_itr = d_itr + 1; - ++p_itr; - continue; - } - else if (dvalid && ((exactly_one == c) || Compare::cmp(c,*(d_itr)))) - { - ++p_itr; ++d_itr; + ++p_itr; + continue; + } + else if (zero_or_more == c) + { + while ((pattern_end != p_itr) && (zero_or_more == *(p_itr))) + { + ++p_itr; + } + + const type d = *(p_itr); + + while ((data_end != d_itr) && !(Compare::cmp(d,*(d_itr)) || (exactly_one == d))) + { + ++d_itr; + } + + // set backtrack iterators + np_itr = p_itr - 1; + nd_itr = d_itr + 1; + continue; } } + else if (data_end == d_itr) + return true; - if ((null_itr != nd_itr) && (nd_itr <= data_end)) - { - p_itr = np_itr; - d_itr = nd_itr; - continue; - } + if ((data_end == d_itr) || (null_itr == nd_itr)) + return false; - return false; + p_itr = np_itr; + d_itr = nd_itr; } return true; @@ -774,7 +780,6 @@ namespace exprtk { struct unknown_type_tag { unknown_type_tag() {} }; struct real_type_tag { real_type_tag () {} }; - struct complex_type_tag { complex_type_tag() {} }; struct int_type_tag { int_type_tag () {} }; template @@ -788,10 +793,6 @@ namespace exprtk template <> struct number_type \ { typedef real_type_tag type; number_type() {} }; \ - #define exprtk_register_complex_type_tag(T) \ - template <> struct number_type > \ - { typedef complex_type_tag type; number_type() {} }; \ - #define exprtk_register_int_type_tag(T) \ template <> struct number_type \ { typedef int_type_tag type; number_type() {} }; \ @@ -800,10 +801,6 @@ namespace exprtk exprtk_register_real_type_tag(long double) exprtk_register_real_type_tag(float ) - exprtk_register_complex_type_tag(double ) - exprtk_register_complex_type_tag(long double) - exprtk_register_complex_type_tag(float ) - exprtk_register_int_type_tag(short ) exprtk_register_int_type_tag(int ) exprtk_register_int_type_tag(_int64_t ) @@ -2063,6 +2060,11 @@ namespace exprtk details::_uint64_t iteration_count; }; + virtual bool check() + { + return true; + } + virtual void handle_runtime_violation(const violation_context&) { throw std::runtime_error("ExprTk Loop run-time violation."); @@ -3318,7 +3320,7 @@ namespace exprtk ignore_set_.insert(symbol); } - inline int insert(const lexer::token& t0, const lexer::token& t1, lexer::token& new_token) + inline int insert(const lexer::token& t0, const lexer::token& t1, lexer::token& new_token) exprtk_override { bool match = false; new_token.type = lexer::token::e_mul; @@ -3373,7 +3375,7 @@ namespace exprtk : token_joiner(stride) {} - inline bool join(const lexer::token& t0, const lexer::token& t1, lexer::token& t) + inline bool join(const lexer::token& t0, const lexer::token& t1, lexer::token& t) exprtk_override { // ': =' --> ':=' if ((t0.type == lexer::token::e_colon) && (t1.type == lexer::token::e_eq)) @@ -3521,7 +3523,7 @@ namespace exprtk inline bool join(const lexer::token& t0, const lexer::token& t1, const lexer::token& t2, - lexer::token& t) + lexer::token& t) exprtk_override { // '[ * ]' --> '[*]' if ( @@ -3626,7 +3628,8 @@ namespace exprtk lexer::token error_token_; }; - class numeric_checker : public lexer::token_scanner + template + class numeric_checker exprtk_final : public lexer::token_scanner { public: @@ -3652,7 +3655,7 @@ namespace exprtk { if (token::e_number == t.type) { - double v; + T v; if (!exprtk::details::string_to_real(t.value,v)) { @@ -3756,7 +3759,7 @@ namespace exprtk replace_map_t replace_map_; }; - class sequence_validator : public lexer::token_scanner + class sequence_validator exprtk_final : public lexer::token_scanner { private: @@ -3928,7 +3931,7 @@ namespace exprtk std::vector > error_list_; }; - class sequence_validator_3tokens : public lexer::token_scanner + class sequence_validator_3tokens exprtk_final : public lexer::token_scanner { private: @@ -4762,12 +4765,12 @@ namespace exprtk inline void dump_ptr(const std::string& s, const void* ptr, const std::size_t size = 0) { if (size) - exprtk_debug(("%s - addr: %p\n",s.c_str(),ptr)); - else exprtk_debug(("%s - addr: %p size: %d\n", s.c_str(), ptr, static_cast(size))); + else + exprtk_debug(("%s - addr: %p\n",s.c_str(),ptr)); } #else inline void dump_ptr(const std::string&, const void*) {} @@ -4811,7 +4814,7 @@ namespace exprtk { if (data && destruct && (0 == ref_count)) { - dump_ptr("~control_block() data",data); + dump_ptr("~vec_data_store::control_block() data",data); delete[] data; data = reinterpret_cast(0); } @@ -5224,12 +5227,6 @@ namespace exprtk return std::not_equal_to()(0.0f,v); } - template - inline bool is_true(const std::complex& v) - { - return std::not_equal_to >()(std::complex(0),v); - } - template inline bool is_true(const expression_node* node) { @@ -5342,7 +5339,11 @@ namespace exprtk template inline bool is_constant_node(const expression_node* node) { - return node && (details::expression_node::e_constant == node->type()); + return node && + ( + details::expression_node::e_constant == node->type() || + details::expression_node::e_stringconst == node->type() + ); } template @@ -5942,16 +5943,16 @@ namespace exprtk : vector_holder_base_(new(buffer)array_vector_impl(vec,vec_size)) {} - vector_holder(const vds_t& vds) + explicit vector_holder(const vds_t& vds) : vector_holder_base_(new(buffer)array_vector_impl(vds.data(),vds.size())) {} template - vector_holder(std::vector& vec) + explicit vector_holder(std::vector& vec) : vector_holder_base_(new(buffer)sequence_vector_impl(vec)) {} - vector_holder(exprtk::vector_view& vec) + explicit vector_holder(exprtk::vector_view& vec) : vector_holder_base_(new(buffer)vector_view_impl(vec)) {} @@ -6069,9 +6070,9 @@ namespace exprtk const bool result = details::numeric::is_nan(v); if (result) - return (equality_) ? T(1) : T(0); + return equality_ ? T(1) : T(0); else - return (equality_) ? T(0) : T(1); + return equality_ ? T(0) : T(1); } inline typename expression_node::node_type type() const exprtk_override @@ -6255,9 +6256,7 @@ namespace exprtk inline T value() const exprtk_override { assert(branch_.first); - const T arg = branch_.first->value(); - return numeric::process(operation_,arg); } @@ -6286,12 +6285,12 @@ namespace exprtk expression_node::ndb_t::collect(branch_, node_delete_list); } - std::size_t node_depth() const exprtk_override exprtk_final + std::size_t node_depth() const exprtk_final { return expression_node::ndb_t::compute_node_depth(branch_); } - protected: + private: operator_type operation_; branch_t branch_; @@ -6321,7 +6320,7 @@ namespace exprtk const T arg0 = branch_[0].first->value(); const T arg1 = branch_[1].first->value(); - return numeric::process(operation_,arg0,arg1); + return numeric::process(operation_, arg0, arg1); } inline typename expression_node::node_type type() const exprtk_override @@ -6349,12 +6348,12 @@ namespace exprtk expression_node::ndb_t::template collect(branch_, node_delete_list); } - std::size_t node_depth() const exprtk_override exprtk_final + std::size_t node_depth() const exprtk_final { return expression_node::ndb_t::template compute_node_depth<2>(branch_); } - protected: + private: operator_type operation_; branch_t branch_[2]; @@ -6733,7 +6732,7 @@ namespace exprtk { if ( (0 == loop_runtime_check_) || - (++iteration_count_ <= max_loop_iterations_) + ((++iteration_count_ <= max_loop_iterations_) && loop_runtime_check_->check()) ) { return true; @@ -8169,6 +8168,8 @@ namespace exprtk typedef vector_node * vector_node_ptr; typedef vec_data_store vds_t; + using binary_node::branch; + swap_vecvec_node(expression_ptr branch0, expression_ptr branch1) : binary_node(details::e_swap, branch0, branch1) @@ -8177,22 +8178,22 @@ namespace exprtk , vec_size_ (0) , initialised_ (false) { - if (is_ivector_node(binary_node::branch_[0].first)) + if (is_ivector_node(branch(0))) { vector_interface* vi = reinterpret_cast*>(0); - if (0 != (vi = dynamic_cast*>(binary_node::branch_[0].first))) + if (0 != (vi = dynamic_cast*>(branch(0)))) { vec0_node_ptr_ = vi->vec(); vds() = vi->vds(); } } - if (is_ivector_node(binary_node::branch_[1].first)) + if (is_ivector_node(branch(1))) { vector_interface* vi = reinterpret_cast*>(0); - if (0 != (vi = dynamic_cast*>(binary_node::branch_[1].first))) + if (0 != (vi = dynamic_cast*>(branch(1)))) { vec1_node_ptr_ = vi->vec(); } @@ -8213,11 +8214,11 @@ namespace exprtk { if (initialised_) { - assert(binary_node::branch_[0].first); - assert(binary_node::branch_[1].first); + assert(branch(0)); + assert(branch(1)); - binary_node::branch_[0].first->value(); - binary_node::branch_[1].first->value(); + binary_node::branch(0)->value(); + binary_node::branch(1)->value(); T* vec0 = vec0_node_ptr_->vds().data(); T* vec1 = vec1_node_ptr_->vds().data(); @@ -8678,6 +8679,8 @@ namespace exprtk typedef expression_node * expression_ptr; typedef string_base_node* str_base_ptr; + using binary_node::branch; + string_concat_node(const operator_type& opr, expression_ptr branch0, expression_ptr branch1) @@ -8694,27 +8697,27 @@ namespace exprtk range_.cache.first = range_.n0_c.second; range_.cache.second = range_.n1_c.second; - if (is_generally_string_node(binary_node::branch_[0].first)) + if (is_generally_string_node(branch(0))) { - str0_base_ptr_ = dynamic_cast(binary_node::branch_[0].first); + str0_base_ptr_ = dynamic_cast(branch(0)); if (0 == str0_base_ptr_) return; - str0_range_ptr_ = dynamic_cast(binary_node::branch_[0].first); + str0_range_ptr_ = dynamic_cast(branch(0)); if (0 == str0_range_ptr_) return; } - if (is_generally_string_node(binary_node::branch_[1].first)) + if (is_generally_string_node(branch(1))) { - str1_base_ptr_ = dynamic_cast(binary_node::branch_[1].first); + str1_base_ptr_ = dynamic_cast(branch(1)); if (0 == str1_base_ptr_) return; - str1_range_ptr_ = dynamic_cast(binary_node::branch_[1].first); + str1_range_ptr_ = dynamic_cast(branch(1)); if (0 == str1_range_ptr_) return; @@ -8732,11 +8735,11 @@ namespace exprtk { if (initialised_) { - assert(binary_node::branch_[0].first); - assert(binary_node::branch_[1].first); + assert(branch(0)); + assert(branch(1)); - binary_node::branch_[0].first->value(); - binary_node::branch_[1].first->value(); + branch(0)->value(); + branch(1)->value(); std::size_t str0_r0 = 0; std::size_t str0_r1 = 0; @@ -8823,20 +8826,22 @@ namespace exprtk typedef stringvar_node * strvar_node_ptr; typedef string_base_node* str_base_ptr; + using binary_node::branch; + swap_string_node(expression_ptr branch0, expression_ptr branch1) : binary_node(details::e_swap, branch0, branch1), initialised_(false), str0_node_ptr_(0), str1_node_ptr_(0) { - if (is_string_node(binary_node::branch_[0].first)) + if (is_string_node(branch(0))) { - str0_node_ptr_ = static_cast(binary_node::branch_[0].first); + str0_node_ptr_ = static_cast(branch(0)); } - if (is_string_node(binary_node::branch_[1].first)) + if (is_string_node(branch(1))) { - str1_node_ptr_ = static_cast(binary_node::branch_[1].first); + str1_node_ptr_ = static_cast(branch(1)); } initialised_ = (str0_node_ptr_ && str1_node_ptr_); @@ -8848,11 +8853,11 @@ namespace exprtk { if (initialised_) { - assert(binary_node::branch_[0].first); - assert(binary_node::branch_[1].first); + assert(branch(0)); + assert(branch(1)); - binary_node::branch_[0].first->value(); - binary_node::branch_[1].first->value(); + branch(0)->value(); + branch(1)->value(); std::swap(str0_node_ptr_->ref(), str1_node_ptr_->ref()); } @@ -8909,6 +8914,8 @@ namespace exprtk typedef expression_node * expression_ptr; typedef string_base_node* str_base_ptr; + using binary_node::branch; + swap_genstrings_node(expression_ptr branch0, expression_ptr branch1) : binary_node(details::e_default, branch0, branch1) @@ -8918,14 +8925,14 @@ namespace exprtk , str1_range_ptr_(0) , initialised_(false) { - if (is_generally_string_node(binary_node::branch_[0].first)) + if (is_generally_string_node(branch(0))) { - str0_base_ptr_ = dynamic_cast(binary_node::branch_[0].first); + str0_base_ptr_ = dynamic_cast(branch(0)); if (0 == str0_base_ptr_) return; - irange_ptr range = dynamic_cast(binary_node::branch_[0].first); + irange_ptr range = dynamic_cast(branch(0)); if (0 == range) return; @@ -8933,14 +8940,14 @@ namespace exprtk str0_range_ptr_ = &(range->range_ref()); } - if (is_generally_string_node(binary_node::branch_[1].first)) + if (is_generally_string_node(branch(1))) { - str1_base_ptr_ = dynamic_cast(binary_node::branch_[1].first); + str1_base_ptr_ = dynamic_cast(branch(1)); if (0 == str1_base_ptr_) return; - irange_ptr range = dynamic_cast(binary_node::branch_[1].first); + irange_ptr range = dynamic_cast(branch(1)); if (0 == range) return; @@ -8960,11 +8967,11 @@ namespace exprtk { if (initialised_) { - assert(binary_node::branch_[0].first); - assert(binary_node::branch_[1].first); + assert(branch(0)); + assert(branch(1)); - binary_node::branch_[0].first->value(); - binary_node::branch_[1].first->value(); + branch(0)->value(); + branch(1)->value(); std::size_t str0_r0 = 0; std::size_t str0_r1 = 0; @@ -9174,6 +9181,8 @@ namespace exprtk typedef stringvar_node * strvar_node_ptr; typedef string_base_node* str_base_ptr; + using binary_node::branch; + assignment_string_node(const operator_type& opr, expression_ptr branch0, expression_ptr branch1) @@ -9184,21 +9193,20 @@ namespace exprtk , str0_node_ptr_ (0) , str1_range_ptr_(0) { - if (is_string_node(binary_node::branch_[0].first)) + if (is_string_node(branch(0))) { - str0_node_ptr_ = static_cast(binary_node::branch_[0].first); - - str0_base_ptr_ = dynamic_cast(binary_node::branch_[0].first); + str0_node_ptr_ = static_cast(branch(0)); + str0_base_ptr_ = dynamic_cast(branch(0)); } - if (is_generally_string_node(binary_node::branch_[1].first)) + if (is_generally_string_node(branch(1))) { - str1_base_ptr_ = dynamic_cast(binary_node::branch_[1].first); + str1_base_ptr_ = dynamic_cast(branch(1)); if (0 == str1_base_ptr_) return; - irange_ptr range = dynamic_cast(binary_node::branch_[1].first); + irange_ptr range = dynamic_cast(branch(1)); if (0 == range) return; @@ -9218,10 +9226,10 @@ namespace exprtk { if (initialised_) { - assert(binary_node::branch_[0].first); - assert(binary_node::branch_[1].first); + assert(branch(0)); + assert(branch(1)); - binary_node::branch_[1].first->value(); + branch(1)->value(); std::size_t r0 = 0; std::size_t r1 = 0; @@ -9234,7 +9242,7 @@ namespace exprtk str1_base_ptr_->base() + r0, (r1 - r0) + 1); - binary_node::branch_[0].first->value(); + branch(0)->value(); } } @@ -9297,6 +9305,8 @@ namespace exprtk typedef string_range_node* str_rng_node_ptr; typedef string_base_node * str_base_ptr; + using binary_node::branch; + assignment_string_range_node(const operator_type& opr, expression_ptr branch0, expression_ptr branch1) @@ -9308,13 +9318,11 @@ namespace exprtk , str0_range_ptr_ (0) , str1_range_ptr_ (0) { - if (is_string_range_node(binary_node::branch_[0].first)) + if (is_string_range_node(branch(0))) { - str0_rng_node_ptr_ = static_cast(binary_node::branch_[0].first); - - str0_base_ptr_ = dynamic_cast(binary_node::branch_[0].first); - - irange_ptr range = dynamic_cast(binary_node::branch_[0].first); + str0_rng_node_ptr_ = static_cast(branch(0)); + str0_base_ptr_ = dynamic_cast(branch(0)); + irange_ptr range = dynamic_cast(branch(0)); if (0 == range) return; @@ -9322,14 +9330,14 @@ namespace exprtk str0_range_ptr_ = &(range->range_ref()); } - if (is_generally_string_node(binary_node::branch_[1].first)) + if (is_generally_string_node(branch(1))) { - str1_base_ptr_ = dynamic_cast(binary_node::branch_[1].first); + str1_base_ptr_ = dynamic_cast(branch(1)); if (0 == str1_base_ptr_) return; - irange_ptr range = dynamic_cast(binary_node::branch_[1].first); + irange_ptr range = dynamic_cast(branch(1)); if (0 == range) return; @@ -9350,11 +9358,11 @@ namespace exprtk { if (initialised_) { - assert(binary_node::branch_[0].first); - assert(binary_node::branch_[1].first); + assert(branch(0)); + assert(branch(1)); - binary_node::branch_[0].first->value(); - binary_node::branch_[1].first->value(); + branch(0)->value(); + branch(1)->value(); std::size_t s0_r0 = 0; std::size_t s0_r1 = 0; @@ -9601,6 +9609,8 @@ namespace exprtk typedef expression_node * expression_ptr; typedef string_base_node* str_base_ptr; + using binary_node::branch; + cons_conditional_str_node(expression_ptr condition, expression_ptr consequent) : binary_node(details::e_default, consequent, condition) @@ -9616,14 +9626,14 @@ namespace exprtk range_.cache.first = range_.n0_c.second; range_.cache.second = range_.n1_c.second; - if (is_generally_string_node(binary_node::branch_[0].first)) + if (is_generally_string_node(branch(0))) { - str0_base_ptr_ = dynamic_cast(binary_node::branch_[0].first); + str0_base_ptr_ = dynamic_cast(branch(0)); if (0 == str0_base_ptr_) return; - str0_range_ptr_ = dynamic_cast(binary_node::branch_[0].first); + str0_range_ptr_ = dynamic_cast(branch(0)); if (0 == str0_range_ptr_) return; @@ -10349,6 +10359,7 @@ namespace exprtk public: typedef expression_node* expression_ptr; + using binary_node::branch; assignment_node(const operator_type& opr, expression_ptr branch0, @@ -10356,9 +10367,9 @@ namespace exprtk : binary_node(opr, branch0, branch1) , var_node_ptr_(0) { - if (is_variable_node(binary_node::branch_[0].first)) + if (is_variable_node(branch(0))) { - var_node_ptr_ = static_cast*>(binary_node::branch_[0].first); + var_node_ptr_ = static_cast*>(branch(0)); } } @@ -10366,11 +10377,10 @@ namespace exprtk { if (var_node_ptr_) { - assert(binary_node::branch_[1].first); + assert(branch(1)); T& result = var_node_ptr_->ref(); - - result = binary_node::branch_[1].first->value(); + result = branch(1)->value(); return result; } @@ -10389,6 +10399,7 @@ namespace exprtk public: typedef expression_node* expression_ptr; + using binary_node::branch; assignment_vec_elem_node(const operator_type& opr, expression_ptr branch0, @@ -10396,9 +10407,9 @@ namespace exprtk : binary_node(opr, branch0, branch1) , vec_node_ptr_(0) { - if (is_vector_elem_node(binary_node::branch_[0].first)) + if (is_vector_elem_node(branch(0))) { - vec_node_ptr_ = static_cast*>(binary_node::branch_[0].first); + vec_node_ptr_ = static_cast*>(branch(0)); } } @@ -10406,11 +10417,10 @@ namespace exprtk { if (vec_node_ptr_) { - assert(binary_node::branch_[1].first); + assert(branch(1)); T& result = vec_node_ptr_->ref(); - - result = binary_node::branch_[1].first->value(); + result = branch(1)->value(); return result; } @@ -10429,6 +10439,7 @@ namespace exprtk public: typedef expression_node* expression_ptr; + using expression_node::branch; assignment_rebasevec_elem_node(const operator_type& opr, expression_ptr branch0, @@ -10436,9 +10447,9 @@ namespace exprtk : binary_node(opr, branch0, branch1) , rbvec_node_ptr_(0) { - if (is_rebasevector_elem_node(binary_node::branch_[0].first)) + if (is_rebasevector_elem_node(branch(0))) { - rbvec_node_ptr_ = static_cast*>(binary_node::branch_[0].first); + rbvec_node_ptr_ = static_cast*>(branch(0)); } } @@ -10446,11 +10457,11 @@ namespace exprtk { if (rbvec_node_ptr_) { - assert(binary_node::branch_[1].first); + assert(branch(1)); T& result = rbvec_node_ptr_->ref(); - result = binary_node::branch_[1].first->value(); + result = branch(1)->value(); return result; } @@ -10469,6 +10480,7 @@ namespace exprtk public: typedef expression_node* expression_ptr; + using binary_node::branch; assignment_rebasevec_celem_node(const operator_type& opr, expression_ptr branch0, @@ -10476,9 +10488,9 @@ namespace exprtk : binary_node(opr, branch0, branch1) , rbvec_node_ptr_(0) { - if (is_rebasevector_celem_node(binary_node::branch_[0].first)) + if (is_rebasevector_celem_node(branch(0))) { - rbvec_node_ptr_ = static_cast*>(binary_node::branch_[0].first); + rbvec_node_ptr_ = static_cast*>(branch(0)); } } @@ -10486,11 +10498,10 @@ namespace exprtk { if (rbvec_node_ptr_) { - assert(binary_node::branch_[1].first); + assert(branch(1)); T& result = rbvec_node_ptr_->ref(); - - result = binary_node::branch_[1].first->value(); + result = branch(1)->value(); return result; } @@ -10514,15 +10525,17 @@ namespace exprtk typedef vector_node* vector_node_ptr; typedef vec_data_store vds_t; + using binary_node::branch; + assignment_vec_node(const operator_type& opr, expression_ptr branch0, expression_ptr branch1) : binary_node(opr, branch0, branch1) , vec_node_ptr_(0) { - if (is_vector_node(binary_node::branch_[0].first)) + if (is_vector_node(branch(0))) { - vec_node_ptr_ = static_cast*>(binary_node::branch_[0].first); + vec_node_ptr_ = static_cast*>(branch(0)); vds() = vec_node_ptr_->vds(); } } @@ -10531,9 +10544,9 @@ namespace exprtk { if (vec_node_ptr_) { - assert(binary_node::branch_[1].first); + assert(branch(1)); - const T v = binary_node::branch_[1].first->value(); + const T v = branch(1)->value(); T* vec = vds().data(); @@ -10634,6 +10647,8 @@ namespace exprtk typedef vector_node* vector_node_ptr; typedef vec_data_store vds_t; + using binary_node::branch; + assignment_vecvec_node(const operator_type& opr, expression_ptr branch0, expression_ptr branch1) @@ -10643,22 +10658,22 @@ namespace exprtk , initialised_(false) , src_is_ivec_(false) { - if (is_vector_node(binary_node::branch_[0].first)) + if (is_vector_node(branch(0))) { - vec0_node_ptr_ = static_cast*>(binary_node::branch_[0].first); + vec0_node_ptr_ = static_cast*>(branch(0)); vds() = vec0_node_ptr_->vds(); } - if (is_vector_node(binary_node::branch_[1].first)) + if (is_vector_node(branch(1))) { - vec1_node_ptr_ = static_cast*>(binary_node::branch_[1].first); + vec1_node_ptr_ = static_cast*>(branch(1)); vds_t::match_sizes(vds(),vec1_node_ptr_->vds()); } - else if (is_ivector_node(binary_node::branch_[1].first)) + else if (is_ivector_node(branch(1))) { vector_interface* vi = reinterpret_cast*>(0); - if (0 != (vi = dynamic_cast*>(binary_node::branch_[1].first))) + if (0 != (vi = dynamic_cast*>(branch(1)))) { vec1_node_ptr_ = vi->vec(); @@ -10681,9 +10696,9 @@ namespace exprtk { if (initialised_) { - assert(binary_node::branch_[1].first); + assert(branch(1)); - binary_node::branch_[1].first->value(); + branch(1)->value(); if (src_is_ivec_) return vec0_node_ptr_->value(); @@ -10787,6 +10802,7 @@ namespace exprtk public: typedef expression_node* expression_ptr; + using binary_node::branch; assignment_op_node(const operator_type& opr, expression_ptr branch0, @@ -10794,9 +10810,9 @@ namespace exprtk : binary_node(opr, branch0, branch1) , var_node_ptr_(0) { - if (is_variable_node(binary_node::branch_[0].first)) + if (is_variable_node(branch(0))) { - var_node_ptr_ = static_cast*>(binary_node::branch_[0].first); + var_node_ptr_ = static_cast*>(branch(0)); } } @@ -10804,10 +10820,10 @@ namespace exprtk { if (var_node_ptr_) { - assert(binary_node::branch_[1].first); + assert(branch(1)); T& v = var_node_ptr_->ref(); - v = Operation::process(v,binary_node::branch_[1].first->value()); + v = Operation::process(v,branch(1)->value()); return v; } @@ -10826,6 +10842,7 @@ namespace exprtk public: typedef expression_node* expression_ptr; + using binary_node::branch; assignment_vec_elem_op_node(const operator_type& opr, expression_ptr branch0, @@ -10833,9 +10850,9 @@ namespace exprtk : binary_node(opr, branch0, branch1) , vec_node_ptr_(0) { - if (is_vector_elem_node(binary_node::branch_[0].first)) + if (is_vector_elem_node(branch(0))) { - vec_node_ptr_ = static_cast*>(binary_node::branch_[0].first); + vec_node_ptr_ = static_cast*>(branch(0)); } } @@ -10843,10 +10860,10 @@ namespace exprtk { if (vec_node_ptr_) { - assert(binary_node::branch_[1].first); + assert(branch(1)); T& v = vec_node_ptr_->ref(); - v = Operation::process(v,binary_node::branch_[1].first->value()); + v = Operation::process(v,branch(1)->value()); return v; } @@ -10865,6 +10882,7 @@ namespace exprtk public: typedef expression_node* expression_ptr; + using binary_node::branch; assignment_rebasevec_elem_op_node(const operator_type& opr, expression_ptr branch0, @@ -10872,9 +10890,9 @@ namespace exprtk : binary_node(opr, branch0, branch1) , rbvec_node_ptr_(0) { - if (is_rebasevector_elem_node(binary_node::branch_[0].first)) + if (is_rebasevector_elem_node(branch(0))) { - rbvec_node_ptr_ = static_cast*>(binary_node::branch_[0].first); + rbvec_node_ptr_ = static_cast*>(branch(0)); } } @@ -10882,10 +10900,10 @@ namespace exprtk { if (rbvec_node_ptr_) { - assert(binary_node::branch_[1].first); + assert(branch(1)); T& v = rbvec_node_ptr_->ref(); - v = Operation::process(v,binary_node::branch_[1].first->value()); + v = Operation::process(v,branch(1)->value()); return v; } @@ -10904,6 +10922,7 @@ namespace exprtk public: typedef expression_node* expression_ptr; + using binary_node::branch; assignment_rebasevec_celem_op_node(const operator_type& opr, expression_ptr branch0, @@ -10911,9 +10930,9 @@ namespace exprtk : binary_node(opr, branch0, branch1) , rbvec_node_ptr_(0) { - if (is_rebasevector_celem_node(binary_node::branch_[0].first)) + if (is_rebasevector_celem_node(branch(0))) { - rbvec_node_ptr_ = static_cast*>(binary_node::branch_[0].first); + rbvec_node_ptr_ = static_cast*>(branch(0)); } } @@ -10921,10 +10940,10 @@ namespace exprtk { if (rbvec_node_ptr_) { - assert(binary_node::branch_[1].first); + assert(branch(1)); T& v = rbvec_node_ptr_->ref(); - v = Operation::process(v,binary_node::branch_[1].first->value()); + v = Operation::process(v,branch(1)->value()); return v; } @@ -10948,15 +10967,17 @@ namespace exprtk typedef vector_node* vector_node_ptr; typedef vec_data_store vds_t; + using binary_node::branch; + assignment_vec_op_node(const operator_type& opr, expression_ptr branch0, expression_ptr branch1) : binary_node(opr, branch0, branch1) , vec_node_ptr_(0) { - if (is_vector_node(binary_node::branch_[0].first)) + if (is_vector_node(branch(0))) { - vec_node_ptr_ = static_cast*>(binary_node::branch_[0].first); + vec_node_ptr_ = static_cast*>(branch(0)); vds() = vec_node_ptr_->vds(); } } @@ -10965,9 +10986,9 @@ namespace exprtk { if (vec_node_ptr_) { - assert(binary_node::branch_[1].first); + assert(branch(1)); - const T v = binary_node::branch_[1].first->value(); + const T v = branch(1)->value(); T* vec = vds().data(); @@ -11073,6 +11094,8 @@ namespace exprtk typedef vector_node* vector_node_ptr; typedef vec_data_store vds_t; + using binary_node::branch; + assignment_vecvec_op_node(const operator_type& opr, expression_ptr branch0, expression_ptr branch1) @@ -11081,22 +11104,22 @@ namespace exprtk , vec1_node_ptr_(0) , initialised_(false) { - if (is_vector_node(binary_node::branch_[0].first)) + if (is_vector_node(branch(0))) { - vec0_node_ptr_ = static_cast*>(binary_node::branch_[0].first); + vec0_node_ptr_ = static_cast*>(branch(0)); vds() = vec0_node_ptr_->vds(); } - if (is_vector_node(binary_node::branch_[1].first)) + if (is_vector_node(branch(1))) { - vec1_node_ptr_ = static_cast*>(binary_node::branch_[1].first); + vec1_node_ptr_ = static_cast*>(branch(1)); vec1_node_ptr_->vds() = vds(); } - else if (is_ivector_node(binary_node::branch_[1].first)) + else if (is_ivector_node(branch(1))) { vector_interface* vi = reinterpret_cast*>(0); - if (0 != (vi = dynamic_cast*>(binary_node::branch_[1].first))) + if (0 != (vi = dynamic_cast*>(branch(1)))) { vec1_node_ptr_ = vi->vec(); vec1_node_ptr_->vds() = vds(); @@ -11114,11 +11137,11 @@ namespace exprtk { if (initialised_) { - assert(binary_node::branch_[0].first); - assert(binary_node::branch_[1].first); + assert(branch(0)); + assert(branch(1)); - binary_node::branch_[0].first->value(); - binary_node::branch_[1].first->value(); + branch(0)->value(); + branch(1)->value(); T* vec0 = vec0_node_ptr_->vds().data(); const T* vec1 = vec1_node_ptr_->vds().data(); @@ -11231,6 +11254,8 @@ namespace exprtk typedef vector_holder* vector_holder_ptr; typedef vec_data_store vds_t; + using binary_node::branch; + vec_binop_vecvec_node(const operator_type& opr, expression_ptr branch0, expression_ptr branch1) @@ -11244,30 +11269,30 @@ namespace exprtk bool v0_is_ivec = false; bool v1_is_ivec = false; - if (is_vector_node(binary_node::branch_[0].first)) + if (is_vector_node(branch(0))) { - vec0_node_ptr_ = static_cast(binary_node::branch_[0].first); + vec0_node_ptr_ = static_cast(branch(0)); } - else if (is_ivector_node(binary_node::branch_[0].first)) + else if (is_ivector_node(branch(0))) { vector_interface* vi = reinterpret_cast*>(0); - if (0 != (vi = dynamic_cast*>(binary_node::branch_[0].first))) + if (0 != (vi = dynamic_cast*>(branch(0)))) { vec0_node_ptr_ = vi->vec(); v0_is_ivec = true; } } - if (is_vector_node(binary_node::branch_[1].first)) + if (is_vector_node(branch(1))) { - vec1_node_ptr_ = static_cast(binary_node::branch_[1].first); + vec1_node_ptr_ = static_cast(branch(1)); } - else if (is_ivector_node(binary_node::branch_[1].first)) + else if (is_ivector_node(branch(1))) { vector_interface* vi = reinterpret_cast*>(0); - if (0 != (vi = dynamic_cast*>(binary_node::branch_[1].first))) + if (0 != (vi = dynamic_cast*>(branch(1)))) { vec1_node_ptr_ = vi->vec(); v1_is_ivec = true; @@ -11305,11 +11330,11 @@ namespace exprtk { if (initialised_) { - assert(binary_node::branch_[0].first); - assert(binary_node::branch_[1].first); + assert(branch(0)); + assert(branch(1)); - binary_node::branch_[0].first->value(); - binary_node::branch_[1].first->value(); + branch(0)->value(); + branch(1)->value(); const T* vec0 = vec0_node_ptr_->vds().data(); const T* vec1 = vec1_node_ptr_->vds().data(); @@ -11421,6 +11446,8 @@ namespace exprtk typedef vector_holder* vector_holder_ptr; typedef vec_data_store vds_t; + using binary_node::branch; + vec_binop_vecval_node(const operator_type& opr, expression_ptr branch0, expression_ptr branch1) @@ -11431,15 +11458,15 @@ namespace exprtk { bool v0_is_ivec = false; - if (is_vector_node(binary_node::branch_[0].first)) + if (is_vector_node(branch(0))) { - vec0_node_ptr_ = static_cast(binary_node::branch_[0].first); + vec0_node_ptr_ = static_cast(branch(0)); } - else if (is_ivector_node(binary_node::branch_[0].first)) + else if (is_ivector_node(branch(0))) { vector_interface* vi = reinterpret_cast*>(0); - if (0 != (vi = dynamic_cast*>(binary_node::branch_[0].first))) + if (0 != (vi = dynamic_cast*>(branch(0)))) { vec0_node_ptr_ = vi->vec(); v0_is_ivec = true; @@ -11468,11 +11495,11 @@ namespace exprtk { if (vec0_node_ptr_) { - assert(binary_node::branch_[0].first); - assert(binary_node::branch_[1].first); + assert(branch(0)); + assert(branch(1)); - binary_node::branch_[0].first->value(); - const T v = binary_node::branch_[1].first->value(); + branch(0)->value(); + const T v = branch(1)->value(); const T* vec0 = vec0_node_ptr_->vds().data(); T* vec1 = vds().data(); @@ -11580,6 +11607,8 @@ namespace exprtk typedef vector_holder* vector_holder_ptr; typedef vec_data_store vds_t; + using binary_node::branch; + vec_binop_valvec_node(const operator_type& opr, expression_ptr branch0, expression_ptr branch1) @@ -11590,15 +11619,15 @@ namespace exprtk { bool v1_is_ivec = false; - if (is_vector_node(binary_node::branch_[1].first)) + if (is_vector_node(branch(1))) { - vec1_node_ptr_ = static_cast(binary_node::branch_[1].first); + vec1_node_ptr_ = static_cast(branch(1)); } - else if (is_ivector_node(binary_node::branch_[1].first)) + else if (is_ivector_node(branch(1))) { vector_interface* vi = reinterpret_cast*>(0); - if (0 != (vi = dynamic_cast*>(binary_node::branch_[1].first))) + if (0 != (vi = dynamic_cast*>(branch(1)))) { vec1_node_ptr_ = vi->vec(); v1_is_ivec = true; @@ -11627,11 +11656,11 @@ namespace exprtk { if (vec1_node_ptr_) { - assert(binary_node::branch_[0].first); - assert(binary_node::branch_[1].first); + assert(branch(0)); + assert(branch(1)); - const T v = binary_node::branch_[0].first->value(); - binary_node::branch_[1].first->value(); + const T v = branch(0)->value(); + branch(1)->value(); T* vec0 = vds().data(); const T* vec1 = vec1_node_ptr_->vds().data(); @@ -11739,6 +11768,8 @@ namespace exprtk typedef vector_holder* vector_holder_ptr; typedef vec_data_store vds_t; + using expression_node::branch; + unary_vector_node(const operator_type& opr, expression_ptr branch0) : unary_node(opr, branch0) , vec0_node_ptr_(0) @@ -11747,15 +11778,15 @@ namespace exprtk { bool vec0_is_ivec = false; - if (is_vector_node(unary_node::branch_.first)) + if (is_vector_node(branch())) { - vec0_node_ptr_ = static_cast(unary_node::branch_.first); + vec0_node_ptr_ = static_cast(branch()); } - else if (is_ivector_node(unary_node::branch_.first)) + else if (is_ivector_node(branch())) { vector_interface* vi = reinterpret_cast*>(0); - if (0 != (vi = dynamic_cast*>(unary_node::branch_.first))) + if (0 != (vi = dynamic_cast*>(branch()))) { vec0_node_ptr_ = vi->vec(); vec0_is_ivec = true; @@ -11782,9 +11813,9 @@ namespace exprtk inline T value() const exprtk_override { - assert(unary_node::branch_.first); + assert(branch()); - unary_node::branch_.first->value(); + branch()->value(); if (vec0_node_ptr_) { @@ -12048,6 +12079,7 @@ namespace exprtk public: typedef expression_node* expression_ptr; + using binary_node::branch; scand_node(const operator_type& opr, expression_ptr branch0, @@ -12057,14 +12089,14 @@ namespace exprtk inline T value() const exprtk_override { - assert(binary_node::branch_[0].first); - assert(binary_node::branch_[1].first); + assert(branch(0)); + assert(branch(1)); return ( std::not_equal_to() - (T(0),binary_node::branch_[0].first->value()) && + (T(0),branch(0)->value()) && std::not_equal_to() - (T(0),binary_node::branch_[1].first->value()) + (T(0),branch(1)->value()) ) ? T(1) : T(0); } }; @@ -12075,6 +12107,7 @@ namespace exprtk public: typedef expression_node* expression_ptr; + using binary_node::branch; scor_node(const operator_type& opr, expression_ptr branch0, @@ -12084,14 +12117,14 @@ namespace exprtk inline T value() const exprtk_override { - assert(binary_node::branch_[0].first); - assert(binary_node::branch_[1].first); + assert(branch(0)); + assert(branch(1)); return ( std::not_equal_to() - (T(0),binary_node::branch_[0].first->value()) || + (T(0),branch(0)->value()) || std::not_equal_to() - (T(0),binary_node::branch_[1].first->value()) + (T(0),branch(1)->value()) ) ? T(1) : T(0); } }; @@ -13518,7 +13551,7 @@ namespace exprtk case 3 : return process_3(arg_list); case 4 : return process_4(arg_list); case 5 : return process_5(arg_list); - default : return vararg_add_op::process(arg_list) / arg_list.size(); + default : return vararg_add_op::process(arg_list) / T(arg_list.size()); } } @@ -14177,8 +14210,7 @@ namespace exprtk static inline T process(const ivector_ptr v) { - const std::size_t vec_size = v->vec()->vds().size(); - + const T vec_size = T(v->vec()->vds().size()); return vec_add_op::process(v) / vec_size; } }; @@ -14959,7 +14991,7 @@ namespace exprtk private: T0oT1oT2(const node_type&) exprtk_delete; - node_type& operator=(const node_type&) { return (*this); } + node_type& operator=(const node_type&) exprtk_delete; T0 t0_; T1 t1_; @@ -15056,7 +15088,7 @@ namespace exprtk private: T0oT1oT2oT3(const node_type&) exprtk_delete; - node_type& operator=(const node_type&) { return (*this); } + node_type& operator=(const node_type&) exprtk_delete; T0 t0_; T1 t1_; @@ -15141,7 +15173,7 @@ namespace exprtk private: T0oT1oT2_sf3(const node_type&) exprtk_delete; - node_type& operator=(const node_type&) { return (*this); } + node_type& operator=(const node_type&) exprtk_delete; T0 t0_; T1 t1_; @@ -15168,8 +15200,6 @@ namespace exprtk { public: - typedef typename details::functor_t functor_t; - typedef typename functor_t::tfunc_t tfunc_t; typedef T value_type; typedef T0oT1oT2_sf3ext node_type; @@ -15231,7 +15261,7 @@ namespace exprtk private: T0oT1oT2_sf3ext(const node_type&) exprtk_delete; - node_type& operator=(const node_type&) { return (*this); } + node_type& operator=(const node_type&) exprtk_delete; T0 t0_; T1 t1_; @@ -15332,7 +15362,7 @@ namespace exprtk private: T0oT1oT2oT3_sf4(const node_type&) exprtk_delete; - node_type& operator=(const node_type&) { return (*this); } + node_type& operator=(const node_type&) exprtk_delete; T0 t0_; T1 t1_; @@ -15346,8 +15376,6 @@ namespace exprtk { public: - typedef typename details::functor_t functor_t; - typedef typename functor_t::tfunc_t tfunc_t; typedef T value_type; typedef T0oT1oT2oT3_sf4ext node_type; @@ -15410,7 +15438,7 @@ namespace exprtk private: T0oT1oT2oT3_sf4ext(const node_type&) exprtk_delete; - node_type& operator=(const node_type&) { return (*this); } + node_type& operator=(const node_type&) exprtk_delete; T0 t0_; T1 t1_; @@ -16111,6 +16139,8 @@ namespace exprtk typedef range_interface irange_t; typedef irange_t* irange_ptr; + using binary_node::branch; + str_sogens_node(const operator_type& opr, expression_ptr branch0, expression_ptr branch1) @@ -16120,14 +16150,14 @@ namespace exprtk , str0_range_ptr_(0) , str1_range_ptr_(0) { - if (is_generally_string_node(binary_node::branch_[0].first)) + if (is_generally_string_node(branch(0))) { - str0_base_ptr_ = dynamic_cast(binary_node::branch_[0].first); + str0_base_ptr_ = dynamic_cast(branch(0)); if (0 == str0_base_ptr_) return; - irange_ptr range = dynamic_cast(binary_node::branch_[0].first); + irange_ptr range = dynamic_cast(branch(0)); if (0 == range) return; @@ -16135,14 +16165,14 @@ namespace exprtk str0_range_ptr_ = &(range->range_ref()); } - if (is_generally_string_node(binary_node::branch_[1].first)) + if (is_generally_string_node(branch(1))) { - str1_base_ptr_ = dynamic_cast(binary_node::branch_[1].first); + str1_base_ptr_ = dynamic_cast(branch(1)); if (0 == str1_base_ptr_) return; - irange_ptr range = dynamic_cast(binary_node::branch_[1].first); + irange_ptr range = dynamic_cast(branch(1)); if (0 == range) return; @@ -16160,8 +16190,8 @@ namespace exprtk str1_range_ptr_ ) { - binary_node::branch_[0].first->value(); - binary_node::branch_[1].first->value(); + branch(0)->value(); + branch(1)->value(); std::size_t str0_r0 = 0; std::size_t str0_r1 = 0; @@ -17281,22 +17311,29 @@ namespace exprtk { public: - typedef T (*ff00_functor)(); - typedef T (*ff01_functor)(T); - typedef T (*ff02_functor)(T, T); - typedef T (*ff03_functor)(T, T, T); - typedef T (*ff04_functor)(T, T, T, T); - typedef T (*ff05_functor)(T, T, T, T, T); - typedef T (*ff06_functor)(T, T, T, T, T, T); - typedef T (*ff07_functor)(T, T, T, T, T, T, T); - typedef T (*ff08_functor)(T, T, T, T, T, T, T, T); - typedef T (*ff09_functor)(T, T, T, T, T, T, T, T, T); - typedef T (*ff10_functor)(T, T, T, T, T, T, T, T, T, T); - typedef T (*ff11_functor)(T, T, T, T, T, T, T, T, T, T, T); - typedef T (*ff12_functor)(T, T, T, T, T, T, T, T, T, T, T, T); - typedef T (*ff13_functor)(T, T, T, T, T, T, T, T, T, T, T, T, T); - typedef T (*ff14_functor)(T, T, T, T, T, T, T, T, T, T, T, T, T, T); - typedef T (*ff15_functor)(T, T, T, T, T, T, T, T, T, T, T, T, T, T, T); + enum symtab_mutability_type + { + e_unknown = 0, + e_mutable = 1, + e_immutable = 2 + }; + + typedef T (*ff00_functor)(); + typedef T (*ff01_functor)(T); + typedef T (*ff02_functor)(T, T); + typedef T (*ff03_functor)(T, T, T); + typedef T (*ff04_functor)(T, T, T, T); + typedef T (*ff05_functor)(T, T, T, T, T); + typedef T (*ff06_functor)(T, T, T, T, T, T); + typedef T (*ff07_functor)(T, T, T, T, T, T, T); + typedef T (*ff08_functor)(T, T, T, T, T, T, T, T); + typedef T (*ff09_functor)(T, T, T, T, T, T, T, T, T); + typedef T (*ff10_functor)(T, T, T, T, T, T, T, T, T, T); + typedef T (*ff11_functor)(T, T, T, T, T, T, T, T, T, T, T); + typedef T (*ff12_functor)(T, T, T, T, T, T, T, T, T, T, T, T); + typedef T (*ff13_functor)(T, T, T, T, T, T, T, T, T, T, T, T, T); + typedef T (*ff14_functor)(T, T, T, T, T, T, T, T, T, T, T, T, T, T); + typedef T (*ff15_functor)(T, T, T, T, T, T, T, T, T, T, T, T, T, T, T); protected: @@ -17938,11 +17975,13 @@ namespace exprtk control_block() : ref_count(1) , data_(st_data::create()) + , mutability_(e_mutable) {} explicit control_block(st_data* data) : ref_count(1) , data_(data) + , mutability_(e_mutable) {} ~control_block() @@ -17978,21 +18017,29 @@ namespace exprtk } } + void set_mutability(const symtab_mutability_type mutability) + { + mutability_ = mutability; + } + std::size_t ref_count; st_data* data_; + symtab_mutability_type mutability_; }; public: - symbol_table() + symbol_table(const symtab_mutability_type mutability = e_mutable) : control_block_(control_block::create()) { + control_block_->set_mutability(mutability); clear(); } ~symbol_table() { - control_block::destroy(control_block_,this); + exprtk::details::dump_ptr("~symbol_table", this); + control_block::destroy(control_block_, this); } symbol_table(const symbol_table& st) @@ -18019,6 +18066,11 @@ namespace exprtk return (this == &st) || (control_block_ == st.control_block_); } + inline symtab_mutability_type mutability() const + { + return valid() ? control_block_->mutability_ : e_unknown; + } + inline void clear_variables(const bool delete_node = true) { local_data().variable_store.clear(delete_node); @@ -19092,6 +19144,7 @@ namespace exprtk inline expression& release() { + exprtk::details::dump_ptr("expression::release", this); control_block::destroy(control_block_); return (*this); @@ -19127,6 +19180,14 @@ namespace exprtk inline void register_symbol_table(symbol_table& st) { + for (std::size_t i = 0; i < symbol_table_list_.size(); ++i) + { + if (&st == &symbol_table_list_[i]) + { + return; + } + } + symbol_table_list_.push_back(st); } @@ -19894,6 +19955,130 @@ namespace exprtk parser_t& parser_; }; + template + struct halfopen_range_policy + { + static inline bool is_within(const T_& v, const T_& begin, const T_& end) + { + assert(begin <= end); + return (begin <= v) && (v < end); + } + + static inline bool is_less(const T_& v, const T_& begin) + { + return (v < begin); + } + + static inline bool is_greater(const T_& v, const T_& end) + { + return (end <= v); + } + + static inline bool end_inclusive() + { + return false; + } + }; + + template + struct closed_range_policy + { + static inline bool is_within(const T_& v, const T_& begin, const T_& end) + { + assert(begin <= end); + return (begin <= v) && (v <= end); + } + + static inline bool is_less(const T_& v, const T_& begin) + { + return (v < begin); + } + + static inline bool is_greater(const T_& v, const T_& end) + { + return (end < v); + } + + static inline bool end_inclusive() + { + return true; + } + }; + + template > + class interval_container_t + { + public: + + typedef IntervalPointType interval_point_t; + typedef std::pair interval_t; + typedef std::map interval_map_t; + typedef typename interval_map_t::const_iterator interval_map_citr_t; + + std::size_t size() const + { + return interval_map_.size(); + } + + void reset() + { + interval_map_.clear(); + } + + bool in_interval(const interval_point_t point, interval_t& interval) const + { + interval_map_citr_t itr = RangePolicy::end_inclusive() ? + interval_map_.lower_bound(point): + interval_map_.upper_bound(point); + + for (; itr != interval_map_.end(); ++itr) + { + const interval_point_t& begin = itr->second.first; + const interval_point_t& end = itr->second.second; + + if (RangePolicy::is_within(point, begin, end)) + { + interval = interval_t(begin,end); + return true; + } + else if (RangePolicy::is_greater(point, end)) + { + break; + } + } + + return false; + } + + bool in_interval(const interval_point_t point) const + { + interval_t interval; + return in_interval(point,interval); + } + + bool add_interval(const interval_point_t begin, const interval_point_t end) + { + if ((end <= begin) || in_interval(begin) || in_interval(end)) + { + return false; + } + + interval_map_[end] = std::make_pair(begin, end); + + return true; + } + + bool add_interval(const interval_t interval) + { + return add_interval(interval.first, interval.second); + } + + private: + + interval_map_t interval_map_; + }; + class stack_limit_handler { public: @@ -19948,6 +20133,41 @@ namespace exprtk typedef typename symbol_table_t::vararg_function_ptr vararg_function_ptr; typedef typename symbol_table_t::generic_function_ptr generic_function_ptr; + struct variable_context + { + variable_context() + : symbol_table(0) + , variable(0) + {} + + const symbol_table_t* symbol_table; + variable_ptr variable; + }; + + struct vector_context + { + vector_context() + : symbol_table(0) + , vector_holder(0) + {} + + const symbol_table_t* symbol_table; + vector_holder_ptr vector_holder; + }; + + #ifndef exprtk_disable_string_capabilities + struct string_context + { + string_context() + : symbol_table(0) + , str_var(0) + {} + + const symbol_table_t* symbol_table; + stringvar_ptr str_var; + }; + #endif + inline bool empty() const { return symtab_list_.empty(); @@ -19988,6 +20208,31 @@ namespace exprtk return false; } + inline variable_context get_variable_context(const std::string& variable_name) const + { + variable_context result; + if (!valid_symbol(variable_name)) + return result; + + for (std::size_t i = 0; i < symtab_list_.size(); ++i) + { + if (!symtab_list_[i].valid()) + { + continue; + } + + result.variable = local_data(i) + .variable_store.get(variable_name); + if (result.variable) + { + result.symbol_table = &symtab_list_[i]; + break; + } + } + + return result; + } + inline variable_ptr get_variable(const std::string& variable_name) const { if (!valid_symbol(variable_name)) @@ -20028,6 +20273,32 @@ namespace exprtk } #ifndef exprtk_disable_string_capabilities + inline string_context get_string_context(const std::string& string_name) const + { + string_context result; + + if (!valid_symbol(string_name)) + return result; + + for (std::size_t i = 0; i < symtab_list_.size(); ++i) + { + if (!symtab_list_[i].valid()) + { + continue; + } + + result.str_var = local_data(i).stringvar_store.get(string_name); + + if (result.str_var) + { + result.symbol_table = &symtab_list_[i]; + break; + } + } + + return result; + } + inline stringvar_ptr get_stringvar(const std::string& string_name) const { if (!valid_symbol(string_name)) @@ -20155,6 +20426,31 @@ namespace exprtk return result; } + inline vector_context get_vector_context(const std::string& vector_name) const + { + vector_context result; + if (!valid_symbol(vector_name)) + return result; + + for (std::size_t i = 0; i < symtab_list_.size(); ++i) + { + if (!symtab_list_[i].valid()) + { + continue; + } + + result.vector_holder = local_data(i).vector_store.get(vector_name); + + if (result.vector_holder) + { + result.symbol_table = &symtab_list_[i]; + break; + } + } + + return result; + } + inline vector_holder_ptr get_vector(const std::string& vector_name) const { if (!valid_symbol(vector_name)) @@ -21540,7 +21836,7 @@ namespace exprtk if (helper_assembly_.error_token_scanner) { lexer::helper::bracket_checker* bracket_checker_ptr = 0; - lexer::helper::numeric_checker* numeric_checker_ptr = 0; + lexer::helper::numeric_checker* numeric_checker_ptr = 0; lexer::helper::sequence_validator* sequence_validator_ptr = 0; lexer::helper::sequence_validator_3tokens* sequence_validator3_ptr = 0; @@ -21552,7 +21848,7 @@ namespace exprtk "ERR005 - Mismatched brackets: '" + bracket_checker_ptr->error_token().value + "'", exprtk_error_location)); } - else if (0 != (numeric_checker_ptr = dynamic_cast(helper_assembly_.error_token_scanner))) + else if (0 != (numeric_checker_ptr = dynamic_cast*>(helper_assembly_.error_token_scanner))) { for (std::size_t i = 0; i < numeric_checker_ptr->error_count(); ++i) { @@ -23204,6 +23500,12 @@ namespace exprtk return parse_base_operation(); } + void handle_brkcnt_scope_exit() + { + assert(!brkcnt_list_.empty()); + brkcnt_list_.pop_front(); + } + inline expression_node_ptr parse_while_loop() { // Parse: [while][(][test expr][)][{][expression][}] @@ -23252,7 +23554,7 @@ namespace exprtk { scoped_inc_dec sid(state_.parsing_loop_stmt_count); - if (0 == (branch = parse_multi_sequence("while-loop"))) + if (0 == (branch = parse_multi_sequence("while-loop", true))) { set_error( make_error(parser_error::e_syntax, @@ -23274,18 +23576,18 @@ namespace exprtk } } + handle_brkcnt_scope_exit(); + if (!result) { free_node(node_allocator_, branch ); free_node(node_allocator_, condition ); free_node(node_allocator_, result_node); - brkcnt_list_.pop_front(); - return error_node(); } - else - return result_node; + + return result_node; } inline expression_node_ptr parse_repeat_until_loop() @@ -23364,8 +23666,6 @@ namespace exprtk if (sdd.delete_ptr) { - brkcnt_list_.pop_front(); - set_error( make_error(parser_error::e_syntax, current_token(), @@ -23378,8 +23678,6 @@ namespace exprtk if (!token_is(token_t::e_lbracket)) { - brkcnt_list_.pop_front(); - set_error( make_error(parser_error::e_syntax, current_token(), @@ -23387,13 +23685,10 @@ namespace exprtk exprtk_error_location)); free_node(node_allocator_,branch); - return error_node(); } else if (0 == (condition = parse_expression())) { - brkcnt_list_.pop_front(); - set_error( make_error(parser_error::e_syntax, current_token(), @@ -23401,7 +23696,6 @@ namespace exprtk exprtk_error_location)); free_node(node_allocator_,branch); - return error_node(); } else if (!token_is(token_t::e_rbracket)) @@ -23415,8 +23709,6 @@ namespace exprtk free_node(node_allocator_, branch ); free_node(node_allocator_, condition); - brkcnt_list_.pop_front(); - return error_node(); } @@ -23435,15 +23727,12 @@ namespace exprtk free_node(node_allocator_,condition); - brkcnt_list_.pop_front(); - return error_node(); } - else - { - brkcnt_list_.pop_front(); - return result; - } + + handle_brkcnt_scope_exit(); + + return result; } inline expression_node_ptr parse_for_loop() @@ -23635,7 +23924,7 @@ namespace exprtk scoped_inc_dec sid(state_.parsing_loop_stmt_count); - if (0 == (loop_body = parse_multi_sequence("for-loop"))) + if (0 == (loop_body = parse_multi_sequence("for-loop", true))) { set_error( make_error(parser_error::e_syntax, @@ -23658,26 +23947,18 @@ namespace exprtk free_node(node_allocator_, condition ); free_node(node_allocator_, incrementor); free_node(node_allocator_, loop_body ); - - if (!brkcnt_list_.empty()) - { - brkcnt_list_.pop_front(); - } - return error_node(); } - else - { - expression_node_ptr result_node = - expression_generator_.for_loop(initialiser, - condition, - incrementor, - loop_body, - brkcnt_list_.front()); - brkcnt_list_.pop_front(); - return result_node; - } + expression_node_ptr result_node = + expression_generator_.for_loop(initialiser, + condition, + incrementor, + loop_body, + brkcnt_list_.front()); + handle_brkcnt_scope_exit(); + + return result_node; } inline expression_node_ptr parse_switch_statement() @@ -23987,7 +24268,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR096 - Unsupported vararg function: " + symbol, + "ERR096 - Unsupported built-in vararg function: " + symbol, exprtk_error_location)); return error_node(); @@ -24010,6 +24291,18 @@ namespace exprtk return error_node(); } + if (token_is(token_t::e_rbracket)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR098 - vararg function: " + symbol + + " requires at least one input parameter", + exprtk_error_location)); + + return error_node(); + } + for ( ; ; ) { expression_node_ptr arg = parse_expression(); @@ -24026,7 +24319,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR098 - Expected ',' for call to vararg function: " + symbol, + "ERR099 - Expected ',' for call to vararg function: " + symbol, exprtk_error_location)); return error_node(); @@ -24047,7 +24340,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR099 - Expected '[' as start of string range definition", + "ERR100 - Expected '[' as start of string range definition", exprtk_error_location)); free_node(node_allocator_,expression); @@ -24075,7 +24368,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR100 - Failed to generate string range node", + "ERR101 - Failed to generate string range node", exprtk_error_location)); free_node(node_allocator_,expression); @@ -24195,15 +24488,18 @@ namespace exprtk return expression_generator_.vararg_function(details::e_multi,expression_list); } - inline expression_node_ptr parse_multi_sequence(const std::string& source = "") + inline expression_node_ptr parse_multi_sequence(const std::string& source = "", + const bool enforce_crlbrackets = false) { + token_t::token_type open_bracket = token_t::e_lcrlbracket; token_t::token_type close_bracket = token_t::e_rcrlbracket; token_t::token_type seperator = token_t::e_eof; - if (!token_is(token_t::e_lcrlbracket)) + if (!token_is(open_bracket)) { - if (token_is(token_t::e_lbracket)) + if (!enforce_crlbrackets && token_is(token_t::e_lbracket)) { + open_bracket = token_t::e_lbracket; close_bracket = token_t::e_rbracket; seperator = token_t::e_comma; } @@ -24212,14 +24508,14 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR101 - Expected '" + token_t::to_str(close_bracket) + "' for call to multi-sequence" + + "ERR102 - Expected '" + token_t::to_str(open_bracket) + "' for call to multi-sequence" + ((!source.empty()) ? std::string(" section of " + source): ""), exprtk_error_location)); return error_node(); } } - else if (token_is(token_t::e_rcrlbracket)) + else if (token_is(close_bracket)) { return node_allocator_.allocate >(); } @@ -24259,7 +24555,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR102 - Expected '" + details::to_str(seperator) + "' for call to multi-sequence section of " + source, + "ERR103 - Expected '" + details::to_str(seperator) + "' for call to multi-sequence section of " + source, exprtk_error_location)); return error_node(); @@ -24269,7 +24565,7 @@ namespace exprtk break; } - result = simplify(arg_list,side_effect_list,source.empty()); + result = simplify(arg_list, side_effect_list, source.empty()); sdd.delete_ptr = (0 == result); return result; @@ -24293,7 +24589,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR103 - Expected '[' for start of range", + "ERR104 - Expected '[' for start of range", exprtk_error_location)); return false; @@ -24314,7 +24610,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR104 - Failed parse begin section of range", + "ERR105 - Failed parse begin section of range", exprtk_error_location)); return false; @@ -24337,7 +24633,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR105 - Range lower bound less than zero! Constraint: r0 >= 0", + "ERR106 - Range lower bound less than zero! Constraint: r0 >= 0", exprtk_error_location)); return false; @@ -24354,7 +24650,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR106 - Expected ':' for break in range", + "ERR107 - Expected ':' for break in range", exprtk_error_location)); rp.free(); @@ -24377,7 +24673,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR107 - Failed parse end section of range", + "ERR108 - Failed parse end section of range", exprtk_error_location)); rp.free(); @@ -24402,7 +24698,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR108 - Range upper bound less than zero! Constraint: r1 >= 0", + "ERR109 - Range upper bound less than zero! Constraint: r1 >= 0", exprtk_error_location)); rp.free(); @@ -24421,7 +24717,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR109 - Expected ']' for start of range", + "ERR110 - Expected ']' for start of range", exprtk_error_location)); rp.free(); @@ -24449,7 +24745,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR110 - Invalid range, Constraint: r0 <= r1", + "ERR111 - Invalid range, Constraint: r0 <= r1", exprtk_error_location)); return false; @@ -24485,24 +24781,36 @@ namespace exprtk } else { - if (!symtab_store_.is_conststr_stringvar(symbol)) + typedef typename symtab_store::string_context str_ctxt_t; + str_ctxt_t str_ctx = symtab_store_.get_string_context(symbol); + + if ((0 == str_ctx.str_var) || !symtab_store_.is_conststr_stringvar(symbol)) { set_error( make_error(parser_error::e_syntax, current_token(), - "ERR111 - Unknown string symbol", + "ERR112 - Unknown string symbol", exprtk_error_location)); return error_node(); } - result = symtab_store_.get_stringvar(symbol); + assert(str_ctx.str_var != 0); + assert(str_ctx.symbol_table != 0); + + result = str_ctx.str_var; if (symtab_store_.is_constant_string(symbol)) { const_str_node = static_cast(result); result = expression_generator_(const_str_node->str()); } + else if (symbol_table_t::e_immutable == str_ctx.symbol_table->mutability()) + { + lodge_immutable_symbol( + current_token(), + make_memory_range(str_ctx.str_var->base(), str_ctx.str_var->size())); + } lodge_symbol(symbol, e_st_string); } @@ -24605,7 +24913,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR112 - Overflow in range for string: '" + const_str + "'[" + + "ERR113 - Overflow in range for string: '" + const_str + "'[" + (rp.n0_c.first ? details::to_str(static_cast(rp.n0_c.second)) : "?") + ":" + (rp.n1_c.first ? details::to_str(static_cast(rp.n1_c.second)) : "?") + "]", exprtk_error_location)); @@ -24646,20 +24954,37 @@ namespace exprtk (scope_element::e_vector != se.type) ) { - if (0 == (vec = symtab_store_.get_vector(symbol))) + typedef typename symtab_store::vector_context vec_ctxt_t; + vec_ctxt_t vec_ctx = symtab_store_.get_vector_context(symbol); + + if (0 == vec_ctx.vector_holder) { set_error( make_error(parser_error::e_syntax, current_token(), - "ERR113 - Symbol '" + symbol+ " not a vector", + "ERR114 - Symbol '" + symbol+ " not a vector", exprtk_error_location)); return error_node(); } + + assert(0 != vec_ctx.vector_holder); + assert(0 != vec_ctx.symbol_table ); + + vec = vec_ctx.vector_holder; + + if (symbol_table_t::e_immutable == vec_ctx.symbol_table->mutability()) + { + lodge_immutable_symbol( + current_token(), + make_memory_range(vec->data(), vec->size())); + } } else vec = se.vec_node; + assert(0 != vec); + expression_node_ptr index_expr = error_node(); next_token(); @@ -24677,7 +25002,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR114 - Failed to parse index for vector: '" + symbol + "'", + "ERR115 - Failed to parse index for vector: '" + symbol + "'", exprtk_error_location)); return error_node(); @@ -24687,7 +25012,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR115 - Expected ']' for index of vector: '" + symbol + "'", + "ERR116 - Expected ']' for index of vector: '" + symbol + "'", exprtk_error_location)); free_node(node_allocator_,index_expr); @@ -24706,7 +25031,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR116 - Index of " + details::to_str(index) + " out of range for " + "ERR117 - Index of " + details::to_str(index) + " out of range for " "vector '" + symbol + "' of size " + details::to_str(vec_size), exprtk_error_location)); @@ -24738,7 +25063,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR117 - Zero parameter call to vararg function: " + "ERR118 - Zero parameter call to vararg function: " + vararg_function_name + " not allowed", exprtk_error_location)); @@ -24763,7 +25088,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR118 - Expected ',' for call to vararg function: " + "ERR119 - Expected ',' for call to vararg function: " + vararg_function_name, exprtk_error_location)); @@ -24777,7 +25102,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR119 - Zero parameter call to vararg function: " + "ERR120 - Zero parameter call to vararg function: " + vararg_function_name + " not allowed", exprtk_error_location)); @@ -24789,7 +25114,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR120 - Invalid number of parameters to call to vararg function: " + "ERR121 - Invalid number of parameters to call to vararg function: " + vararg_function_name + ", require at least " + details::to_str(static_cast(vararg_function->min_num_args())) + " parameters", exprtk_error_location)); @@ -24801,7 +25126,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR121 - Invalid number of parameters to call to vararg function: " + "ERR122 - Invalid number of parameters to call to vararg function: " + vararg_function_name + ", require no more than " + details::to_str(static_cast(vararg_function->max_num_args())) + " parameters", exprtk_error_location)); @@ -24879,7 +25204,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, parser_.current_token(), - "ERR122 - Failed parameter type check for function '" + function_name_ + "', " + "ERR123 - Failed parameter type check for function '" + function_name_ + "', " "Expected '" + function_definition_list_[0].param_seq + "' call set: '" + param_seq + "'", exprtk_error_location)); @@ -24901,7 +25226,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, parser_.current_token(), - "ERR123 - Failed parameter type check for function '" + function_name_ + "', " + "ERR124 - Failed parameter type check for function '" + function_name_ + "', " "Best match: '" + function_definition_list_[max_diff_index].param_seq + "' call set: '" + param_seq + "'", exprtk_error_location)); @@ -25043,7 +25368,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, parser_.current_token(), - "ERR124 - Invalid parameter sequence of '" + param_seq_list[i] + + "ERR125 - Invalid parameter sequence of '" + param_seq_list[i] + "' for function: " + function_name_, exprtk_error_location)); return; @@ -25059,7 +25384,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, parser_.current_token(), - "ERR125 - Function '" + function_name_ + "' has a parameter sequence conflict between " + + "ERR126 - Function '" + function_name_ + "' has a parameter sequence conflict between " + "pseq_idx[" + details::to_str(seq_itr->second) + "] and" + "pseq_idx[" + details::to_str(i) + "] " + "param seq: " + param_seq_list[i], @@ -25091,14 +25416,18 @@ namespace exprtk std::string param_type_list; - type_checker tc((*this), function_name, function->parameter_sequence, type_checker::e_string); + type_checker tc( + (*this), + function_name, + function->parameter_sequence, + type_checker::e_string); if (tc.invalid()) { set_error( make_error(parser_error::e_syntax, current_token(), - "ERR126 - Type checker instantiation failure for generic function: " + function_name, + "ERR127 - Type checker instantiation failure for generic function: " + function_name, exprtk_error_location)); return error_node(); @@ -25116,7 +25445,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR127 - Zero parameter call to generic function: " + "ERR128 - Zero parameter call to generic function: " + function_name + " not allowed", exprtk_error_location)); @@ -25148,7 +25477,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR128 - Expected ',' for call to generic function: " + function_name, + "ERR129 - Expected ',' for call to generic function: " + function_name, exprtk_error_location)); return error_node(); @@ -25165,7 +25494,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR129 - Zero parameter call to generic function: " + "ERR130 - Zero parameter call to generic function: " + function_name + " not allowed", exprtk_error_location)); @@ -25182,7 +25511,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR130 - Invalid input parameter sequence for call to generic function: " + function_name, + "ERR131 - Invalid input parameter sequence for call to generic function: " + function_name, exprtk_error_location)); return error_node(); @@ -25220,7 +25549,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR131 - Zero parameter call to generic function: " + "ERR132 - Zero parameter call to generic function: " + function_name + " not allowed", exprtk_error_location)); @@ -25252,7 +25581,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR132 - Expected ',' for call to string function: " + function_name, + "ERR133 - Expected ',' for call to string function: " + function_name, exprtk_error_location)); return false; @@ -25299,7 +25628,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR133 - Invalid input parameter sequence for call to string function: " + function_name, + "ERR134 - Invalid input parameter sequence for call to string function: " + function_name, exprtk_error_location)); return error_node(); @@ -25351,7 +25680,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR134 - Invalid input parameter sequence for call to overloaded function: " + function_name, + "ERR135 - Invalid input parameter sequence for call to overloaded function: " + function_name, exprtk_error_location)); return error_node(); @@ -25382,7 +25711,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR135 - Invalid return type for call to overloaded function: " + function_name, + "ERR136 - Invalid return type for call to overloaded function: " + function_name, exprtk_error_location)); } @@ -25410,7 +25739,7 @@ namespace exprtk p.set_error( make_error(parser_error::e_syntax, p.current_token(), - "ERR136 - Expected '(' for special function '" + sf_name + "'", + "ERR137 - Expected '(' for special function '" + sf_name + "'", exprtk_error_location)); return error_node(); @@ -25431,7 +25760,7 @@ namespace exprtk p.set_error( make_error(parser_error::e_syntax, p.current_token(), - "ERR137 - Expected ',' before next parameter of special function '" + sf_name + "'", + "ERR138 - Expected ',' before next parameter of special function '" + sf_name + "'", exprtk_error_location)); return p.error_node(); @@ -25444,7 +25773,7 @@ namespace exprtk p.set_error( make_error(parser_error::e_syntax, p.current_token(), - "ERR138 - Invalid number of parameters for special function '" + sf_name + "'", + "ERR139 - Invalid number of parameters for special function '" + sf_name + "'", exprtk_error_location)); return p.error_node(); @@ -25471,7 +25800,7 @@ namespace exprtk set_error( make_error(parser_error::e_token, current_token(), - "ERR139 - Invalid special function[1]: " + sf_name, + "ERR140 - Invalid special function[1]: " + sf_name, exprtk_error_location)); return error_node(); @@ -25485,7 +25814,7 @@ namespace exprtk set_error( make_error(parser_error::e_token, current_token(), - "ERR140 - Invalid special function[2]: " + sf_name, + "ERR141 - Invalid special function[2]: " + sf_name, exprtk_error_location)); return error_node(); @@ -25517,7 +25846,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR141 - Invoking 'break' within a break call is not allowed", + "ERR142 - Invoking 'break' within a break call is not allowed", exprtk_error_location)); return error_node(); @@ -25527,7 +25856,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR142 - Invalid use of 'break', allowed only in the scope of a loop", + "ERR143 - Invalid use of 'break', allowed only in the scope of a loop", exprtk_error_location)); return error_node(); @@ -25550,7 +25879,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR143 - Failed to parse return expression for 'break' statement", + "ERR144 - Failed to parse return expression for 'break' statement", exprtk_error_location)); return error_node(); @@ -25560,7 +25889,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR144 - Expected ']' at the completion of break's return expression", + "ERR145 - Expected ']' at the completion of break's return expression", exprtk_error_location)); free_node(node_allocator_,return_expr); @@ -25578,7 +25907,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR145 - Invalid use of 'break', allowed only in the scope of a loop", + "ERR146 - Invalid use of 'break', allowed only in the scope of a loop", exprtk_error_location)); } @@ -25592,7 +25921,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR146 - Invalid use of 'continue', allowed only in the scope of a loop", + "ERR147 - Invalid use of 'continue', allowed only in the scope of a loop", exprtk_error_location)); return error_node(); @@ -25618,7 +25947,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR147 - Expected '[' as part of vector size definition", + "ERR148 - Expected '[' as part of vector size definition", exprtk_error_location)); return error_node(); @@ -25628,7 +25957,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR148 - Failed to determine size of vector '" + vec_name + "'", + "ERR149 - Failed to determine size of vector '" + vec_name + "'", exprtk_error_location)); return error_node(); @@ -25640,7 +25969,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR149 - Expected a literal number as size of vector '" + vec_name + "'", + "ERR150 - Expected a literal number as size of vector '" + vec_name + "'", exprtk_error_location)); return error_node(); @@ -25662,7 +25991,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR150 - Invalid vector size. Must be an integer in the range [0,2e9], size: " + + "ERR151 - Invalid vector size. Must be an integer in the range [0,2e9], size: " + details::to_str(details::numeric::to_int32(vector_size)), exprtk_error_location)); @@ -25682,7 +26011,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR151 - Expected ']' as part of vector size definition", + "ERR152 - Expected ']' as part of vector size definition", exprtk_error_location)); return error_node(); @@ -25694,7 +26023,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR152 - Expected ':=' as part of vector definition", + "ERR153 - Expected ':=' as part of vector definition", exprtk_error_location)); return error_node(); @@ -25708,7 +26037,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR153 - Failed to parse single vector initialiser", + "ERR154 - Failed to parse single vector initialiser", exprtk_error_location)); return error_node(); @@ -25721,7 +26050,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR154 - Expected ']' to close single value vector initialiser", + "ERR155 - Expected ']' to close single value vector initialiser", exprtk_error_location)); return error_node(); @@ -25768,7 +26097,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR155 - Expected '{' as part of vector initialiser list", + "ERR156 - Expected '{' as part of vector initialiser list", exprtk_error_location)); return error_node(); @@ -25788,7 +26117,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR156 - Expected '{' as part of vector initialiser list", + "ERR157 - Expected '{' as part of vector initialiser list", exprtk_error_location)); return error_node(); @@ -25806,7 +26135,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR157 - Expected ',' between vector initialisers", + "ERR158 - Expected ',' between vector initialisers", exprtk_error_location)); return error_node(); @@ -25828,19 +26157,19 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR158 - Expected ';' at end of vector definition", + "ERR159 - Expected ';' at end of vector definition", exprtk_error_location)); return error_node(); } } - if (vec_initilizer_list.size() > vector_size) + if (T(vec_initilizer_list.size()) > vector_size) { set_error( make_error(parser_error::e_syntax, current_token(), - "ERR159 - Initialiser list larger than the number of elements in the vector: '" + vec_name + "'", + "ERR160 - Initialiser list larger than the number of elements in the vector: '" + vec_name + "'", exprtk_error_location)); return error_node(); @@ -25860,7 +26189,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR160 - Illegal redefinition of local vector: '" + vec_name + "'", + "ERR161 - Illegal redefinition of local vector: '" + vec_name + "'", exprtk_error_location)); return error_node(); @@ -25894,7 +26223,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR161 - Failed to add new local vector '" + vec_name + "' to SEM", + "ERR162 - Failed to add new local vector '" + vec_name + "' to SEM", exprtk_error_location)); sem_.free_element(nse); @@ -25953,7 +26282,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR162 - Illegal redefinition of local variable: '" + str_name + "'", + "ERR163 - Illegal redefinition of local variable: '" + str_name + "'", exprtk_error_location)); free_node(node_allocator_,initialisation_expression); @@ -25985,7 +26314,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR163 - Failed to add new local string variable '" + str_name + "' to SEM", + "ERR164 - Failed to add new local string variable '" + str_name + "' to SEM", exprtk_error_location)); free_node(node_allocator_,initialisation_expression); @@ -26031,7 +26360,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR164 - Illegal variable definition", + "ERR165 - Illegal variable definition", exprtk_error_location)); return error_node(); @@ -26052,7 +26381,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR165 - Expected a symbol for variable definition", + "ERR166 - Expected a symbol for variable definition", exprtk_error_location)); return error_node(); @@ -26062,7 +26391,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR166 - Illegal redefinition of reserved keyword: '" + var_name + "'", + "ERR167 - Illegal redefinition of reserved keyword: '" + var_name + "'", exprtk_error_location)); return error_node(); @@ -26072,7 +26401,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR167 - Illegal redefinition of variable '" + var_name + "'", + "ERR168 - Illegal redefinition of variable '" + var_name + "'", exprtk_error_location)); return error_node(); @@ -26082,7 +26411,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR168 - Illegal redefinition of local variable: '" + var_name + "'", + "ERR169 - Illegal redefinition of local variable: '" + var_name + "'", exprtk_error_location)); return error_node(); @@ -26102,7 +26431,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR169 - Failed to parse initialisation expression", + "ERR170 - Failed to parse initialisation expression", exprtk_error_location)); return error_node(); @@ -26120,7 +26449,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR170 - Expected ';' after variable definition", + "ERR171 - Expected ';' after variable definition", exprtk_error_location)); free_node(node_allocator_,initialisation_expression); @@ -26148,7 +26477,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR171 - Illegal redefinition of local variable: '" + var_name + "'", + "ERR172 - Illegal redefinition of local variable: '" + var_name + "'", exprtk_error_location)); free_node(node_allocator_, initialisation_expression); @@ -26180,7 +26509,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR172 - Failed to add new local variable '" + var_name + "' to SEM", + "ERR173 - Failed to add new local variable '" + var_name + "' to SEM", exprtk_error_location)); free_node(node_allocator_, initialisation_expression); @@ -26217,7 +26546,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR173 - Expected a '{}' for uninitialised var definition", + "ERR174 - Expected a '{}' for uninitialised var definition", exprtk_error_location)); return error_node(); @@ -26227,7 +26556,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR174 - Expected ';' after uninitialised variable definition", + "ERR175 - Expected ';' after uninitialised variable definition", exprtk_error_location)); return error_node(); @@ -26244,7 +26573,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR175 - Illegal redefinition of local variable: '" + var_name + "'", + "ERR176 - Illegal redefinition of local variable: '" + var_name + "'", exprtk_error_location)); return error_node(); @@ -26274,7 +26603,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR176 - Failed to add new local variable '" + var_name + "' to SEM", + "ERR177 - Failed to add new local variable '" + var_name + "' to SEM", exprtk_error_location)); sem_.free_element(nse); @@ -26307,7 +26636,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR177 - Expected '(' at start of swap statement", + "ERR178 - Expected '(' at start of swap statement", exprtk_error_location)); return error_node(); @@ -26326,7 +26655,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR178 - Expected a symbol for variable or vector element definition", + "ERR179 - Expected a symbol for variable or vector element definition", exprtk_error_location)); return error_node(); @@ -26338,7 +26667,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR179 - First parameter to swap is an invalid vector element: '" + var0_name + "'", + "ERR180 - First parameter to swap is an invalid vector element: '" + var0_name + "'", exprtk_error_location)); return error_node(); @@ -26371,7 +26700,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR180 - First parameter to swap is an invalid variable: '" + var0_name + "'", + "ERR181 - First parameter to swap is an invalid variable: '" + var0_name + "'", exprtk_error_location)); return error_node(); @@ -26385,7 +26714,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR181 - Expected ',' between parameters to swap", + "ERR182 - Expected ',' between parameters to swap", exprtk_error_location)); if (variable0_generated) @@ -26403,7 +26732,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR182 - Expected a symbol for variable or vector element definition", + "ERR183 - Expected a symbol for variable or vector element definition", exprtk_error_location)); if (variable0_generated) @@ -26420,7 +26749,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR183 - Second parameter to swap is an invalid vector element: '" + var1_name + "'", + "ERR184 - Second parameter to swap is an invalid vector element: '" + var1_name + "'", exprtk_error_location)); if (variable0_generated) @@ -26458,7 +26787,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR184 - Second parameter to swap is an invalid variable: '" + var1_name + "'", + "ERR185 - Second parameter to swap is an invalid variable: '" + var1_name + "'", exprtk_error_location)); if (variable0_generated) @@ -26477,7 +26806,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR185 - Expected ')' at end of swap statement", + "ERR186 - Expected ')' at end of swap statement", exprtk_error_location)); if (variable0_generated) @@ -26534,7 +26863,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR186 - Return call within a return call is not allowed", + "ERR187 - Return call within a return call is not allowed", exprtk_error_location)); return error_node(); @@ -26558,7 +26887,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR187 - Expected '[' at start of return statement", + "ERR188 - Expected '[' at start of return statement", exprtk_error_location)); return error_node(); @@ -26581,7 +26910,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR188 - Expected ',' between values during call to return", + "ERR189 - Expected ',' between values during call to return", exprtk_error_location)); return error_node(); @@ -26593,7 +26922,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR189 - Zero parameter return statement not allowed", + "ERR190 - Zero parameter return statement not allowed", exprtk_error_location)); return error_node(); @@ -26608,7 +26937,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, prev_token, - "ERR190 - Invalid ']' found during return call", + "ERR191 - Invalid ']' found during return call", exprtk_error_location)); return error_node(); @@ -26661,7 +26990,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR191 - Invalid sequence of variable '"+ symbol + "' and bracket", + "ERR192 - Invalid sequence of variable '" + symbol + "' and bracket", exprtk_error_location)); return false; @@ -26709,7 +27038,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR192 - Invalid sequence of brackets", + "ERR193 - Invalid sequence of brackets", exprtk_error_location)); return false; @@ -26725,27 +27054,65 @@ namespace exprtk return true; } + typedef typename interval_container_t::interval_t interval_t; + typedef interval_container_t immutable_memory_map_t; + typedef std::map immutable_symtok_map_t; + + inline interval_t make_memory_range(const T& t) + { + const T* begin = reinterpret_cast(&t); + const T* end = begin + 1; + return interval_t(begin, end); + } + + inline interval_t make_memory_range(const T* begin, const std::size_t size) + { + return interval_t(begin, begin + size); + } + + inline interval_t make_memory_range(details::char_cptr begin, const std::size_t size) + { + return interval_t(begin, begin + size); + } + + void lodge_immutable_symbol(const lexer::token& token, const interval_t interval) + { + immutable_memory_map_.add_interval(interval); + immutable_symtok_map_[interval] = token; + } + inline expression_node_ptr parse_symtab_symbol() { const std::string symbol = current_token().value; // Are we dealing with a variable or a special constant? - expression_node_ptr variable = symtab_store_.get_variable(symbol); + typedef typename symtab_store::variable_context var_ctxt_t; + var_ctxt_t var_ctx = symtab_store_.get_variable_context(symbol); - if (variable) + if (var_ctx.variable) { + assert(var_ctx.symbol_table); + + expression_node_ptr result_variable = var_ctx.variable; + if (symtab_store_.is_constant_node(symbol)) { - variable = expression_generator_(variable->value()); + result_variable = expression_generator_(var_ctx.variable->value()); + } + else if (symbol_table_t::e_immutable == var_ctx.symbol_table->mutability()) + { + lodge_immutable_symbol(current_token(), make_memory_range(var_ctx.variable->ref())); + result_variable = var_ctx.variable; } if (!post_variable_process(symbol)) return error_node(); lodge_symbol(symbol, e_st_variable); + next_token(); - return variable; + return result_variable; } // Are we dealing with a locally defined variable, vector or string? @@ -26806,7 +27173,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR193 - Failed to generate node for function: '" + symbol + "'", + "ERR194 - Failed to generate node for function: '" + symbol + "'", exprtk_error_location)); return error_node(); @@ -26832,7 +27199,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR194 - Failed to generate node for vararg function: '" + symbol + "'", + "ERR195 - Failed to generate node for vararg function: '" + symbol + "'", exprtk_error_location)); return error_node(); @@ -26858,7 +27225,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR195 - Failed to generate node for generic function: '" + symbol + "'", + "ERR196 - Failed to generate node for generic function: '" + symbol + "'", exprtk_error_location)); return error_node(); @@ -26885,7 +27252,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR196 - Failed to generate node for string function: '" + symbol + "'", + "ERR197 - Failed to generate node for string function: '" + symbol + "'", exprtk_error_location)); return error_node(); @@ -26911,7 +27278,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR197 - Failed to generate node for overload function: '" + symbol + "'", + "ERR198 - Failed to generate node for overload function: '" + symbol + "'", exprtk_error_location)); return error_node(); @@ -26937,7 +27304,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR198 - Invalid use of reserved symbol '" + symbol + "'", + "ERR199 - Invalid use of reserved symbol '" + symbol + "'", exprtk_error_location)); return error_node(); @@ -27000,7 +27367,7 @@ namespace exprtk set_error( make_error(parser_error::e_symtab, current_token(), - "ERR199 - Failed to create variable: '" + symbol + "'" + + "ERR200 - Failed to create variable: '" + symbol + "'" + (error_message.empty() ? "" : " - " + error_message), exprtk_error_location)); @@ -27020,7 +27387,7 @@ namespace exprtk set_error( make_error(parser_error::e_symtab, current_token(), - "ERR200 - Failed to resolve symbol: '" + symbol + "'" + + "ERR201 - Failed to resolve symbol: '" + symbol + "'" + (error_message.empty() ? "" : " - " + error_message), exprtk_error_location)); } @@ -27032,7 +27399,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR201 - Undefined symbol: '" + symbol + "'", + "ERR202 - Undefined symbol: '" + symbol + "'", exprtk_error_location)); return error_node(); @@ -27146,7 +27513,7 @@ namespace exprtk set_error( make_error(parser_error::e_symtab, current_token(), - "ERR202 - Variable or function detected, yet symbol-table is invalid, Symbol: " + symbol, + "ERR203 - Variable or function detected, yet symbol-table is invalid, Symbol: " + symbol, exprtk_error_location)); return error_node(); @@ -27177,7 +27544,7 @@ namespace exprtk set_error( make_error(parser_error::e_numeric, current_token(), - "ERR203 - Failed generate node for scalar: '" + current_token().value + "'", + "ERR204 - Failed generate node for scalar: '" + current_token().value + "'", exprtk_error_location)); return error_node(); @@ -27191,7 +27558,7 @@ namespace exprtk set_error( make_error(parser_error::e_numeric, current_token(), - "ERR204 - Failed to convert '" + current_token().value + "' to a number", + "ERR205 - Failed to convert '" + current_token().value + "' to a number", exprtk_error_location)); return error_node(); @@ -27218,7 +27585,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR205 - Expected ')' instead of: '" + current_token().value + "'", + "ERR206 - Expected ')' instead of: '" + current_token().value + "'", exprtk_error_location)); details::free_node(node_allocator_,branch); @@ -27243,7 +27610,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR206 - Expected ']' instead of: '" + current_token().value + "'", + "ERR207 - Expected ']' instead of: '" + current_token().value + "'", exprtk_error_location)); details::free_node(node_allocator_,branch); @@ -27268,7 +27635,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR207 - Expected '}' instead of: '" + current_token().value + "'", + "ERR208 - Expected '}' instead of: '" + current_token().value + "'", exprtk_error_location)); details::free_node(node_allocator_,branch); @@ -27317,7 +27684,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR208 - Premature end of expression[1]", + "ERR209 - Premature end of expression[1]", exprtk_error_location)); return error_node(); @@ -27327,7 +27694,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR209 - Premature end of expression[2]", + "ERR210 - Premature end of expression[2]", exprtk_error_location)); return error_node(); @@ -29616,43 +29983,105 @@ namespace exprtk } } + const void* base_ptr(expression_node_ptr node) + { + if (node) + { + switch(node->type()) + { + case details::expression_node::e_variable: + return reinterpret_cast(&static_cast(node)->ref()); + + case details::expression_node::e_vecelem: + return reinterpret_cast(&static_cast(node)->ref()); + + case details::expression_node::e_rbvecelem: + return reinterpret_cast(&static_cast(node)->ref()); + + case details::expression_node::e_rbveccelem: + return reinterpret_cast(&static_cast(node)->ref()); + + case details::expression_node::e_vector: + return reinterpret_cast(static_cast(node)->vec_holder().data()); + + #ifndef exprtk_disable_string_capabilities + case details::expression_node::e_stringvar: + return reinterpret_cast((static_cast(node)->base())); + + case details::expression_node::e_stringvarrng: + return reinterpret_cast((static_cast(node)->base())); + #endif + default : return reinterpret_cast(0); + } + } + + return reinterpret_cast(0); + } + + bool assign_immutable_symbol(expression_node_ptr node) + { + interval_t interval; + const void* baseptr_addr = base_ptr(node); + + exprtk_debug(("assign_immutable_symbol - base ptr addr: %p\n", baseptr_addr)); + + if (parser_->immutable_memory_map_.in_interval(baseptr_addr,interval)) + { + typename immutable_symtok_map_t::iterator itr = parser_->immutable_symtok_map_.find(interval); + + if (parser_->immutable_symtok_map_.end() != itr) + { + token_t& token = itr->second; + parser_->set_error( + parser_error::make_error(parser_error::e_parser, + token, + "ERR211 - Symbol '" + token.value + "' cannot be assigned-to as it is immutable.", + exprtk_error_location)); + } + else + parser_->set_synthesis_error("Unable to assign symbol is immutable."); + + return true; + } + + return false; + } + inline expression_node_ptr synthesize_assignment_expression(const details::operator_type& operation, expression_node_ptr (&branch)[2]) { - if (details::is_variable_node(branch[0])) + if (assign_immutable_symbol(branch[0])) + { + return error_node(); + } + else if (details::is_variable_node(branch[0])) { lodge_assignment(e_st_variable,branch[0]); - return synthesize_expression(operation,branch); } else if (details::is_vector_elem_node(branch[0])) { lodge_assignment(e_st_vecelem,branch[0]); - return synthesize_expression(operation, branch); } else if (details::is_rebasevector_elem_node(branch[0])) { lodge_assignment(e_st_vecelem,branch[0]); - return synthesize_expression(operation, branch); } else if (details::is_rebasevector_celem_node(branch[0])) { lodge_assignment(e_st_vecelem,branch[0]); - return synthesize_expression(operation, branch); } #ifndef exprtk_disable_string_capabilities else if (details::is_string_node(branch[0])) { lodge_assignment(e_st_string,branch[0]); - return synthesize_expression(operation, branch); } else if (details::is_string_range_node(branch[0])) { lodge_assignment(e_st_string,branch[0]); - return synthesize_expression(operation, branch); } #endif @@ -29676,6 +30105,11 @@ namespace exprtk inline expression_node_ptr synthesize_assignment_operation_expression(const details::operator_type& operation, expression_node_ptr (&branch)[2]) { + if (assign_immutable_symbol(branch[0])) + { + return error_node(); + } + if (details::is_variable_node(branch[0])) { lodge_assignment(e_st_variable,branch[0]); @@ -36995,6 +37429,9 @@ namespace exprtk std::string synthesis_error_; scope_element_manager sem_; + immutable_memory_map_t immutable_memory_map_; + immutable_symtok_map_t immutable_symtok_map_; + lexer::helper::helper_assembly helper_assembly_; lexer::helper::commutative_inserter commutative_inserter_; @@ -37002,7 +37439,7 @@ namespace exprtk lexer::helper::operator_joiner operator_joiner_3_; lexer::helper::symbol_replacer symbol_replacer_; lexer::helper::bracket_checker bracket_checker_; - lexer::helper::numeric_checker numeric_checker_; + lexer::helper::numeric_checker numeric_checker_; lexer::helper::sequence_validator sequence_validator_; lexer::helper::sequence_validator_3tokens sequence_validator_3tkns_; @@ -38541,202 +38978,7 @@ namespace exprtk std::vector auxiliary_symtab_list_; }; // class function_compositor - template - inline bool pgo_primer() - { - static const std::string expression_list[] = - { - "(y + x)", - "2 * (y + x)", - "(2 * y + 2 * x)", - "(y + x / y) * (x - y / x)", - "x / ((x + y) * (x - y)) / y", - "1 - ((x * y) + (y / x)) - 3", - "sin(2 * x) + cos(pi / y)", - "1 - sin(2 * x) + cos(pi / y)", - "sqrt(1 - sin(2 * x) + cos(pi / y) / 3)", - "(x^2 / sin(2 * pi / y)) -x / 2", - "x + (cos(y - sin(2 / x * pi)) - sin(x - cos(2 * y / pi))) - y", - "clamp(-1.0, sin(2 * pi * x) + cos(y / 2 * pi), +1.0)", - "iclamp(-1.0, sin(2 * pi * x) + cos(y / 2 * pi), +1.0)", - "max(3.33, min(sqrt(1 - sin(2 * x) + cos(pi / y) / 3), 1.11))", - "if(avg(x,y) <= x + y, x - y, x * y) + 2 * pi / x", - "1.1x^1 + 2.2y^2 - 3.3x^3 + 4.4y^4 - 5.5x^5 + 6.6y^6 - 7.7x^27 + 8.8y^55", - "(yy + xx)", - "2 * (yy + xx)", - "(2 * yy + 2 * xx)", - "(yy + xx / yy) * (xx - yy / xx)", - "xx / ((xx + yy) * (xx - yy)) / yy", - "1 - ((xx * yy) + (yy / xx)) - 3", - "sin(2 * xx) + cos(pi / yy)", - "1 - sin(2 * xx) + cos(pi / yy)", - "sqrt(1 - sin(2 * xx) + cos(pi / yy) / 3)", - "(xx^2 / sin(2 * pi / yy)) -xx / 2", - "xx + (cos(yy - sin(2 / xx * pi)) - sin(xx - cos(2 * yy / pi))) - yy", - "clamp(-1.0, sin(2 * pi * xx) + cos(yy / 2 * pi), +1.0)", - "max(3.33, min(sqrt(1 - sin(2 * xx) + cos(pi / yy) / 3), 1.11))", - "if(avg(xx,yy) <= xx + yy, xx - yy, xx * yy) + 2 * pi / xx", - "1.1xx^1 + 2.2yy^2 - 3.3xx^3 + 4.4yy^4 - 5.5xx^5 + 6.6yy^6 - 7.7xx^27 + 8.8yy^55", - "(1.1*(2.2*(3.3*(4.4*(5.5*(6.6*(7.7*(8.8*(9.9+x)))))))))", - "(((((((((x+9.9)*8.8)*7.7)*6.6)*5.5)*4.4)*3.3)*2.2)*1.1)", - "(x + y) * z", "x + (y * z)", "(x + y) * 7", "x + (y * 7)", - "(x + 7) * y", "x + (7 * y)", "(7 + x) * y", "7 + (x * y)", - "(2 + x) * 3", "2 + (x * 3)", "(2 + 3) * x", "2 + (3 * x)", - "(x + 2) * 3", "x + (2 * 3)", - "(x + y) * (z / w)", "(x + y) * (z / 7)", "(x + y) * (7 / z)", "(x + 7) * (y / z)", - "(7 + x) * (y / z)", "(2 + x) * (y / z)", "(x + 2) * (y / 3)", "(2 + x) * (y / 3)", - "(x + 2) * (3 / y)", "x + (y * (z / w))", "x + (y * (z / 7))", "x + (y * (7 / z))", - "x + (7 * (y / z))", "7 + (x * (y / z))", "2 + (x * (3 / y))", "x + (2 * (y / 4))", - "2 + (x * (y / 3))", "x + (2 * (3 / y))", - "x + ((y * z) / w)", "x + ((y * z) / 7)", "x + ((y * 7) / z)", "x + ((7 * y) / z)", - "7 + ((y * z) / w)", "2 + ((x * 3) / y)", "x + ((2 * y) / 3)", "2 + ((x * y) / 3)", - "x + ((2 * 3) / y)", "(((x + y) * z) / w)", - "(((x + y) * z) / 7)", "(((x + y) * 7) / z)", "(((x + 7) * y) / z)", "(((7 + x) * y) / z)", - "(((2 + x) * 3) / y)", "(((x + 2) * y) / 3)", "(((2 + x) * y) / 3)", "(((x + 2) * 3) / y)", - "((x + (y * z)) / w)", "((x + (y * z)) / 7)", "((x + (y * 7)) / y)", "((x + (7 * y)) / z)", - "((7 + (x * y)) / z)", "((2 + (x * 3)) / y)", "((x + (2 * y)) / 3)", "((2 + (x * y)) / 3)", - "((x + (2 * 3)) / y)", - "(xx + yy) * zz", "xx + (yy * zz)", - "(xx + yy) * 7", "xx + (yy * 7)", - "(xx + 7) * yy", "xx + (7 * yy)", - "(7 + xx) * yy", "7 + (xx * yy)", - "(2 + x) * 3", "2 + (x * 3)", - "(2 + 3) * x", "2 + (3 * x)", - "(x + 2) * 3", "x + (2 * 3)", - "(xx + yy) * (zz / ww)", "(xx + yy) * (zz / 7)", - "(xx + yy) * (7 / zz)", "(xx + 7) * (yy / zz)", - "(7 + xx) * (yy / zz)", "(2 + xx) * (yy / zz)", - "(xx + 2) * (yy / 3)", "(2 + xx) * (yy / 3)", - "(xx + 2) * (3 / yy)", "xx + (yy * (zz / ww))", - "xx + (yy * (zz / 7))", "xx + (yy * (7 / zz))", - "xx + (7 * (yy / zz))", "7 + (xx * (yy / zz))", - "2 + (xx * (3 / yy))", "xx + (2 * (yy / 4))", - "2 + (xx * (yy / 3))", "xx + (2 * (3 / yy))", - "xx + ((yy * zz) / ww)", "xx + ((yy * zz) / 7)", - "xx + ((yy * 7) / zz)", "xx + ((7 * yy) / zz)", - "7 + ((yy * zz) / ww)", "2 + ((xx * 3) / yy)", - "xx + ((2 * yy) / 3)", "2 + ((xx * yy) / 3)", - "xx + ((2 * 3) / yy)", "(((xx + yy) * zz) / ww)", - "(((xx + yy) * zz) / 7)", "(((xx + yy) * 7) / zz)", - "(((xx + 7) * yy) / zz)", "(((7 + xx) * yy) / zz)", - "(((2 + xx) * 3) / yy)", "(((xx + 2) * yy) / 3)", - "(((2 + xx) * yy) / 3)", "(((xx + 2) * 3) / yy)", - "((xx + (yy * zz)) / ww)", "((xx + (yy * zz)) / 7)", - "((xx + (yy * 7)) / yy)", "((xx + (7 * yy)) / zz)", - "((7 + (xx * yy)) / zz)", "((2 + (xx * 3)) / yy)", - "((xx + (2 * yy)) / 3)", "((2 + (xx * yy)) / 3)", - "((xx + (2 * 3)) / yy)" - }; - - static const std::size_t expression_list_size = sizeof(expression_list) / sizeof(std::string); - - T x = T(0); - T y = T(0); - T z = T(0); - T w = T(0); - T xx = T(0); - T yy = T(0); - T zz = T(0); - T ww = T(0); - - exprtk::symbol_table symbol_table; - symbol_table.add_constants(); - symbol_table.add_variable( "x", x); - symbol_table.add_variable( "y", y); - symbol_table.add_variable( "z", z); - symbol_table.add_variable( "w", w); - symbol_table.add_variable("xx",xx); - symbol_table.add_variable("yy",yy); - symbol_table.add_variable("zz",zz); - symbol_table.add_variable("ww",ww); - - typedef typename std::deque > expr_list_t; - expr_list_t expr_list; - - const std::size_t rounds = 50; - - { - for (std::size_t r = 0; r < rounds; ++r) - { - expr_list.clear(); - exprtk::parser parser; - - for (std::size_t i = 0; i < expression_list_size; ++i) - { - exprtk::expression expression; - expression.register_symbol_table(symbol_table); - - if (!parser.compile(expression_list[i],expression)) - { - return false; - } - - expr_list.push_back(expression); - } - } - } - - struct execute - { - static inline T process(T& x, T& y, expression& expression) - { - static const T lower_bound = T(-20); - static const T upper_bound = T(+20); - static const T delta = T(0.1); - - T total = T(0); - - for (x = lower_bound; x <= upper_bound; x += delta) - { - for (y = lower_bound; y <= upper_bound; y += delta) - { - total += expression.value(); - } - } - - return total; - } - }; - - for (std::size_t i = 0; i < expr_list.size(); ++i) - { - execute::process( x, y, expr_list[i]); - execute::process(xx, yy, expr_list[i]); - } - - { - for (std::size_t i = 0; i < 10000; ++i) - { - const T v = T(123.456 + i); - - if (details::is_true(details::numeric::nequal(details::numeric::fast_exp::result(v),details::numeric::pow(v,T(1))))) - return false; - - #define else_stmt(N) \ - else if (details::is_true(details::numeric::nequal(details::numeric::fast_exp::result(v),details::numeric::pow(v,T(N))))) \ - return false; \ - - else_stmt( 2) else_stmt( 3) else_stmt( 4) else_stmt( 5) - else_stmt( 6) else_stmt( 7) else_stmt( 8) else_stmt( 9) - else_stmt(10) else_stmt(11) else_stmt(12) else_stmt(13) - else_stmt(14) else_stmt(15) else_stmt(16) else_stmt(17) - else_stmt(18) else_stmt(19) else_stmt(20) else_stmt(21) - else_stmt(22) else_stmt(23) else_stmt(24) else_stmt(25) - else_stmt(26) else_stmt(27) else_stmt(28) else_stmt(29) - else_stmt(30) else_stmt(31) else_stmt(32) else_stmt(33) - else_stmt(34) else_stmt(35) else_stmt(36) else_stmt(37) - else_stmt(38) else_stmt(39) else_stmt(40) else_stmt(41) - else_stmt(42) else_stmt(43) else_stmt(44) else_stmt(45) - else_stmt(46) else_stmt(47) else_stmt(48) else_stmt(49) - else_stmt(50) else_stmt(51) else_stmt(52) else_stmt(53) - else_stmt(54) else_stmt(55) else_stmt(56) else_stmt(57) - else_stmt(58) else_stmt(59) else_stmt(60) else_stmt(61) - } - } - - return true; - } -} +} // namespace exprtk #if defined(_WIN32) || defined(__WIN32__) || defined(WIN32) # ifndef NOMINMAX @@ -39012,6 +39254,9 @@ namespace exprtk { namespace rtl { namespace io { namespace file { namespace details { + using ::exprtk::details::char_ptr; + using ::exprtk::details::char_cptr; + enum file_mode { e_error = 0, @@ -39120,11 +39365,11 @@ namespace exprtk switch (mode) { case e_write : reinterpret_cast(stream_ptr)-> - write(reinterpret_cast(view.begin() + offset), amount * sizeof(typename View::value_t)); + write(reinterpret_cast(view.begin() + offset), amount * sizeof(typename View::value_t)); break; case e_rdwrt : reinterpret_cast(stream_ptr)-> - write(reinterpret_cast(view.begin() + offset) , amount * sizeof(typename View::value_t)); + write(reinterpret_cast(view.begin() + offset) , amount * sizeof(typename View::value_t)); break; default : return false; @@ -39139,11 +39384,11 @@ namespace exprtk switch (mode) { case e_read : reinterpret_cast(stream_ptr)-> - read(reinterpret_cast(view.begin() + offset), amount * sizeof(typename View::value_t)); + read(reinterpret_cast(view.begin() + offset), amount * sizeof(typename View::value_t)); break; case e_rdwrt : reinterpret_cast(stream_ptr)-> - read(reinterpret_cast(view.begin() + offset) , amount * sizeof(typename View::value_t)); + read(reinterpret_cast(view.begin() + offset) , amount * sizeof(typename View::value_t)); break; default : return false; @@ -39207,12 +39452,11 @@ namespace exprtk template file_descriptor* make_handle(T v) { + const std::size_t fd_size = sizeof(details::file_descriptor*); details::file_descriptor* fd = reinterpret_cast(0); - const std::size_t fd_size = sizeof(details::file_descriptor*); - - std::memcpy(reinterpret_cast(&fd), - reinterpret_cast(&v), + std::memcpy(reinterpret_cast(&fd), + reinterpret_cast(&v ), fd_size); return fd; } @@ -39253,18 +39497,18 @@ namespace exprtk inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) { - std::string file_name = to_str(string_t(parameters[0])); - std::string access; + const std::string file_name = to_str(string_t(parameters[0])); if (file_name.empty()) return T(0); - if (0 == ps_index) - access = "r"; - else if (0 == string_t(parameters[1]).size()) + if ((1 == ps_index) && (0 == string_t(parameters[1]).size())) + { return T(0); - else - access = to_str(string_t(parameters[1])); + } + + const std::string access = + (0 == ps_index) ? "r" : to_str(string_t(parameters[1])); details::file_descriptor* fd = new details::file_descriptor(file_name,access); @@ -40685,18 +40929,22 @@ namespace exprtk { namespace information { - static const char* library = "Mathematical Expression Toolkit"; - static const char* version = "2.7182818284590452353602874713526" - "624977572470936999595749669676277" - "240766303535475945713821785251664" - "274274663919320030599218174135966"; - static const char* date = "20220101"; + using ::exprtk::details::char_cptr; + + static char_cptr library = "Mathematical Expression Toolkit"; + static char_cptr version = "2.71828182845904523536028747135266" + "2497757247093699959574966967627724" + "0766303535475945713821785251664274" + "2746639193200305992181741359662904"; + static char_cptr date = "20230101"; + static char_cptr min_cpp = "199711L"; static inline std::string data() { static const std::string info_str = std::string(library) + std::string(" v") + std::string(version) + - std::string(" (") + date + std::string(")"); + std::string(" (") + date + std::string(")") + + std::string(" (") + min_cpp + std::string(")"); return info_str; } diff --git a/exprtk_benchmark.cpp b/exprtk_benchmark.cpp index 09472fb..54bbcc2 100644 --- a/exprtk_benchmark.cpp +++ b/exprtk_benchmark.cpp @@ -3,14 +3,14 @@ * C++ Mathematical Expression Toolkit Library * * * * ExprTk vs Native Benchmarks * - * Author: Arash Partow (1999-2022) * - * URL: http://www.partow.net/programming/exprtk/index.html * + * Author: Arash Partow (1999-2023) * + * URL: https://www.partow.net/programming/exprtk/index.html * * * * Copyright notice: * * Free use of the Mathematical Expression Toolkit Library is * * permitted under the guidelines and in accordance with the * * most current version of the MIT License. * - * http://www.opensource.org/licenses/MIT * + * https://www.opensource.org/licenses/MIT * * * ************************************************************** */ @@ -361,8 +361,6 @@ int main(int argc, char* argv[]) double pgo_primer() { - exprtk::pgo_primer(); - static const double lower_bound_x = -50.0; static const double lower_bound_y = -50.0; static const double upper_bound_x = +50.0; diff --git a/exprtk_functional_test.txt b/exprtk_functional_test.txt index 9d9f8e9..9ec9488 100644 --- a/exprtk_functional_test.txt +++ b/exprtk_functional_test.txt @@ -8303,4 +8303,8 @@ equal(true,~{var v0[3] := {1,2,3}; var v1[4] := {6,7,8,9}; ((1 > 2) ? v0 - v1 : equal(true,~{var v0[3] := {1,2,3}; var v1[4] := {6,7,8,9}; var x_ := 1; var y_ := 2; ((x_ < y_) ? v0 : v1) == v0}) equal(true,~{var v0[3] := {1,2,3}; var v1[4] := {6,7,8,9}; var x_ := 1; var y_ := 2; ((x_ > y_) ? v0 : v1) == v1}) equal(true,~{var v0[3] := {1,2,3}; var v1[4] := {6,7,8,9}; var x_ := 1; var y_ := 2; ((x_ < y_) ? v0 - v1 : v1 - v0) == (v0 - v1)}) -equal(true,~{var v0[3] := {1,2,3}; var v1[4] := {6,7,8,9}; var x_ := 1; var y_ := 2; ((x_ > y_) ? v0 - v1 : v1 - v0) == (v1 - v0)}) \ No newline at end of file +equal(true,~{var v0[3] := {1,2,3}; var v1[4] := {6,7,8,9}; var x_ := 1; var y_ := 2; ((x_ > y_) ? v0 - v1 : v1 - v0) == (v1 - v0)}) +equal(true,~{var xx := 0; for(var i:= 0; i < 10; i+=1) { for(var j:= 0; j < 100; j+=1) { if (j > i) break; xx += 1; } }; xx == 55}) +equal(true,~{var xx := 0; for(var i:= 0; i < 10; i+=1) { for(var j:= 0; j < 100; j+=1) { xx += 1; if (j > i) break; } }; xx == 65}) +equal(true,~{var xx := 0; var i := 0; while(i < 10) { var j := 0; while(j < 100) { if (j > i) break; xx += 1; j+=1 }; i+=1 }; xx == 55}) +equal(true,~{var xx := 0; var i := 0; while(i < 10) { var j := 0; while(j < 100) { xx += 1; if (j > i) break; j+=1 }; i+=1 }; xx == 65}) \ No newline at end of file diff --git a/exprtk_simple_example_01.cpp b/exprtk_simple_example_01.cpp index fa6d661..d20e2ed 100644 --- a/exprtk_simple_example_01.cpp +++ b/exprtk_simple_example_01.cpp @@ -3,14 +3,14 @@ * C++ Mathematical Expression Toolkit Library * * * * Simple Example 1 * - * Author: Arash Partow (1999-2022) * - * URL: http://www.partow.net/programming/exprtk/index.html * + * Author: Arash Partow (1999-2023) * + * URL: https://www.partow.net/programming/exprtk/index.html * * * * Copyright notice: * * Free use of the Mathematical Expression Toolkit Library is * * permitted under the guidelines and in accordance with the * * most current version of the MIT License. * - * http://www.opensource.org/licenses/MIT * + * https://www.opensource.org/licenses/MIT * * * ************************************************************** */ diff --git a/exprtk_simple_example_02.cpp b/exprtk_simple_example_02.cpp index 927c431..77c8c60 100644 --- a/exprtk_simple_example_02.cpp +++ b/exprtk_simple_example_02.cpp @@ -3,14 +3,14 @@ * C++ Mathematical Expression Toolkit Library * * * * Simple Example 2 * - * Author: Arash Partow (1999-2022) * - * URL: http://www.partow.net/programming/exprtk/index.html * + * Author: Arash Partow (1999-2023) * + * URL: https://www.partow.net/programming/exprtk/index.html * * * * Copyright notice: * * Free use of the Mathematical Expression Toolkit Library is * * permitted under the guidelines and in accordance with the * * most current version of the MIT License. * - * http://www.opensource.org/licenses/MIT * + * https://www.opensource.org/licenses/MIT * * * ************************************************************** */ diff --git a/exprtk_simple_example_03.cpp b/exprtk_simple_example_03.cpp index 709b9bf..e133df0 100644 --- a/exprtk_simple_example_03.cpp +++ b/exprtk_simple_example_03.cpp @@ -3,14 +3,14 @@ * C++ Mathematical Expression Toolkit Library * * * * Simple Example 3 * - * Author: Arash Partow (1999-2022) * - * URL: http://www.partow.net/programming/exprtk/index.html * + * Author: Arash Partow (1999-2023) * + * URL: https://www.partow.net/programming/exprtk/index.html * * * * Copyright notice: * * Free use of the Mathematical Expression Toolkit Library is * * permitted under the guidelines and in accordance with the * * most current version of the MIT License. * - * http://www.opensource.org/licenses/MIT * + * https://www.opensource.org/licenses/MIT * * * ************************************************************** */ diff --git a/exprtk_simple_example_04.cpp b/exprtk_simple_example_04.cpp index 15cbc39..69a663e 100644 --- a/exprtk_simple_example_04.cpp +++ b/exprtk_simple_example_04.cpp @@ -3,14 +3,14 @@ * C++ Mathematical Expression Toolkit Library * * * * Simple Example 4 * - * Author: Arash Partow (1999-2022) * - * URL: http://www.partow.net/programming/exprtk/index.html * + * Author: Arash Partow (1999-2023) * + * URL: https://www.partow.net/programming/exprtk/index.html * * * * Copyright notice: * * Free use of the Mathematical Expression Toolkit Library is * * permitted under the guidelines and in accordance with the * * most current version of the MIT License. * - * http://www.opensource.org/licenses/MIT * + * https://www.opensource.org/licenses/MIT * * * ************************************************************** */ diff --git a/exprtk_simple_example_05.cpp b/exprtk_simple_example_05.cpp index e185ee0..fdbabc9 100644 --- a/exprtk_simple_example_05.cpp +++ b/exprtk_simple_example_05.cpp @@ -3,14 +3,14 @@ * C++ Mathematical Expression Toolkit Library * * * * Simple Example 5 * - * Author: Arash Partow (1999-2022) * - * URL: http://www.partow.net/programming/exprtk/index.html * + * Author: Arash Partow (1999-2023) * + * URL: https://www.partow.net/programming/exprtk/index.html * * * * Copyright notice: * * Free use of the Mathematical Expression Toolkit Library is * * permitted under the guidelines and in accordance with the * * most current version of the MIT License. * - * http://www.opensource.org/licenses/MIT * + * https://www.opensource.org/licenses/MIT * * * ************************************************************** */ diff --git a/exprtk_simple_example_06.cpp b/exprtk_simple_example_06.cpp index 395ec76..b50660b 100644 --- a/exprtk_simple_example_06.cpp +++ b/exprtk_simple_example_06.cpp @@ -3,14 +3,14 @@ * C++ Mathematical Expression Toolkit Library * * * * Simple Example 6 * - * Author: Arash Partow (1999-2022) * - * URL: http://www.partow.net/programming/exprtk/index.html * + * Author: Arash Partow (1999-2023) * + * URL: https://www.partow.net/programming/exprtk/index.html * * * * Copyright notice: * * Free use of the Mathematical Expression Toolkit Library is * * permitted under the guidelines and in accordance with the * * most current version of the MIT License. * - * http://www.opensource.org/licenses/MIT * + * https://www.opensource.org/licenses/MIT * * * ************************************************************** */ diff --git a/exprtk_simple_example_07.cpp b/exprtk_simple_example_07.cpp index a5fcdaf..845b158 100644 --- a/exprtk_simple_example_07.cpp +++ b/exprtk_simple_example_07.cpp @@ -3,14 +3,14 @@ * C++ Mathematical Expression Toolkit Library * * * * Simple Example 7 * - * Author: Arash Partow (1999-2022) * - * URL: http://www.partow.net/programming/exprtk/index.html * + * Author: Arash Partow (1999-2023) * + * URL: https://www.partow.net/programming/exprtk/index.html * * * * Copyright notice: * * Free use of the Mathematical Expression Toolkit Library is * * permitted under the guidelines and in accordance with the * * most current version of the MIT License. * - * http://www.opensource.org/licenses/MIT * + * https://www.opensource.org/licenses/MIT * * * ************************************************************** */ diff --git a/exprtk_simple_example_08.cpp b/exprtk_simple_example_08.cpp index 338bbf4..bfacb1e 100644 --- a/exprtk_simple_example_08.cpp +++ b/exprtk_simple_example_08.cpp @@ -3,14 +3,14 @@ * C++ Mathematical Expression Toolkit Library * * * * Simple Example 8 * - * Author: Arash Partow (1999-2022) * - * URL: http://www.partow.net/programming/exprtk/index.html * + * Author: Arash Partow (1999-2023) * + * URL: https://www.partow.net/programming/exprtk/index.html * * * * Copyright notice: * * Free use of the Mathematical Expression Toolkit Library is * * permitted under the guidelines and in accordance with the * * most current version of the MIT License. * - * http://www.opensource.org/licenses/MIT * + * https://www.opensource.org/licenses/MIT * * * ************************************************************** */ diff --git a/exprtk_simple_example_09.cpp b/exprtk_simple_example_09.cpp index 6b385cd..8934523 100644 --- a/exprtk_simple_example_09.cpp +++ b/exprtk_simple_example_09.cpp @@ -3,14 +3,14 @@ * C++ Mathematical Expression Toolkit Library * * * * Simple Example 9 * - * Author: Arash Partow (1999-2022) * - * URL: http://www.partow.net/programming/exprtk/index.html * + * Author: Arash Partow (1999-2023) * + * URL: https://www.partow.net/programming/exprtk/index.html * * * * Copyright notice: * * Free use of the Mathematical Expression Toolkit Library is * * permitted under the guidelines and in accordance with the * * most current version of the MIT License. * - * http://www.opensource.org/licenses/MIT * + * https://www.opensource.org/licenses/MIT * * * ************************************************************** */ diff --git a/exprtk_simple_example_10.cpp b/exprtk_simple_example_10.cpp index 36669dc..0a0add4 100644 --- a/exprtk_simple_example_10.cpp +++ b/exprtk_simple_example_10.cpp @@ -3,14 +3,14 @@ * C++ Mathematical Expression Toolkit Library * * * * Simple Example 10 * - * Author: Arash Partow (1999-2022) * - * URL: http://www.partow.net/programming/exprtk/index.html * + * Author: Arash Partow (1999-2023) * + * URL: https://www.partow.net/programming/exprtk/index.html * * * * Copyright notice: * * Free use of the Mathematical Expression Toolkit Library is * * permitted under the guidelines and in accordance with the * * most current version of the MIT License. * - * http://www.opensource.org/licenses/MIT * + * https://www.opensource.org/licenses/MIT * * * ************************************************************** */ diff --git a/exprtk_simple_example_11.cpp b/exprtk_simple_example_11.cpp index 86c245e..fdf123c 100644 --- a/exprtk_simple_example_11.cpp +++ b/exprtk_simple_example_11.cpp @@ -3,14 +3,14 @@ * C++ Mathematical Expression Toolkit Library * * * * Simple Example 11 * - * Author: Arash Partow (1999-2022) * - * URL: http://www.partow.net/programming/exprtk/index.html * + * Author: Arash Partow (1999-2023) * + * URL: https://www.partow.net/programming/exprtk/index.html * * * * Copyright notice: * * Free use of the Mathematical Expression Toolkit Library is * * permitted under the guidelines and in accordance with the * * most current version of the MIT License. * - * http://www.opensource.org/licenses/MIT * + * https://www.opensource.org/licenses/MIT * * * ************************************************************** */ diff --git a/exprtk_simple_example_12.cpp b/exprtk_simple_example_12.cpp index 9297224..aafeebb 100644 --- a/exprtk_simple_example_12.cpp +++ b/exprtk_simple_example_12.cpp @@ -3,14 +3,14 @@ * C++ Mathematical Expression Toolkit Library * * * * Simple Example 12 * - * Author: Arash Partow (1999-2022) * - * URL: http://www.partow.net/programming/exprtk/index.html * + * Author: Arash Partow (1999-2023) * + * URL: https://www.partow.net/programming/exprtk/index.html * * * * Copyright notice: * * Free use of the Mathematical Expression Toolkit Library is * * permitted under the guidelines and in accordance with the * * most current version of the MIT License. * - * http://www.opensource.org/licenses/MIT * + * https://www.opensource.org/licenses/MIT * * * ************************************************************** */ diff --git a/exprtk_simple_example_13.cpp b/exprtk_simple_example_13.cpp index b865406..29ac239 100644 --- a/exprtk_simple_example_13.cpp +++ b/exprtk_simple_example_13.cpp @@ -3,14 +3,14 @@ * C++ Mathematical Expression Toolkit Library * * * * Simple Example 13 * - * Author: Arash Partow (1999-2022) * - * URL: http://www.partow.net/programming/exprtk/index.html * + * Author: Arash Partow (1999-2023) * + * URL: https://www.partow.net/programming/exprtk/index.html * * * * Copyright notice: * * Free use of the Mathematical Expression Toolkit Library is * * permitted under the guidelines and in accordance with the * * most current version of the MIT License. * - * http://www.opensource.org/licenses/MIT * + * https://www.opensource.org/licenses/MIT * * * ************************************************************** */ diff --git a/exprtk_simple_example_14.cpp b/exprtk_simple_example_14.cpp index 887ce57..259067b 100644 --- a/exprtk_simple_example_14.cpp +++ b/exprtk_simple_example_14.cpp @@ -3,14 +3,14 @@ * C++ Mathematical Expression Toolkit Library * * * * Simple Example 14 * - * Author: Arash Partow (1999-2022) * - * URL: http://www.partow.net/programming/exprtk/index.html * + * Author: Arash Partow (1999-2023) * + * URL: https://www.partow.net/programming/exprtk/index.html * * * * Copyright notice: * * Free use of the Mathematical Expression Toolkit Library is * * permitted under the guidelines and in accordance with the * * most current version of the MIT License. * - * http://www.opensource.org/licenses/MIT * + * https://www.opensource.org/licenses/MIT * * * ************************************************************** */ diff --git a/exprtk_simple_example_15.cpp b/exprtk_simple_example_15.cpp index 011514a..7affeb7 100644 --- a/exprtk_simple_example_15.cpp +++ b/exprtk_simple_example_15.cpp @@ -3,14 +3,14 @@ * C++ Mathematical Expression Toolkit Library * * * * Simple Example 15 * - * Author: Arash Partow (1999-2022) * - * URL: http://www.partow.net/programming/exprtk/index.html * + * Author: Arash Partow (1999-2023) * + * URL: https://www.partow.net/programming/exprtk/index.html * * * * Copyright notice: * * Free use of the Mathematical Expression Toolkit Library is * * permitted under the guidelines and in accordance with the * * most current version of the MIT License. * - * http://www.opensource.org/licenses/MIT * + * https://www.opensource.org/licenses/MIT * * * ************************************************************** */ diff --git a/exprtk_simple_example_16.cpp b/exprtk_simple_example_16.cpp index e7e8ef4..2480500 100644 --- a/exprtk_simple_example_16.cpp +++ b/exprtk_simple_example_16.cpp @@ -3,14 +3,14 @@ * C++ Mathematical Expression Toolkit Library * * * * Simple Example 16 * - * Author: Arash Partow (1999-2022) * - * URL: http://www.partow.net/programming/exprtk/index.html * + * Author: Arash Partow (1999-2023) * + * URL: https://www.partow.net/programming/exprtk/index.html * * * * Copyright notice: * * Free use of the Mathematical Expression Toolkit Library is * * permitted under the guidelines and in accordance with the * * most current version of the MIT License. * - * http://www.opensource.org/licenses/MIT * + * https://www.opensource.org/licenses/MIT * * * ************************************************************** */ diff --git a/exprtk_simple_example_17.cpp b/exprtk_simple_example_17.cpp index 9345eeb..24ae15b 100644 --- a/exprtk_simple_example_17.cpp +++ b/exprtk_simple_example_17.cpp @@ -3,14 +3,14 @@ * C++ Mathematical Expression Toolkit Library * * * * Simple Example 17 * - * Author: Arash Partow (1999-2022) * - * URL: http://www.partow.net/programming/exprtk/index.html * + * Author: Arash Partow (1999-2023) * + * URL: https://www.partow.net/programming/exprtk/index.html * * * * Copyright notice: * * Free use of the Mathematical Expression Toolkit Library is * * permitted under the guidelines and in accordance with the * * most current version of the MIT License. * - * http://www.opensource.org/licenses/MIT * + * https://www.opensource.org/licenses/MIT * * * ************************************************************** */ diff --git a/exprtk_simple_example_18.cpp b/exprtk_simple_example_18.cpp index de8ee31..ad4631e 100644 --- a/exprtk_simple_example_18.cpp +++ b/exprtk_simple_example_18.cpp @@ -3,14 +3,14 @@ * C++ Mathematical Expression Toolkit Library * * * * Simple Example 18 * - * Author: Arash Partow (1999-2022) * - * URL: http://www.partow.net/programming/exprtk/index.html * + * Author: Arash Partow (1999-2023) * + * URL: https://www.partow.net/programming/exprtk/index.html * * * * Copyright notice: * * Free use of the Mathematical Expression Toolkit Library is * * permitted under the guidelines and in accordance with the * * most current version of the MIT License. * - * http://www.opensource.org/licenses/MIT * + * https://www.opensource.org/licenses/MIT * * * ************************************************************** */ diff --git a/exprtk_simple_example_19.cpp b/exprtk_simple_example_19.cpp index 8401582..7929b8b 100644 --- a/exprtk_simple_example_19.cpp +++ b/exprtk_simple_example_19.cpp @@ -3,14 +3,14 @@ * C++ Mathematical Expression Toolkit Library * * * * Simple Example 19 * - * Author: Arash Partow (1999-2022) * - * URL: http://www.partow.net/programming/exprtk/index.html * + * Author: Arash Partow (1999-2023) * + * URL: https://www.partow.net/programming/exprtk/index.html * * * * Copyright notice: * * Free use of the Mathematical Expression Toolkit Library is * * permitted under the guidelines and in accordance with the * * most current version of the MIT License. * - * http://www.opensource.org/licenses/MIT * + * https://www.opensource.org/licenses/MIT * * * ************************************************************** */ diff --git a/exprtk_test.cpp b/exprtk_test.cpp index 1aa78ad..65661d7 100644 --- a/exprtk_test.cpp +++ b/exprtk_test.cpp @@ -3,14 +3,14 @@ * C++ Mathematical Expression Toolkit Library * * * * Examples and Unit-Tests * - * Author: Arash Partow (1999-2022) * - * URL: http://www.partow.net/programming/exprtk/index.html * + * Author: Arash Partow (1999-2023) * + * URL: https://www.partow.net/programming/exprtk/index.html * * * * Copyright notice: * * Free use of the Mathematical Expression Toolkit Library is * * permitted under the guidelines and in accordance with the * * most current version of the MIT License. * - * http://www.opensource.org/licenses/MIT * + * https://www.opensource.org/licenses/MIT * * * ************************************************************** */ @@ -5072,12 +5072,6 @@ inline bool run_test11() } } - if (!exprtk::pgo_primer()) - { - printf("run_test11() - Failed PGO primer\n"); - return false; - } - return true; } @@ -7206,7 +7200,7 @@ inline bool run_test18() { v.rebase(v0.data() + i); - T sum = expression.value(); + const T sum = expression.value(); if (not_equal(sum,s[i])) { @@ -7259,7 +7253,7 @@ inline bool run_test18() return false; } - const T expected_result0 = std::accumulate(v0, v0 + v0_size,T(0)); + const T expected_result0 = std::accumulate(v0, v0 + v0_size, T(0)); if (expression.value() != expected_result0) { @@ -7273,7 +7267,7 @@ inline bool run_test18() v.rebase(v1); - const T expected_result1 = std::accumulate(v1, v1 + v1_size,T(0)); + const T expected_result1 = std::accumulate(v1, v1 + v1_size, T(0)); if (expression.value() != expected_result1) { @@ -8436,7 +8430,7 @@ inline bool run_test19() const T result = expression.value(); - if (not_equal(result,std::sqrt(x),T(0.0000001))) + if (not_equal(result, std::sqrt(x), T(0.0000001))) { printf("run_test19() - Computation Error " "Expression: [%s]\tExpected: %12.8f\tResult: %12.8f\n", @@ -9060,17 +9054,17 @@ inline bool run_test21() typedef exprtk::expression expression_t; typedef exprtk::parser parser_t; - T x = T(1.1); - T y = T(2.2); - T z = T(3.3); - - symbol_table_t symbol_table; - symbol_table.add_constants(); - symbol_table.add_variable("x",x); - symbol_table.add_variable("y",y); - symbol_table.add_variable("z",z); - { + T x = T(1.1); + T y = T(2.2); + T z = T(3.3); + + symbol_table_t symbol_table; + symbol_table.add_constants(); + symbol_table.add_variable("x",x); + symbol_table.add_variable("y",y); + symbol_table.add_variable("z",z); + static const std::string expression_list[] = { "return[]; x;", @@ -9169,6 +9163,16 @@ inline bool run_test21() } { + T x = T(1.1); + T y = T(2.2); + T z = T(3.3); + + symbol_table_t symbol_table; + symbol_table.add_constants(); + symbol_table.add_variable("x",x); + symbol_table.add_variable("y",y); + symbol_table.add_variable("z",z); + static const std::string expression_list[] = { "x := 1; x + 1; x + 2; x + 3; x + 5; x + 7; return [x + 1]; ", @@ -9260,6 +9264,86 @@ inline bool run_test21() return false; } + { + const std::string invalid_expressions[] = + { + "x := 1", + "x += 1", + "v := 1 + v", + "v += 1", + "v += x + 1", + "v += v", + "v[0] += x", + "v[1] += x", + "v[2] += x", + "v[3] += x", + "v[4] += x", + "var i := 2; v[i] := x", + "var i := 2; v[i] += x", + "s := 'abc' + s", + "s[0:2] := 'abc'", + "s[1:3] := 'abc'", + "aa[4:4] := bb", + "aa[1:3] := bb", + "var i := 2; aa[i:3] := bb", + "var i := 2; aa[i+1:3] := bb", + "var i := 2; aa[0:i] := bb", + "var i := 2; aa[0:i+1] := bb", + "var i := 1; var j := 3; aa[i:j] := bb", + "var i := 1; var j := 3; aa[i+1:j] := bb", + "var i := 1; var j := 3; aa[i:j+1] := bb", + "var i := 1; var j := 3; aa[i+1:j+1] := bb", + }; + + const std::size_t invalid_expressions_size = sizeof(invalid_expressions) / sizeof(std::string); + + for (std::size_t i = 0; i < invalid_expressions_size; ++i) + { + symbol_table_t mutable_symbol_table; + symbol_table_t immutable_symbol_table(symbol_table_t::e_immutable); + + T x = 0.0; + T v[5]; + std::string s = "xyz"; + std::string aa = "0123456789"; + std::string bb = "A"; + + T x_ = 0.0; + T v_[5]; + std::string s_ = "xyz"; + + std::string a_ = "0123456789"; + std::string b_ = "A"; + + immutable_symbol_table.add_variable ("x" , x ); + immutable_symbol_table.add_vector ("v" , v ); + immutable_symbol_table.add_stringvar("s" , s ); + immutable_symbol_table.add_stringvar("aa", aa); + immutable_symbol_table.add_stringvar("bb", bb); + + mutable_symbol_table.add_variable ("x_", x_); + mutable_symbol_table.add_vector ("v_", v_); + mutable_symbol_table.add_stringvar ("s_", s_); + mutable_symbol_table.add_stringvar ("a_", a_); + mutable_symbol_table.add_stringvar ("b_", b_); + + const std::string& expression_str = invalid_expressions[i]; + expression_t expression; + expression.register_symbol_table(immutable_symbol_table); + expression.register_symbol_table(mutable_symbol_table ); + + parser_t parser; + const bool compile_result = parser.compile(expression_str, expression); + + if (compile_result) + { + expression.value(); + printf("run_test21() - Invalid expression due to immutability was successfully compiled. Expression: %s\n", + expression_str.c_str()); + } + } + } + return true; } diff --git a/readme.txt b/readme.txt index f0d363c..e1e0275 100644 --- a/readme.txt +++ b/readme.txt @@ -115,7 +115,7 @@ Free use of the C++ Mathematical Expression Toolkit Library is permitted under the guidelines and in accordance with the most current version of the MIT License. -http://www.opensource.org/licenses/MIT +https://www.opensource.org/licenses/MIT ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -707,7 +707,7 @@ the expression instance and to also allow the expression to be evaluated using the current value of the element. Note: Any variable reference provided to a given symbol_table -instance, must have a life time at least as long as the life-time of +instance, must have a life-time at least as long as the life-time of the symbol_table instance. In the event the variable reference is invalidated before the symbol_table or any dependent expression instances have been destructed, then any associated expression @@ -868,6 +868,66 @@ a false result due to one or more of the following reasons: 6. The symbol_table instance is in an invalid state +A further property of symbol tables is that they can be classified at +instantiation as either being mutable (by default) or immutable. The +following demonstrates construction of an immutable symbol table +instance: + + symbol_table_t immutable_symbol_table + (symbol_table_t::symtab_mutability_type::e_immutable); + + +When a symbol table, that has been constructed as being immutable, is +registered with an expression, any statements in the expression string +that modify the variables that are managed by the immutable symbol +table will result in a compilation error. The operations that trigger +the mutability constraint are the following assignment operators: + + 1. Assignment: := + 2. Assign operation: +=, -=, *=, /= , %= + + +The main reason for this functionality is that, one may want the +immutability properties that come with constness of a variable such as +scalars, vectors and strings, but not necessarily the accompanying +compile time const-folding optimisations, that would result in the +value of the variables being retrieved only once at compile time, +causing external updates to the variables to not be part of the +expression evaluation. + + symbol_table_t immutable_symbol_table + (symbol_table_t::symtab_mutability_type::e_immutable); + + T x = 0.0; + + const std::string expression_str = "x + (y + y)"; + + immutable_symbol_table.add_variable("x" , x ); + immutable_symbol_table.add_constant("y" , 123.0); + + expression_t expression; + expression.register_symbol_table(immutabile_symbol_table); + + parser_t parser; + parser.compile(expression_str, expression) + + for (; x < 10.0; ++x) + { + const auto expected_value = x + (123.0 + 123.0); + const auto result_value = expression.value(); + assert(expression.value() != expected_value); + } + + +In the above example, there are two variables X and Y. Where Y is a +constant and X is a normal variable. Both are registered with a symbol +table that is immutable. The expression when compiled will result in +the "(y + y)" part being const-folded at compile time to the literal +value of 246. Whereas the current value of X, being updated via the +for-loop, externally to the expression and the symbol table will be +available to the expression upon each evaluation. + + (2) Expression A structure that holds an Abstract Syntax Tree or AST for a specified expression and is used to evaluate said expression. Evaluation of the @@ -1020,7 +1080,7 @@ 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, it will then result in two or more identical expressions -utilizing the exact same references for variables. This obviously is +utilising 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 multi-threading et al. @@ -1110,6 +1170,7 @@ enabled by default. The options and their explanations are as follows: (5) Sequence Check (6) Commutative Check (7) Strength Reduction Check + (8) Stack And Node Depth Check (1) Replacer (e_replacer) @@ -1218,6 +1279,43 @@ desired over the strength reduced form. In these situations it is best to turn off strength reduction optimisations or to use a type with a larger numerical bound. + +(8) Stack And Node Depth Check +ExprTk incorporates a recursive descent parser. When parsing +expressions comprising inner sub-expressions, the recursive nature of +the parsing process causes the stack to grow. If the expression causes +the stack to grow beyond the stack size limit, this would lead to a +stackoverflow and its associated stack corruption and security +vulnerability issues. + +Similarly to parsing, evaluating an expression may cause the stack to +grow. Such things like user defined functions, composite functions and +the general nature of the AST being evaluated can cause the stack to +grow, and may result in potential stackoverflow issues as denoted +above. + +ExprTk provides a set of checks that prevent both of the above denoted +problems at compile time. These check rely on two specific limits +being set on the parser instance, these limits are: + + 1. max_stack_depth (default: 400) + 2. max_node_depth (default: 10000) + + +The following demonstrates how these two parser parameters can be set: + + parser_t parser; + + parser.set_max_stack_depth(100); + parser.set_max_node_depth(200); + + +In the above code, during parsing if the stack depth reaches or +exceeds 100 levels, the parsing process will immediately halt and +return with a failure. Similarly, during synthesizing the AST nodes, +if the compilation process detects an AST tree depth exceeding 200 +levels the parsing process will halt and return a parsing failure. + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ [SECTION 12 - EXPRESSION STRUCTURES] @@ -1780,7 +1878,7 @@ value is not a vector but rather a single value. sum(x > 0 and x < 5) == x[] -When utilizing external user defined vectors via the symbol table as +When utilising external user defined vectors via the symbol table as opposed to expression local defined vectors, the typical 'add_vector' method from the symbol table will register the entirety of the vector that is passed. The following example attempts to evaluate the sum of @@ -3489,7 +3587,7 @@ ExprTk reserved words, the add_function call will fail. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ [SECTION 20 - EXPRESSION RETURN VALUES] -ExprTk expressions can return immediately from any point by utilizing +ExprTk expressions can return immediately from any point by utilising the return call. Furthermore the return call can be used to transfer out multiple return values from within the expression. @@ -4591,52 +4689,58 @@ part of a compiler command line switch or scoped around the include to the ExprTk header. The defines are as follows: (01) exprtk_enable_debugging - (02) exprtk_disable_comments - (03) exprtk_disable_break_continue - (04) exprtk_disable_sc_andor - (05) exprtk_disable_return_statement - (06) exprtk_disable_enhanced_features - (07) exprtk_disable_string_capabilities - (08) exprtk_disable_superscalar_unroll - (09) exprtk_disable_rtl_io_file - (10) exprtk_disable_rtl_vecops - (11) exprtk_disable_caseinsensitivity - + (02) exprtk_disable_cardinal_pow_optimisation + (03) exprtk_disable_comments + (04) exprtk_disable_break_continue + (05) exprtk_disable_sc_andor + (06) exprtk_disable_return_statement + (07) exprtk_disable_enhanced_features + (08) exprtk_disable_string_capabilities + (09) exprtk_disable_superscalar_unroll + (10) exprtk_disable_rtl_io + (11) exprtk_disable_rtl_io_file + (12) exprtk_disable_rtl_vecops + (13) exprtk_disable_caseinsensitivity + (14) exprtk_enable_range_runtime_checks (01) exprtk_enable_debugging This define will enable printing of debug information to stdout during the compilation process. -(02) exprtk_disable_comments +(02) exprtk_disable_cardinal_pow_optimisation +This define will disable the optimisation invoked when constant +integers are used as powers in exponentiation expressions (eg: x^7). + +(03) exprtk_disable_comments This define will disable the ability for expressions to have comments. Expressions that have comments when parsed with a build that has this option, will result in a compilation failure. -(03) exprtk_disable_break_continue +(04) exprtk_disable_break_continue This define will disable the loop-wise 'break' and 'continue' capabilities. Any expression that contains those keywords will result in a compilation failure. -(04) exprtk_disable_sc_andor +(05) exprtk_disable_sc_andor This define will disable the short-circuit '&' (and) and '|' (or) operators -(05) exprtk_disable_return_statement +(06) exprtk_disable_return_statement This define will disable use of return statements within expressions. -(06) exprtk_disable_enhanced_features +(07) exprtk_disable_enhanced_features This define will disable all enhanced features such as strength reduction and special function optimisations and expression specific type instantiations. This feature will reduce compilation times and binary sizes but will also result in massive performance degradation of expression evaluations. -(07) exprtk_disable_string_capabilities +(08) exprtk_disable_string_capabilities This define will disable all string processing capabilities. Any expression that contains a string or string related syntax will result in a compilation failure. -(08) exprtk_disable_superscalar_unroll +(09) exprtk_disable_superscalar_unroll This define will set the loop unroll batch size to 4 operations per loop instead of the default 8 operations. This define is used in operations that involve vectors and aggregations over vectors. When @@ -4644,22 +4748,32 @@ targeting non-superscalar architectures, it may be recommended to build using this particular option if efficiency of evaluations is of concern. -(09) exprtk_disable_rtl_io_file +(10) exprtk_disable_rtl_io +This define will disable all of basic IO RTL package features. When +present, any attempt to register the basic IO RTL package with a given +symbol table will fail causing a compilation error. + +(11) exprtk_disable_rtl_io_file This define will disable the file I/O RTL package features. When present, any attempts to register the file I/O package with a given symbol table will fail causing a compilation error. -(10) exprtk_disable_rtl_vecops +(12) exprtk_disable_rtl_vecops This define will disable the extended vector operations RTL package features. When present, any attempts to register the vector operations package with a given symbol table will fail causing a compilation error. -(11) exprtk_disable_caseinsensitivity +(13) exprtk_disable_caseinsensitivity This define will disable case-insensitivity when matching variables and functions. Furthermore all reserved and keywords will only be acknowledged when in all lower-case. +(14) exprtk_enable_range_runtime_checks +This define will enable run-time checks pertaining to vector indexing +operations used in any of the vector-to-vector and vector-to-scalar +operations. + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ [SECTION 28 - FILES]