From c7c219480d9678eec7383a4a99030683c4a84d91 Mon Sep 17 00:00:00 2001 From: Arash Partow Date: Wed, 1 Jan 2020 00:00:00 +0000 Subject: [PATCH] C++ Mathematical Expression Library (ExprTk) http://www.partow.net/programming/exprtk/index.html --- .circleci/config.yml | 34 + .travis.yml | 12 - Makefile | 45 +- exprtk.hpp | 6739 +++++++++++++++++++++------------- exprtk_benchmark.cpp | 2 +- exprtk_simple_example_01.cpp | 10 +- exprtk_simple_example_02.cpp | 24 +- exprtk_simple_example_03.cpp | 8 +- exprtk_simple_example_04.cpp | 5 +- exprtk_simple_example_05.cpp | 7 +- exprtk_simple_example_06.cpp | 5 +- exprtk_simple_example_07.cpp | 7 +- exprtk_simple_example_08.cpp | 9 +- exprtk_simple_example_09.cpp | 9 +- exprtk_simple_example_10.cpp | 42 +- exprtk_simple_example_11.cpp | 9 +- exprtk_simple_example_12.cpp | 5 +- exprtk_simple_example_13.cpp | 7 +- exprtk_simple_example_14.cpp | 7 +- exprtk_simple_example_15.cpp | 9 +- exprtk_simple_example_16.cpp | 5 +- exprtk_simple_example_17.cpp | 4 +- exprtk_simple_example_18.cpp | 4 +- exprtk_simple_example_19.cpp | 6 +- exprtk_test.cpp | 836 ++++- readme.txt | 209 +- 26 files changed, 5396 insertions(+), 2663 deletions(-) create mode 100644 .circleci/config.yml delete mode 100644 .travis.yml diff --git a/.circleci/config.yml b/.circleci/config.yml new file mode 100644 index 0000000..8e95be7 --- /dev/null +++ b/.circleci/config.yml @@ -0,0 +1,34 @@ +version: 2.1 +jobs: + + build_gcc_6: + docker: + - image: gcc:6 + steps: + - checkout + - run: make all -j 2 + - run: ./exprtk_test + + build_gcc_7: + docker: + - image: gcc:7 + steps: + - checkout + - run: make all -j 2 + - run: ./exprtk_test + + build_gcc_latest: + docker: + - image: gcc:latest + steps: + - checkout + - run: make all -j 2 + - run: ./exprtk_test + +workflows: + version: 2 + build_and_test: + jobs: + - build_gcc_6 + - build_gcc_7 + - build_gcc_latest diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 5ce5a53..0000000 --- a/.travis.yml +++ /dev/null @@ -1,12 +0,0 @@ -language: cpp - -sudo: required - -dist: trusty - -compiler: - - gcc - -script: - - make clean all - - ./exprtk_test diff --git a/Makefile b/Makefile index bc602a3..76d43a0 100644 --- a/Makefile +++ b/Makefile @@ -2,7 +2,7 @@ # ************************************************************** # * C++ Mathematical Expression Toolkit Library * # * * -# * Author: Arash Partow (1999-2018) * +# * Author: Arash Partow (1999-2020) * # * URL: http://www.partow.net/programming/exprtk/index.html * # * * # * Copyright notice: * @@ -15,37 +15,18 @@ # -COMPILER = -c++ -#COMPILER = -clang -OPTIMIZATION_OPT = -O1 -BASE_OPTIONS = -pedantic-errors -Wall -Wextra -Werror -Wno-long-long -OPTIONS = $(BASE_OPTIONS) $(OPTIMIZATION_OPT) -LINKER_OPT = -L/usr/lib -lstdc++ -lm -ASAN_OPT = -g -fsanitize=address -fno-omit-frame-pointer -MSAN_OPT = -g -fsanitize=memory -fno-omit-frame-pointer -LSAN_OPT = -g -fsanitize=leak -fno-omit-frame-pointer - -BUILD_LIST+=exprtk_test -BUILD_LIST+=exprtk_benchmark -BUILD_LIST+=exprtk_simple_example_01 -BUILD_LIST+=exprtk_simple_example_02 -BUILD_LIST+=exprtk_simple_example_03 -BUILD_LIST+=exprtk_simple_example_04 -BUILD_LIST+=exprtk_simple_example_05 -BUILD_LIST+=exprtk_simple_example_06 -BUILD_LIST+=exprtk_simple_example_07 -BUILD_LIST+=exprtk_simple_example_08 -BUILD_LIST+=exprtk_simple_example_09 -BUILD_LIST+=exprtk_simple_example_10 -BUILD_LIST+=exprtk_simple_example_11 -BUILD_LIST+=exprtk_simple_example_12 -BUILD_LIST+=exprtk_simple_example_13 -BUILD_LIST+=exprtk_simple_example_14 -BUILD_LIST+=exprtk_simple_example_15 -BUILD_LIST+=exprtk_simple_example_16 -BUILD_LIST+=exprtk_simple_example_17 -BUILD_LIST+=exprtk_simple_example_18 -BUILD_LIST+=exprtk_simple_example_19 +COMPILER := -c++ +#COMPILER := -clang++ +OPTIMIZATION_OPT := -O1 +BASE_OPTIONS := -pedantic-errors -Wall -Wextra -Werror -Wno-long-long +OPTIONS := $(BASE_OPTIONS) $(OPTIMIZATION_OPT) +LINKER_OPT := -L/usr/lib -lstdc++ -lm +ASAN_OPT := -g -fsanitize=address -fno-omit-frame-pointer +MSAN_OPT := -g -fsanitize=memory -fno-omit-frame-pointer +LSAN_OPT := -g -fsanitize=leak -fno-omit-frame-pointer +USAN_OPT := -g -fsanitize=undefined -fno-omit-frame-pointer +BUILD_SRC := $(sort $(wildcard exprtk_*.cpp)) +BUILD_LIST := $(BUILD_SRC:%.cpp=%) all: $(BUILD_LIST) diff --git a/exprtk.hpp b/exprtk.hpp index 2e62bf5..0b2081e 100644 --- a/exprtk.hpp +++ b/exprtk.hpp @@ -2,7 +2,7 @@ ****************************************************************** * C++ Mathematical Expression Toolkit Library * * * - * Author: Arash Partow (1999-2018) * + * Author: Arash Partow (1999-2020) * * URL: http://www.partow.net/programming/exprtk/index.html * * * * Copyright notice: * @@ -35,6 +35,7 @@ #include +#include #include #include #include @@ -67,7 +68,7 @@ namespace exprtk #define exprtk_error_location \ "exprtk.hpp:" + details::to_str(__LINE__) \ - #if __GNUC__ >= 7 + #if defined(__GNUC__) && (__GNUC__ >= 7) #define exprtk_disable_fallthrough_begin \ _Pragma ("GCC diagnostic push") \ @@ -83,8 +84,14 @@ namespace exprtk namespace details { - typedef unsigned char uchar_t; - typedef char char_t; + typedef unsigned char uchar_t; + typedef char char_t; + typedef uchar_t* uchar_ptr; + typedef char_t* char_ptr; + typedef uchar_t const* uchar_cptr; + typedef char_t const* char_cptr; + typedef unsigned long long int _uint64_t; + typedef long long int _int64_t; inline bool is_whitespace(const char_t c) { @@ -158,6 +165,12 @@ namespace exprtk ('\'' != c); } + inline bool is_valid_string_char(const char_t c) + { + return std::isprint(static_cast(c)) || + is_whitespace(c); + } + #ifndef exprtk_disable_caseinsensitivity inline void case_normalise(std::string& s) { @@ -304,31 +317,30 @@ namespace exprtk } template - inline void parse_hex(Iterator& itr, Iterator end, std::string::value_type& result) + inline bool parse_hex(Iterator& itr, Iterator end, + std::string::value_type& result) { if ( - (end != (itr )) && - (end != (itr + 1)) && - (end != (itr + 2)) && - (end != (itr + 3)) && - ('0' == *(itr )) && - ( - ('x' == *(itr + 1)) || - ('X' == *(itr + 1)) - ) && - (is_hex_digit(*(itr + 2))) && - (is_hex_digit(*(itr + 3))) + (end == (itr )) || + (end == (itr + 1)) || + (end == (itr + 2)) || + (end == (itr + 3)) || + ('0' != *(itr )) || + ('X' != std::toupper(*(itr + 1))) || + (!is_hex_digit(*(itr + 2))) || + (!is_hex_digit(*(itr + 3))) ) { - result = hex_to_bin(static_cast(*(itr + 2))) << 4 | - hex_to_bin(static_cast(*(itr + 3))) ; - itr += 3; + return false; } - else - result = '\0'; + + result = hex_to_bin(static_cast(*(itr + 2))) << 4 | + hex_to_bin(static_cast(*(itr + 3))) ; + + return true; } - inline void cleanup_escapes(std::string& s) + inline bool cleanup_escapes(std::string& s) { typedef std::string::iterator str_itr_t; @@ -342,36 +354,41 @@ namespace exprtk { if ('\\' == (*itr1)) { - ++removal_count; - if (end == ++itr1) - break; - else if ('\\' != (*itr1)) { - switch (*itr1) - { - case 'n' : (*itr1) = '\n'; break; - case 'r' : (*itr1) = '\r'; break; - case 't' : (*itr1) = '\t'; break; - case '0' : parse_hex(itr1, end, (*itr1)); - removal_count += 3; - break; - } - - continue; + return false; } + else if (parse_hex(itr1, end, *itr2)) + { + itr1+= 4; + itr2+= 1; + removal_count +=4; + } + else if ('a' == (*itr1)) { (*itr2++) = '\a'; ++itr1; ++removal_count; } + else if ('b' == (*itr1)) { (*itr2++) = '\b'; ++itr1; ++removal_count; } + else if ('f' == (*itr1)) { (*itr2++) = '\f'; ++itr1; ++removal_count; } + else if ('n' == (*itr1)) { (*itr2++) = '\n'; ++itr1; ++removal_count; } + else if ('r' == (*itr1)) { (*itr2++) = '\r'; ++itr1; ++removal_count; } + else if ('t' == (*itr1)) { (*itr2++) = '\t'; ++itr1; ++removal_count; } + else if ('v' == (*itr1)) { (*itr2++) = '\v'; ++itr1; ++removal_count; } + else if ('0' == (*itr1)) { (*itr2++) = '\0'; ++itr1; ++removal_count; } + else + { + (*itr2++) = (*itr1++); + ++removal_count; + } + continue; } - - if (itr1 != itr2) - { - (*itr2) = (*itr1); - } - - ++itr1; - ++itr2; + else + (*itr2++) = (*itr1++); } + if ((removal_count > s.size()) || (0 == removal_count)) + return false; + s.resize(s.size() - removal_count); + + return true; } class build_string @@ -389,7 +406,7 @@ namespace exprtk return (*this); } - inline build_string& operator << (const char_t* s) + inline build_string& operator << (char_cptr s) { data_ += std::string(s); return (*this); @@ -576,83 +593,82 @@ namespace exprtk template inline bool match_impl(const Iterator pattern_begin, - const Iterator pattern_end, - const Iterator data_begin, - const Iterator data_end, + const Iterator pattern_end , + const Iterator data_begin , + const Iterator data_end , const typename std::iterator_traits::value_type& zero_or_more, - const typename std::iterator_traits::value_type& zero_or_one) + const typename std::iterator_traits::value_type& zero_or_one ) { - if (0 == std::distance(data_begin,data_end)) - { - return false; - } + const Iterator null_itr(0); - Iterator d_itr = data_begin; - Iterator p_itr = pattern_begin; - Iterator c_itr = data_begin; - Iterator m_itr = data_begin; + Iterator d_itr = data_begin; + Iterator p_itr = pattern_begin; + Iterator tb_p_itr = null_itr; + Iterator tb_d_itr = null_itr; - while ((data_end != d_itr) && (zero_or_more != (*p_itr))) + while (d_itr != data_end) { - if ((!Compare::cmp((*p_itr),(*d_itr))) && (zero_or_one != (*p_itr))) + if (zero_or_more == *p_itr) { - return false; - } + while ((pattern_end != p_itr) && ((zero_or_more == *p_itr) || (zero_or_one == *p_itr))) + { + ++p_itr; + } - ++p_itr; - ++d_itr; - } + if (pattern_end == p_itr) + return true; - while (data_end != d_itr) - { - if (zero_or_more == (*p_itr)) - { - if (pattern_end == (++p_itr)) + const typename std::iterator_traits::value_type c = *(p_itr); + + while ((data_end != d_itr) && !Compare::cmp(c,*d_itr)) { - return true; + ++d_itr; } - m_itr = p_itr; - c_itr = d_itr; - ++c_itr; - } - else if ((Compare::cmp((*p_itr),(*d_itr))) || (zero_or_one == (*p_itr))) - { - ++p_itr; - ++d_itr; + tb_p_itr = p_itr; + tb_d_itr = d_itr; + + continue; } - else + else if (!Compare::cmp(*p_itr, *d_itr) && (zero_or_one != *p_itr)) { - p_itr = m_itr; - d_itr = c_itr++; + if (null_itr == tb_d_itr) + return false; + + d_itr = tb_d_itr++; + p_itr = tb_p_itr; + + continue; } + + ++p_itr; + ++d_itr; } - while ((p_itr != pattern_end) && (zero_or_more == (*p_itr))) { ++p_itr; } + while ((pattern_end != p_itr) && ((zero_or_more == *p_itr) || (zero_or_one == *p_itr))) + { + ++p_itr; + } - return (p_itr == pattern_end); + return (pattern_end == p_itr); } inline bool wc_match(const std::string& wild_card, const std::string& str) { - return match_impl(wild_card.data(), - wild_card.data() + wild_card.size(), - str.data(), - str.data() + str.size(), - '*', - '?'); + return match_impl( + wild_card.data(), wild_card.data() + wild_card.size(), + str.data(), str.data() + str.size(), + '*', '?'); } inline bool wc_imatch(const std::string& wild_card, const std::string& str) { - return match_impl(wild_card.data(), - wild_card.data() + wild_card.size(), - str.data(), - str.data() + str.size(), - '*', - '?'); + return match_impl( + wild_card.data(), wild_card.data() + wild_card.size(), + str.data(), str.data() + str.size(), + '*', '?'); } inline bool sequence_match(const std::string& pattern, @@ -733,7 +749,7 @@ namespace exprtk 1.0E+013, 1.0E+014, 1.0E+015, 1.0E+016 }; - static const std::size_t pow10_size = sizeof(pow10) / sizeof(double); + static const std::size_t pow10_size = sizeof(pow10) / sizeof(double); namespace numeric { @@ -785,12 +801,12 @@ namespace exprtk 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(long long int ) - exprtk_register_int_type_tag(unsigned short ) - exprtk_register_int_type_tag(unsigned int ) - exprtk_register_int_type_tag(unsigned long long int) + exprtk_register_int_type_tag(short ) + exprtk_register_int_type_tag(int ) + exprtk_register_int_type_tag(_int64_t ) + exprtk_register_int_type_tag(unsigned short) + exprtk_register_int_type_tag(unsigned int ) + exprtk_register_int_type_tag(_uint64_t ) #undef exprtk_register_real_type_tag #undef exprtk_register_int_type_tag @@ -838,9 +854,9 @@ namespace exprtk } template - inline long long int to_int64_impl(const T v, real_type_tag) + inline _int64_t to_int64_impl(const T v, real_type_tag) { - return static_cast(v); + return static_cast<_int64_t>(v); } template @@ -1316,8 +1332,8 @@ namespace exprtk template inline T frac_impl(const T v, real_type_tag) { return (v - static_cast(v)); } template inline T trunc_impl(const T v, real_type_tag) { return T(static_cast(v)); } - template inline T const_pi_impl(real_type_tag) { return numeric::constant::pi; } - template inline T const_e_impl (real_type_tag) { return numeric::constant::e; } + template inline T const_pi_impl(real_type_tag) { return T(numeric::constant::pi); } + template inline T const_e_impl (real_type_tag) { return T(numeric::constant::e); } template inline T abs_impl(const T v, int_type_tag) { return ((v >= T(0)) ? v : -v); } template inline T exp_impl(const T v, int_type_tag) { return std::exp (v); } @@ -1378,7 +1394,7 @@ namespace exprtk } template - inline long long int to_int64(const T v) + inline _int64_t to_int64(const T v) { const typename details::number_type::type num_type; return to_int64_impl(v, num_type); @@ -1798,7 +1814,7 @@ namespace exprtk if ((3 != length) && (inf_length != length)) return false; - const char_t* inf_itr = ('i' == (*itr)) ? inf_lc : inf_uc; + char_cptr inf_itr = ('i' == (*itr)) ? inf_lc : inf_uc; while (end != itr) { @@ -1820,6 +1836,13 @@ namespace exprtk return true; } + template + inline bool valid_exponent(const int exponent, numeric::details::real_type_tag) + { + return (std::numeric_limits::min_exponent10 <= exponent) && + (exponent <= std::numeric_limits::max_exponent10) ; + } + template inline bool string_to_real(Iterator& itr_external, const Iterator end, T& t, numeric::details::real_type_tag) { @@ -1839,7 +1862,7 @@ namespace exprtk bool instate = false; - static const char zero = static_cast('0'); + static const char_t zero = static_cast('0'); #define parse_digit_1(d) \ if ((digit = (*itr - zero)) < 10) \ @@ -1860,12 +1883,12 @@ namespace exprtk while ((end != itr) && (zero == (*itr))) ++itr; - unsigned int digit; - while (end != itr) { // Note: For 'physical' superscalar architectures it // is advised that the following loop be: 4xPD1 and 1xPD2 + unsigned int digit; + #ifdef exprtk_enable_superscalar parse_digit_1(d) parse_digit_1(d) @@ -1885,11 +1908,12 @@ namespace exprtk if ('.' == (*itr)) { const Iterator curr = ++itr; - unsigned int digit; T tmp_d = T(0); while (end != itr) { + unsigned int digit; + #ifdef exprtk_enable_superscalar parse_digit_1(tmp_d) parse_digit_1(tmp_d) @@ -1903,7 +1927,13 @@ namespace exprtk if (curr != itr) { instate = true; - d += compute_pow10(tmp_d,static_cast(-std::distance(curr,itr))); + + const int exponent = static_cast(-std::distance(curr, itr)); + + if (!valid_exponent(exponent, numeric::details::real_type_tag())) + return false; + + d += compute_pow10(tmp_d, exponent); } #undef parse_digit_1 @@ -1974,6 +2004,8 @@ namespace exprtk if ((end != itr) || (!instate)) return false; + else if (!valid_exponent(exponent, numeric::details::real_type_tag())) + return false; else if (exponent) d = compute_pow10(d,exponent); @@ -1986,8 +2018,8 @@ namespace exprtk { const typename numeric::details::number_type::type num_type; - const char_t* begin = s.data(); - const char_t* end = s.data() + s.size(); + char_cptr begin = s.data(); + char_cptr end = s.data() + s.size(); return string_to_real(begin, end, t, num_type); } @@ -2012,6 +2044,50 @@ namespace exprtk } // namespace details + struct loop_runtime_check + { + enum loop_types + { + e_invalid = 0, + e_for_loop = 1, + e_while_loop = 2, + e_repeat_until_loop = 4, + e_all_loops = 7 + }; + + enum violation_type + { + e_unknown = 0, + e_iteration_count = 1, + e_timeout = 2 + }; + + loop_types loop_set; + + loop_runtime_check() + : loop_set(e_invalid), + max_loop_iterations(0) + {} + + details::_uint64_t max_loop_iterations; + + struct violation_context + { + loop_types loop; + violation_type violation; + details::_uint64_t iteration_count; + }; + + virtual void handle_runtime_violation(const violation_context&) + { + throw std::runtime_error("ExprTk Loop run-time violation."); + } + + virtual ~loop_runtime_check() {} + }; + + typedef loop_runtime_check* loop_runtime_check_ptr; + namespace lexer { struct token @@ -2192,7 +2268,7 @@ namespace exprtk typedef token token_t; typedef std::vector token_list_t; - typedef std::vector::iterator token_list_itr_t; + typedef token_list_t::iterator token_list_itr_t; typedef details::char_t char_t; generator() @@ -2316,8 +2392,8 @@ namespace exprtk inline std::string substr(const std::size_t& begin, const std::size_t& end) { - const char_t* begin_itr = ((base_itr_ + begin) < s_end_) ? (base_itr_ + begin) : s_end_; - const char_t* end_itr = ((base_itr_ + end) < s_end_) ? (base_itr_ + end) : s_end_; + const details::char_cptr begin_itr = ((base_itr_ + begin) < s_end_) ? (base_itr_ + begin) : s_end_; + const details::char_cptr end_itr = ((base_itr_ + end) < s_end_) ? (base_itr_ + end) : s_end_; return std::string(begin_itr,end_itr); } @@ -2327,19 +2403,19 @@ namespace exprtk if (finished()) return ""; else if (token_list_.begin() != token_itr_) - return std::string(base_itr_ + (token_itr_ - 1)->position,s_end_); + return std::string(base_itr_ + (token_itr_ - 1)->position, s_end_); else - return std::string(base_itr_ + token_itr_->position,s_end_); + return std::string(base_itr_ + token_itr_->position, s_end_); } private: - inline bool is_end(const char_t* itr) + inline bool is_end(details::char_cptr itr) { return (s_end_ == itr); } - inline bool is_comment_start(const char_t* itr) + inline bool is_comment_start(details::char_cptr itr) { #ifndef exprtk_disable_comments const char_t c0 = *(itr + 0); @@ -2408,7 +2484,7 @@ namespace exprtk else if (!test::comment_start(*s_itr_, *(s_itr_ + 1), mode, increment)) return; - const char_t* cmt_start = s_itr_; + details::char_cptr cmt_start = s_itr_; s_itr_ += increment; @@ -2564,7 +2640,7 @@ namespace exprtk inline void scan_symbol() { - const char_t* initial_itr = s_itr_; + details::char_cptr initial_itr = s_itr_; while (!is_end(s_itr_)) { @@ -2615,11 +2691,11 @@ namespace exprtk (15) .1234e-3 */ - const char_t* initial_itr = s_itr_; - bool dot_found = false; - bool e_found = false; - bool post_e_sign_found = false; - bool post_e_digit_found = false; + details::char_cptr initial_itr = s_itr_; + bool dot_found = false; + bool e_found = false; + bool post_e_sign_found = false; + bool post_e_digit_found = false; token_t t; while (!is_end(s_itr_)) @@ -2630,6 +2706,7 @@ namespace exprtk { t.set_error(token::e_err_number, initial_itr, s_itr_, base_itr_); token_list_.push_back(t); + return; } @@ -2702,7 +2779,7 @@ namespace exprtk inline void scan_special_function() { - const char_t* initial_itr = s_itr_; + details::char_cptr initial_itr = s_itr_; token_t t; // $fdd(x,x,x) = at least 11 chars @@ -2738,13 +2815,14 @@ namespace exprtk #ifndef exprtk_disable_string_capabilities inline void scan_string() { - const char_t* initial_itr = s_itr_ + 1; + details::char_cptr initial_itr = s_itr_ + 1; token_t t; if (std::distance(s_itr_,s_end_) < 2) { t.set_error(token::e_err_string, s_itr_, s_end_, base_itr_); token_list_.push_back(t); + return; } @@ -2755,7 +2833,14 @@ namespace exprtk while (!is_end(s_itr_)) { - if (!escaped && ('\\' == *s_itr_)) + if (!details::is_valid_string_char(*s_itr_)) + { + t.set_error(token::e_err_string, initial_itr, s_itr_, base_itr_); + token_list_.push_back(t); + + return; + } + else if (!escaped && ('\\' == *s_itr_)) { escaped_found = true; escaped = true; @@ -2770,28 +2855,17 @@ namespace exprtk } else if (escaped) { - if (!is_end(s_itr_) && ('0' == *(s_itr_))) + if ( + !is_end(s_itr_) && ('0' == *(s_itr_)) && + ((s_itr_ + 4) <= s_end_) + ) { - /* - Note: The following 'awkward' conditional is - due to various broken msvc compilers. - */ - #if _MSC_VER == 1600 - const bool within_range = !is_end(s_itr_ + 2) && - !is_end(s_itr_ + 3) ; - #else - const bool within_range = !is_end(s_itr_ + 1) && - !is_end(s_itr_ + 2) && - !is_end(s_itr_ + 3) ; - #endif - - const bool x_seperator = ('x' == *(s_itr_ + 1)) || - ('X' == *(s_itr_ + 1)) ; + const bool x_seperator = ('X' == std::toupper(*(s_itr_ + 1))); - const bool both_digits = details::is_hex_digit(*(s_itr_ + 2)) && - details::is_hex_digit(*(s_itr_ + 3)) ; + const bool both_digits = details::is_hex_digit(*(s_itr_ + 2)) && + details::is_hex_digit(*(s_itr_ + 3)) ; - if (!within_range || !x_seperator || !both_digits) + if (!(x_seperator && both_digits)) { t.set_error(token::e_err_string, initial_itr, s_itr_, base_itr_); token_list_.push_back(t); @@ -2822,7 +2896,13 @@ namespace exprtk { std::string parsed_string(initial_itr,s_itr_); - details::cleanup_escapes(parsed_string); + if (!details::cleanup_escapes(parsed_string)) + { + t.set_error(token::e_err_string, initial_itr, s_itr_, base_itr_); + token_list_.push_back(t); + + return; + } t.set_string( parsed_string, @@ -2838,13 +2918,13 @@ namespace exprtk private: - token_list_t token_list_; - token_list_itr_t token_itr_; - token_list_itr_t store_token_itr_; - token_t eof_token_; - const char_t* base_itr_; - const char_t* s_itr_; - const char_t* s_end_; + token_list_t token_list_; + token_list_itr_t token_itr_; + token_list_itr_t store_token_itr_; + token_t eof_token_; + details::char_cptr base_itr_; + details::char_cptr s_itr_; + details::char_cptr s_end_; friend class token_scanner; friend class token_modifier; @@ -3011,6 +3091,10 @@ namespace exprtk std::size_t changes = 0; + typedef std::pair insert_t; + std::vector insert_list; + insert_list.reserve(10000); + for (std::size_t i = 0; i < (g.token_list_.size() - stride_ + 1); ++i) { int insert_index = -1; @@ -3034,17 +3118,36 @@ namespace exprtk break; } - typedef std::iterator_traits::difference_type diff_t; - if ((insert_index >= 0) && (insert_index <= (static_cast(stride_) + 1))) { - g.token_list_.insert( - g.token_list_.begin() + static_cast(i + static_cast(insert_index)), t); - + insert_list.push_back(insert_t(i, t)); changes++; } } + if (!insert_list.empty()) + { + generator::token_list_t token_list; + + std::size_t insert_index = 0; + + for (std::size_t i = 0; i < g.token_list_.size(); ++i) + { + token_list.push_back(g.token_list_[i]); + + if ( + (insert_index < insert_list.size()) && + (insert_list[insert_index].first == i) + ) + { + token_list.push_back(insert_list[insert_index].second); + insert_index++; + } + } + + std::swap(g.token_list_,token_list); + } + return changes; } @@ -3079,7 +3182,7 @@ namespace exprtk { public: - token_joiner(const std::size_t& stride) + explicit token_joiner(const std::size_t& stride) : stride_(stride) {} @@ -3103,53 +3206,82 @@ namespace exprtk inline std::size_t process_stride_2(generator& g) { - typedef std::iterator_traits::difference_type diff_t; - if (g.token_list_.size() < 2) return 0; std::size_t changes = 0; - for (std::size_t i = 0; i < (g.token_list_.size() - 1); ++i) + generator::token_list_t token_list; + token_list.reserve(10000); + + for (int i = 0; i < static_cast(g.token_list_.size() - 1); ++i) { token t; - while (join(g[i], g[i + 1], t)) + for ( ; ; ) { - g.token_list_[i] = t; + if (!join(g[i], g[i + 1], t)) + { + token_list.push_back(g[i]); + break; + } - g.token_list_.erase(g.token_list_.begin() + static_cast(i + 1)); + token_list.push_back(t); ++changes; + + i+=2; + + if (static_cast(i) >= g.token_list_.size()) + break; } } + token_list.push_back(g.token_list_.back()); + + std::swap(token_list, g.token_list_); + return changes; } inline std::size_t process_stride_3(generator& g) { - typedef std::iterator_traits::difference_type diff_t; - if (g.token_list_.size() < 3) return 0; std::size_t changes = 0; - for (std::size_t i = 0; i < (g.token_list_.size() - 2); ++i) + generator::token_list_t token_list; + token_list.reserve(10000); + + for (int i = 0; i < static_cast(g.token_list_.size() - 2); ++i) { token t; - while (join(g[i], g[i + 1], g[i + 2], t)) + for ( ; ; ) { - g.token_list_[i] = t; + if (!join(g[i], g[i + 1], g[i + 2], t)) + { + token_list.push_back(g[i]); + break; + } + + token_list.push_back(t); - g.token_list_.erase(g.token_list_.begin() + static_cast(i + 1), - g.token_list_.begin() + static_cast(i + 3)); ++changes; + + i+=3; + + if (static_cast(i) >= g.token_list_.size()) + break; } } + token_list.push_back(*(g.token_list_.begin() + g.token_list_.size() - 2)); + token_list.push_back(*(g.token_list_.begin() + g.token_list_.size() - 1)); + + std::swap(token_list, g.token_list_); + return changes; } @@ -3159,11 +3291,11 @@ namespace exprtk namespace helper { - inline void dump(lexer::generator& generator) + inline void dump(const lexer::generator& generator) { for (std::size_t i = 0; i < generator.size(); ++i) { - lexer::token t = generator[i]; + const lexer::token& t = generator[i]; printf("Token[%02d] @ %03d %6s --> '%s'\n", static_cast(i), static_cast(t.position), @@ -3224,6 +3356,7 @@ namespace exprtk else if ((t0.type == lexer::token::e_rbracket ) && (t1.type == lexer::token::e_symbol )) match = true; else if ((t0.type == lexer::token::e_rcrlbracket) && (t1.type == lexer::token::e_symbol )) match = true; else if ((t0.type == lexer::token::e_rsqrbracket) && (t1.type == lexer::token::e_symbol )) match = true; + else if ((t0.type == lexer::token::e_symbol ) && (t1.type == lexer::token::e_symbol )) match = true; return (match) ? 1 : -1; } @@ -3237,7 +3370,7 @@ namespace exprtk { public: - operator_joiner(const std::size_t& stride) + explicit operator_joiner(const std::size_t& stride) : token_joiner(stride) {} @@ -3635,10 +3768,11 @@ namespace exprtk sequence_validator() : lexer::token_scanner(2) { - add_invalid(lexer::token::e_number ,lexer::token::e_number ); - add_invalid(lexer::token::e_string ,lexer::token::e_string ); - add_invalid(lexer::token::e_number ,lexer::token::e_string ); - add_invalid(lexer::token::e_string ,lexer::token::e_number ); + add_invalid(lexer::token::e_number, lexer::token::e_number); + add_invalid(lexer::token::e_string, lexer::token::e_string); + add_invalid(lexer::token::e_number, lexer::token::e_string); + add_invalid(lexer::token::e_string, lexer::token::e_number); + add_invalid_set1(lexer::token::e_assign ); add_invalid_set1(lexer::token::e_shr ); add_invalid_set1(lexer::token::e_shl ); @@ -3666,7 +3800,7 @@ namespace exprtk bool operator() (const lexer::token& t0, const lexer::token& t1) { - set_t::value_type p = std::make_pair(t0.type,t1.type); + const set_t::value_type p = std::make_pair(t0.type,t1.type); if (invalid_bracket_check(t0.type,t1.type)) { @@ -3680,7 +3814,7 @@ namespace exprtk return true; } - std::size_t error_count() + std::size_t error_count() const { return error_list_.size(); } @@ -3712,21 +3846,21 @@ namespace exprtk void add_invalid_set1(lexer::token::token_type t) { - add_invalid(t,lexer::token::e_assign); - add_invalid(t,lexer::token::e_shr ); - add_invalid(t,lexer::token::e_shl ); - add_invalid(t,lexer::token::e_lte ); - add_invalid(t,lexer::token::e_ne ); - add_invalid(t,lexer::token::e_gte ); - add_invalid(t,lexer::token::e_lt ); - add_invalid(t,lexer::token::e_gt ); - add_invalid(t,lexer::token::e_eq ); - add_invalid(t,lexer::token::e_comma ); - add_invalid(t,lexer::token::e_div ); - add_invalid(t,lexer::token::e_mul ); - add_invalid(t,lexer::token::e_mod ); - add_invalid(t,lexer::token::e_pow ); - add_invalid(t,lexer::token::e_colon ); + add_invalid(t, lexer::token::e_assign); + add_invalid(t, lexer::token::e_shr ); + add_invalid(t, lexer::token::e_shl ); + add_invalid(t, lexer::token::e_lte ); + add_invalid(t, lexer::token::e_ne ); + add_invalid(t, lexer::token::e_gte ); + add_invalid(t, lexer::token::e_lt ); + add_invalid(t, lexer::token::e_gt ); + add_invalid(t, lexer::token::e_eq ); + add_invalid(t, lexer::token::e_comma ); + add_invalid(t, lexer::token::e_div ); + add_invalid(t, lexer::token::e_mul ); + add_invalid(t, lexer::token::e_mod ); + add_invalid(t, lexer::token::e_pow ); + add_invalid(t, lexer::token::e_colon ); } bool invalid_bracket_check(lexer::token::token_type base, lexer::token::token_type t) @@ -3736,7 +3870,7 @@ namespace exprtk switch (t) { case lexer::token::e_assign : return (']' != base); - case lexer::token::e_string : return true; + case lexer::token::e_string : return (')' != base); default : return false; } } @@ -3757,7 +3891,7 @@ namespace exprtk case lexer::token::e_sub : return false; case lexer::token::e_colon : return false; case lexer::token::e_ternary : return false; - default : return true; + default : return true ; } } } @@ -3771,7 +3905,7 @@ namespace exprtk case lexer::token::e_eof : return false; case lexer::token::e_colon : return false; case lexer::token::e_ternary : return false; - default : return true; + default : return true ; } } else if (details::is_left_bracket(static_cast(t))) @@ -3792,6 +3926,91 @@ namespace exprtk std::vector > error_list_; }; + class sequence_validator_3tokens : public lexer::token_scanner + { + private: + + typedef lexer::token::token_type token_t; + typedef std::pair > token_triplet_t; + typedef std::set set_t; + + public: + + using lexer::token_scanner::operator(); + + sequence_validator_3tokens() + : lexer::token_scanner(3) + { + add_invalid(lexer::token::e_number, lexer::token::e_number, lexer::token::e_number); + add_invalid(lexer::token::e_string, lexer::token::e_string, lexer::token::e_string); + add_invalid(lexer::token::e_comma , lexer::token::e_comma , lexer::token::e_comma ); + + add_invalid(lexer::token::e_add , lexer::token::e_add , lexer::token::e_add ); + add_invalid(lexer::token::e_sub , lexer::token::e_sub , lexer::token::e_sub ); + add_invalid(lexer::token::e_div , lexer::token::e_div , lexer::token::e_div ); + add_invalid(lexer::token::e_mul , lexer::token::e_mul , lexer::token::e_mul ); + add_invalid(lexer::token::e_mod , lexer::token::e_mod , lexer::token::e_mod ); + add_invalid(lexer::token::e_pow , lexer::token::e_pow , lexer::token::e_pow ); + + add_invalid(lexer::token::e_add , lexer::token::e_sub , lexer::token::e_add ); + add_invalid(lexer::token::e_sub , lexer::token::e_add , lexer::token::e_sub ); + add_invalid(lexer::token::e_div , lexer::token::e_mul , lexer::token::e_div ); + add_invalid(lexer::token::e_mul , lexer::token::e_div , lexer::token::e_mul ); + add_invalid(lexer::token::e_mod , lexer::token::e_pow , lexer::token::e_mod ); + add_invalid(lexer::token::e_pow , lexer::token::e_mod , lexer::token::e_pow ); + } + + bool result() + { + return error_list_.empty(); + } + + bool operator() (const lexer::token& t0, const lexer::token& t1, const lexer::token& t2) + { + const set_t::value_type p = std::make_pair(t0.type,std::make_pair(t1.type,t2.type)); + + if (invalid_comb_.find(p) != invalid_comb_.end()) + { + error_list_.push_back(std::make_pair(t0,t1)); + } + + return true; + } + + std::size_t error_count() const + { + return error_list_.size(); + } + + std::pair error(const std::size_t index) + { + if (index < error_list_.size()) + { + return error_list_[index]; + } + else + { + static const lexer::token error_token; + return std::make_pair(error_token,error_token); + } + } + + void clear_errors() + { + error_list_.clear(); + } + + private: + + void add_invalid(token_t t0, token_t t1, token_t t2) + { + invalid_comb_.insert(std::make_pair(t0,std::make_pair(t1,t2))); + } + + set_t invalid_comb_; + std::vector > error_list_; + }; + struct helper_assembly { inline bool register_scanner(lexer::token_scanner* scanner) @@ -4046,40 +4265,6 @@ namespace exprtk return true; } - inline bool token_is_then_assign(const token_t::token_type& ttype, - std::string& token, - const token_advance_mode mode = e_advance) - { - if (current_token_.type != ttype) - { - return false; - } - - token = current_token_.value; - - advance_token(mode); - - return true; - } - - template class Container> - inline bool token_is_then_assign(const token_t::token_type& ttype, - Container& token_list, - const token_advance_mode mode = e_advance) - { - if (current_token_.type != ttype) - { - return false; - } - - token_list.push_back(current_token_.value); - - advance_token(mode); - - return true; - } - inline bool peek_token_is(const token_t::token_type& ttype) { return (lexer_.peek_next_token().type == ttype); @@ -4166,14 +4351,14 @@ namespace exprtk inline vector_view make_vector_view(T* data, const std::size_t size, const std::size_t offset = 0) { - return vector_view(data + offset,size); + return vector_view(data + offset, size); } template inline vector_view make_vector_view(std::vector& v, const std::size_t size, const std::size_t offset = 0) { - return vector_view(v.data() + offset,size); + return vector_view(v.data() + offset, size); } template class results_context; @@ -4190,13 +4375,18 @@ namespace exprtk }; type_store() - : size(0), - data(0), + : data(0), + size(0), type(e_unknown) {} + union + { + void* data; + T* vec_data; + }; + std::size_t size; - void* data; store_type type; class parameter_list @@ -4502,27 +4692,33 @@ namespace exprtk { switch (opr) { - case e_add : return "+"; - case e_sub : return "-"; - case e_mul : return "*"; - case e_div : return "/"; - case e_mod : return "%"; - case e_pow : return "^"; - case e_assign : return ":="; - case e_addass : return "+="; - case e_subass : return "-="; - case e_mulass : return "*="; - case e_divass : return "/="; - case e_modass : return "%="; - case e_lt : return "<"; - case e_lte : return "<="; - case e_eq : return "=="; - case e_equal : return "="; - case e_ne : return "!="; - case e_nequal : return "<>"; - case e_gte : return ">="; - case e_gt : return ">"; - default : return"N/A"; + case e_add : return "+" ; + case e_sub : return "-" ; + case e_mul : return "*" ; + case e_div : return "/" ; + case e_mod : return "%" ; + case e_pow : return "^" ; + case e_assign : return ":=" ; + case e_addass : return "+=" ; + case e_subass : return "-=" ; + case e_mulass : return "*=" ; + case e_divass : return "/=" ; + case e_modass : return "%=" ; + case e_lt : return "<" ; + case e_lte : return "<=" ; + case e_eq : return "==" ; + case e_equal : return "=" ; + case e_ne : return "!=" ; + case e_nequal : return "<>" ; + case e_gte : return ">=" ; + case e_gt : return ">" ; + case e_and : return "and" ; + case e_or : return "or" ; + case e_xor : return "xor" ; + case e_nand : return "nand"; + case e_nor : return "nor" ; + case e_xnor : return "xnor"; + default : return "N/A" ; } } @@ -4547,8 +4743,8 @@ namespace exprtk struct details { - details(const std::size_t& vsize, - const unsigned int loop_batch_size = global_loop_batch_size) + explicit details(const std::size_t& vsize, + const unsigned int loop_batch_size = global_loop_batch_size) : batch_size(loop_batch_size ), remainder (vsize % batch_size), upper_bound(static_cast(vsize - (remainder ? loop_batch_size : 0))) @@ -4596,16 +4792,16 @@ namespace exprtk {} control_block(const std::size_t& dsize) - : ref_count(1), + : ref_count(1 ), size (dsize), - data (0), - destruct (true) + data (0 ), + destruct (true ) { create_data(); } control_block(const std::size_t& dsize, data_t dptr, bool dstrct = false) - : ref_count(1), - size (dsize), - data (dptr ), + : ref_count(1 ), + size (dsize ), + data (dptr ), destruct (dstrct) {} @@ -4662,7 +4858,7 @@ namespace exprtk { destruct = true; data = new T[size]; - std::fill_n(data,size,T(0)); + std::fill_n(data, size, T(0)); dump_ptr("control_block::create_data() - data",data,size); } }; @@ -4759,7 +4955,7 @@ namespace exprtk static inline void match_sizes(type& vds0, type& vds1) { - std::size_t size = min_size(vds0.control_block_,vds1.control_block_); + const std::size_t size = min_size(vds0.control_block_,vds1.control_block_); vds0.control_block_->size = size; vds1.control_block_->size = size; } @@ -4768,8 +4964,8 @@ namespace exprtk static inline std::size_t min_size(control_block* cb0, control_block* cb1) { - std::size_t size0 = cb0->size; - std::size_t size1 = cb1->size; + const std::size_t size0 = cb0->size; + const std::size_t size1 = cb1->size; if (size0 && size1) return std::min(size0,size1); @@ -4856,19 +5052,19 @@ namespace exprtk case e_ne : return std::not_equal_to()(arg0,arg1) ? T(1) : T(0); case e_gte : return (arg0 >= arg1) ? T(1) : T(0); case e_gt : return (arg0 > arg1) ? T(1) : T(0); - case e_and : return and_opr (arg0,arg1); + case e_and : return and_opr (arg0,arg1); case e_nand : return nand_opr(arg0,arg1); - case e_or : return or_opr (arg0,arg1); - case e_nor : return nor_opr (arg0,arg1); - case e_xor : return xor_opr (arg0,arg1); + case e_or : return or_opr (arg0,arg1); + case e_nor : return nor_opr (arg0,arg1); + case e_xor : return xor_opr (arg0,arg1); case e_xnor : return xnor_opr(arg0,arg1); - case e_root : return root (arg0,arg1); - case e_roundn : return roundn (arg0,arg1); + case e_root : return root (arg0,arg1); + case e_roundn : return roundn (arg0,arg1); case e_equal : return equal (arg0,arg1); case e_nequal : return nequal (arg0,arg1); - case e_hypot : return hypot (arg0,arg1); - case e_shr : return shr (arg0,arg1); - case e_shl : return shl (arg0,arg1); + case e_hypot : return hypot (arg0,arg1); + case e_shr : return shr (arg0,arg1); + case e_shl : return shl (arg0,arg1); default : exprtk_debug(("numeric::details::process_impl - Invalid binary operation.\n")); return std::numeric_limits::quiet_NaN(); @@ -4923,58 +5119,77 @@ namespace exprtk template inline T process(const operator_type operation, const T arg0, const T arg1) { - return exprtk::details::numeric::details::process_impl(operation,arg0,arg1); + return exprtk::details::numeric::details::process_impl(operation, arg0, arg1); } } + template + struct node_collector_interface + { + typedef Node* node_ptr_t; + typedef Node** node_pp_t; + typedef std::vector noderef_list_t; + + virtual ~node_collector_interface() {} + + virtual void collect_nodes(noderef_list_t&) {} + }; + + template + struct node_depth_base; + template - class expression_node + class expression_node : public node_collector_interface >, + public node_depth_base > { public: enum node_type { - e_none , e_null , e_constant , e_unary , - e_binary , e_binary_ext , e_trinary , e_quaternary , - e_vararg , e_conditional , e_while , e_repeat , - e_for , e_switch , e_mswitch , e_return , - e_retenv , e_variable , e_stringvar , e_stringconst , - e_stringvarrng , e_cstringvarrng, e_strgenrange , e_strconcat , - e_stringvarsize, e_strswap , e_stringsize , e_stringvararg , - e_function , e_vafunction , e_genfunction , e_strfunction , - e_strcondition , e_strccondition, e_add , e_sub , - e_mul , e_div , e_mod , e_pow , - e_lt , e_lte , e_gt , e_gte , - e_eq , e_ne , e_and , e_nand , - e_or , e_nor , e_xor , e_xnor , - e_in , e_like , e_ilike , e_inranges , - e_ipow , e_ipowinv , e_abs , e_acos , - e_acosh , e_asin , e_asinh , e_atan , - e_atanh , e_ceil , e_cos , e_cosh , - e_exp , e_expm1 , e_floor , e_log , - e_log10 , e_log2 , e_log1p , e_neg , - e_pos , e_round , e_sin , e_sinc , - e_sinh , e_sqrt , e_tan , e_tanh , - e_cot , e_sec , e_csc , e_r2d , - e_d2r , e_d2g , e_g2d , e_notl , - e_sgn , e_erf , e_erfc , e_ncdf , - e_frac , e_trunc , e_uvouv , e_vov , - e_cov , e_voc , e_vob , e_bov , - e_cob , e_boc , e_vovov , e_vovoc , - e_vocov , e_covov , e_covoc , e_vovovov , - e_vovovoc , e_vovocov , e_vocovov , e_covovov , - e_covocov , e_vocovoc , e_covovoc , e_vococov , - e_sf3ext , e_sf4ext , e_nulleq , e_strass , - e_vector , e_vecelem , e_rbvecelem , e_rbveccelem , - e_vecdefass , e_vecvalass , e_vecvecass , e_vecopvalass , - e_vecopvecass , e_vecfunc , e_vecvecswap , e_vecvecineq , - e_vecvalineq , e_valvecineq , e_vecvecarith , e_vecvalarith , - e_valvecarith , e_vecunaryop , e_break , e_continue , + e_none , e_null , e_constant , e_unary , + e_binary , e_binary_ext , e_trinary , e_quaternary , + e_vararg , e_conditional , e_while , e_repeat , + e_for , e_switch , e_mswitch , e_return , + e_retenv , e_variable , e_stringvar , e_stringconst , + e_stringvarrng , e_cstringvarrng , e_strgenrange , e_strconcat , + e_stringvarsize , e_strswap , e_stringsize , e_stringvararg , + e_function , e_vafunction , e_genfunction , e_strfunction , + e_strcondition , e_strccondition , e_add , e_sub , + e_mul , e_div , e_mod , e_pow , + e_lt , e_lte , e_gt , e_gte , + e_eq , e_ne , e_and , e_nand , + e_or , e_nor , e_xor , e_xnor , + e_in , e_like , e_ilike , e_inranges , + e_ipow , e_ipowinv , e_abs , e_acos , + e_acosh , e_asin , e_asinh , e_atan , + e_atanh , e_ceil , e_cos , e_cosh , + e_exp , e_expm1 , e_floor , e_log , + e_log10 , e_log2 , e_log1p , e_neg , + e_pos , e_round , e_sin , e_sinc , + e_sinh , e_sqrt , e_tan , e_tanh , + e_cot , e_sec , e_csc , e_r2d , + e_d2r , e_d2g , e_g2d , e_notl , + e_sgn , e_erf , e_erfc , e_ncdf , + e_frac , e_trunc , e_uvouv , e_vov , + e_cov , e_voc , e_vob , e_bov , + e_cob , e_boc , e_vovov , e_vovoc , + e_vocov , e_covov , e_covoc , e_vovovov , + e_vovovoc , e_vovocov , e_vocovov , e_covovov , + e_covocov , e_vocovoc , e_covovoc , e_vococov , + e_sf3ext , e_sf4ext , e_nulleq , e_strass , + e_vector , e_vecelem , e_rbvecelem , e_rbveccelem , + e_vecdefass , e_vecvalass , e_vecvecass , e_vecopvalass , + e_vecopvecass , e_vecfunc , e_vecvecswap , e_vecvecineq , + e_vecvalineq , e_valvecineq , e_vecvecarith , e_vecvalarith , + e_valvecarith , e_vecunaryop , e_break , e_continue , e_swap }; typedef T value_type; typedef expression_node* expression_ptr; + typedef node_collector_interface > nci_t; + typedef typename nci_t::noderef_list_t noderef_list_t; + typedef node_depth_base > ndb_t; virtual ~expression_node() {} @@ -5025,12 +5240,24 @@ namespace exprtk return std::not_equal_to()(T(0),node->value()); } + template + inline bool is_true(const std::pair*,bool>& node) + { + return std::not_equal_to()(T(0),node.first->value()); + } + template inline bool is_false(const expression_node* node) { return std::equal_to()(T(0),node->value()); } + template + inline bool is_false(const std::pair*,bool>& node) + { + return std::equal_to()(T(0),node.first->value()); + } + template inline bool is_unary_node(const expression_node* node) { @@ -5173,7 +5400,8 @@ namespace exprtk template inline bool branch_deletable(expression_node* node) { - return !is_variable_node(node) && + return (0 != node) && + !is_variable_node(node) && !is_string_node (node) ; } @@ -5190,7 +5418,7 @@ namespace exprtk template class Sequence> + template class Sequence> inline bool all_nodes_valid(const Sequence*,Allocator>& b) { for (std::size_t i = 0; i < b.size(); ++i) @@ -5217,7 +5445,7 @@ namespace exprtk template class Sequence> + template class Sequence> inline bool all_nodes_variables(Sequence*,Allocator>& b) { for (std::size_t i = 0; i < b.size(); ++i) @@ -5231,6 +5459,76 @@ namespace exprtk return true; } + template + class node_collection_destructor + { + public: + + typedef node_collector_interface nci_t; + + typedef typename nci_t::node_ptr_t node_ptr_t; + typedef typename nci_t::node_pp_t node_pp_t; + typedef typename nci_t::noderef_list_t noderef_list_t; + + static void delete_nodes(node_ptr_t& root) + { + std::vector node_delete_list; + node_delete_list.reserve(1000); + + collect_nodes(root, node_delete_list); + + for (std::size_t i = 0; i < node_delete_list.size(); ++i) + { + node_ptr_t& node = *node_delete_list[i]; + exprtk_debug(("ncd::delete_nodes() - deleting: %p\n", static_cast(node))); + delete node; + node = reinterpret_cast(0); + } + } + + private: + + static void collect_nodes(node_ptr_t& root, noderef_list_t& node_delete_list) + { + std::deque node_list; + node_list.push_back(root); + node_delete_list.push_back(&root); + + noderef_list_t child_node_delete_list; + child_node_delete_list.reserve(1000); + + while (!node_list.empty()) + { + node_list.front()->collect_nodes(child_node_delete_list); + + if (!child_node_delete_list.empty()) + { + for (std::size_t i = 0; i < child_node_delete_list.size(); ++i) + { + node_pp_t& node = child_node_delete_list[i]; + + if (0 == (*node)) + { + exprtk_debug(("ncd::collect_nodes() - null node encountered.\n")); + } + + node_list.push_back(*node); + } + + node_delete_list.insert( + node_delete_list.end(), + child_node_delete_list.begin(), child_node_delete_list.end()); + + child_node_delete_list.clear(); + } + + node_list.pop_front(); + } + + std::reverse(node_delete_list.begin(), node_delete_list.end()); + } + }; + template inline void free_all_nodes(NodeAllocator& node_allocator, expression_node* (&b)[N]) { @@ -5243,7 +5541,7 @@ namespace exprtk template class Sequence> + template class Sequence> inline void free_all_nodes(NodeAllocator& node_allocator, Sequence*,Allocator>& b) { for (std::size_t i = 0; i < b.size(); ++i) @@ -5255,28 +5553,239 @@ namespace exprtk } template - inline void free_node(NodeAllocator& node_allocator, expression_node*& node, const bool force_delete = false) + inline void free_node(NodeAllocator&, expression_node*& node) { - if (0 != node) + if ((0 == node) || is_variable_node(node) || is_string_node(node)) { - if ( - (is_variable_node(node) || is_string_node(node)) || - force_delete - ) - return; - - node_allocator.free(node); - node = reinterpret_cast*>(0); + return; } + + node_collection_destructor > + ::delete_nodes(node); } template inline void destroy_node(expression_node*& node) { - delete node; - node = reinterpret_cast*>(0); + if (0 != node) + { + node_collection_destructor > + ::delete_nodes(node); + } } + template + struct node_depth_base + { + node_depth_base() + : depth_set(false), + depth(0) + {} + + virtual ~node_depth_base() {} + + virtual std::size_t node_depth() const { return 1; } + + std::size_t compute_node_depth(const Node* const& node) const + { + if (!depth_set) + { + depth = 1 + (node ? node->node_depth() : 0); + depth_set = true; + } + + return depth; + } + + std::size_t compute_node_depth(const std::pair& branch) const + { + if (!depth_set) + { + depth = 1 + (branch.first ? branch.first->node_depth() : 0); + depth_set = true; + } + + return depth; + } + + template + std::size_t compute_node_depth(const std::pair (&branch)[N]) const + { + if (!depth_set) + { + depth = 0; + for (std::size_t i = 0; i < N; ++i) + { + if (branch[i].first) + { + depth = std::max(depth,branch[i].first->node_depth()); + } + } + depth += 1; + depth_set = true; + } + + return depth; + } + + template + std::size_t compute_node_depth(const BranchType& n0, const BranchType& n1) const + { + if (!depth_set) + { + depth = 1 + std::max(compute_node_depth(n0), compute_node_depth(n1)); + depth_set = true; + } + + return depth; + } + + template + std::size_t compute_node_depth(const BranchType& n0, const BranchType& n1, + const BranchType& n2) const + { + if (!depth_set) + { + depth = 1 + std::max( + std::max(compute_node_depth(n0), compute_node_depth(n1)), + compute_node_depth(n2)); + depth_set = true; + } + + return depth; + } + + template + std::size_t compute_node_depth(const BranchType& n0, const BranchType& n1, + const BranchType& n2, const BranchType& n3) const + { + if (!depth_set) + { + depth = 1 + std::max( + std::max(compute_node_depth(n0), compute_node_depth(n1)), + std::max(compute_node_depth(n2), compute_node_depth(n3))); + depth_set = true; + } + + return depth; + } + + template class Sequence> + std::size_t compute_node_depth(const Sequence& branch_list) const + { + if (!depth_set) + { + for (std::size_t i = 0; i < branch_list.size(); ++i) + { + if (branch_list[i]) + { + depth = std::max(depth, compute_node_depth(branch_list[i])); + } + } + depth_set = true; + } + + return depth; + } + + template class Sequence> + std::size_t compute_node_depth(const Sequence,Allocator>& branch_list) const + { + if (!depth_set) + { + for (std::size_t i = 0; i < branch_list.size(); ++i) + { + if (branch_list[i].first) + { + depth = std::max(depth, compute_node_depth(branch_list[i].first)); + } + } + depth_set = true; + } + + return depth; + } + + mutable bool depth_set; + mutable std::size_t depth; + + template + void collect(Node*const& node, + const bool deletable, + NodeSequence& delete_node_list) const + { + if ((0 != node) && deletable) + { + delete_node_list.push_back(const_cast(&node)); + } + } + + template + void collect(const std::pair& branch, + NodeSequence& delete_node_list) const + { + collect(branch.first, branch.second, delete_node_list); + } + + template + void collect(Node*& node, + NodeSequence& delete_node_list) const + { + collect(node, branch_deletable(node), delete_node_list); + } + + template + void collect(const std::pair(&branch)[N], + NodeSequence& delete_node_list) const + { + for (std::size_t i = 0; i < N; ++i) + { + collect(branch[i].first, branch[i].second, delete_node_list); + } + } + + template class Sequence, + typename NodeSequence> + void collect(const Sequence, Allocator>& branch, + NodeSequence& delete_node_list) const + { + for (std::size_t i = 0; i < branch.size(); ++i) + { + collect(branch[i].first, branch[i].second, delete_node_list); + } + } + + template class Sequence, + typename NodeSequence> + void collect(const Sequence& branch_list, + NodeSequence& delete_node_list) const + { + for (std::size_t i = 0; i < branch_list.size(); ++i) + { + collect(branch_list[i], branch_deletable(branch_list[i]), delete_node_list); + } + } + + template class Sequence, + typename NodeSequence> + void collect(const Sequence& branch_list, + const Sequence& branch_deletable_list, + NodeSequence& delete_node_list) const + { + for (std::size_t i = 0; i < branch_list.size(); ++i) + { + collect(branch_list[i], branch_deletable_list[i], delete_node_list); + } + } + }; + template class vector_holder { @@ -5353,7 +5862,7 @@ namespace exprtk }; template class Sequence> + template class Sequence> class sequence_vector_impl : public vector_holder_base { public: @@ -5490,30 +5999,70 @@ namespace exprtk } }; + template + inline void construct_branch_pair(std::pair*,bool> (&branch)[N], + expression_node* b, + const std::size_t& index) + { + if (b && (index < N)) + { + branch[index] = std::make_pair(b,branch_deletable(b)); + } + } + + template + inline void construct_branch_pair(std::pair*,bool>& branch, expression_node* b) + { + if (b) + { + branch = std::make_pair(b,branch_deletable(b)); + } + } + + template + inline void init_branches(std::pair*,bool> (&branch)[N], + expression_node* b0, + expression_node* b1 = reinterpret_cast*>(0), + expression_node* b2 = reinterpret_cast*>(0), + expression_node* b3 = reinterpret_cast*>(0), + expression_node* b4 = reinterpret_cast*>(0), + expression_node* b5 = reinterpret_cast*>(0), + expression_node* b6 = reinterpret_cast*>(0), + expression_node* b7 = reinterpret_cast*>(0), + expression_node* b8 = reinterpret_cast*>(0), + expression_node* b9 = reinterpret_cast*>(0)) + { + construct_branch_pair(branch, b0, 0); + construct_branch_pair(branch, b1, 1); + construct_branch_pair(branch, b2, 2); + construct_branch_pair(branch, b3, 3); + construct_branch_pair(branch, b4, 4); + construct_branch_pair(branch, b5, 5); + construct_branch_pair(branch, b6, 6); + construct_branch_pair(branch, b7, 7); + construct_branch_pair(branch, b8, 8); + construct_branch_pair(branch, b9, 9); + } + template class null_eq_node : public expression_node { public: typedef expression_node* expression_ptr; + typedef std::pair branch_t; - null_eq_node(expression_ptr brnch, const bool equality = true) - : branch_(brnch), - branch_deletable_(branch_deletable(branch_)), - equality_(equality) - {} - - ~null_eq_node() + explicit null_eq_node(expression_ptr branch, const bool equality = true) + : equality_(equality) { - if (branch_ && branch_deletable_) - { - destroy_node(branch_); - } + construct_branch_pair(branch_, branch); } inline T value() const { - const T v = branch_->value(); + assert(branch_.first); + + const T v = branch_.first->value(); const bool result = details::numeric::is_nan(v); if (result) @@ -5534,14 +6083,23 @@ namespace exprtk inline expression_node* branch(const std::size_t&) const { - return branch_; + return branch_.first; + } + + void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) + { + expression_node::ndb_t::collect(branch_,node_delete_list); + } + + std::size_t node_depth() const + { + return expression_node::ndb_t::compute_node_depth(branch_); } private: - expression_ptr branch_; - const bool branch_deletable_; bool equality_; + branch_t branch_; }; template @@ -5610,7 +6168,7 @@ namespace exprtk virtual std::string str () const = 0; - virtual const char_t* base() const = 0; + virtual char_cptr base() const = 0; virtual std::size_t size() const = 0; }; @@ -5653,7 +6211,7 @@ namespace exprtk return value_; } - const char_t* base() const + char_cptr base() const { return value_.data(); } @@ -5689,25 +6247,19 @@ namespace exprtk public: typedef expression_node* expression_ptr; + typedef std::pair branch_t; - unary_node(const operator_type& opr, - expression_ptr brnch) - : operation_(opr), - branch_(brnch), - branch_deletable_(branch_deletable(branch_)) - {} - - ~unary_node() + unary_node(const operator_type& opr, expression_ptr branch) + : operation_(opr) { - if (branch_ && branch_deletable_) - { - destroy_node(branch_); - } + construct_branch_pair(branch_,branch); } inline T value() const { - const T arg = branch_->value(); + assert(branch_.first); + + const T arg = branch_.first->value(); return numeric::process(operation_,arg); } @@ -5724,94 +6276,28 @@ namespace exprtk inline expression_node* branch(const std::size_t&) const { - return branch_; + return branch_.first; } inline void release() { - branch_deletable_ = false; + branch_.second = false; } - protected: - - operator_type operation_; - expression_ptr branch_; - bool branch_deletable_; - }; - - template - struct construct_branch_pair - { - template - static inline void process(std::pair*,bool> (&)[N], expression_node*) - {} - }; - - template - struct construct_branch_pair - { - template - static inline void process(std::pair*,bool> (&branch)[N], expression_node* b) + void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) { - if (b) - { - branch[D] = std::make_pair(b,branch_deletable(b)); - } + expression_node::ndb_t::collect(branch_, node_delete_list); } - }; - - template - inline void init_branches(std::pair*,bool> (&branch)[N], - expression_node* b0, - expression_node* b1 = reinterpret_cast*>(0), - expression_node* b2 = reinterpret_cast*>(0), - expression_node* b3 = reinterpret_cast*>(0), - expression_node* b4 = reinterpret_cast*>(0), - expression_node* b5 = reinterpret_cast*>(0), - expression_node* b6 = reinterpret_cast*>(0), - expression_node* b7 = reinterpret_cast*>(0), - expression_node* b8 = reinterpret_cast*>(0), - expression_node* b9 = reinterpret_cast*>(0)) - { - construct_branch_pair 0)>::process(branch,b0); - construct_branch_pair 1)>::process(branch,b1); - construct_branch_pair 2)>::process(branch,b2); - construct_branch_pair 3)>::process(branch,b3); - construct_branch_pair 4)>::process(branch,b4); - construct_branch_pair 5)>::process(branch,b5); - construct_branch_pair 6)>::process(branch,b6); - construct_branch_pair 7)>::process(branch,b7); - construct_branch_pair 8)>::process(branch,b8); - construct_branch_pair 9)>::process(branch,b9); - } - struct cleanup_branches - { - template - static inline void execute(std::pair*,bool> (&branch)[N]) + std::size_t node_depth() const { - for (std::size_t i = 0; i < N; ++i) - { - if (branch[i].first && branch[i].second) - { - destroy_node(branch[i].first); - } - } + return expression_node::ndb_t::compute_node_depth(branch_); } - template class Sequence> - static inline void execute(Sequence*,bool>,Allocator>& branch) - { - for (std::size_t i = 0; i < branch.size(); ++i) - { - if (branch[i].first && branch[i].second) - { - destroy_node(branch[i].first); - } - } - } + protected: + + operator_type operation_; + branch_t branch_; }; template @@ -5830,13 +6316,11 @@ namespace exprtk init_branches<2>(branch_, branch0, branch1); } - ~binary_node() - { - cleanup_branches::execute(branch_); - } - inline T value() const { + assert(branch_[0].first); + assert(branch_[1].first); + const T arg0 = branch_[0].first->value(); const T arg1 = branch_[1].first->value(); @@ -5863,6 +6347,16 @@ namespace exprtk return reinterpret_cast(0); } + void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) + { + expression_node::ndb_t::template collect(branch_, node_delete_list); + } + + std::size_t node_depth() const + { + return expression_node::ndb_t::template compute_node_depth<2>(branch_); + } + protected: operator_type operation_; @@ -5882,13 +6376,11 @@ namespace exprtk init_branches<2>(branch_, branch0, branch1); } - ~binary_ext_node() - { - cleanup_branches::execute(branch_); - } - inline T value() const { + assert(branch_[0].first); + assert(branch_[1].first); + const T arg0 = branch_[0].first->value(); const T arg1 = branch_[1].first->value(); @@ -5915,6 +6407,16 @@ namespace exprtk return reinterpret_cast(0); } + void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) + { + expression_node::ndb_t::template collect(branch_, node_delete_list); + } + + std::size_t node_depth() const + { + return expression_node::ndb_t::template compute_node_depth<2>(branch_); + } + protected: branch_t branch_[2]; @@ -5937,13 +6439,12 @@ namespace exprtk init_branches<3>(branch_, branch0, branch1, branch2); } - ~trinary_node() - { - cleanup_branches::execute(branch_); - } - inline T value() const { + assert(branch_[0].first); + assert(branch_[1].first); + assert(branch_[2].first); + const T arg0 = branch_[0].first->value(); const T arg1 = branch_[1].first->value(); const T arg2 = branch_[2].first->value(); @@ -5959,10 +6460,8 @@ namespace exprtk else return ((T(2) * arg1 <= (arg2 + arg0)) ? arg0 : arg2); - default : { - exprtk_debug(("trinary_node::value() - Error: Invalid operation\n")); - return std::numeric_limits::quiet_NaN(); - } + default : exprtk_debug(("trinary_node::value() - Error: Invalid operation\n")); + return std::numeric_limits::quiet_NaN(); } } @@ -5971,6 +6470,16 @@ namespace exprtk return expression_node::e_trinary; } + void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) + { + expression_node::ndb_t::template collect(branch_, node_delete_list); + } + + std::size_t node_depth() const + { + return expression_node::ndb_t::template compute_node_depth<3>(branch_); + } + protected: operator_type operation_; @@ -5995,11 +6504,6 @@ namespace exprtk init_branches<4>(branch_, branch0, branch1, branch2, branch3); } - ~quaternary_node() - { - cleanup_branches::execute(branch_); - } - inline T value() const { return std::numeric_limits::quiet_NaN(); @@ -6010,6 +6514,16 @@ namespace exprtk return expression_node::e_quaternary; } + void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) + { + expression_node::ndb_t::template collect(branch_, node_delete_list); + } + + std::size_t node_depth() const + { + return expression_node::ndb_t::template compute_node_depth<4>(branch_); + } + protected: operator_type operation_; @@ -6022,42 +6536,27 @@ namespace exprtk public: typedef expression_node* expression_ptr; + typedef std::pair branch_t; - conditional_node(expression_ptr test, + conditional_node(expression_ptr condition, expression_ptr consequent, expression_ptr alternative) - : test_(test), - consequent_(consequent), - alternative_(alternative), - test_deletable_(branch_deletable(test_)), - consequent_deletable_(branch_deletable(consequent_)), - alternative_deletable_(branch_deletable(alternative_)) - {} - - ~conditional_node() { - if (test_ && test_deletable_) - { - destroy_node(test_); - } - - if (consequent_ && consequent_deletable_ ) - { - destroy_node(consequent_); - } - - if (alternative_ && alternative_deletable_) - { - destroy_node(alternative_); - } + construct_branch_pair(condition_ , condition ); + construct_branch_pair(consequent_ , consequent ); + construct_branch_pair(alternative_, alternative); } inline T value() const { - if (is_true(test_)) - return consequent_->value(); + assert(condition_ .first); + assert(consequent_ .first); + assert(alternative_.first); + + if (is_true(condition_)) + return consequent_.first->value(); else - return alternative_->value(); + return alternative_.first->value(); } inline typename expression_node::node_type type() const @@ -6065,14 +6564,24 @@ namespace exprtk return expression_node::e_conditional; } + void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) + { + expression_node::ndb_t::collect(condition_ , node_delete_list); + expression_node::ndb_t::collect(consequent_ , node_delete_list); + expression_node::ndb_t::collect(alternative_, node_delete_list); + } + + std::size_t node_depth() const + { + return expression_node::ndb_t::compute_node_depth + (condition_, consequent_, alternative_); + } + private: - expression_ptr test_; - expression_ptr consequent_; - expression_ptr alternative_; - const bool test_deletable_; - const bool consequent_deletable_; - const bool alternative_deletable_; + branch_t condition_; + branch_t consequent_; + branch_t alternative_; }; template @@ -6082,32 +6591,22 @@ namespace exprtk // Consequent only conditional statement node typedef expression_node* expression_ptr; + typedef std::pair branch_t; - cons_conditional_node(expression_ptr test, + cons_conditional_node(expression_ptr condition, expression_ptr consequent) - : test_(test), - consequent_(consequent), - test_deletable_(branch_deletable(test_)), - consequent_deletable_(branch_deletable(consequent_)) - {} - - ~cons_conditional_node() { - if (test_ && test_deletable_) - { - destroy_node(test_); - } - - if (consequent_ && consequent_deletable_) - { - destroy_node(consequent_); - } + construct_branch_pair(condition_ , condition ); + construct_branch_pair(consequent_, consequent); } inline T value() const { - if (is_true(test_)) - return consequent_->value(); + assert(condition_ .first); + assert(consequent_.first); + + if (is_true(condition_)) + return consequent_.first->value(); else return std::numeric_limits::quiet_NaN(); } @@ -6117,12 +6616,22 @@ namespace exprtk return expression_node::e_conditional; } + void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) + { + expression_node::ndb_t::collect(condition_ , node_delete_list); + expression_node::ndb_t::collect(consequent_, node_delete_list); + } + + std::size_t node_depth() const + { + return expression_node::ndb_t:: + compute_node_depth(condition_, consequent_); + } + private: - expression_ptr test_; - expression_ptr consequent_; - const bool test_deletable_; - const bool consequent_deletable_; + branch_t condition_; + branch_t consequent_; }; #ifndef exprtk_disable_break_continue @@ -6147,23 +6656,16 @@ namespace exprtk public: typedef expression_node* expression_ptr; + typedef std::pair branch_t; break_node(expression_ptr ret = expression_ptr(0)) - : return_(ret), - return_deletable_(branch_deletable(return_)) - {} - - ~break_node() { - if (return_deletable_) - { - destroy_node(return_); - } + construct_branch_pair(return_, ret); } inline T value() const { - throw break_exception(return_ ? return_->value() : std::numeric_limits::quiet_NaN()); + throw break_exception(return_.first ? return_.first->value() : std::numeric_limits::quiet_NaN()); #ifndef _MSC_VER return std::numeric_limits::quiet_NaN(); #endif @@ -6174,10 +6676,19 @@ namespace exprtk return expression_node::e_break; } + void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) + { + expression_node::ndb_t::collect(return_, node_delete_list); + } + + std::size_t node_depth() const + { + return expression_node::ndb_t::compute_node_depth(return_); + } + private: - expression_ptr return_; - const bool return_deletable_; + branch_t return_; }; template @@ -6200,40 +6711,90 @@ namespace exprtk }; #endif - template - class while_loop_node : public expression_node + #ifdef exprtk_enable_runtime_checks + struct loop_runtime_checker { - public: - - typedef expression_node* expression_ptr; - - while_loop_node(expression_ptr condition, expression_ptr loop_body) - : condition_(condition), - loop_body_(loop_body), - condition_deletable_(branch_deletable(condition_)), - loop_body_deletable_(branch_deletable(loop_body_)) + loop_runtime_checker(loop_runtime_check_ptr loop_rt_chk = loop_runtime_check_ptr(0), + loop_runtime_check::loop_types lp_typ = loop_runtime_check::e_invalid) + : iteration_count_(0), + loop_runtime_check_(loop_rt_chk), + loop_type(lp_typ) {} - ~while_loop_node() + inline void reset(const _uint64_t initial_value = 0) const { - if (condition_ && condition_deletable_) - { - destroy_node(condition_); - } + iteration_count_ = initial_value; + } - if (loop_body_ && loop_body_deletable_) + inline bool check() const + { + if ( + (0 == loop_runtime_check_) || + (++iteration_count_ <= loop_runtime_check_->max_loop_iterations) + ) { - destroy_node(loop_body_); + return true; } + + loop_runtime_check::violation_context ctxt; + ctxt.loop = loop_type; + ctxt.violation = loop_runtime_check::e_iteration_count; + + loop_runtime_check_->handle_runtime_violation(ctxt); + + return false; + } + + mutable _uint64_t iteration_count_; + mutable loop_runtime_check_ptr loop_runtime_check_; + loop_runtime_check::loop_types loop_type; + }; + #else + struct loop_runtime_checker + { + loop_runtime_checker(loop_runtime_check_ptr, loop_runtime_check::loop_types) + {} + + inline void reset(const _uint64_t = 0) const + {} + + inline bool check() const + { + return true; + } + }; + #endif + + template + class while_loop_node : public expression_node, + public loop_runtime_checker + { + public: + + typedef expression_node* expression_ptr; + typedef std::pair branch_t; + + while_loop_node(expression_ptr condition, + expression_ptr loop_body, + loop_runtime_check_ptr loop_rt_chk = loop_runtime_check_ptr(0)) + : loop_runtime_checker(loop_rt_chk,loop_runtime_check::e_while_loop) + { + construct_branch_pair(condition_, condition); + construct_branch_pair(loop_body_, loop_body); } inline T value() const { + assert(condition_.first); + assert(loop_body_.first); + T result = T(0); - while (is_true(condition_)) + loop_runtime_checker::reset(); + + while (is_true(condition_) && loop_runtime_checker::check()) { - result = loop_body_->value(); + result = loop_body_.first->value(); } return result; @@ -6244,50 +6805,55 @@ namespace exprtk return expression_node::e_while; } + void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) + { + expression_node::ndb_t::collect(condition_, node_delete_list); + expression_node::ndb_t::collect(loop_body_, node_delete_list); + } + + std::size_t node_depth() const + { + return expression_node::ndb_t::compute_node_depth(condition_, loop_body_); + } + private: - expression_ptr condition_; - expression_ptr loop_body_; - const bool condition_deletable_; - const bool loop_body_deletable_; + branch_t condition_; + branch_t loop_body_; }; template - class repeat_until_loop_node : public expression_node + class repeat_until_loop_node : public expression_node, + public loop_runtime_checker { public: typedef expression_node* expression_ptr; + typedef std::pair branch_t; - repeat_until_loop_node(expression_ptr condition, expression_ptr loop_body) - : condition_(condition), - loop_body_(loop_body), - condition_deletable_(branch_deletable(condition_)), - loop_body_deletable_(branch_deletable(loop_body_)) - {} - - ~repeat_until_loop_node() + repeat_until_loop_node(expression_ptr condition, + expression_ptr loop_body, + loop_runtime_check_ptr loop_rt_chk = loop_runtime_check_ptr(0)) + : loop_runtime_checker(loop_rt_chk, loop_runtime_check::e_repeat_until_loop) { - if (condition_ && condition_deletable_) - { - destroy_node(condition_); - } - - if (loop_body_ && loop_body_deletable_) - { - destroy_node(loop_body_); - } + construct_branch_pair(condition_, condition); + construct_branch_pair(loop_body_, loop_body); } inline T value() const { + assert(condition_.first); + assert(loop_body_.first); + T result = T(0); + loop_runtime_checker::reset(1); + do { - result = loop_body_->value(); + result = loop_body_.first->value(); } - while (is_false(condition_)); + while (is_false(condition_.first) && loop_runtime_checker::check()); return result; } @@ -6297,78 +6863,70 @@ namespace exprtk return expression_node::e_repeat; } + void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) + { + expression_node::ndb_t::collect(condition_, node_delete_list); + expression_node::ndb_t::collect(loop_body_, node_delete_list); + } + + std::size_t node_depth() const + { + return expression_node::ndb_t::compute_node_depth(condition_, loop_body_); + } + private: - expression_ptr condition_; - expression_ptr loop_body_; - const bool condition_deletable_; - const bool loop_body_deletable_; + branch_t condition_; + branch_t loop_body_; }; template - class for_loop_node : public expression_node + class for_loop_node : public expression_node, + public loop_runtime_checker { public: typedef expression_node* expression_ptr; + typedef std::pair branch_t; for_loop_node(expression_ptr initialiser, expression_ptr condition, expression_ptr incrementor, - expression_ptr loop_body) - : initialiser_(initialiser), - condition_ (condition ), - incrementor_(incrementor), - loop_body_ (loop_body ), - initialiser_deletable_(branch_deletable(initialiser_)), - condition_deletable_ (branch_deletable(condition_ )), - incrementor_deletable_(branch_deletable(incrementor_)), - loop_body_deletable_ (branch_deletable(loop_body_ )) - {} - - ~for_loop_node() + expression_ptr loop_body, + loop_runtime_check_ptr loop_rt_chk = loop_runtime_check_ptr(0)) + : loop_runtime_checker(loop_rt_chk, loop_runtime_check::e_for_loop) { - if (initialiser_ && initialiser_deletable_) - { - destroy_node(initialiser_); - } - - if (condition_ && condition_deletable_) - { - destroy_node(condition_); - } - - if (incrementor_ && incrementor_deletable_) - { - destroy_node(incrementor_); - } - - if (loop_body_ && loop_body_deletable_) - { - destroy_node(loop_body_); - } + construct_branch_pair(initialiser_, initialiser); + construct_branch_pair(condition_ , condition ); + construct_branch_pair(incrementor_, incrementor); + construct_branch_pair(loop_body_ , loop_body ); } inline T value() const { + assert(condition_.first); + assert(loop_body_.first); + T result = T(0); - if (initialiser_) - initialiser_->value(); + loop_runtime_checker::reset(); - if (incrementor_) + if (initialiser_.first) + initialiser_.first->value(); + + if (incrementor_.first) { - while (is_true(condition_)) + while (is_true(condition_) && loop_runtime_checker::check()) { - result = loop_body_->value(); - incrementor_->value(); + result = loop_body_.first->value(); + incrementor_.first->value(); } } else { - while (is_true(condition_)) + while (is_true(condition_) && loop_runtime_checker::check()) { - result = loop_body_->value(); + result = loop_body_.first->value(); } } @@ -6380,55 +6938,61 @@ namespace exprtk return expression_node::e_for; } + void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) + { + expression_node::ndb_t::collect(initialiser_, node_delete_list); + expression_node::ndb_t::collect(condition_ , node_delete_list); + expression_node::ndb_t::collect(incrementor_, node_delete_list); + expression_node::ndb_t::collect(loop_body_ , node_delete_list); + } + + std::size_t node_depth() const + { + return expression_node::ndb_t::compute_node_depth + (initialiser_, condition_, incrementor_, loop_body_); + } + private: - expression_ptr initialiser_ ; - expression_ptr condition_ ; - expression_ptr incrementor_ ; - expression_ptr loop_body_ ; - const bool initialiser_deletable_; - const bool condition_deletable_ ; - const bool incrementor_deletable_; - const bool loop_body_deletable_ ; + branch_t initialiser_; + branch_t condition_ ; + branch_t incrementor_; + branch_t loop_body_ ; }; #ifndef exprtk_disable_break_continue template - class while_loop_bc_node : public expression_node + class while_loop_bc_node : public expression_node, + public loop_runtime_checker { public: typedef expression_node* expression_ptr; + typedef std::pair branch_t; - while_loop_bc_node(expression_ptr condition, expression_ptr loop_body) - : condition_(condition), - loop_body_(loop_body), - condition_deletable_(branch_deletable(condition_)), - loop_body_deletable_(branch_deletable(loop_body_)) - {} - - ~while_loop_bc_node() + while_loop_bc_node(expression_ptr condition, + expression_ptr loop_body, + loop_runtime_check_ptr loop_rt_chk = loop_runtime_check_ptr(0)) + : loop_runtime_checker(loop_rt_chk, loop_runtime_check::e_while_loop) { - if (condition_ && condition_deletable_) - { - destroy_node(condition_); - } - - if (loop_body_ && loop_body_deletable_) - { - destroy_node(loop_body_); - } + construct_branch_pair(condition_, condition); + construct_branch_pair(loop_body_, loop_body); } inline T value() const { + assert(condition_.first); + assert(loop_body_.first); + T result = T(0); - while (is_true(condition_)) + loop_runtime_checker::reset(); + + while (is_true(condition_) && loop_runtime_checker::check()) { try { - result = loop_body_->value(); + result = loop_body_.first->value(); } catch(const break_exception& e) { @@ -6446,50 +7010,55 @@ namespace exprtk return expression_node::e_while; } + void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) + { + expression_node::ndb_t::collect(condition_, node_delete_list); + expression_node::ndb_t::collect(loop_body_, node_delete_list); + } + + std::size_t node_depth() const + { + return expression_node::ndb_t::compute_node_depth(condition_, loop_body_); + } + private: - expression_ptr condition_; - expression_ptr loop_body_; - const bool condition_deletable_; - const bool loop_body_deletable_; + branch_t condition_; + branch_t loop_body_; }; template - class repeat_until_loop_bc_node : public expression_node + class repeat_until_loop_bc_node : public expression_node, + public loop_runtime_checker { public: typedef expression_node* expression_ptr; + typedef std::pair branch_t; - repeat_until_loop_bc_node(expression_ptr condition, expression_ptr loop_body) - : condition_(condition), - loop_body_(loop_body), - condition_deletable_(branch_deletable(condition_)), - loop_body_deletable_(branch_deletable(loop_body_)) - {} - - ~repeat_until_loop_bc_node() + repeat_until_loop_bc_node(expression_ptr condition, + expression_ptr loop_body, + loop_runtime_check_ptr loop_rt_chk = loop_runtime_check_ptr(0)) + : loop_runtime_checker(loop_rt_chk, loop_runtime_check::e_repeat_until_loop) { - if (condition_ && condition_deletable_) - { - destroy_node(condition_); - } - - if (loop_body_ && loop_body_deletable_) - { - destroy_node(loop_body_); - } + construct_branch_pair(condition_, condition); + construct_branch_pair(loop_body_, loop_body); } inline T value() const { + assert(condition_.first); + assert(loop_body_.first); + T result = T(0); + loop_runtime_checker::reset(); + do { try { - result = loop_body_->value(); + result = loop_body_.first->value(); } catch(const break_exception& e) { @@ -6498,7 +7067,7 @@ namespace exprtk catch(const continue_exception&) {} } - while (is_false(condition_)); + while (is_false(condition_.first) && loop_runtime_checker::check()); return result; } @@ -6508,72 +7077,64 @@ namespace exprtk return expression_node::e_repeat; } + void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) + { + expression_node::ndb_t::collect(condition_, node_delete_list); + expression_node::ndb_t::collect(loop_body_, node_delete_list); + } + + std::size_t node_depth() const + { + return expression_node::ndb_t::compute_node_depth(condition_, loop_body_); + } + private: - expression_ptr condition_; - expression_ptr loop_body_; - const bool condition_deletable_; - const bool loop_body_deletable_; + branch_t condition_; + branch_t loop_body_; }; template - class for_loop_bc_node : public expression_node + class for_loop_bc_node : public expression_node, + public loop_runtime_checker { public: typedef expression_node* expression_ptr; + typedef std::pair branch_t; for_loop_bc_node(expression_ptr initialiser, - expression_ptr condition, - expression_ptr incrementor, - expression_ptr loop_body) - : initialiser_(initialiser), - condition_ (condition ), - incrementor_(incrementor), - loop_body_ (loop_body ), - initialiser_deletable_(branch_deletable(initialiser_)), - condition_deletable_ (branch_deletable(condition_ )), - incrementor_deletable_(branch_deletable(incrementor_)), - loop_body_deletable_ (branch_deletable(loop_body_ )) - {} - - ~for_loop_bc_node() + expression_ptr condition, + expression_ptr incrementor, + expression_ptr loop_body, + loop_runtime_check_ptr loop_rt_chk = loop_runtime_check_ptr(0)) + : loop_runtime_checker(loop_rt_chk, loop_runtime_check::e_for_loop) { - if (initialiser_ && initialiser_deletable_) - { - destroy_node(initialiser_); - } - - if (condition_ && condition_deletable_) - { - destroy_node(condition_); - } - - if (incrementor_ && incrementor_deletable_) - { - destroy_node(incrementor_); - } - - if (loop_body_ && loop_body_deletable_) - { - destroy_node(loop_body_); - } + construct_branch_pair(initialiser_, initialiser); + construct_branch_pair(condition_ , condition ); + construct_branch_pair(incrementor_, incrementor); + construct_branch_pair(loop_body_ , loop_body ); } inline T value() const { + assert(condition_.first); + assert(loop_body_.first); + T result = T(0); - if (initialiser_) - initialiser_->value(); + loop_runtime_checker::reset(); - if (incrementor_) + if (initialiser_.first) + initialiser_.first->value(); + + if (incrementor_.first) { - while (is_true(condition_)) + while (is_true(condition_) && loop_runtime_checker::check()) { try { - result = loop_body_->value(); + result = loop_body_.first->value(); } catch(const break_exception& e) { @@ -6582,16 +7143,16 @@ namespace exprtk catch(const continue_exception&) {} - incrementor_->value(); + incrementor_.first->value(); } } else { - while (is_true(condition_)) + while (is_true(condition_) && loop_runtime_checker::check()) { try { - result = loop_body_->value(); + result = loop_body_.first->value(); } catch(const break_exception& e) { @@ -6610,16 +7171,26 @@ namespace exprtk return expression_node::e_for; } + void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) + { + expression_node::ndb_t::collect(initialiser_, node_delete_list); + expression_node::ndb_t::collect(condition_ , node_delete_list); + expression_node::ndb_t::collect(incrementor_, node_delete_list); + expression_node::ndb_t::collect(loop_body_ , node_delete_list); + } + + std::size_t node_depth() const + { + return expression_node::ndb_t::compute_node_depth + (initialiser_, condition_, incrementor_, loop_body_); + } + private: - expression_ptr initialiser_; - expression_ptr condition_ ; - expression_ptr incrementor_; - expression_ptr loop_body_ ; - const bool initialiser_deletable_; - const bool condition_deletable_ ; - const bool incrementor_deletable_; - const bool loop_body_deletable_ ; + branch_t initialiser_; + branch_t condition_ ; + branch_t incrementor_; + branch_t loop_body_ ; }; #endif @@ -6629,44 +7200,31 @@ namespace exprtk public: typedef expression_node* expression_ptr; + typedef std::pair branch_t; template class Sequence> - switch_node(const Sequence& arg_list) + template class Sequence> + explicit switch_node(const Sequence& arg_list) { if (1 != (arg_list.size() & 1)) return; arg_list_.resize(arg_list.size()); - delete_branch_.resize(arg_list.size()); for (std::size_t i = 0; i < arg_list.size(); ++i) { if (arg_list[i]) { - arg_list_[i] = arg_list[i]; - delete_branch_[i] = static_cast(branch_deletable(arg_list_[i]) ? 1 : 0); + construct_branch_pair(arg_list_[i], arg_list[i]); } else { arg_list_.clear(); - delete_branch_.clear(); return; } } } - ~switch_node() - { - for (std::size_t i = 0; i < arg_list_.size(); ++i) - { - if (arg_list_[i] && delete_branch_[i]) - { - destroy_node(arg_list_[i]); - } - } - } - inline T value() const { if (!arg_list_.empty()) @@ -6675,8 +7233,8 @@ namespace exprtk for (std::size_t i = 0; i < upper_bound; i += 2) { - expression_ptr condition = arg_list_[i ]; - expression_ptr consequent = arg_list_[i + 1]; + expression_ptr condition = arg_list_[i ].first; + expression_ptr consequent = arg_list_[i + 1].first; if (is_true(condition)) { @@ -6684,7 +7242,7 @@ namespace exprtk } } - return arg_list_[upper_bound]->value(); + return arg_list_[upper_bound].first->value(); } else return std::numeric_limits::quiet_NaN(); @@ -6695,10 +7253,19 @@ namespace exprtk return expression_node::e_switch; } + void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) + { + expression_node::ndb_t::collect(arg_list_, node_delete_list); + } + + std::size_t node_depth() const + { + return expression_node::ndb_t::compute_node_depth(arg_list_); + } + protected: - std::vector arg_list_; - std::vector delete_branch_; + std::vector arg_list_; }; template @@ -6709,8 +7276,8 @@ namespace exprtk typedef expression_node* expression_ptr; template class Sequence> - switch_n_node(const Sequence& arg_list) + template class Sequence> + explicit switch_n_node(const Sequence& arg_list) : switch_node(arg_list) {} @@ -6726,44 +7293,31 @@ namespace exprtk public: typedef expression_node* expression_ptr; + typedef std::pair branch_t; template class Sequence> - multi_switch_node(const Sequence& arg_list) + template class Sequence> + explicit multi_switch_node(const Sequence& arg_list) { if (0 != (arg_list.size() & 1)) return; arg_list_.resize(arg_list.size()); - delete_branch_.resize(arg_list.size()); for (std::size_t i = 0; i < arg_list.size(); ++i) { if (arg_list[i]) { - arg_list_[i] = arg_list[i]; - delete_branch_[i] = static_cast(branch_deletable(arg_list_[i]) ? 1 : 0); + construct_branch_pair(arg_list_[i], arg_list[i]); } else { arg_list_.clear(); - delete_branch_.clear(); return; } } } - ~multi_switch_node() - { - for (std::size_t i = 0; i < arg_list_.size(); ++i) - { - if (arg_list_[i] && delete_branch_[i]) - { - destroy_node(arg_list_[i]); - } - } - } - inline T value() const { T result = T(0); @@ -6777,8 +7331,8 @@ namespace exprtk for (std::size_t i = 0; i < upper_bound; i += 2) { - expression_ptr condition = arg_list_[i ]; - expression_ptr consequent = arg_list_[i + 1]; + expression_ptr condition = arg_list_[i ].first; + expression_ptr consequent = arg_list_[i + 1].first; if (is_true(condition)) { @@ -6794,10 +7348,19 @@ namespace exprtk return expression_node::e_mswitch; } + void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) + { + expression_node::ndb_t::collect(arg_list_, node_delete_list); + } + + std::size_t node_depth() const + { + return expression_node::ndb_t::compute_node_depth(arg_list_); + } + private: - std::vector arg_list_; - std::vector delete_branch_; + std::vector arg_list_; }; template @@ -6824,7 +7387,7 @@ namespace exprtk : value_(&null_value) {} - variable_node(T& v) + explicit variable_node(T& v) : value_(&v) {} @@ -6913,30 +7476,26 @@ namespace exprtk } } - bool const_range() + bool const_range() const { return ( n0_c.first && n1_c.first) && (!n0_e.first && !n1_e.first); } - bool var_range() + bool var_range() const { return ( n0_e.first && n1_e.first) && (!n0_c.first && !n1_c.first); } - bool operator() (std::size_t& r0, std::size_t& r1, const std::size_t& size = std::numeric_limits::max()) const + bool operator() (std::size_t& r0, std::size_t& r1, + const std::size_t& size = std::numeric_limits::max()) const { if (n0_c.first) r0 = n0_c.second; else if (n0_e.first) { - T r0_value = n0_e.second->value(); - - if (r0_value < 0) - return false; - else - r0 = static_cast(details::numeric::to_int64(r0_value)); + r0 = static_cast(details::numeric::to_int64(n0_e.second->value())); } else return false; @@ -6945,12 +7504,7 @@ namespace exprtk r1 = n1_c.second; else if (n1_e.first) { - T r1_value = n1_e.second->value(); - - if (r1_value < 0) - return false; - else - r1 = static_cast(details::numeric::to_int64(r1_value)); + r1 = static_cast(details::numeric::to_int64(n1_e.second->value())); } else return false; @@ -6966,7 +7520,11 @@ namespace exprtk cache.first = r0; cache.second = r1; + #ifndef exprtk_enable_runtime_checks return (r0 <= r1); + #else + return range_runtime_check(r0, r1, size); + #endif } inline std::size_t const_size() const @@ -6984,6 +7542,27 @@ namespace exprtk std::pair n0_c; std::pair n1_c; mutable cached_range_t cache; + + #ifdef exprtk_enable_runtime_checks + bool range_runtime_check(const std::size_t r0, + const std::size_t r1, + const std::size_t size) const + { + if ((r0 < 0) || (r0 >= size)) + { + throw std::runtime_error("range error: (r0 < 0) || (r0 >= size)"); + return false; + } + + if ((r1 < 0) || (r1 >= size)) + { + throw std::runtime_error("range error: (r1 < 0) || (r1 >= size)"); + return false; + } + + return (r0 <= r1); + } + #endif }; template @@ -7047,7 +7626,7 @@ namespace exprtk typedef vector_node* vector_node_ptr; typedef vec_data_store vds_t; - vector_node(vector_holder_t* vh) + explicit vector_node(vector_holder_t* vh) : vector_holder_(vh), vds_((*vector_holder_).size(),(*vector_holder_)[0]) { @@ -7111,38 +7690,31 @@ namespace exprtk { public: - typedef expression_node* expression_ptr; - typedef vector_holder vector_holder_t; - typedef vector_holder_t* vector_holder_ptr; + typedef expression_node* expression_ptr; + typedef vector_holder vector_holder_t; + typedef vector_holder_t* vector_holder_ptr; + typedef std::pair branch_t; vector_elem_node(expression_ptr index, vector_holder_ptr vec_holder) - : index_(index), - vec_holder_(vec_holder), - vector_base_((*vec_holder)[0]), - index_deletable_(branch_deletable(index_)) - {} - - ~vector_elem_node() + : vec_holder_(vec_holder), + vector_base_((*vec_holder)[0]) { - if (index_ && index_deletable_) - { - destroy_node(index_); - } + construct_branch_pair(index_, index); } inline T value() const { - return *(vector_base_ + static_cast(details::numeric::to_int64(index_->value()))); + return *(vector_base_ + static_cast(details::numeric::to_int64(index_.first->value()))); } inline T& ref() { - return *(vector_base_ + static_cast(details::numeric::to_int64(index_->value()))); + return *(vector_base_ + static_cast(details::numeric::to_int64(index_.first->value()))); } inline const T& ref() const { - return *(vector_base_ + static_cast(details::numeric::to_int64(index_->value()))); + return *(vector_base_ + static_cast(details::numeric::to_int64(index_.first->value()))); } inline typename expression_node::node_type type() const @@ -7155,12 +7727,21 @@ namespace exprtk return (*vec_holder_); } + void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) + { + expression_node::ndb_t::collect(index_, node_delete_list); + } + + std::size_t node_depth() const + { + return expression_node::ndb_t::compute_node_depth(index_); + } + private: - expression_ptr index_; vector_holder_ptr vec_holder_; T* vector_base_; - const bool index_deletable_; + branch_t index_; }; template @@ -7169,41 +7750,33 @@ namespace exprtk { public: - typedef expression_node* expression_ptr; - typedef vector_holder vector_holder_t; - typedef vector_holder_t* vector_holder_ptr; - typedef vec_data_store vds_t; + typedef expression_node* expression_ptr; + typedef vector_holder vector_holder_t; + typedef vector_holder_t* vector_holder_ptr; + typedef vec_data_store vds_t; + typedef std::pair branch_t; rebasevector_elem_node(expression_ptr index, vector_holder_ptr vec_holder) - : index_(index), - index_deletable_(branch_deletable(index_)), - vector_holder_(vec_holder), + : vector_holder_(vec_holder), vds_((*vector_holder_).size(),(*vector_holder_)[0]) { vector_holder_->set_ref(&vds_.ref()); - } - - ~rebasevector_elem_node() - { - if (index_ && index_deletable_) - { - destroy_node(index_); - } + construct_branch_pair(index_, index); } inline T value() const { - return *(vds_.data() + static_cast(details::numeric::to_int64(index_->value()))); + return *(vds_.data() + static_cast(details::numeric::to_int64(index_.first->value()))); } inline T& ref() { - return *(vds_.data() + static_cast(details::numeric::to_int64(index_->value()))); + return *(vds_.data() + static_cast(details::numeric::to_int64(index_.first->value()))); } inline const T& ref() const { - return *(vds_.data() + static_cast(details::numeric::to_int64(index_->value()))); + return *(vds_.data() + static_cast(details::numeric::to_int64(index_.first->value()))); } inline typename expression_node::node_type type() const @@ -7216,12 +7789,21 @@ namespace exprtk return (*vector_holder_); } + void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) + { + expression_node::ndb_t::template collect(index_, node_delete_list); + } + + std::size_t node_depth() const + { + return expression_node::ndb_t::compute_node_depth(index_); + } + private: - expression_ptr index_; - const bool index_deletable_; vector_holder_ptr vector_holder_; vds_t vds_; + branch_t index_; }; template @@ -7292,17 +7874,6 @@ namespace exprtk single_value_initialse_(single_value_initialse) {} - ~vector_assignment_node() - { - for (std::size_t i = 0; i < initialiser_list_.size(); ++i) - { - if (branch_deletable(initialiser_list_[i])) - { - destroy_node(initialiser_list_[i]); - } - } - } - inline T value() const { if (single_value_initialse_) @@ -7338,6 +7909,16 @@ namespace exprtk return expression_node::e_vecdefass; } + void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) + { + expression_node::ndb_t::collect(initialiser_list_, node_delete_list); + } + + std::size_t node_depth() const + { + return expression_node::ndb_t::compute_node_depth(initialiser_list_); + } + private: vector_assignment_node& operator=(const vector_assignment_node&); @@ -7459,6 +8040,9 @@ namespace exprtk inline T value() const { + assert(binary_node::branch_[0].first); + assert(binary_node::branch_[1].first); + if (initialised_) { binary_node::branch_[0].first->value(); @@ -7560,7 +8144,7 @@ namespace exprtk return ref(); } - const char_t* base() const + char_cptr base() const { return &(*value_)[0]; } @@ -7640,7 +8224,7 @@ namespace exprtk return (*value_); } - const char_t* base() const + char_cptr base() const { return &(*value_)[0]; } @@ -7718,7 +8302,7 @@ namespace exprtk return value_; } - const char_t* base() const + char_cptr base() const { return value_.data(); } @@ -7763,18 +8347,18 @@ namespace exprtk { public: - typedef expression_node * expression_ptr; - typedef stringvar_node * strvar_node_ptr; - typedef string_base_node* str_base_ptr; - typedef range_pack range_t; - typedef range_t* range_ptr; - typedef range_interface irange_t; - typedef irange_t* irange_ptr; + typedef expression_node * expression_ptr; + typedef stringvar_node * strvar_node_ptr; + typedef string_base_node* str_base_ptr; + typedef range_pack range_t; + typedef range_t* range_ptr; + typedef range_interface irange_t; + typedef irange_t* irange_ptr; + typedef std::pair branch_t; + generic_string_range_node(expression_ptr str_branch, const range_t& brange) : initialised_(false), - branch_(str_branch), - branch_deletable_(branch_deletable(branch_)), str_base_ptr_ (0), str_range_ptr_(0), base_range_(brange) @@ -7784,14 +8368,16 @@ namespace exprtk range_.cache.first = range_.n0_c.second; range_.cache.second = range_.n1_c.second; - if (is_generally_string_node(branch_)) + construct_branch_pair(branch_, str_branch); + + if (is_generally_string_node(branch_.first)) { - str_base_ptr_ = dynamic_cast(branch_); + str_base_ptr_ = dynamic_cast(branch_.first); if (0 == str_base_ptr_) return; - str_range_ptr_ = dynamic_cast(branch_); + str_range_ptr_ = dynamic_cast(branch_.first); if (0 == str_range_ptr_) return; @@ -7803,18 +8389,15 @@ namespace exprtk ~generic_string_range_node() { base_range_.free(); - - if (branch_ && branch_deletable_) - { - destroy_node(branch_); - } } inline T value() const { if (initialised_) { - branch_->value(); + assert(branch_.first); + + branch_.first->value(); std::size_t str_r0 = 0; std::size_t str_r1 = 0; @@ -7822,13 +8405,13 @@ namespace exprtk std::size_t r0 = 0; std::size_t r1 = 0; - range_t& range = str_range_ptr_->range_ref(); + const range_t& range = str_range_ptr_->range_ref(); const std::size_t base_str_size = str_base_ptr_->size(); if ( - range (str_r0,str_r1,base_str_size) && - base_range_( r0, r1,base_str_size) + range (str_r0, str_r1, base_str_size) && + base_range_( r0, r1, base_str_size) ) { const std::size_t size = (r1 - r0) + 1; @@ -7848,7 +8431,7 @@ namespace exprtk return value_; } - const char_t* base() const + char_cptr base() const { return &value_[0]; } @@ -7873,11 +8456,20 @@ namespace exprtk return expression_node::e_strgenrange; } + void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) + { + expression_node::ndb_t::collect(branch_, node_delete_list); + } + + std::size_t node_depth() const + { + return expression_node::ndb_t::compute_node_depth(branch_); + } + private: bool initialised_; - expression_ptr branch_; - const bool branch_deletable_; + branch_t branch_; str_base_ptr str_base_ptr_; irange_ptr str_range_ptr_; mutable range_t base_range_; @@ -7951,6 +8543,9 @@ namespace exprtk { if (initialised_) { + assert(binary_node::branch_[0].first); + assert(binary_node::branch_[1].first); + binary_node::branch_[0].first->value(); binary_node::branch_[1].first->value(); @@ -7960,12 +8555,12 @@ namespace exprtk std::size_t str1_r0 = 0; std::size_t str1_r1 = 0; - range_t& range0 = str0_range_ptr_->range_ref(); - range_t& range1 = str1_range_ptr_->range_ref(); + const range_t& range0 = str0_range_ptr_->range_ref(); + const range_t& range1 = str1_range_ptr_->range_ref(); if ( - range0(str0_r0,str0_r1,str0_base_ptr_->size()) && - range1(str1_r0,str1_r1,str1_base_ptr_->size()) + range0(str0_r0, str0_r1, str0_base_ptr_->size()) && + range1(str1_r0, str1_r1, str1_base_ptr_->size()) ) { const std::size_t size0 = (str0_r1 - str0_r0) + 1; @@ -7987,7 +8582,7 @@ namespace exprtk return value_; } - const char_t* base() const + char_cptr base() const { return &value_[0]; } @@ -8061,10 +8656,13 @@ namespace exprtk { if (initialised_) { + assert(binary_node::branch_[0].first); + assert(binary_node::branch_[1].first); + binary_node::branch_[0].first->value(); binary_node::branch_[1].first->value(); - std::swap(str0_node_ptr_->ref(),str1_node_ptr_->ref()); + std::swap(str0_node_ptr_->ref(), str1_node_ptr_->ref()); } return std::numeric_limits::quiet_NaN(); @@ -8075,7 +8673,7 @@ namespace exprtk return str0_node_ptr_->str(); } - const char_t* base() const + char_cptr base() const { return str0_node_ptr_->base(); } @@ -8135,12 +8733,12 @@ namespace exprtk if (0 == str0_base_ptr_) return; - irange_ptr range_ptr = dynamic_cast(binary_node::branch_[0].first); + irange_ptr range = dynamic_cast(binary_node::branch_[0].first); - if (0 == range_ptr) + if (0 == range) return; - str0_range_ptr_ = &(range_ptr->range_ref()); + str0_range_ptr_ = &(range->range_ref()); } if (is_generally_string_node(binary_node::branch_[1].first)) @@ -8150,12 +8748,12 @@ namespace exprtk if (0 == str1_base_ptr_) return; - irange_ptr range_ptr = dynamic_cast(binary_node::branch_[1].first); + irange_ptr range = dynamic_cast(binary_node::branch_[1].first); - if (0 == range_ptr) + if (0 == range) return; - str1_range_ptr_ = &(range_ptr->range_ref()); + str1_range_ptr_ = &(range->range_ref()); } initialised_ = str0_base_ptr_ && @@ -8168,6 +8766,9 @@ namespace exprtk { if (initialised_) { + assert(binary_node::branch_[0].first); + assert(binary_node::branch_[1].first); + binary_node::branch_[0].first->value(); binary_node::branch_[1].first->value(); @@ -8177,23 +8778,23 @@ namespace exprtk std::size_t str1_r0 = 0; std::size_t str1_r1 = 0; - range_t& range0 = (*str0_range_ptr_); - range_t& range1 = (*str1_range_ptr_); + const range_t& range0 = (*str0_range_ptr_); + const range_t& range1 = (*str1_range_ptr_); if ( - range0(str0_r0,str0_r1,str0_base_ptr_->size()) && - range1(str1_r0,str1_r1,str1_base_ptr_->size()) + range0(str0_r0, str0_r1, str0_base_ptr_->size()) && + range1(str1_r0, str1_r1, str1_base_ptr_->size()) ) { const std::size_t size0 = range0.cache_size(); const std::size_t size1 = range1.cache_size(); const std::size_t max_size = std::min(size0,size1); - char_t* s0 = const_cast(str0_base_ptr_->base() + str0_r0); - char_t* s1 = const_cast(str1_base_ptr_->base() + str1_r0); + char_ptr s0 = const_cast(str0_base_ptr_->base() + str0_r0); + char_ptr s1 = const_cast(str1_base_ptr_->base() + str1_r0); loop_unroll::details lud(max_size); - const char_t* upper_bound = s0 + lud.upper_bound; + char_cptr upper_bound = s0 + lud.upper_bound; while (s0 < upper_bound) { @@ -8220,8 +8821,8 @@ namespace exprtk exprtk_disable_fallthrough_begin switch (lud.remainder) { - #define case_stmt(N) \ - case N : { std::swap(s0[i],s1[i]); ++i; } \ + #define case_stmt(N) \ + case N : { std::swap(s0[i], s1[i]); ++i; } \ #ifndef exprtk_disable_superscalar_unroll case_stmt(15) case_stmt(14) @@ -8299,38 +8900,32 @@ namespace exprtk { public: - typedef expression_node * expression_ptr; - typedef string_base_node* str_base_ptr; + typedef expression_node * expression_ptr; + typedef string_base_node* str_base_ptr; + typedef std::pair branch_t; - string_size_node(expression_ptr brnch) - : branch_(brnch), - branch_deletable_(branch_deletable(branch_)), - str_base_ptr_(0) + + explicit string_size_node(expression_ptr branch) + : str_base_ptr_(0) { - if (is_generally_string_node(branch_)) + construct_branch_pair(branch_, branch); + + if (is_generally_string_node(branch_.first)) { - str_base_ptr_ = dynamic_cast(branch_); + str_base_ptr_ = dynamic_cast(branch_.first); if (0 == str_base_ptr_) return; } } - ~string_size_node() - { - if (branch_ && branch_deletable_) - { - destroy_node(branch_); - } - } - inline T value() const { T result = std::numeric_limits::quiet_NaN(); if (str_base_ptr_) { - branch_->value(); + branch_.first->value(); result = T(str_base_ptr_->size()); } @@ -8342,22 +8937,31 @@ namespace exprtk return expression_node::e_stringsize; } + void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) + { + expression_node::ndb_t::collect(branch_, node_delete_list); + } + + std::size_t node_depth() const + { + return expression_node::ndb_t::compute_node_depth(branch_); + } + private: - expression_ptr branch_; - const bool branch_deletable_; - str_base_ptr str_base_ptr_; + branch_t branch_; + str_base_ptr str_base_ptr_; }; struct asn_assignment { - static inline void execute(std::string& s, const char_t* data, const std::size_t size) + static inline void execute(std::string& s, char_cptr data, const std::size_t size) { s.assign(data,size); } }; struct asn_addassignment { - static inline void execute(std::string& s, const char_t* data, const std::size_t size) + static inline void execute(std::string& s, char_cptr data, const std::size_t size) { s.append(data,size); } }; @@ -8400,12 +9004,12 @@ namespace exprtk if (0 == str1_base_ptr_) return; - irange_ptr range_ptr = dynamic_cast(binary_node::branch_[1].first); + irange_ptr range = dynamic_cast(binary_node::branch_[1].first); - if (0 == range_ptr) + if (0 == range) return; - str1_range_ptr_ = &(range_ptr->range_ref()); + str1_range_ptr_ = &(range->range_ref()); } initialised_ = str0_base_ptr_ && @@ -8418,12 +9022,15 @@ namespace exprtk { if (initialised_) { + assert(binary_node::branch_[0].first); + assert(binary_node::branch_[1].first); + binary_node::branch_[1].first->value(); std::size_t r0 = 0; std::size_t r1 = 0; - range_t& range = (*str1_range_ptr_); + const range_t& range = (*str1_range_ptr_); if (range(r0, r1, str1_base_ptr_->size())) { @@ -8443,7 +9050,7 @@ namespace exprtk return str0_node_ptr_->str(); } - const char_t* base() const + char_cptr base() const { return str0_node_ptr_->base(); } @@ -8484,37 +9091,38 @@ namespace exprtk { public: - typedef expression_node * expression_ptr; - typedef stringvar_node * strvar_node_ptr; - typedef string_base_node* str_base_ptr; - typedef range_pack range_t; - typedef range_t* range_ptr; - typedef range_interface irange_t; - typedef irange_t* irange_ptr; + typedef expression_node * expression_ptr; + typedef stringvar_node * strvar_node_ptr; + typedef string_range_node* str_rng_node_ptr; + typedef string_base_node * str_base_ptr; + typedef range_pack range_t; + typedef range_t* range_ptr; + typedef range_interface irange_t; + typedef irange_t* irange_ptr; assignment_string_range_node(const operator_type& opr, expression_ptr branch0, expression_ptr branch1) : binary_node(opr, branch0, branch1), initialised_(false), - str0_base_ptr_ (0), - str1_base_ptr_ (0), - str0_node_ptr_ (0), - str0_range_ptr_(0), - str1_range_ptr_(0) + str0_base_ptr_ (0), + str1_base_ptr_ (0), + str0_rng_node_ptr_ (0), + str0_range_ptr_ (0), + str1_range_ptr_ (0) { if (is_string_range_node(binary_node::branch_[0].first)) { - str0_node_ptr_ = static_cast(binary_node::branch_[0].first); + str0_rng_node_ptr_ = static_cast(binary_node::branch_[0].first); str0_base_ptr_ = dynamic_cast(binary_node::branch_[0].first); - irange_ptr range_ptr = dynamic_cast(binary_node::branch_[0].first); + irange_ptr range = dynamic_cast(binary_node::branch_[0].first); - if (0 == range_ptr) + if (0 == range) return; - str0_range_ptr_ = &(range_ptr->range_ref()); + str0_range_ptr_ = &(range->range_ref()); } if (is_generally_string_node(binary_node::branch_[1].first)) @@ -8524,25 +9132,28 @@ namespace exprtk if (0 == str1_base_ptr_) return; - irange_ptr range_ptr = dynamic_cast(binary_node::branch_[1].first); + irange_ptr range = dynamic_cast(binary_node::branch_[1].first); - if (0 == range_ptr) + if (0 == range) return; - str1_range_ptr_ = &(range_ptr->range_ref()); + str1_range_ptr_ = &(range->range_ref()); } - initialised_ = str0_base_ptr_ && - str1_base_ptr_ && - str0_node_ptr_ && - str0_range_ptr_ && - str1_range_ptr_ ; + initialised_ = str0_base_ptr_ && + str1_base_ptr_ && + str0_rng_node_ptr_ && + str0_range_ptr_ && + str1_range_ptr_ ; } inline T value() const { if (initialised_) { + assert(binary_node::branch_[0].first); + assert(binary_node::branch_[1].first); + binary_node::branch_[0].first->value(); binary_node::branch_[1].first->value(); @@ -8552,19 +9163,19 @@ namespace exprtk std::size_t s1_r0 = 0; std::size_t s1_r1 = 0; - range_t& range0 = (*str0_range_ptr_); - range_t& range1 = (*str1_range_ptr_); + const range_t& range0 = (*str0_range_ptr_); + const range_t& range1 = (*str1_range_ptr_); if ( range0(s0_r0, s0_r1, str0_base_ptr_->size()) && range1(s1_r0, s1_r1, str1_base_ptr_->size()) ) { - std::size_t size = std::min((s0_r1 - s0_r0),(s1_r1 - s1_r0)) + 1; + const std::size_t size = std::min((s0_r1 - s0_r0), (s1_r1 - s1_r0)) + 1; std::copy(str1_base_ptr_->base() + s1_r0, str1_base_ptr_->base() + s1_r0 + size, - const_cast(base() + s0_r0)); + const_cast(base() + s0_r0)); } } @@ -8573,27 +9184,27 @@ namespace exprtk std::string str() const { - return str0_node_ptr_->str(); + return str0_base_ptr_->str(); } - const char_t* base() const + char_cptr base() const { - return str0_node_ptr_->base(); + return str0_base_ptr_->base(); } std::size_t size() const { - return str0_node_ptr_->size(); + return str0_base_ptr_->size(); } range_t& range_ref() { - return str0_node_ptr_->range_ref(); + return str0_rng_node_ptr_->range_ref(); } const range_t& range_ref() const { - return str0_node_ptr_->range_ref(); + return str0_rng_node_ptr_->range_ref(); } inline typename expression_node::node_type type() const @@ -8603,12 +9214,12 @@ namespace exprtk private: - bool initialised_; - str_base_ptr str0_base_ptr_; - str_base_ptr str1_base_ptr_; - strvar_node_ptr str0_node_ptr_; - range_ptr str0_range_ptr_; - range_ptr str1_range_ptr_; + bool initialised_; + str_base_ptr str0_base_ptr_; + str_base_ptr str1_base_ptr_; + str_rng_node_ptr str0_rng_node_ptr_; + range_ptr str0_range_ptr_; + range_ptr str1_range_ptr_; }; template @@ -8625,16 +9236,16 @@ namespace exprtk typedef range_interface irange_t; typedef irange_t* irange_ptr; - conditional_string_node(expression_ptr test, + conditional_string_node(expression_ptr condition, expression_ptr consequent, expression_ptr alternative) - : trinary_node(details::e_default,consequent,alternative,test), + : trinary_node(details::e_default,consequent,alternative,condition), initialised_(false), str0_base_ptr_ (0), str1_base_ptr_ (0), str0_range_ptr_(0), str1_range_ptr_(0), - test_ (test), + condition_ (condition), consequent_ (consequent), alternative_(alternative) { @@ -8681,16 +9292,20 @@ namespace exprtk { if (initialised_) { + assert(condition_ ); + assert(consequent_ ); + assert(alternative_); + std::size_t r0 = 0; std::size_t r1 = 0; - if (is_true(test_)) + if (is_true(condition_)) { consequent_->value(); - range_t& range = str0_range_ptr_->range_ref(); + const range_t& range = str0_range_ptr_->range_ref(); - if (range(r0,r1,str0_base_ptr_->size())) + if (range(r0, r1, str0_base_ptr_->size())) { const std::size_t size = (r1 - r0) + 1; @@ -8706,9 +9321,9 @@ namespace exprtk { alternative_->value(); - range_t& range = str1_range_ptr_->range_ref(); + const range_t& range = str1_range_ptr_->range_ref(); - if (range(r0,r1,str1_base_ptr_->size())) + if (range(r0, r1, str1_base_ptr_->size())) { const std::size_t size = (r1 - r0) + 1; @@ -8730,7 +9345,7 @@ namespace exprtk return value_; } - const char_t* base() const + char_cptr base() const { return &value_[0]; } @@ -8765,7 +9380,7 @@ namespace exprtk mutable range_t range_; mutable std::string value_; - expression_ptr test_; + expression_ptr condition_; expression_ptr consequent_; expression_ptr alternative_; }; @@ -8784,13 +9399,13 @@ namespace exprtk typedef range_interface irange_t; typedef irange_t* irange_ptr; - cons_conditional_str_node(expression_ptr test, + cons_conditional_str_node(expression_ptr condition, expression_ptr consequent) - : binary_node(details::e_default, consequent, test), + : binary_node(details::e_default, consequent, condition), initialised_(false), str0_base_ptr_ (0), str0_range_ptr_(0), - test_ (test), + condition_ (condition), consequent_(consequent) { range_.n0_c = std::make_pair(true,0); @@ -8819,16 +9434,19 @@ namespace exprtk { if (initialised_) { - if (is_true(test_)) + assert(condition_ ); + assert(consequent_); + + if (is_true(condition_)) { consequent_->value(); - range_t& range = str0_range_ptr_->range_ref(); + const range_t& range = str0_range_ptr_->range_ref(); std::size_t r0 = 0; std::size_t r1 = 0; - if (range(r0,r1,str0_base_ptr_->size())) + if (range(r0, r1, str0_base_ptr_->size())) { const std::size_t size = (r1 - r0) + 1; @@ -8850,7 +9468,7 @@ namespace exprtk return value_; } - const char_t* base() const + char_cptr base() const { return &value_[0]; } @@ -8883,7 +9501,7 @@ namespace exprtk mutable range_t range_; mutable std::string value_; - expression_ptr test_; + expression_ptr condition_; expression_ptr consequent_; }; @@ -8894,33 +9512,34 @@ namespace exprtk { public: - typedef expression_node * expression_ptr; - typedef string_base_node* str_base_ptr; - typedef range_pack range_t; - typedef range_t* range_ptr; - typedef range_interface irange_t; - typedef irange_t* irange_ptr; + typedef expression_node * expression_ptr; + typedef string_base_node* str_base_ptr; + typedef range_pack range_t; + typedef range_t* range_ptr; + typedef range_interface irange_t; + typedef irange_t* irange_ptr; + typedef std::pair branch_t; template class Sequence> - str_vararg_node(const Sequence& arg_list) - : final_node_(arg_list.back()), - final_deletable_(branch_deletable(final_node_)), - initialised_(false), + template class Sequence> + explicit str_vararg_node(const Sequence& arg_list) + : initialised_(false), str_base_ptr_ (0), str_range_ptr_(0) { - if (0 == final_node_) + construct_branch_pair(final_node_, const_cast(arg_list.back())); + + if (0 == final_node_.first) return; - else if (!is_generally_string_node(final_node_)) + else if (!is_generally_string_node(final_node_.first)) return; - str_base_ptr_ = dynamic_cast(final_node_); + str_base_ptr_ = dynamic_cast(final_node_.first); if (0 == str_base_ptr_) return; - str_range_ptr_ = dynamic_cast(final_node_); + str_range_ptr_ = dynamic_cast(final_node_.first); if (0 == str_range_ptr_) return; @@ -8932,41 +9551,22 @@ namespace exprtk const std::size_t arg_list_size = arg_list.size() - 1; arg_list_.resize(arg_list_size); - delete_branch_.resize(arg_list_size); for (std::size_t i = 0; i < arg_list_size; ++i) { if (arg_list[i]) { - arg_list_[i] = arg_list[i]; - delete_branch_[i] = static_cast(branch_deletable(arg_list_[i]) ? 1 : 0); + construct_branch_pair(arg_list_[i], arg_list[i]); } else { arg_list_.clear(); - delete_branch_.clear(); return; } } } } - ~str_vararg_node() - { - if (final_node_ && final_deletable_) - { - destroy_node(final_node_); - } - - for (std::size_t i = 0; i < arg_list_.size(); ++i) - { - if (arg_list_[i] && delete_branch_[i]) - { - destroy_node(arg_list_[i]); - } - } - } - inline T value() const { if (!arg_list_.empty()) @@ -8974,7 +9574,7 @@ namespace exprtk VarArgFunction::process(arg_list_); } - final_node_->value(); + final_node_.first->value(); return std::numeric_limits::quiet_NaN(); } @@ -8984,7 +9584,7 @@ namespace exprtk return str_base_ptr_->str(); } - const char_t* base() const + char_cptr base() const { return str_base_ptr_->base(); } @@ -9009,15 +9609,26 @@ namespace exprtk return expression_node::e_stringvararg; } + void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) + { + expression_node::ndb_t::collect(final_node_, node_delete_list); + expression_node::ndb_t::collect(arg_list_ , node_delete_list); + } + + std::size_t node_depth() const + { + return std::max( + expression_node::ndb_t::compute_node_depth(final_node_), + expression_node::ndb_t::compute_node_depth(arg_list_ )); + } + private: - expression_ptr final_node_; - bool final_deletable_; - bool initialised_; - str_base_ptr str_base_ptr_; - irange_ptr str_range_ptr_; - std::vector arg_list_; - std::vector delete_branch_; + bool initialised_; + branch_t final_node_; + str_base_ptr str_base_ptr_; + irange_ptr str_range_ptr_; + std::vector arg_list_; }; #endif @@ -9050,14 +9661,14 @@ namespace exprtk template \ struct sf##NN##_op : public sf_base \ { \ - typedef typename sf_base::Type Type; \ + typedef typename sf_base::Type const Type; \ static inline T process(Type x, Type y, Type z) \ { \ return (OP0); \ } \ static inline std::string id() \ { \ - return OP1; \ + return (OP1); \ } \ }; \ @@ -9114,12 +9725,15 @@ namespace exprtk template \ struct sf##NN##_op : public sf_base \ { \ - typedef typename sf_base::Type Type; \ + typedef typename sf_base::Type const Type; \ static inline T process(Type x, Type y, Type z, Type w) \ { \ return (OP0); \ } \ - static inline std::string id() { return OP1; } \ + static inline std::string id() \ + { \ + return (OP1); \ + } \ }; \ define_sfop4(48,(x + ((y + z) / w)),"t+((t+t)/t)") @@ -9258,6 +9872,10 @@ namespace exprtk inline T value() const { + assert(trinary_node::branch_[0].first); + assert(trinary_node::branch_[1].first); + assert(trinary_node::branch_[2].first); + const T x = trinary_node::branch_[0].first->value(); const T y = trinary_node::branch_[1].first->value(); const T z = trinary_node::branch_[2].first->value(); @@ -9283,6 +9901,11 @@ namespace exprtk inline T value() const { + assert(quaternary_node::branch_[0].first); + assert(quaternary_node::branch_[1].first); + assert(quaternary_node::branch_[2].first); + assert(quaternary_node::branch_[3].first); + const T x = quaternary_node::branch_[0].first->value(); const T y = quaternary_node::branch_[1].first->value(); const T z = quaternary_node::branch_[2].first->value(); @@ -9366,47 +9989,31 @@ namespace exprtk public: typedef expression_node* expression_ptr; + typedef std::pair branch_t; template class Sequence> - vararg_node(const Sequence& arg_list) + template class Sequence> + explicit vararg_node(const Sequence& arg_list) { - arg_list_ .resize(arg_list.size()); - delete_branch_.resize(arg_list.size()); + arg_list_.resize(arg_list.size()); for (std::size_t i = 0; i < arg_list.size(); ++i) { if (arg_list[i]) { - arg_list_[i] = arg_list[i]; - delete_branch_[i] = static_cast(branch_deletable(arg_list_[i]) ? 1 : 0); + construct_branch_pair(arg_list_[i],arg_list[i]); } else { arg_list_.clear(); - delete_branch_.clear(); return; } } } - ~vararg_node() - { - for (std::size_t i = 0; i < arg_list_.size(); ++i) - { - if (arg_list_[i] && delete_branch_[i]) - { - destroy_node(arg_list_[i]); - } - } - } - inline T value() const { - if (!arg_list_.empty()) - return VarArgFunction::process(arg_list_); - else - return std::numeric_limits::quiet_NaN(); + return VarArgFunction::process(arg_list_); } inline typename expression_node::node_type type() const @@ -9414,10 +10021,19 @@ namespace exprtk return expression_node::e_vararg; } + void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) + { + expression_node::ndb_t::collect(arg_list_, node_delete_list); + } + + std::size_t node_depth() const + { + return expression_node::ndb_t::compute_node_depth(arg_list_); + } + private: - std::vector arg_list_; - std::vector delete_branch_; + std::vector arg_list_; }; template @@ -9428,8 +10044,8 @@ namespace exprtk typedef expression_node* expression_ptr; template class Sequence> - vararg_varnode(const Sequence& arg_list) + template class Sequence> + explicit vararg_varnode(const Sequence& arg_list) { arg_list_.resize(arg_list.size()); @@ -9472,33 +10088,29 @@ namespace exprtk public: typedef expression_node* expression_ptr; + typedef std::pair branch_t; - vectorize_node(const expression_ptr v) - : ivec_ptr_(0), - v_(v), - v_deletable_(branch_deletable(v_)) + explicit vectorize_node(const expression_ptr v) + : ivec_ptr_(0) { - if (is_ivector_node(v)) + construct_branch_pair(v_, v); + + if (is_ivector_node(v_.first)) { - ivec_ptr_ = dynamic_cast*>(v); + ivec_ptr_ = dynamic_cast*>(v_.first); } else ivec_ptr_ = 0; } - ~vectorize_node() - { - if (v_ && v_deletable_) - { - destroy_node(v_); - } - } - inline T value() const { if (ivec_ptr_) { - v_->value(); + assert(v_.first); + + v_.first->value(); + return VecFunction::process(ivec_ptr_); } else @@ -9510,11 +10122,20 @@ namespace exprtk return expression_node::e_vecfunc; } + void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) + { + expression_node::ndb_t::collect(v_, node_delete_list); + } + + std::size_t node_depth() const + { + return expression_node::ndb_t::compute_node_depth(v_); + } + private: vector_interface* ivec_ptr_; - expression_ptr v_; - const bool v_deletable_; + branch_t v_; }; template @@ -9540,6 +10161,8 @@ namespace exprtk { if (var_node_ptr_) { + assert(binary_node::branch_[1].first); + T& result = var_node_ptr_->ref(); result = binary_node::branch_[1].first->value(); @@ -9578,6 +10201,8 @@ namespace exprtk { if (vec_node_ptr_) { + assert(binary_node::branch_[1].first); + T& result = vec_node_ptr_->ref(); result = binary_node::branch_[1].first->value(); @@ -9616,6 +10241,8 @@ namespace exprtk { if (rbvec_node_ptr_) { + assert(binary_node::branch_[1].first); + T& result = rbvec_node_ptr_->ref(); result = binary_node::branch_[1].first->value(); @@ -9654,6 +10281,8 @@ namespace exprtk { if (rbvec_node_ptr_) { + assert(binary_node::branch_[1].first); + T& result = rbvec_node_ptr_->ref(); result = binary_node::branch_[1].first->value(); @@ -9696,6 +10325,8 @@ namespace exprtk { if (vec_node_ptr_) { + assert(binary_node::branch_[1].first); + const T v = binary_node::branch_[1].first->value(); T* vec = vds().data(); @@ -9705,8 +10336,8 @@ namespace exprtk while (vec < upper_bound) { - #define exprtk_loop(N) \ - vec[N] = v; \ + #define exprtk_loop(N) \ + vec[N] = v; \ exprtk_loop( 0) exprtk_loop( 1) exprtk_loop( 2) exprtk_loop( 3) @@ -9841,6 +10472,8 @@ namespace exprtk { if (initialised_) { + assert(binary_node::branch_[1].first); + binary_node::branch_[1].first->value(); if (src_is_ivec_) @@ -9962,6 +10595,8 @@ namespace exprtk { if (var_node_ptr_) { + assert(binary_node::branch_[1].first); + T& v = var_node_ptr_->ref(); v = Operation::process(v,binary_node::branch_[1].first->value()); @@ -9999,6 +10634,8 @@ namespace exprtk { if (vec_node_ptr_) { + assert(binary_node::branch_[1].first); + T& v = vec_node_ptr_->ref(); v = Operation::process(v,binary_node::branch_[1].first->value()); @@ -10036,6 +10673,8 @@ namespace exprtk { if (rbvec_node_ptr_) { + assert(binary_node::branch_[1].first); + T& v = rbvec_node_ptr_->ref(); v = Operation::process(v,binary_node::branch_[1].first->value()); @@ -10073,6 +10712,8 @@ namespace exprtk { if (rbvec_node_ptr_) { + assert(binary_node::branch_[1].first); + T& v = rbvec_node_ptr_->ref(); v = Operation::process(v,binary_node::branch_[1].first->value()); @@ -10114,6 +10755,8 @@ namespace exprtk { if (vec_node_ptr_) { + assert(binary_node::branch_[1].first); + const T v = binary_node::branch_[1].first->value(); T* vec = vds().data(); @@ -10259,19 +10902,22 @@ namespace exprtk { if (initialised_) { + assert(binary_node::branch_[0].first); + assert(binary_node::branch_[1].first); + binary_node::branch_[0].first->value(); binary_node::branch_[1].first->value(); - T* vec0 = vec0_node_ptr_->vds().data(); - T* vec1 = vec1_node_ptr_->vds().data(); + T* vec0 = vec0_node_ptr_->vds().data(); + const T* vec1 = vec1_node_ptr_->vds().data(); loop_unroll::details lud(size()); const T* upper_bound = vec0 + lud.upper_bound; while (vec0 < upper_bound) { - #define exprtk_loop(N) \ - vec0[N] = Operation::process(vec0[N],vec1[N]); \ + #define exprtk_loop(N) \ + vec0[N] = Operation::process(vec0[N], vec1[N]); \ exprtk_loop( 0) exprtk_loop( 1) exprtk_loop( 2) exprtk_loop( 3) @@ -10293,8 +10939,8 @@ namespace exprtk exprtk_disable_fallthrough_begin switch (lud.remainder) { - #define case_stmt(N) \ - case N : { vec0[i] = Operation::process(vec0[i],vec1[i]); ++i; } \ + #define case_stmt(N) \ + case N : { vec0[i] = Operation::process(vec0[i], vec1[i]); ++i; } \ #ifndef exprtk_disable_superscalar_unroll case_stmt(15) case_stmt(14) @@ -10444,20 +11090,23 @@ namespace exprtk { if (initialised_) { + assert(binary_node::branch_[0].first); + assert(binary_node::branch_[1].first); + binary_node::branch_[0].first->value(); binary_node::branch_[1].first->value(); - T* vec0 = vec0_node_ptr_->vds().data(); - T* vec1 = vec1_node_ptr_->vds().data(); - T* vec2 = vds().data(); + const T* vec0 = vec0_node_ptr_->vds().data(); + const T* vec1 = vec1_node_ptr_->vds().data(); + T* vec2 = vds().data(); loop_unroll::details lud(size()); const T* upper_bound = vec2 + lud.upper_bound; while (vec2 < upper_bound) { - #define exprtk_loop(N) \ - vec2[N] = Operation::process(vec0[N],vec1[N]); \ + #define exprtk_loop(N) \ + vec2[N] = Operation::process(vec0[N], vec1[N]); \ exprtk_loop( 0) exprtk_loop( 1) exprtk_loop( 2) exprtk_loop( 3) @@ -10480,8 +11129,8 @@ namespace exprtk exprtk_disable_fallthrough_begin switch (lud.remainder) { - #define case_stmt(N) \ - case N : { vec2[i] = Operation::process(vec0[i],vec1[i]); ++i; } \ + #define case_stmt(N) \ + case N : { vec2[i] = Operation::process(vec0[i], vec1[i]); ++i; } \ #ifndef exprtk_disable_superscalar_unroll case_stmt(15) case_stmt(14) @@ -10603,19 +11252,22 @@ namespace exprtk { if (vec0_node_ptr_) { + assert(binary_node::branch_[0].first); + assert(binary_node::branch_[1].first); + binary_node::branch_[0].first->value(); const T v = binary_node::branch_[1].first->value(); - T* vec0 = vec0_node_ptr_->vds().data(); - T* vec1 = vds().data(); + const T* vec0 = vec0_node_ptr_->vds().data(); + T* vec1 = vds().data(); loop_unroll::details lud(size()); const T* upper_bound = vec0 + lud.upper_bound; while (vec0 < upper_bound) { - #define exprtk_loop(N) \ - vec1[N] = Operation::process(vec0[N],v); \ + #define exprtk_loop(N) \ + vec1[N] = Operation::process(vec0[N], v); \ exprtk_loop( 0) exprtk_loop( 1) exprtk_loop( 2) exprtk_loop( 3) @@ -10637,8 +11289,8 @@ namespace exprtk exprtk_disable_fallthrough_begin switch (lud.remainder) { - #define case_stmt(N) \ - case N : { vec1[i] = Operation::process(vec0[i],v); ++i; } \ + #define case_stmt(N) \ + case N : { vec1[i] = Operation::process(vec0[i], v); ++i; } \ #ifndef exprtk_disable_superscalar_unroll case_stmt(15) case_stmt(14) @@ -10758,19 +11410,22 @@ namespace exprtk { if (vec1_node_ptr_) { + assert(binary_node::branch_[0].first); + assert(binary_node::branch_[1].first); + const T v = binary_node::branch_[0].first->value(); binary_node::branch_[1].first->value(); - T* vec0 = vds().data(); - T* vec1 = vec1_node_ptr_->vds().data(); + T* vec0 = vds().data(); + const T* vec1 = vec1_node_ptr_->vds().data(); loop_unroll::details lud(size()); const T* upper_bound = vec0 + lud.upper_bound; while (vec0 < upper_bound) { - #define exprtk_loop(N) \ - vec0[N] = Operation::process(v,vec1[N]); \ + #define exprtk_loop(N) \ + vec0[N] = Operation::process(v, vec1[N]); \ exprtk_loop( 0) exprtk_loop( 1) exprtk_loop( 2) exprtk_loop( 3) @@ -10792,8 +11447,8 @@ namespace exprtk exprtk_disable_fallthrough_begin switch (lud.remainder) { - #define case_stmt(N) \ - case N : { vec0[i] = Operation::process(v,vec1[i]); ++i; } \ + #define case_stmt(N) \ + case N : { vec0[i] = Operation::process(v, vec1[i]); ++i; } \ #ifndef exprtk_disable_superscalar_unroll case_stmt(15) case_stmt(14) @@ -10874,15 +11529,15 @@ namespace exprtk { bool vec0_is_ivec = false; - if (is_vector_node(unary_node::branch_)) + if (is_vector_node(unary_node::branch_.first)) { - vec0_node_ptr_ = static_cast(unary_node::branch_); + vec0_node_ptr_ = static_cast(unary_node::branch_.first); } - else if (is_ivector_node(unary_node::branch_)) + else if (is_ivector_node(unary_node::branch_.first)) { vector_interface* vi = reinterpret_cast*>(0); - if (0 != (vi = dynamic_cast*>(unary_node::branch_))) + if (0 != (vi = dynamic_cast*>(unary_node::branch_.first))) { vec0_node_ptr_ = vi->vec(); vec0_is_ivec = true; @@ -10909,12 +11564,14 @@ namespace exprtk inline T value() const { - unary_node::branch_->value(); + assert(unary_node::branch_.first); + + unary_node::branch_.first->value(); if (vec0_node_ptr_) { - T* vec0 = vec0_node_ptr_->vds().data(); - T* vec1 = vds().data(); + const T* vec0 = vec0_node_ptr_->vds().data(); + T* vec1 = vds().data(); loop_unroll::details lud(size()); const T* upper_bound = vec0 + lud.upper_bound; @@ -11022,6 +11679,9 @@ namespace exprtk inline T value() const { + assert(binary_node::branch_[0].first); + assert(binary_node::branch_[1].first); + return ( std::not_equal_to() (T(0),binary_node::branch_[0].first->value()) && @@ -11046,6 +11706,9 @@ namespace exprtk inline T value() const { + assert(binary_node::branch_[0].first); + assert(binary_node::branch_[1].first); + return ( std::not_equal_to() (T(0),binary_node::branch_[0].first->value()) || @@ -11065,16 +11728,11 @@ namespace exprtk typedef std::pair branch_t; typedef IFunction ifunction; - function_N_node(ifunction* func) + explicit function_N_node(ifunction* func) : function_((N == func->param_count) ? func : reinterpret_cast(0)), parameter_count_(func->param_count) {} - ~function_N_node() - { - cleanup_branches::execute(branch_); - } - template bool init_branches(expression_ptr (&b)[NumBranches]) { @@ -11341,6 +11999,16 @@ namespace exprtk return expression_node::e_function; } + void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) + { + expression_node::ndb_t::template collect(branch_, node_delete_list); + } + + std::size_t node_depth() const + { + return expression_node::ndb_t::template compute_node_depth(branch_); + } + private: ifunction* function_; @@ -11356,7 +12024,7 @@ namespace exprtk typedef expression_node* expression_ptr; typedef IFunction ifunction; - function_N_node(ifunction* func) + explicit function_N_node(ifunction* func) : function_((0 == func->param_count) ? func : reinterpret_cast(0)) {} @@ -11398,17 +12066,6 @@ namespace exprtk value_list_.resize(arg_list.size(),std::numeric_limits::quiet_NaN()); } - ~vararg_function_node() - { - for (std::size_t i = 0; i < arg_list_.size(); ++i) - { - if (arg_list_[i] && !details::is_variable_node(arg_list_[i])) - { - destroy_node(arg_list_[i]); - } - } - } - inline bool operator <(const vararg_function_node& fn) const { return this < (&fn); @@ -11430,6 +12087,22 @@ namespace exprtk return expression_node::e_vafunction; } + void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) + { + for (std::size_t i = 0; i < arg_list_.size(); ++i) + { + if (arg_list_[i] && !details::is_variable_node(arg_list_[i])) + { + node_delete_list.push_back(&arg_list_[i]); + } + } + } + + std::size_t node_depth() const + { + return expression_node::ndb_t::compute_node_depth(arg_list_); + } + private: inline void populate_value_list() const @@ -11465,15 +12138,23 @@ namespace exprtk typedef std::vector typestore_list_t; typedef std::vector range_list_t; - generic_function_node(const std::vector& arg_list, - GenericFunction* func = (GenericFunction*)(0)) + explicit generic_function_node(const std::vector& arg_list, + GenericFunction* func = (GenericFunction*)(0)) : function_(func), arg_list_(arg_list) {} virtual ~generic_function_node() + {} + + void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) + { + expression_node::ndb_t::collect(branch_, node_delete_list); + } + + std::size_t node_depth() const { - cleanup_branches::execute(branch_); + return expression_node::ndb_t::compute_node_depth(branch_); } virtual bool init_branches() @@ -11499,6 +12180,7 @@ namespace exprtk ts.size = vi->size(); ts.data = vi->vds().data(); ts.type = type_store_t::e_vector; + vi->vec()->vec_holder().set_ref(&ts.vec_data); } #ifndef exprtk_disable_string_capabilities else if (is_generally_string_node(arg_list_[i])) @@ -11509,7 +12191,7 @@ namespace exprtk return false; ts.size = sbn->size(); - ts.data = reinterpret_cast(const_cast(sbn->base())); + ts.data = reinterpret_cast(const_cast(sbn->base())); ts.type = type_store_t::e_string; range_list_[i].data = ts.data; @@ -11522,7 +12204,7 @@ namespace exprtk if (0 == (ri = dynamic_cast(arg_list_[i]))) return false; - range_t& rp = ri->range_ref(); + const range_t& rp = ri->range_ref(); if ( rp.const_range() && @@ -11530,7 +12212,7 @@ namespace exprtk ) { ts.size = rp.const_size(); - ts.data = static_cast(ts.data) + rp.n0_c.second; + ts.data = static_cast(ts.data) + rp.n0_c.second; range_list_[i].range = reinterpret_cast(0); } else @@ -11601,21 +12283,21 @@ namespace exprtk if (rdt.range) { - range_t& rp = (*rdt.range); - std::size_t r0 = 0; - std::size_t r1 = 0; + const range_t& rp = (*rdt.range); + std::size_t r0 = 0; + std::size_t r1 = 0; - if (rp(r0,r1,rdt.size)) + if (rp(r0, r1, rdt.size)) { type_store_t& ts = typestore_list_[i]; ts.size = rp.cache_size(); #ifndef exprtk_disable_string_capabilities if (ts.type == type_store_t::e_string) - ts.data = const_cast(rdt.str_node->base()) + rp.cache.first; + ts.data = const_cast(rdt.str_node->base()) + rp.cache.first; else #endif - ts.data = static_cast(rdt.data) + (rp.cache.first * rdt.type_size); + ts.data = static_cast(rdt.data) + (rp.cache.first * rdt.type_size); } else return false; @@ -11664,16 +12346,17 @@ namespace exprtk inline T value() const { - T result = std::numeric_limits::quiet_NaN(); - if (gen_function_t::function_) { if (gen_function_t::populate_value_list()) { typedef typename StringFunction::parameter_list_t parameter_list_t; - result = (*gen_function_t::function_)(ret_string_, - parameter_list_t(gen_function_t::typestore_list_)); + const T result = (*gen_function_t::function_) + ( + ret_string_, + parameter_list_t(gen_function_t::typestore_list_) + ); range_.n1_c.second = ret_string_.size() - 1; range_.cache.second = range_.n1_c.second; @@ -11682,7 +12365,7 @@ namespace exprtk } } - return result; + return std::numeric_limits::quiet_NaN(); } inline typename expression_node::node_type type() const @@ -11695,7 +12378,7 @@ namespace exprtk return ret_string_; } - const char_t* base() const + char_cptr base() const { return &ret_string_[0]; } @@ -11739,20 +12422,21 @@ namespace exprtk inline T value() const { - T result = std::numeric_limits::quiet_NaN(); - if (gen_function_t::function_) { if (gen_function_t::populate_value_list()) { typedef typename GenericFunction::parameter_list_t parameter_list_t; - return (*gen_function_t::function_)(param_seq_index_, - parameter_list_t(gen_function_t::typestore_list_)); + return (*gen_function_t::function_) + ( + param_seq_index_, + parameter_list_t(gen_function_t::typestore_list_) + ); } } - return result; + return std::numeric_limits::quiet_NaN(); } inline typename expression_node::node_type type() const @@ -11783,17 +12467,18 @@ namespace exprtk inline T value() const { - T result = std::numeric_limits::quiet_NaN(); - if (str_function_t::function_) { if (str_function_t::populate_value_list()) { typedef typename StringFunction::parameter_list_t parameter_list_t; - result = (*str_function_t::function_)(param_seq_index_, - str_function_t::ret_string_, - parameter_list_t(str_function_t::typestore_list_)); + const T result = (*str_function_t::function_) + ( + param_seq_index_, + str_function_t::ret_string_, + parameter_list_t(str_function_t::typestore_list_) + ); str_function_t::range_.n1_c.second = str_function_t::ret_string_.size() - 1; str_function_t::range_.cache.second = str_function_t::range_.n1_c.second; @@ -11802,7 +12487,7 @@ namespace exprtk } } - return result; + return std::numeric_limits::quiet_NaN(); } inline typename expression_node::node_type type() const @@ -11888,30 +12573,25 @@ namespace exprtk typedef expression_node* expression_ptr; typedef results_context results_context_t; + typedef std::pair branch_t; return_envelope_node(expression_ptr body, results_context_t& rc) : results_context_(&rc ), - return_invoked_ (false), - body_ (body ), - body_deletable_ (branch_deletable(body_)) - {} - - ~return_envelope_node() + return_invoked_ (false) { - if (body_ && body_deletable_) - { - destroy_node(body_); - } + construct_branch_pair(body_, body); } inline T value() const { + assert(body_.first); + try { return_invoked_ = false; results_context_->clear(); - return body_->value(); + return body_.first->value(); } catch(const return_exception&) { @@ -11930,12 +12610,21 @@ namespace exprtk return &return_invoked_; } + void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) + { + expression_node::ndb_t::collect(body_, node_delete_list); + } + + std::size_t node_depth() const + { + return expression_node::ndb_t::compute_node_depth(body_); + } + private: results_context_t* results_context_; - mutable bool return_invoked_; - expression_ptr body_; - const bool body_deletable_; + mutable bool return_invoked_; + branch_t body_; }; #endif @@ -12007,20 +12696,21 @@ namespace exprtk template struct opr_base { - typedef typename details::functor_t::Type Type; + typedef typename details::functor_t::Type Type; typedef typename details::functor_t::RefType RefType; - typedef typename details::functor_t functor_t; - typedef typename functor_t::qfunc_t quaternary_functor_t; - typedef typename functor_t::tfunc_t trinary_functor_t; - typedef typename functor_t::bfunc_t binary_functor_t; - typedef typename functor_t::ufunc_t unary_functor_t; + typedef typename details::functor_t functor_t; + typedef typename functor_t::qfunc_t quaternary_functor_t; + typedef typename functor_t::tfunc_t trinary_functor_t; + typedef typename functor_t::bfunc_t binary_functor_t; + typedef typename functor_t::ufunc_t unary_functor_t; }; template struct add_op : public opr_base { - typedef typename opr_base::Type Type; + typedef typename opr_base::Type Type; typedef typename opr_base::RefType RefType; + static inline T process(Type t1, Type t2) { return t1 + t2; } static inline T process(Type t1, Type t2, Type t3) { return t1 + t2 + t3; } static inline void assign(RefType t1, Type t2) { t1 += t2; } @@ -12031,8 +12721,9 @@ namespace exprtk template struct mul_op : public opr_base { - typedef typename opr_base::Type Type; + typedef typename opr_base::Type Type; typedef typename opr_base::RefType RefType; + static inline T process(Type t1, Type t2) { return t1 * t2; } static inline T process(Type t1, Type t2, Type t3) { return t1 * t2 * t3; } static inline void assign(RefType t1, Type t2) { t1 *= t2; } @@ -12043,8 +12734,9 @@ namespace exprtk template struct sub_op : public opr_base { - typedef typename opr_base::Type Type; + typedef typename opr_base::Type Type; typedef typename opr_base::RefType RefType; + static inline T process(Type t1, Type t2) { return t1 - t2; } static inline T process(Type t1, Type t2, Type t3) { return t1 - t2 - t3; } static inline void assign(RefType t1, Type t2) { t1 -= t2; } @@ -12055,8 +12747,9 @@ namespace exprtk template struct div_op : public opr_base { - typedef typename opr_base::Type Type; + typedef typename opr_base::Type Type; typedef typename opr_base::RefType RefType; + static inline T process(Type t1, Type t2) { return t1 / t2; } static inline T process(Type t1, Type t2, Type t3) { return t1 / t2 / t3; } static inline void assign(RefType t1, Type t2) { t1 /= t2; } @@ -12067,8 +12760,9 @@ namespace exprtk template struct mod_op : public opr_base { - typedef typename opr_base::Type Type; + typedef typename opr_base::Type Type; typedef typename opr_base::RefType RefType; + static inline T process(Type t1, Type t2) { return numeric::modulus(t1,t2); } static inline void assign(RefType t1, Type t2) { t1 = numeric::modulus(t1,t2); } static inline typename expression_node::node_type type() { return expression_node::e_mod; } @@ -12078,8 +12772,9 @@ namespace exprtk template struct pow_op : public opr_base { - typedef typename opr_base::Type Type; + typedef typename opr_base::Type Type; typedef typename opr_base::RefType RefType; + static inline T process(Type t1, Type t2) { return numeric::pow(t1,t2); } static inline void assign(RefType t1, Type t2) { t1 = numeric::pow(t1,t2); } static inline typename expression_node::node_type type() { return expression_node::e_pow; } @@ -12090,6 +12785,7 @@ namespace exprtk struct lt_op : public opr_base { typedef typename opr_base::Type Type; + static inline T process(Type t1, Type t2) { return ((t1 < t2) ? T(1) : T(0)); } static inline T process(const std::string& t1, const std::string& t2) { return ((t1 < t2) ? T(1) : T(0)); } static inline typename expression_node::node_type type() { return expression_node::e_lt; } @@ -12100,6 +12796,7 @@ namespace exprtk struct lte_op : public opr_base { typedef typename opr_base::Type Type; + static inline T process(Type t1, Type t2) { return ((t1 <= t2) ? T(1) : T(0)); } static inline T process(const std::string& t1, const std::string& t2) { return ((t1 <= t2) ? T(1) : T(0)); } static inline typename expression_node::node_type type() { return expression_node::e_lte; } @@ -12110,6 +12807,7 @@ namespace exprtk struct gt_op : public opr_base { typedef typename opr_base::Type Type; + static inline T process(Type t1, Type t2) { return ((t1 > t2) ? T(1) : T(0)); } static inline T process(const std::string& t1, const std::string& t2) { return ((t1 > t2) ? T(1) : T(0)); } static inline typename expression_node::node_type type() { return expression_node::e_gt; } @@ -12120,6 +12818,7 @@ namespace exprtk struct gte_op : public opr_base { typedef typename opr_base::Type Type; + static inline T process(Type t1, Type t2) { return ((t1 >= t2) ? T(1) : T(0)); } static inline T process(const std::string& t1, const std::string& t2) { return ((t1 >= t2) ? T(1) : T(0)); } static inline typename expression_node::node_type type() { return expression_node::e_gte; } @@ -12140,6 +12839,7 @@ namespace exprtk struct equal_op : public opr_base { typedef typename opr_base::Type Type; + static inline T process(Type t1, Type t2) { return numeric::equal(t1,t2); } static inline T process(const std::string& t1, const std::string& t2) { return ((t1 == t2) ? T(1) : T(0)); } static inline typename expression_node::node_type type() { return expression_node::e_eq; } @@ -12150,6 +12850,7 @@ namespace exprtk struct ne_op : public opr_base { typedef typename opr_base::Type Type; + static inline T process(Type t1, Type t2) { return (std::not_equal_to()(t1,t2) ? T(1) : T(0)); } static inline T process(const std::string& t1, const std::string& t2) { return ((t1 != t2) ? T(1) : T(0)); } static inline typename expression_node::node_type type() { return expression_node::e_ne; } @@ -12160,6 +12861,7 @@ namespace exprtk struct and_op : public opr_base { typedef typename opr_base::Type Type; + static inline T process(Type t1, Type t2) { return (details::is_true(t1) && details::is_true(t2)) ? T(1) : T(0); } static inline typename expression_node::node_type type() { return expression_node::e_and; } static inline details::operator_type operation() { return details::e_and; } @@ -12169,6 +12871,7 @@ namespace exprtk struct nand_op : public opr_base { typedef typename opr_base::Type Type; + static inline T process(Type t1, Type t2) { return (details::is_true(t1) && details::is_true(t2)) ? T(0) : T(1); } static inline typename expression_node::node_type type() { return expression_node::e_nand; } static inline details::operator_type operation() { return details::e_nand; } @@ -12178,6 +12881,7 @@ namespace exprtk struct or_op : public opr_base { typedef typename opr_base::Type Type; + static inline T process(Type t1, Type t2) { return (details::is_true(t1) || details::is_true(t2)) ? T(1) : T(0); } static inline typename expression_node::node_type type() { return expression_node::e_or; } static inline details::operator_type operation() { return details::e_or; } @@ -12187,6 +12891,7 @@ namespace exprtk struct nor_op : public opr_base { typedef typename opr_base::Type Type; + static inline T process(Type t1, Type t2) { return (details::is_true(t1) || details::is_true(t2)) ? T(0) : T(1); } static inline typename expression_node::node_type type() { return expression_node::e_nor; } static inline details::operator_type operation() { return details::e_nor; } @@ -12196,6 +12901,7 @@ namespace exprtk struct xor_op : public opr_base { typedef typename opr_base::Type Type; + static inline T process(Type t1, Type t2) { return numeric::xor_opr(t1,t2); } static inline typename expression_node::node_type type() { return expression_node::e_nor; } static inline details::operator_type operation() { return details::e_xor; } @@ -12205,6 +12911,7 @@ namespace exprtk struct xnor_op : public opr_base { typedef typename opr_base::Type Type; + static inline T process(Type t1, Type t2) { return numeric::xnor_opr(t1,t2); } static inline typename expression_node::node_type type() { return expression_node::e_nor; } static inline details::operator_type operation() { return details::e_xnor; } @@ -12214,6 +12921,7 @@ namespace exprtk struct in_op : public opr_base { typedef typename opr_base::Type Type; + static inline T process(const T&, const T&) { return std::numeric_limits::quiet_NaN(); } static inline T process(const std::string& t1, const std::string& t2) { return ((std::string::npos != t2.find(t1)) ? T(1) : T(0)); } static inline typename expression_node::node_type type() { return expression_node::e_in; } @@ -12224,6 +12932,7 @@ namespace exprtk struct like_op : public opr_base { typedef typename opr_base::Type Type; + static inline T process(const T&, const T&) { return std::numeric_limits::quiet_NaN(); } static inline T process(const std::string& t1, const std::string& t2) { return (details::wc_match(t2,t1) ? T(1) : T(0)); } static inline typename expression_node::node_type type() { return expression_node::e_like; } @@ -12234,6 +12943,7 @@ namespace exprtk struct ilike_op : public opr_base { typedef typename opr_base::Type Type; + static inline T process(const T&, const T&) { return std::numeric_limits::quiet_NaN(); } static inline T process(const std::string& t1, const std::string& t2) { return (details::wc_imatch(t2,t1) ? T(1) : T(0)); } static inline typename expression_node::node_type type() { return expression_node::e_ilike; } @@ -12244,6 +12954,7 @@ namespace exprtk struct inrange_op : public opr_base { typedef typename opr_base::Type Type; + static inline T process(const T& t0, const T& t1, const T& t2) { return ((t0 <= t1) && (t1 <= t2)) ? T(1) : T(0); } static inline T process(const std::string& t0, const std::string& t1, const std::string& t2) { @@ -12260,11 +12971,23 @@ namespace exprtk } template - inline T value(T* t) + inline T value(std::pair*,bool> n) + { + return n.first->value(); + } + + template + inline T value(const T* t) { return (*t); } + template + inline T value(const T& t) + { + return t; + } + template struct vararg_add_op : public opr_base { @@ -12272,7 +12995,7 @@ namespace exprtk template class Sequence> + template class Sequence> static inline T process(const Sequence& arg_list) { switch (arg_list.size()) @@ -12313,14 +13036,14 @@ namespace exprtk static inline T process_3(const Sequence& arg_list) { return value(arg_list[0]) + value(arg_list[1]) + - value(arg_list[2]); + value(arg_list[2]) ; } template static inline T process_4(const Sequence& arg_list) { return value(arg_list[0]) + value(arg_list[1]) + - value(arg_list[2]) + value(arg_list[3]); + value(arg_list[2]) + value(arg_list[3]) ; } template @@ -12328,7 +13051,7 @@ namespace exprtk { return value(arg_list[0]) + value(arg_list[1]) + value(arg_list[2]) + value(arg_list[3]) + - value(arg_list[4]); + value(arg_list[4]) ; } }; @@ -12339,7 +13062,7 @@ namespace exprtk template class Sequence> + template class Sequence> static inline T process(const Sequence& arg_list) { switch (arg_list.size()) @@ -12380,14 +13103,14 @@ namespace exprtk static inline T process_3(const Sequence& arg_list) { return value(arg_list[0]) * value(arg_list[1]) * - value(arg_list[2]); + value(arg_list[2]) ; } template static inline T process_4(const Sequence& arg_list) { return value(arg_list[0]) * value(arg_list[1]) * - value(arg_list[2]) * value(arg_list[3]); + value(arg_list[2]) * value(arg_list[3]) ; } template @@ -12395,7 +13118,7 @@ namespace exprtk { return value(arg_list[0]) * value(arg_list[1]) * value(arg_list[2]) * value(arg_list[3]) * - value(arg_list[4]); + value(arg_list[4]) ; } }; @@ -12406,7 +13129,7 @@ namespace exprtk template class Sequence> + template class Sequence> static inline T process(const Sequence& arg_list) { switch (arg_list.size()) @@ -12462,7 +13185,7 @@ namespace exprtk template class Sequence> + template class Sequence> static inline T process(const Sequence& arg_list) { switch (arg_list.size()) @@ -12512,16 +13235,16 @@ namespace exprtk static inline T process_4(const Sequence& arg_list) { return std::min( - std::min(value(arg_list[0]),value(arg_list[1])), - std::min(value(arg_list[2]),value(arg_list[3]))); + std::min(value(arg_list[0]), value(arg_list[1])), + std::min(value(arg_list[2]), value(arg_list[3]))); } template static inline T process_5(const Sequence& arg_list) { return std::min( - std::min(std::min(value(arg_list[0]),value(arg_list[1])), - std::min(value(arg_list[2]),value(arg_list[3]))), + std::min(std::min(value(arg_list[0]), value(arg_list[1])), + std::min(value(arg_list[2]), value(arg_list[3]))), value(arg_list[4])); } }; @@ -12533,7 +13256,7 @@ namespace exprtk template class Sequence> + template class Sequence> static inline T process(const Sequence& arg_list) { switch (arg_list.size()) @@ -12583,16 +13306,16 @@ namespace exprtk static inline T process_4(const Sequence& arg_list) { return std::max( - std::max(value(arg_list[0]),value(arg_list[1])), - std::max(value(arg_list[2]),value(arg_list[3]))); + std::max(value(arg_list[0]), value(arg_list[1])), + std::max(value(arg_list[2]), value(arg_list[3]))); } template static inline T process_5(const Sequence& arg_list) { return std::max( - std::max(std::max(value(arg_list[0]),value(arg_list[1])), - std::max(value(arg_list[2]),value(arg_list[3]))), + std::max(std::max(value(arg_list[0]), value(arg_list[1])), + std::max(value(arg_list[2]), value(arg_list[3]))), value(arg_list[4])); } }; @@ -12604,7 +13327,7 @@ namespace exprtk template class Sequence> + template class Sequence> static inline T process(const Sequence& arg_list) { switch (arg_list.size()) @@ -12618,7 +13341,7 @@ namespace exprtk { for (std::size_t i = 0; i < arg_list.size(); ++i) { - if (std::equal_to()(T(0),value(arg_list[i]))) + if (std::equal_to()(T(0), value(arg_list[i]))) return T(0); } @@ -12631,15 +13354,15 @@ namespace exprtk static inline T process_1(const Sequence& arg_list) { return std::not_equal_to() - (T(0),value(arg_list[0])) ? T(1) : T(0); + (T(0), value(arg_list[0])) ? T(1) : T(0); } template static inline T process_2(const Sequence& arg_list) { return ( - std::not_equal_to()(T(0),value(arg_list[0])) && - std::not_equal_to()(T(0),value(arg_list[1])) + std::not_equal_to()(T(0), value(arg_list[0])) && + std::not_equal_to()(T(0), value(arg_list[1])) ) ? T(1) : T(0); } @@ -12647,9 +13370,9 @@ namespace exprtk static inline T process_3(const Sequence& arg_list) { return ( - std::not_equal_to()(T(0),value(arg_list[0])) && - std::not_equal_to()(T(0),value(arg_list[1])) && - std::not_equal_to()(T(0),value(arg_list[2])) + std::not_equal_to()(T(0), value(arg_list[0])) && + std::not_equal_to()(T(0), value(arg_list[1])) && + std::not_equal_to()(T(0), value(arg_list[2])) ) ? T(1) : T(0); } @@ -12657,10 +13380,10 @@ namespace exprtk static inline T process_4(const Sequence& arg_list) { return ( - std::not_equal_to()(T(0),value(arg_list[0])) && - std::not_equal_to()(T(0),value(arg_list[1])) && - std::not_equal_to()(T(0),value(arg_list[2])) && - std::not_equal_to()(T(0),value(arg_list[3])) + std::not_equal_to()(T(0), value(arg_list[0])) && + std::not_equal_to()(T(0), value(arg_list[1])) && + std::not_equal_to()(T(0), value(arg_list[2])) && + std::not_equal_to()(T(0), value(arg_list[3])) ) ? T(1) : T(0); } @@ -12668,11 +13391,11 @@ namespace exprtk static inline T process_5(const Sequence& arg_list) { return ( - std::not_equal_to()(T(0),value(arg_list[0])) && - std::not_equal_to()(T(0),value(arg_list[1])) && - std::not_equal_to()(T(0),value(arg_list[2])) && - std::not_equal_to()(T(0),value(arg_list[3])) && - std::not_equal_to()(T(0),value(arg_list[4])) + std::not_equal_to()(T(0), value(arg_list[0])) && + std::not_equal_to()(T(0), value(arg_list[1])) && + std::not_equal_to()(T(0), value(arg_list[2])) && + std::not_equal_to()(T(0), value(arg_list[3])) && + std::not_equal_to()(T(0), value(arg_list[4])) ) ? T(1) : T(0); } }; @@ -12684,7 +13407,7 @@ namespace exprtk template class Sequence> + template class Sequence> static inline T process(const Sequence& arg_list) { switch (arg_list.size()) @@ -12698,7 +13421,7 @@ namespace exprtk { for (std::size_t i = 0; i < arg_list.size(); ++i) { - if (std::not_equal_to()(T(0),value(arg_list[i]))) + if (std::not_equal_to()(T(0), value(arg_list[i]))) return T(1); } @@ -12711,15 +13434,15 @@ namespace exprtk static inline T process_1(const Sequence& arg_list) { return std::not_equal_to() - (T(0),value(arg_list[0])) ? T(1) : T(0); + (T(0), value(arg_list[0])) ? T(1) : T(0); } template static inline T process_2(const Sequence& arg_list) { return ( - std::not_equal_to()(T(0),value(arg_list[0])) || - std::not_equal_to()(T(0),value(arg_list[1])) + std::not_equal_to()(T(0), value(arg_list[0])) || + std::not_equal_to()(T(0), value(arg_list[1])) ) ? T(1) : T(0); } @@ -12727,9 +13450,9 @@ namespace exprtk static inline T process_3(const Sequence& arg_list) { return ( - std::not_equal_to()(T(0),value(arg_list[0])) || - std::not_equal_to()(T(0),value(arg_list[1])) || - std::not_equal_to()(T(0),value(arg_list[2])) + std::not_equal_to()(T(0), value(arg_list[0])) || + std::not_equal_to()(T(0), value(arg_list[1])) || + std::not_equal_to()(T(0), value(arg_list[2])) ) ? T(1) : T(0); } @@ -12737,10 +13460,10 @@ namespace exprtk static inline T process_4(const Sequence& arg_list) { return ( - std::not_equal_to()(T(0),value(arg_list[0])) || - std::not_equal_to()(T(0),value(arg_list[1])) || - std::not_equal_to()(T(0),value(arg_list[2])) || - std::not_equal_to()(T(0),value(arg_list[3])) + std::not_equal_to()(T(0), value(arg_list[0])) || + std::not_equal_to()(T(0), value(arg_list[1])) || + std::not_equal_to()(T(0), value(arg_list[2])) || + std::not_equal_to()(T(0), value(arg_list[3])) ) ? T(1) : T(0); } @@ -12748,11 +13471,11 @@ namespace exprtk static inline T process_5(const Sequence& arg_list) { return ( - std::not_equal_to()(T(0),value(arg_list[0])) || - std::not_equal_to()(T(0),value(arg_list[1])) || - std::not_equal_to()(T(0),value(arg_list[2])) || - std::not_equal_to()(T(0),value(arg_list[3])) || - std::not_equal_to()(T(0),value(arg_list[4])) + std::not_equal_to()(T(0), value(arg_list[0])) || + std::not_equal_to()(T(0), value(arg_list[1])) || + std::not_equal_to()(T(0), value(arg_list[2])) || + std::not_equal_to()(T(0), value(arg_list[3])) || + std::not_equal_to()(T(0), value(arg_list[4])) ) ? T(1) : T(0); } }; @@ -12764,7 +13487,7 @@ namespace exprtk template class Sequence> + template class Sequence> static inline T process(const Sequence& arg_list) { switch (arg_list.size()) @@ -13096,7 +13819,7 @@ namespace exprtk for (std::size_t i = 1; i < vec_size; ++i) { - T v_i = vec[i]; + const T v_i = vec[i]; if (v_i < result) result = v_i; @@ -13120,7 +13843,7 @@ namespace exprtk for (std::size_t i = 1; i < vec_size; ++i) { - T v_i = vec[i]; + const T v_i = vec[i]; if (v_i > result) result = v_i; @@ -13211,8 +13934,8 @@ namespace exprtk { public: - virtual ~cob_base_node() - {} + virtual ~cob_base_node() + {} inline virtual operator_type operation() const { @@ -13431,24 +14154,17 @@ namespace exprtk public: typedef expression_node* expression_ptr; + typedef std::pair branch_t; typedef Operation operation_t; - explicit unary_branch_node(expression_ptr brnch) - : branch_(brnch), - branch_deletable_(branch_deletable(branch_)) - {} - - ~unary_branch_node() + explicit unary_branch_node(expression_ptr branch) { - if (branch_ && branch_deletable_) - { - destroy_node(branch_); - } + construct_branch_pair(branch_, branch); } inline T value() const { - return Operation::process(branch_->value()); + return Operation::process(branch_.first->value()); } inline typename expression_node::node_type type() const @@ -13463,12 +14179,22 @@ namespace exprtk inline expression_node* branch(const std::size_t&) const { - return branch_; + return branch_.first; } inline void release() { - branch_deletable_ = false; + branch_.second = false; + } + + void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) + { + expression_node::ndb_t::collect(branch_, node_delete_list); + } + + std::size_t node_depth() const + { + return expression_node::ndb_t::compute_node_depth(branch_); } private: @@ -13476,8 +14202,7 @@ namespace exprtk unary_branch_node(unary_branch_node&); unary_branch_node& operator=(unary_branch_node&); - expression_ptr branch_; - bool branch_deletable_; + branch_t branch_; }; template struct is_const { enum {result = 0}; }; @@ -13664,15 +14389,15 @@ namespace exprtk template \ const typename expression_node::node_type nodetype_T0oT1::result = expression_node:: v_; \ - synthesis_node_type_define(const T0&,const T1&, e_vov) - synthesis_node_type_define(const T0&,const T1 , e_voc) - synthesis_node_type_define(const T0 ,const T1&, e_cov) - synthesis_node_type_define( T0&, T1&,e_none) - synthesis_node_type_define(const T0 ,const T1 ,e_none) - synthesis_node_type_define( T0&,const T1 ,e_none) - synthesis_node_type_define(const T0 , T1&,e_none) - synthesis_node_type_define(const T0&, T1&,e_none) - synthesis_node_type_define( T0&,const T1&,e_none) + synthesis_node_type_define(const T0&, const T1&, e_vov) + synthesis_node_type_define(const T0&, const T1 , e_voc) + synthesis_node_type_define(const T0 , const T1&, e_cov) + synthesis_node_type_define( T0&, T1&, e_none) + synthesis_node_type_define(const T0 , const T1 , e_none) + synthesis_node_type_define( T0&, const T1 , e_none) + synthesis_node_type_define(const T0 , T1&, e_none) + synthesis_node_type_define(const T0&, T1&, e_none) + synthesis_node_type_define( T0&, const T1&, e_none) #undef synthesis_node_type_define template @@ -13686,15 +14411,15 @@ namespace exprtk template \ const typename expression_node::node_type nodetype_T0oT1oT2::result = expression_node:: v_; \ - synthesis_node_type_define(const T0&,const T1&,const T2&, e_vovov) - synthesis_node_type_define(const T0&,const T1&,const T2 , e_vovoc) - synthesis_node_type_define(const T0&,const T1 ,const T2&, e_vocov) - synthesis_node_type_define(const T0 ,const T1&,const T2&, e_covov) - synthesis_node_type_define(const T0 ,const T1&,const T2 , e_covoc) - synthesis_node_type_define(const T0 ,const T1 ,const T2 , e_none ) - synthesis_node_type_define(const T0 ,const T1 ,const T2&, e_none ) - synthesis_node_type_define(const T0&,const T1 ,const T2 , e_none ) - synthesis_node_type_define( T0&, T1&, T2&, e_none ) + synthesis_node_type_define(const T0&, const T1&, const T2&, e_vovov) + synthesis_node_type_define(const T0&, const T1&, const T2 , e_vovoc) + synthesis_node_type_define(const T0&, const T1 , const T2&, e_vocov) + synthesis_node_type_define(const T0 , const T1&, const T2&, e_covov) + synthesis_node_type_define(const T0 , const T1&, const T2 , e_covoc) + synthesis_node_type_define(const T0 , const T1 , const T2 , e_none ) + synthesis_node_type_define(const T0 , const T1 , const T2&, e_none ) + synthesis_node_type_define(const T0&, const T1 , const T2 , e_none ) + synthesis_node_type_define( T0&, T1&, T2&, e_none ) #undef synthesis_node_type_define template @@ -13708,22 +14433,22 @@ namespace exprtk template \ const typename expression_node::node_type nodetype_T0oT1oT2oT3::result = expression_node:: v_; \ - synthesis_node_type_define(const T0&,const T1&,const T2&, const T3&,e_vovovov) - synthesis_node_type_define(const T0&,const T1&,const T2&, const T3 ,e_vovovoc) - synthesis_node_type_define(const T0&,const T1&,const T2 , const T3&,e_vovocov) - synthesis_node_type_define(const T0&,const T1 ,const T2&, const T3&,e_vocovov) - synthesis_node_type_define(const T0 ,const T1&,const T2&, const T3&,e_covovov) - synthesis_node_type_define(const T0 ,const T1&,const T2 , const T3&,e_covocov) - synthesis_node_type_define(const T0&,const T1 ,const T2&, const T3 ,e_vocovoc) - synthesis_node_type_define(const T0 ,const T1&,const T2&, const T3 ,e_covovoc) - synthesis_node_type_define(const T0&,const T1 ,const T2 , const T3&,e_vococov) - synthesis_node_type_define(const T0 ,const T1 ,const T2 , const T3 ,e_none ) - synthesis_node_type_define(const T0 ,const T1 ,const T2 , const T3&,e_none ) - synthesis_node_type_define(const T0 ,const T1 ,const T2&, const T3 ,e_none ) - synthesis_node_type_define(const T0 ,const T1&,const T2 , const T3 ,e_none ) - synthesis_node_type_define(const T0&,const T1 ,const T2 , const T3 ,e_none ) - synthesis_node_type_define(const T0 ,const T1 ,const T2&, const T3&,e_none ) - synthesis_node_type_define(const T0&,const T1&,const T2 , const T3 ,e_none ) + synthesis_node_type_define(const T0&, const T1&, const T2&, const T3&, e_vovovov) + synthesis_node_type_define(const T0&, const T1&, const T2&, const T3 , e_vovovoc) + synthesis_node_type_define(const T0&, const T1&, const T2 , const T3&, e_vovocov) + synthesis_node_type_define(const T0&, const T1 , const T2&, const T3&, e_vocovov) + synthesis_node_type_define(const T0 , const T1&, const T2&, const T3&, e_covovov) + synthesis_node_type_define(const T0 , const T1&, const T2 , const T3&, e_covocov) + synthesis_node_type_define(const T0&, const T1 , const T2&, const T3 , e_vocovoc) + synthesis_node_type_define(const T0 , const T1&, const T2&, const T3 , e_covovoc) + synthesis_node_type_define(const T0&, const T1 , const T2 , const T3&, e_vococov) + synthesis_node_type_define(const T0 , const T1 , const T2 , const T3 , e_none ) + synthesis_node_type_define(const T0 , const T1 , const T2 , const T3&, e_none ) + synthesis_node_type_define(const T0 , const T1 , const T2&, const T3 , e_none ) + synthesis_node_type_define(const T0 , const T1&, const T2 , const T3 , e_none ) + synthesis_node_type_define(const T0&, const T1 , const T2 , const T3 , e_none ) + synthesis_node_type_define(const T0 , const T1 , const T2&, const T3&, e_none ) + synthesis_node_type_define(const T0&, const T1&, const T2 , const T3 , e_none ) #undef synthesis_node_type_define template @@ -13779,7 +14504,7 @@ namespace exprtk bfunc_t p2) { return allocator - .template allocate_type + .template allocate_type (p0, p1, p2); } @@ -13825,7 +14550,7 @@ namespace exprtk inline T value() const { - return ProcessMode::process(t0_,t1_,t2_,f0_,f1_); + return ProcessMode::process(t0_, t1_, t2_, f0_, f1_); } inline T0 t0() const @@ -13867,7 +14592,7 @@ namespace exprtk static inline expression_node* allocate(Allocator& allocator, T0 p0, T1 p1, T2 p2, bfunc_t p3, bfunc_t p4) { return allocator - .template allocate_type + .template allocate_type (p0, p1, p2, p3, p4); } @@ -13955,7 +14680,7 @@ namespace exprtk static inline std::string id() { - return process_mode_t::template id(); + return process_mode_t::template id(); } template @@ -13964,7 +14689,7 @@ namespace exprtk bfunc_t p4, bfunc_t p5, bfunc_t p6) { return allocator - .template allocate_type + .template allocate_type (p0, p1, p2, p3, p4, p5, p6); } @@ -14049,7 +14774,7 @@ namespace exprtk static inline expression_node* allocate(Allocator& allocator, T0 p0, T1 p1, T2 p2, tfunc_t p3) { return allocator - .template allocate_type + .template allocate_type (p0, p1, p2, p3); } @@ -14140,7 +14865,7 @@ namespace exprtk static inline expression_node* allocate(Allocator& allocator, T0 p0, T1 p1, T2 p2) { return allocator - .template allocate_type + .template allocate_type (p0, p1, p2); } @@ -14241,7 +14966,7 @@ namespace exprtk static inline expression_node* allocate(Allocator& allocator, T0 p0, T1 p1, T2 p2, T3 p3, qfunc_t p4) { return allocator - .template allocate_type + .template allocate_type (p0, p1, p2, p3, p4); } @@ -14307,7 +15032,7 @@ namespace exprtk inline T3 t3() const { - return t2_; + return t3_; } std::string type_id() const @@ -14324,7 +15049,7 @@ namespace exprtk static inline expression_node* allocate(Allocator& allocator, T0 p0, T1 p1, T2 p2, T3 p3) { return allocator - .template allocate_type + .template allocate_type (p0, p1, p2, p3); } @@ -14360,27 +15085,27 @@ namespace exprtk template struct T0oT1_define { - typedef details::T0oT1 type0; + typedef details::T0oT1 type0; }; template struct T0oT1oT2_define { - typedef details::T0oT1oT2::mode0> type0; - typedef details::T0oT1oT2::mode1> type1; - typedef details::T0oT1oT2_sf3 sf3_type; - typedef details::sf3ext_type_node sf3_type_node; + typedef details::T0oT1oT2::mode0> type0; + typedef details::T0oT1oT2::mode1> type1; + typedef details::T0oT1oT2_sf3 sf3_type; + typedef details::sf3ext_type_node sf3_type_node; }; template struct T0oT1oT2oT3_define { - typedef details::T0oT1oT2oT3::mode0> type0; - typedef details::T0oT1oT2oT3::mode1> type1; - typedef details::T0oT1oT2oT3::mode2> type2; - typedef details::T0oT1oT2oT3::mode3> type3; - typedef details::T0oT1oT2oT3::mode4> type4; - typedef details::T0oT1oT2oT3_sf4 sf4_type; + typedef details::T0oT1oT2oT3::mode0> type0; + typedef details::T0oT1oT2oT3::mode1> type1; + typedef details::T0oT1oT2oT3::mode2> type2; + typedef details::T0oT1oT2oT3::mode3> type3; + typedef details::T0oT1oT2oT3::mode4> type4; + typedef details::T0oT1oT2oT3_sf4 sf4_type; }; template @@ -14538,20 +15263,16 @@ namespace exprtk typedef Operation operation_t; // variable op constant node - explicit vob_node(const T& var, const expression_ptr brnch) + explicit vob_node(const T& var, const expression_ptr branch) : v_(var) { - init_branches<1>(branch_,brnch); - } - - ~vob_node() - { - cleanup_branches::execute(branch_); + construct_branch_pair(branch_, branch); } inline T value() const { - return Operation::process(v_,branch_[0].first->value()); + assert(branch_.first); + return Operation::process(v_,branch_.first->value()); } inline operator_type operation() const @@ -14566,7 +15287,17 @@ namespace exprtk inline expression_node* branch(const std::size_t&) const { - return branch_[0].first; + return branch_.first; + } + + void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) + { + expression_node::ndb_t::template collect(branch_, node_delete_list); + } + + std::size_t node_depth() const + { + return expression_node::ndb_t::compute_node_depth(branch_); } private: @@ -14575,7 +15306,7 @@ namespace exprtk vob_node& operator=(const vob_node&); const T& v_; - branch_t branch_[1]; + branch_t branch_; }; template @@ -14588,20 +15319,16 @@ namespace exprtk typedef Operation operation_t; // variable op constant node - explicit bov_node(const expression_ptr brnch, const T& var) + explicit bov_node(const expression_ptr branch, const T& var) : v_(var) { - init_branches<1>(branch_,brnch); - } - - ~bov_node() - { - cleanup_branches::execute(branch_); + construct_branch_pair(branch_, branch); } inline T value() const { - return Operation::process(branch_[0].first->value(),v_); + assert(branch_.first); + return Operation::process(branch_.first->value(),v_); } inline operator_type operation() const @@ -14616,7 +15343,17 @@ namespace exprtk inline expression_node* branch(const std::size_t&) const { - return branch_[0].first; + return branch_.first; + } + + void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) + { + expression_node::ndb_t::template collect(branch_, node_delete_list); + } + + std::size_t node_depth() const + { + return expression_node::ndb_t::compute_node_depth(branch_); } private: @@ -14625,7 +15362,7 @@ namespace exprtk bov_node& operator=(const bov_node&); const T& v_; - branch_t branch_[1]; + branch_t branch_; }; template @@ -14638,20 +15375,16 @@ namespace exprtk typedef Operation operation_t; // variable op constant node - explicit cob_node(const T const_var, const expression_ptr brnch) + explicit cob_node(const T const_var, const expression_ptr branch) : c_(const_var) { - init_branches<1>(branch_,brnch); - } - - ~cob_node() - { - cleanup_branches::execute(branch_); + construct_branch_pair(branch_, branch); } inline T value() const { - return Operation::process(c_,branch_[0].first->value()); + assert(branch_.first); + return Operation::process(c_,branch_.first->value()); } inline operator_type operation() const @@ -14671,13 +15404,23 @@ namespace exprtk inline expression_node* branch(const std::size_t&) const { - return branch_[0].first; + return branch_.first; } inline expression_node* move_branch(const std::size_t&) { - branch_[0].second = false; - return branch_[0].first; + branch_.second = false; + return branch_.first; + } + + void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) + { + expression_node::ndb_t::template collect(branch_, node_delete_list); + } + + std::size_t node_depth() const + { + return expression_node::ndb_t::compute_node_depth(branch_); } private: @@ -14686,7 +15429,7 @@ namespace exprtk cob_node& operator=(const cob_node&); const T c_; - branch_t branch_[1]; + branch_t branch_; }; template @@ -14699,20 +15442,16 @@ namespace exprtk typedef Operation operation_t; // variable op constant node - explicit boc_node(const expression_ptr brnch, const T const_var) + explicit boc_node(const expression_ptr branch, const T const_var) : c_(const_var) { - init_branches<1>(branch_,brnch); - } - - ~boc_node() - { - cleanup_branches::execute(branch_); + construct_branch_pair(branch_, branch); } inline T value() const { - return Operation::process(branch_[0].first->value(),c_); + assert(branch_.first); + return Operation::process(branch_.first->value(),c_); } inline operator_type operation() const @@ -14732,13 +15471,23 @@ namespace exprtk inline expression_node* branch(const std::size_t&) const { - return branch_[0].first; + return branch_.first; } inline expression_node* move_branch(const std::size_t&) { - branch_[0].second = false; - return branch_[0].first; + branch_.second = false; + return branch_.first; + } + + void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) + { + expression_node::ndb_t::template collect(branch_, node_delete_list); + } + + std::size_t node_depth() const + { + return expression_node::ndb_t::compute_node_depth(branch_); } private: @@ -14747,7 +15496,7 @@ namespace exprtk boc_node& operator=(const boc_node&); const T c_; - branch_t branch_[1]; + branch_t branch_; }; #ifndef exprtk_disable_string_capabilities @@ -15031,12 +15780,12 @@ namespace exprtk if (0 == str0_base_ptr_) return; - irange_ptr range_ptr = dynamic_cast(binary_node::branch_[0].first); + irange_ptr range = dynamic_cast(binary_node::branch_[0].first); - if (0 == range_ptr) + if (0 == range) return; - str0_range_ptr_ = &(range_ptr->range_ref()); + str0_range_ptr_ = &(range->range_ref()); } if (is_generally_string_node(binary_node::branch_[1].first)) @@ -15046,12 +15795,12 @@ namespace exprtk if (0 == str1_base_ptr_) return; - irange_ptr range_ptr = dynamic_cast(binary_node::branch_[1].first); + irange_ptr range = dynamic_cast(binary_node::branch_[1].first); - if (0 == range_ptr) + if (0 == range) return; - str1_range_ptr_ = &(range_ptr->range_ref()); + str1_range_ptr_ = &(range->range_ref()); } } @@ -15073,8 +15822,8 @@ namespace exprtk std::size_t str1_r0 = 0; std::size_t str1_r1 = 0; - range_t& range0 = (*str0_range_ptr_); - range_t& range1 = (*str1_range_ptr_); + const range_t& range0 = (*str0_range_ptr_); + const range_t& range1 = (*str1_range_ptr_); if ( range0(str0_r0, str0_r1, str0_base_ptr_->size()) && @@ -15209,19 +15958,15 @@ namespace exprtk typedef std::pair branch_t; typedef PowOp operation_t; - explicit bipow_node(expression_ptr brnch) + explicit bipow_node(expression_ptr branch) { - init_branches<1>(branch_, brnch); - } - - ~bipow_node() - { - cleanup_branches::execute(branch_); + construct_branch_pair(branch_, branch); } inline T value() const { - return PowOp::result(branch_[0].first->value()); + assert(branch_.first); + return PowOp::result(branch_.first->value()); } inline typename expression_node::node_type type() const @@ -15229,12 +15974,22 @@ namespace exprtk return expression_node::e_ipow; } + void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) + { + expression_node::ndb_t::collect(branch_, node_delete_list); + } + + std::size_t node_depth() const + { + return expression_node::ndb_t::compute_node_depth(branch_); + } + private: bipow_node(const bipow_node&); bipow_node& operator=(const bipow_node&); - branch_t branch_[1]; + branch_t branch_; }; template @@ -15276,19 +16031,15 @@ namespace exprtk typedef std::pair branch_t; typedef PowOp operation_t; - explicit bipowninv_node(expression_ptr brnch) + explicit bipowninv_node(expression_ptr branch) { - init_branches<1>(branch_, brnch); - } - - ~bipowninv_node() - { - cleanup_branches::execute(branch_); + construct_branch_pair(branch_, branch); } inline T value() const { - return (T(1) / PowOp::result(branch_[0].first->value())); + assert(branch_.first); + return (T(1) / PowOp::result(branch_.first->value())); } inline typename expression_node::node_type type() const @@ -15296,12 +16047,22 @@ namespace exprtk return expression_node::e_ipowinv; } + void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) + { + expression_node::ndb_t::template collect(branch_, node_delete_list); + } + + std::size_t node_depth() const + { + return expression_node::ndb_t::compute_node_depth(branch_); + } + private: bipowninv_node(const bipowninv_node&); bipowninv_node& operator=(const bipowninv_node&); - branch_t branch_[1]; + branch_t branch_; }; template @@ -15450,37 +16211,55 @@ namespace exprtk template inline expression_node* allocate(OpType& operation, ExprNode (&branch)[1]) { - return allocate(operation,branch[0]); + expression_node* result = + allocate(operation, branch[0]); + result->node_depth(); + return result; } template inline expression_node* allocate(OpType& operation, ExprNode (&branch)[2]) { - return allocate(operation,branch[0],branch[1]); + expression_node* result = + allocate(operation, branch[0], branch[1]); + result->node_depth(); + return result; } template inline expression_node* allocate(OpType& operation, ExprNode (&branch)[3]) { - return allocate(operation,branch[0],branch[1],branch[2]); + expression_node* result = + allocate(operation, branch[0], branch[1], branch[2]); + result->node_depth(); + return result; } template inline expression_node* allocate(OpType& operation, ExprNode (&branch)[4]) { - return allocate(operation,branch[0],branch[1],branch[2],branch[3]); + expression_node* result = + allocate(operation, branch[0], branch[1], branch[2], branch[3]); + result->node_depth(); + return result; } template inline expression_node* allocate(OpType& operation, ExprNode (&branch)[5]) { - return allocate(operation,branch[0],branch[1],branch[2],branch[3],branch[4]); + expression_node* result = + allocate(operation, branch[0],branch[1], branch[2], branch[3], branch[4]); + result->node_depth(); + return result; } template inline expression_node* allocate(OpType& operation, ExprNode (&branch)[6]) { - return allocate(operation,branch[0],branch[1],branch[2],branch[3],branch[4],branch[5]); + expression_node* result = + allocate(operation, branch[0], branch[1], branch[2], branch[3], branch[4], branch[5]); + result->node_depth(); + return result; } template @@ -15492,92 +16271,131 @@ namespace exprtk template class Sequence> + template class Sequence> inline expression_node* allocate(const Sequence& seq) const { - return (new node_type(seq)); + expression_node* + result = (new node_type(seq)); + result->node_depth(); + return result; } template inline expression_node* allocate(T1& t1) const { - return (new node_type(t1)); + expression_node* + result = (new node_type(t1)); + result->node_depth(); + return result; } template inline expression_node* allocate_c(const T1& t1) const { - return (new node_type(t1)); + expression_node* + result = (new node_type(t1)); + result->node_depth(); + return result; } template inline expression_node* allocate(const T1& t1, const T2& t2) const { - return (new node_type(t1,t2)); + expression_node* + result = (new node_type(t1, t2)); + result->node_depth(); + return result; } template inline expression_node* allocate_cr(const T1& t1, T2& t2) const { - return (new node_type(t1,t2)); + expression_node* + result = (new node_type(t1, t2)); + result->node_depth(); + return result; } template inline expression_node* allocate_rc(T1& t1, const T2& t2) const { - return (new node_type(t1,t2)); + expression_node* + result = (new node_type(t1, t2)); + result->node_depth(); + return result; } template inline expression_node* allocate_rr(T1& t1, T2& t2) const { - return (new node_type(t1,t2)); + expression_node* + result = (new node_type(t1, t2)); + result->node_depth(); + return result; } template inline expression_node* allocate_tt(T1 t1, T2 t2) const { - return (new node_type(t1,t2)); + expression_node* + result = (new node_type(t1, t2)); + result->node_depth(); + return result; } template inline expression_node* allocate_ttt(T1 t1, T2 t2, T3 t3) const { - return (new node_type(t1,t2,t3)); + expression_node* + result = (new node_type(t1, t2, t3)); + result->node_depth(); + return result; } template inline expression_node* allocate_tttt(T1 t1, T2 t2, T3 t3, T4 t4) const { - return (new node_type(t1,t2,t3,t4)); + expression_node* + result = (new node_type(t1, t2, t3, t4)); + result->node_depth(); + return result; } template inline expression_node* allocate_rrr(T1& t1, T2& t2, T3& t3) const { - return (new node_type(t1,t2,t3)); + expression_node* + result = (new node_type(t1, t2, t3)); + result->node_depth(); + return result; } template inline expression_node* allocate_rrrr(T1& t1, T2& t2, T3& t3, T4& t4) const { - return (new node_type(t1,t2,t3,t4)); + expression_node* + result = (new node_type(t1, t2, t3, t4)); + result->node_depth(); + return result; } template inline expression_node* allocate_rrrrr(T1& t1, T2& t2, T3& t3, T4& t4, T5& t5) const { - return (new node_type(t1,t2,t3,t4,t5)); + expression_node* + result = (new node_type(t1, t2, t3, t4, t5)); + result->node_depth(); + return result; } template * allocate(const T1& t1, const T2& t2, const T3& t3) const { - return (new node_type(t1,t2,t3)); + expression_node* + result = (new node_type(t1, t2, t3)); + result->node_depth(); + return result; } template * allocate(const T1& t1, const T2& t2, const T3& t3, const T4& t4) const { - return (new node_type(t1,t2,t3,t4)); + expression_node* + result = (new node_type(t1, t2, t3, t4)); + result->node_depth(); + return result; } template * + result = (new node_type(t1, t2, t3, t4, t5)); + result->node_depth(); + return result; } template * + result = (new node_type(t1, t2, t3, t4, t5, t6)); + result->node_depth(); + return result; } template * + result = (new node_type(t1, t2, t3, t4, t5, t6, t7)); + result->node_depth(); + return result; } template * + result = (new node_type(t1, t2, t3, t4, t5, t6, t7, t8)); + result->node_depth(); + return result; } template * + result = (new node_type(t1, t2, t3, t4, t5, t6, t7, t8, t9)); + result->node_depth(); + return result; } template * + result = (new node_type(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10)); + result->node_depth(); + return result; } template inline expression_node* allocate_type(T1 t1, T2 t2, T3 t3) const { - return (new node_type(t1,t2,t3)); + expression_node* + result = (new node_type(t1, t2, t3)); + result->node_depth(); + return result; } template * allocate_type(T1 t1, T2 t2, T3 t3, T4 t4) const { - return (new node_type(t1,t2,t3,t4)); + expression_node* + result = (new node_type(t1, t2, t3, t4)); + result->node_depth(); + return result; } template * + result = (new node_type(t1, t2, t3, t4, t5)); + result->node_depth(); + return result; } template * + result = (new node_type(t1, t2, t3, t4, t5, t6)); + result->node_depth(); + return result; } template * + result = (new node_type(t1, t2, t3, t4, t5, t6, t7)); + result->node_depth(); + return result; } template void inline free(expression_node*& e) const { + exprtk_debug(("node_allocator::free() - deleting expression_node " + "type: %03d addr: %p\n", + static_cast(e->type()), + reinterpret_cast(e))); delete e; e = 0; } @@ -15886,83 +16747,84 @@ namespace exprtk virtual ~ifunction() {} - #define empty_method_body \ + #define empty_method_body(N) \ { \ + exprtk_debug(("ifunction::operator() - Operator(" #N ") has not been overridden\n")); \ return std::numeric_limits::quiet_NaN(); \ } \ inline virtual T operator() () - empty_method_body + empty_method_body(0) - inline virtual T operator() (const T&) - empty_method_body + inline virtual T operator() (const T&) + empty_method_body(1) - inline virtual T operator() (const T&,const T&) - empty_method_body + inline virtual T operator() (const T&,const T&) + empty_method_body(2) - inline virtual T operator() (const T&, const T&, const T&) - empty_method_body + inline virtual T operator() (const T&, const T&, const T&) + empty_method_body(3) inline virtual T operator() (const T&, const T&, const T&, const T&) - empty_method_body + empty_method_body(4) inline virtual T operator() (const T&, const T&, const T&, const T&, const T&) - empty_method_body + empty_method_body(5) inline virtual T operator() (const T&, const T&, const T&, const T&, const T&, const T&) - empty_method_body + empty_method_body(6) inline virtual T operator() (const T&, const T&, const T&, const T&, const T&, const T&, const T&) - empty_method_body + empty_method_body(7) inline virtual T operator() (const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&) - empty_method_body + empty_method_body(8) inline virtual T operator() (const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&) - empty_method_body + empty_method_body(9) inline virtual T operator() (const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&) - empty_method_body + empty_method_body(10) inline virtual T operator() (const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, - const T&) - empty_method_body + const T&) + empty_method_body(11) inline virtual T operator() (const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&) - empty_method_body + empty_method_body(12) inline virtual T operator() (const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&) - empty_method_body + empty_method_body(13) inline virtual T operator() (const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&) - empty_method_body + empty_method_body(14) inline virtual T operator() (const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&) - empty_method_body + empty_method_body(15) inline virtual T operator() (const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&) - empty_method_body + empty_method_body(16) inline virtual T operator() (const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&) - empty_method_body + empty_method_body(17) inline virtual T operator() (const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&) - empty_method_body + empty_method_body(18) inline virtual T operator() (const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&) - empty_method_body + empty_method_body(19) inline virtual T operator() (const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&) - empty_method_body + empty_method_body(20) #undef empty_method_body @@ -15979,7 +16841,7 @@ namespace exprtk inline virtual T operator() (const std::vector&) { - exprtk_debug(("ivararg_function::operator() - Operator has not been overridden.\n")); + exprtk_debug(("ivararg_function::operator() - Operator has not been overridden\n")); return std::numeric_limits::quiet_NaN(); } }; @@ -15991,8 +16853,9 @@ namespace exprtk enum return_type { - e_rtrn_scalar = 0, - e_rtrn_string = 1 + e_rtrn_scalar = 0, + e_rtrn_string = 1, + e_rtrn_overload = 2 }; typedef T type; @@ -16009,7 +16872,7 @@ namespace exprtk #define igeneric_function_empty_body(N) \ { \ - exprtk_debug(("igeneric_function::operator() - Operator has not been overridden. ["#N"]\n")); \ + exprtk_debug(("igeneric_function::operator() - Operator(" #N ") has not been overridden\n")); \ return std::numeric_limits::quiet_NaN(); \ } \ @@ -16043,20 +16906,20 @@ namespace exprtk 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); + 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: @@ -16064,7 +16927,7 @@ namespace exprtk { using exprtk::ifunction::operator(); - freefunc00(ff00_functor ff) : exprtk::ifunction(0), f(ff) {} + explicit freefunc00(ff00_functor ff) : exprtk::ifunction(0), f(ff) {} inline T operator() () { return f(); } ff00_functor f; @@ -16074,7 +16937,7 @@ namespace exprtk { using exprtk::ifunction::operator(); - freefunc01(ff01_functor ff) : exprtk::ifunction(1), f(ff) {} + explicit freefunc01(ff01_functor ff) : exprtk::ifunction(1), f(ff) {} inline T operator() (const T& v0) { return f(v0); } ff01_functor f; @@ -16084,7 +16947,7 @@ namespace exprtk { using exprtk::ifunction::operator(); - freefunc02(ff02_functor ff) : exprtk::ifunction(2), f(ff) {} + explicit freefunc02(ff02_functor ff) : exprtk::ifunction(2), f(ff) {} inline T operator() (const T& v0, const T& v1) { return f(v0, v1); } ff02_functor f; @@ -16094,7 +16957,7 @@ namespace exprtk { using exprtk::ifunction::operator(); - freefunc03(ff03_functor ff) : exprtk::ifunction(3), f(ff) {} + explicit freefunc03(ff03_functor ff) : exprtk::ifunction(3), f(ff) {} inline T operator() (const T& v0, const T& v1, const T& v2) { return f(v0, v1, v2); } ff03_functor f; @@ -16104,7 +16967,7 @@ namespace exprtk { using exprtk::ifunction::operator(); - freefunc04(ff04_functor ff) : exprtk::ifunction(4), f(ff) {} + explicit freefunc04(ff04_functor ff) : exprtk::ifunction(4), f(ff) {} inline T operator() (const T& v0, const T& v1, const T& v2, const T& v3) { return f(v0, v1, v2, v3); } ff04_functor f; @@ -16114,7 +16977,7 @@ namespace exprtk { using exprtk::ifunction::operator(); - freefunc05(ff05_functor ff) : exprtk::ifunction(5), f(ff) {} + explicit freefunc05(ff05_functor ff) : exprtk::ifunction(5), f(ff) {} inline T operator() (const T& v0, const T& v1, const T& v2, const T& v3, const T& v4) { return f(v0, v1, v2, v3, v4); } ff05_functor f; @@ -16124,7 +16987,7 @@ namespace exprtk { using exprtk::ifunction::operator(); - freefunc06(ff06_functor ff) : exprtk::ifunction(6), f(ff) {} + explicit freefunc06(ff06_functor ff) : exprtk::ifunction(6), f(ff) {} inline T operator() (const T& v0, const T& v1, const T& v2, const T& v3, const T& v4, const T& v5) { return f(v0, v1, v2, v3, v4, v5); } ff06_functor f; @@ -16134,7 +16997,7 @@ namespace exprtk { using exprtk::ifunction::operator(); - freefunc07(ff07_functor ff) : exprtk::ifunction(7), f(ff) {} + explicit freefunc07(ff07_functor ff) : exprtk::ifunction(7), f(ff) {} inline T operator() (const T& v0, const T& v1, const T& v2, const T& v3, const T& v4, const T& v5, const T& v6) { return f(v0, v1, v2, v3, v4, v5, v6); } @@ -16145,7 +17008,7 @@ namespace exprtk { using exprtk::ifunction::operator(); - freefunc08(ff08_functor ff) : exprtk::ifunction(8), f(ff) {} + explicit freefunc08(ff08_functor ff) : exprtk::ifunction(8), f(ff) {} inline T operator() (const T& v0, const T& v1, const T& v2, const T& v3, const T& v4, const T& v5, const T& v6, const T& v7) { return f(v0, v1, v2, v3, v4, v5, v6, v7); } @@ -16156,7 +17019,7 @@ namespace exprtk { using exprtk::ifunction::operator(); - freefunc09(ff09_functor ff) : exprtk::ifunction(9), f(ff) {} + explicit freefunc09(ff09_functor ff) : exprtk::ifunction(9), f(ff) {} inline T operator() (const T& v0, const T& v1, const T& v2, const T& v3, const T& v4, const T& v5, const T& v6, const T& v7, const T& v8) { return f(v0, v1, v2, v3, v4, v5, v6, v7, v8); } @@ -16167,7 +17030,7 @@ namespace exprtk { using exprtk::ifunction::operator(); - freefunc10(ff10_functor ff) : exprtk::ifunction(10), f(ff) {} + explicit freefunc10(ff10_functor ff) : exprtk::ifunction(10), f(ff) {} inline T operator() (const T& v0, const T& v1, const T& v2, const T& v3, const T& v4, const T& v5, const T& v6, const T& v7, const T& v8, const T& v9) { return f(v0, v1, v2, v3, v4, v5, v6, v7, v8, v9); } @@ -16178,7 +17041,7 @@ namespace exprtk { using exprtk::ifunction::operator(); - freefunc11(ff11_functor ff) : exprtk::ifunction(11), f(ff) {} + explicit freefunc11(ff11_functor ff) : exprtk::ifunction(11), f(ff) {} inline T operator() (const T& v0, const T& v1, const T& v2, const T& v3, const T& v4, const T& v5, const T& v6, const T& v7, const T& v8, const T& v9, const T& v10) { return f(v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10); } @@ -16189,7 +17052,7 @@ namespace exprtk { using exprtk::ifunction::operator(); - freefunc12(ff12_functor ff) : exprtk::ifunction(12), f(ff) {} + explicit freefunc12(ff12_functor ff) : exprtk::ifunction(12), f(ff) {} inline T operator() (const T& v00, const T& v01, const T& v02, const T& v03, const T& v04, const T& v05, const T& v06, const T& v07, const T& v08, const T& v09, const T& v10, const T& v11) @@ -16201,7 +17064,7 @@ namespace exprtk { using exprtk::ifunction::operator(); - freefunc13(ff13_functor ff) : exprtk::ifunction(13), f(ff) {} + explicit freefunc13(ff13_functor ff) : exprtk::ifunction(13), f(ff) {} inline T operator() (const T& v00, const T& v01, const T& v02, const T& v03, const T& v04, const T& v05, const T& v06, const T& v07, const T& v08, const T& v09, const T& v10, const T& v11, const T& v12) @@ -16213,7 +17076,7 @@ namespace exprtk { using exprtk::ifunction::operator(); - freefunc14(ff14_functor ff) : exprtk::ifunction(14), f(ff) {} + explicit freefunc14(ff14_functor ff) : exprtk::ifunction(14), f(ff) {} inline T operator() (const T& v00, const T& v01, const T& v02, const T& v03, const T& v04, const T& v05, const T& v06, const T& v07, const T& v08, const T& v09, const T& v10, const T& v11, const T& v12, const T& v13) @@ -16225,7 +17088,7 @@ namespace exprtk { using exprtk::ifunction::operator(); - freefunc15(ff15_functor ff) : exprtk::ifunction(15), f(ff) {} + explicit freefunc15(ff15_functor ff) : exprtk::ifunction(15), f(ff) {} inline T operator() (const T& v00, const T& v01, const T& v02, const T& v03, const T& v04, const T& v05, const T& v06, const T& v07, const T& v08, const T& v09, const T& v10, const T& v11, const T& v12, const T& v13, const T& v14) @@ -16644,11 +17507,12 @@ namespace exprtk #ifndef exprtk_disable_string_capabilities type_store,std::string> stringvar_store; #endif - type_store,ifunction > function_store; + type_store,ifunction > function_store; type_store,ivararg_function > vararg_function_store; type_store,igeneric_function > generic_function_store; type_store,igeneric_function > string_function_store; - type_store vector_store; + type_store,igeneric_function > overload_function_store; + type_store vector_store; st_data() { @@ -16698,7 +17562,7 @@ namespace exprtk data_(st_data::create()) {} - control_block(st_data* data) + explicit control_block(st_data* data) : ref_count(1), data_(data) {} @@ -16772,7 +17636,7 @@ namespace exprtk return (*this); } - inline bool operator==(const symbol_table& st) + inline bool operator==(const symbol_table& st) const { return (this == &st) || (control_block_ == st.control_block_); } @@ -16919,6 +17783,16 @@ namespace exprtk return local_data().string_function_store.get(function_name); } + inline generic_function_ptr get_overload_function(const std::string& function_name) const + { + if (!valid()) + return reinterpret_cast(0); + else if (!valid_symbol(function_name)) + return reinterpret_cast(0); + else + return local_data().overload_function_store.get(function_name); + } + typedef vector_holder_t* vector_holder_ptr; inline vector_holder_ptr get_vector(const std::string& vector_name) const @@ -17020,7 +17894,7 @@ namespace exprtk else if (symbol_exists(variable_name)) return false; else - return local_data().variable_store.add(variable_name,t,is_constant); + return local_data().variable_store.add(variable_name, t, is_constant); } inline bool add_constant(const std::string& constant_name, const T& value) @@ -17035,7 +17909,7 @@ namespace exprtk local_data().local_symbol_list_.push_back(value); T& t = local_data().local_symbol_list_.back(); - return add_variable(constant_name,t,true); + return add_variable(constant_name, t, true); } #ifndef exprtk_disable_string_capabilities @@ -17048,7 +17922,7 @@ namespace exprtk else if (symbol_exists(stringvar_name)) return false; else - return local_data().stringvar_store.add(stringvar_name,s,is_constant); + return local_data().stringvar_store.add(stringvar_name, s, is_constant); } #endif @@ -17084,14 +17958,33 @@ namespace exprtk return false; else if (symbol_exists(function_name)) return false; - else if (std::string::npos != function.parameter_sequence.find_first_not_of("STVZ*?|")) + else if ( + ( + (generic_function_t::e_rtrn_scalar == function.rtrn_type) || + (generic_function_t::e_rtrn_string == function.rtrn_type) + ) && + std::string::npos != function.parameter_sequence.find_first_not_of("STVZ*?|") + ) return false; - else if (generic_function_t::e_rtrn_scalar == function.rtrn_type) - return local_data().generic_function_store.add(function_name,function); - else if (generic_function_t::e_rtrn_string == function.rtrn_type) - return local_data().string_function_store.add(function_name, function); - else + else if ( + (generic_function_t::e_rtrn_overload == function.rtrn_type) && + std::string::npos != function.parameter_sequence.find_first_not_of("STVZ*?|:") + ) return false; + + switch (function.rtrn_type) + { + case generic_function_t::e_rtrn_scalar : + return local_data().generic_function_store.add(function_name,function); + + case generic_function_t::e_rtrn_string : + return local_data().string_function_store.add(function_name,function); + + case generic_function_t::e_rtrn_overload : + return local_data().overload_function_store.add(function_name,function); + } + + return false; } #define exprtk_define_freefunction(NN) \ @@ -17154,14 +18047,33 @@ namespace exprtk return false; else if (symbol_exists(function_name,false)) return false; - else if (std::string::npos != function.parameter_sequence.find_first_not_of("STV*?|")) + else if ( + ( + (generic_function_t::e_rtrn_scalar == function.rtrn_type) || + (generic_function_t::e_rtrn_string == function.rtrn_type) + ) && + std::string::npos != function.parameter_sequence.find_first_not_of("STV*?|") + ) return false; - else if (generic_function_t::e_rtrn_scalar == function.rtrn_type) - return local_data().generic_function_store.add(function_name,function); - else if (generic_function_t::e_rtrn_string == function.rtrn_type) - return local_data().string_function_store.add(function_name, function); - else + else if ( + generic_function_t::e_rtrn_overload && + std::string::npos != function.parameter_sequence.find_first_not_of("STV*?|:") + ) return false; + + switch (function.rtrn_type) + { + case generic_function_t::e_rtrn_scalar : + return local_data().generic_function_store.add(function_name,function); + + case generic_function_t::e_rtrn_string : + return local_data().string_function_store.add(function_name,function); + + case generic_function_t::e_rtrn_overload : + return local_data().overload_function_store.add(function_name,function); + } + + return false; } template @@ -17188,7 +18100,7 @@ namespace exprtk else if (0 == v_size) return false; else - return local_data().vector_store.add(vector_name,v,v_size); + return local_data().vector_store.add(vector_name, v, v_size); } template @@ -17350,8 +18262,8 @@ namespace exprtk { /* Function will return true if symbol_name exists as either a - reserved symbol, variable, stringvar or function name in any - of the type stores. + reserved symbol, variable, stringvar, vector or function name + in any of the type stores. */ if (!valid()) return false; @@ -17361,6 +18273,8 @@ namespace exprtk else if (local_data().stringvar_store.symbol_exists(symbol_name)) return true; #endif + else if (local_data().vector_store.symbol_exists(symbol_name)) + return true; else if (local_data().function_store.symbol_exists(symbol_name)) return true; else if (check_reserved_symb && local_data().is_reserved_symbol(symbol_name)) @@ -17515,6 +18429,21 @@ namespace exprtk } } } + + { + std::vector name_list; + + st.local_data().overload_function_store.get_list(name_list); + + if (!name_list.empty()) + { + for (std::size_t i = 0; i < name_list.size(); ++i) + { + exprtk::igeneric_function& ifunc = *st.get_overload_function(name_list[i]); + add_function(name_list[i],ifunc); + } + } + } } private: @@ -17534,7 +18463,7 @@ namespace exprtk ('_' != symbol[i]) ) { - if (('.' == symbol[i]) && (i < (symbol.size() - 1))) + if ((i < (symbol.size() - 1)) && ('.' == symbol[i])) continue; else return false; @@ -17560,7 +18489,7 @@ namespace exprtk ('_' != symbol[i]) ) { - if (('.' == symbol[i]) && (i < (symbol.size() - 1))) + if ((i < (symbol.size() - 1)) && ('.' == symbol[i])) continue; else return false; @@ -17620,7 +18549,7 @@ namespace exprtk size(0) {} - data_pack(void* ptr, data_type dt, std::size_t sz = 0) + data_pack(void* ptr, const data_type dt, const std::size_t sz = 0) : pointer(ptr), type(dt), size(sz) @@ -17642,7 +18571,7 @@ namespace exprtk return_invoked(&retinv_null) {} - control_block(expression_ptr e) + explicit control_block(expression_ptr e) : ref_count(1), expr (e), results (0), @@ -17735,6 +18664,13 @@ namespace exprtk control_block_->ref_count++; } + explicit expression(const symbol_table& symbol_table) + : control_block_(0) + { + set_expression(new details::null_node()); + symbol_table_list_.push_back(symbol_table); + } + inline expression& operator=(const expression& e) { if (this != &e) @@ -17760,7 +18696,7 @@ namespace exprtk return *this; } - inline bool operator==(const expression& e) + inline bool operator==(const expression& e) const { return (this == &e); } @@ -17787,6 +18723,9 @@ namespace exprtk inline T value() const { + assert(control_block_ ); + assert(control_block_->expr); + return control_block_->expr->value(); } @@ -17909,7 +18848,7 @@ namespace exprtk control_block_-> local_data_list.push_back( typename expression::control_block:: - data_pack(reinterpret_cast(data),dt,size)); + data_pack(reinterpret_cast(data), dt, size)); } } } @@ -17944,7 +18883,7 @@ namespace exprtk } control_block* control_block_; - symtab_list_t symbol_table_list_; + symtab_list_t symbol_table_list_; friend class parser; friend class expression_helper; @@ -18003,7 +18942,8 @@ namespace exprtk e_numeric = 4, e_symtab = 5, e_lexer = 6, - e_helper = 7 + e_helper = 7, + e_parser = 8 }; struct type @@ -18023,7 +18963,7 @@ namespace exprtk std::size_t column_no; }; - inline type make_error(error_mode mode, + inline type make_error(const error_mode mode, const std::string& diagnostic = "", const std::string& src_location = "") { @@ -18036,7 +18976,7 @@ namespace exprtk return t; } - inline type make_error(error_mode mode, + inline type make_error(const error_mode mode, const lexer::token& tk, const std::string& diagnostic = "", const std::string& src_location = "") @@ -18061,6 +19001,7 @@ namespace exprtk case e_symtab : return std::string("Symbol Error" ); case e_lexer : return std::string("Lexer Error" ); case e_helper : return std::string("Helper Error" ); + case e_parser : return std::string("Parser Error" ); default : return std::string("Unknown Error"); } } @@ -18207,11 +19148,11 @@ namespace exprtk typedef typename expression::symtab_list_t symbol_table_list_t; typedef details::vector_holder* vector_holder_ptr; - typedef typename details::functor_t functor_t; - typedef typename functor_t::qfunc_t quaternary_functor_t; - typedef typename functor_t::tfunc_t trinary_functor_t; - typedef typename functor_t::bfunc_t binary_functor_t; - typedef typename functor_t::ufunc_t unary_functor_t; + typedef typename details::functor_t functor_t; + typedef typename functor_t::qfunc_t quaternary_functor_t; + typedef typename functor_t::tfunc_t trinary_functor_t; + typedef typename functor_t::bfunc_t binary_functor_t; + typedef typename functor_t::ufunc_t unary_functor_t; typedef details::operator_type operator_t; @@ -18349,7 +19290,7 @@ namespace exprtk typedef variable_node_t* variable_node_ptr; typedef parser parser_t; - scope_element_manager(parser& p) + explicit scope_element_manager(parser& p) : parser_(p), input_param_cnt_(0) {} @@ -18460,6 +19401,10 @@ namespace exprtk inline void free_element(scope_element& se) { + #ifdef exprtk_enable_debugging + exprtk_debug(("free_element() - se[%s]\n", se.name.c_str())); + #endif + switch (se.type) { case scope_element::e_variable : if (se.data ) delete (T*) se.data; @@ -18542,12 +19487,12 @@ namespace exprtk typedef parser parser_t; - scope_handler(parser& p) + explicit scope_handler(parser& p) : parser_(p) { parser_.state_.scope_depth++; #ifdef exprtk_enable_debugging - std::string depth(2 * parser_.state_.scope_depth,'-'); + const std::string depth(2 * parser_.state_.scope_depth,'-'); exprtk_debug(("%s> Scope Depth: %02d\n", depth.c_str(), static_cast(parser_.state_.scope_depth))); @@ -18559,7 +19504,7 @@ namespace exprtk parser_.sem_.deactivate(parser_.state_.scope_depth); parser_.state_.scope_depth--; #ifdef exprtk_enable_debugging - std::string depth(2 * parser_.state_.scope_depth,'-'); + const std::string depth(2 * parser_.state_.scope_depth,'-'); exprtk_debug(("<%s Scope Depth: %02d\n", depth.c_str(), static_cast(parser_.state_.scope_depth))); @@ -18573,6 +19518,45 @@ namespace exprtk parser_t& parser_; }; + class stack_limit_handler + { + public: + + typedef parser parser_t; + + explicit stack_limit_handler(parser& p) + : parser_(p), + limit_exceeded_(false) + { + if (++parser_.state_.stack_depth > parser_.settings_.max_stack_depth_) + { + limit_exceeded_ = true; + parser_.set_error( + make_error(parser_error::e_parser, + "ERR000 - Current stack depth " + details::to_str(parser_.state_.stack_depth) + + " exceeds maximum allowed stack depth of " + details::to_str(parser_.settings_.max_stack_depth_), + exprtk_error_location)); + } + } + + ~stack_limit_handler() + { + parser_.state_.stack_depth--; + } + + bool operator!() + { + return limit_exceeded_; + } + + private: + + stack_limit_handler& operator=(const stack_limit_handler&); + + parser_t& parser_; + bool limit_exceeded_; + }; + struct symtab_store { symbol_table_list_t symtab_list_; @@ -18773,6 +19757,27 @@ namespace exprtk return result; } + inline generic_function_ptr get_overload_function(const std::string& function_name) const + { + if (!valid_function_name(function_name)) + return reinterpret_cast(0); + + generic_function_ptr result = reinterpret_cast(0); + + for (std::size_t i = 0; i < symtab_list_.size(); ++i) + { + if (!symtab_list_[i].valid()) + continue; + else + result = + local_data(i).overload_function_store.get(function_name); + + if (result) break; + } + + return result; + } + inline vector_holder_ptr get_vector(const std::string& vector_name) const { if (!valid_symbol(vector_name)) @@ -18995,11 +20000,13 @@ namespace exprtk void reset() { - parsing_return_stmt = false; - parsing_break_stmt = false; - return_stmt_present = false; - side_effect_present = false; - scope_depth = 0; + parsing_return_stmt = false; + parsing_break_stmt = false; + return_stmt_present = false; + side_effect_present = false; + scope_depth = 0; + stack_depth = 0; + parsing_loop_stmt_count = 0; } #ifndef exprtk_enable_debugging @@ -19022,6 +20029,8 @@ namespace exprtk bool side_effect_present; bool type_check_enabled; std::size_t scope_depth; + std::size_t stack_depth; + std::size_t parsing_loop_stmt_count; }; public: @@ -19031,8 +20040,9 @@ namespace exprtk enum usr_symbol_type { - e_usr_variable_type = 0, - e_usr_constant_type = 1 + e_usr_unknown_type = 0, + e_usr_variable_type = 1, + e_usr_constant_type = 2 }; enum usr_mode @@ -19111,7 +20121,7 @@ namespace exprtk {} template class Sequence> + template class Sequence> inline std::size_t symbols(Sequence& symbols_list) { if (!collect_variables_ && !collect_functions_) @@ -19134,7 +20144,7 @@ namespace exprtk } template class Sequence> + template class Sequence> inline std::size_t assignment_symbols(Sequence& assignment_list) { if (!collect_assignments_) @@ -19347,6 +20357,8 @@ namespace exprtk e_strength_reduction; settings_store(const std::size_t compile_options = compile_all_opts) + : max_stack_depth_(400), + max_node_depth_(10000) { load_compile_options(compile_options); } @@ -19467,7 +20479,7 @@ namespace exprtk bool rsrvd_sym_usr_disabled () const { return disable_rsrvd_sym_usr_; } bool zero_return_disabled () const { return disable_zero_return_; } - bool function_enabled(const std::string& function_name) + bool function_enabled(const std::string& function_name) const { if (disabled_func_set_.empty()) return true; @@ -19475,7 +20487,7 @@ namespace exprtk return (disabled_func_set_.end() == disabled_func_set_.find(function_name)); } - bool control_struct_enabled(const std::string& control_struct) + bool control_struct_enabled(const std::string& control_struct) const { if (disabled_ctrl_set_.empty()) return true; @@ -19483,7 +20495,7 @@ namespace exprtk return (disabled_ctrl_set_.end() == disabled_ctrl_set_.find(control_struct)); } - bool logic_enabled(const std::string& logic_operation) + bool logic_enabled(const std::string& logic_operation) const { if (disabled_logic_set_.empty()) return true; @@ -19491,7 +20503,7 @@ namespace exprtk return (disabled_logic_set_.end() == disabled_logic_set_.find(logic_operation)); } - bool arithmetic_enabled(const details::operator_type& arithmetic_operation) + bool arithmetic_enabled(const details::operator_type& arithmetic_operation) const { if (disabled_logic_set_.empty()) return true; @@ -19500,7 +20512,7 @@ namespace exprtk .find(arith_opr_to_string(arithmetic_operation)); } - bool assignment_enabled(const details::operator_type& assignment) + bool assignment_enabled(const details::operator_type& assignment) const { if (disabled_assignment_set_.empty()) return true; @@ -19509,7 +20521,7 @@ namespace exprtk .find(assign_opr_to_string(assignment)); } - bool inequality_enabled(const details::operator_type& inequality) + bool inequality_enabled(const details::operator_type& inequality) const { if (disabled_inequality_set_.empty()) return true; @@ -19518,7 +20530,7 @@ namespace exprtk .find(inequality_opr_to_string(inequality)); } - bool function_disabled(const std::string& function_name) + bool function_disabled(const std::string& function_name) const { if (disabled_func_set_.empty()) return false; @@ -19526,7 +20538,7 @@ namespace exprtk return (disabled_func_set_.end() != disabled_func_set_.find(function_name)); } - bool control_struct_disabled(const std::string& control_struct) + bool control_struct_disabled(const std::string& control_struct) const { if (disabled_ctrl_set_.empty()) return false; @@ -19534,7 +20546,7 @@ namespace exprtk return (disabled_ctrl_set_.end() != disabled_ctrl_set_.find(control_struct)); } - bool logic_disabled(const std::string& logic_operation) + bool logic_disabled(const std::string& logic_operation) const { if (disabled_logic_set_.empty()) return false; @@ -19542,7 +20554,7 @@ namespace exprtk return (disabled_logic_set_.end() != disabled_logic_set_.find(logic_operation)); } - bool assignment_disabled(const details::operator_type assignment_operation) + bool assignment_disabled(const details::operator_type assignment_operation) const { if (disabled_assignment_set_.empty()) return false; @@ -19551,7 +20563,16 @@ namespace exprtk .find(assign_opr_to_string(assignment_operation)); } - bool arithmetic_disabled(const details::operator_type arithmetic_operation) + bool logic_disabled(const details::operator_type logic_operation) const + { + if (disabled_logic_set_.empty()) + return false; + else + return disabled_logic_set_.end() != disabled_logic_set_ + .find(logic_opr_to_string(logic_operation)); + } + + bool arithmetic_disabled(const details::operator_type arithmetic_operation) const { if (disabled_arithmetic_set_.empty()) return false; @@ -19560,7 +20581,7 @@ namespace exprtk .find(arith_opr_to_string(arithmetic_operation)); } - bool inequality_disabled(const details::operator_type& inequality) + bool inequality_disabled(const details::operator_type& inequality) const { if (disabled_inequality_set_.empty()) return false; @@ -19755,6 +20776,16 @@ namespace exprtk return (*this); } + void set_max_stack_depth(const std::size_t mx_stack_depth) + { + max_stack_depth_ = mx_stack_depth; + } + + void set_max_node_depth(const std::size_t max_node_depth) + { + max_node_depth_ = max_node_depth; + } + private: void load_compile_options(const std::size_t compile_options) @@ -19774,7 +20805,7 @@ namespace exprtk disable_zero_return_ = (compile_options & e_disable_zero_return ) == e_disable_zero_return; } - std::string assign_opr_to_string(details::operator_type opr) + std::string assign_opr_to_string(details::operator_type opr) const { switch (opr) { @@ -19788,7 +20819,7 @@ namespace exprtk } } - std::string arith_opr_to_string(details::operator_type opr) + std::string arith_opr_to_string(details::operator_type opr) const { switch (opr) { @@ -19801,7 +20832,7 @@ namespace exprtk } } - std::string inequality_opr_to_string(details::operator_type opr) + std::string inequality_opr_to_string(details::operator_type opr) const { switch (opr) { @@ -19817,6 +20848,21 @@ namespace exprtk } } + std::string logic_opr_to_string(details::operator_type opr) const + { + switch (opr) + { + case details::e_and : return "and" ; + case details::e_or : return "or" ; + case details::e_xor : return "xor" ; + case details::e_nand : return "nand"; + case details::e_nor : return "nor" ; + case details::e_xnor : return "xnor"; + case details::e_notl : return "not" ; + default : return "" ; + } + } + bool enable_replacer_; bool enable_joiner_; bool enable_numeric_check_; @@ -19838,6 +20884,9 @@ namespace exprtk disabled_entity_set_t disabled_assignment_set_; disabled_entity_set_t disabled_inequality_set_; + std::size_t max_stack_depth_; + std::size_t max_node_depth_; + friend class parser; }; @@ -19857,7 +20906,8 @@ namespace exprtk #pragma warning(pop) #endif operator_joiner_2_(2), - operator_joiner_3_(3) + operator_joiner_3_(3), + loop_runtime_check_(0) { init_precompilation(); @@ -19895,8 +20945,8 @@ namespace exprtk if (settings_.replacer_enabled()) { symbol_replacer_.clear(); - symbol_replacer_.add_replace("true" ,"1",lexer::token::e_number); - symbol_replacer_.add_replace("false","0",lexer::token::e_number); + symbol_replacer_.add_replace("true" , "1", lexer::token::e_number); + symbol_replacer_.add_replace("false", "0", lexer::token::e_number); helper_assembly_.token_modifier_list.clear(); helper_assembly_.register_modifier(&symbol_replacer_); } @@ -19939,7 +20989,8 @@ namespace exprtk if (settings_.sequence_check_enabled()) { - helper_assembly_.register_scanner(&sequence_validator_); + helper_assembly_.register_scanner(&sequence_validator_ ); + helper_assembly_.register_scanner(&sequence_validator_3tkns_); } } } @@ -19960,7 +21011,7 @@ namespace exprtk { set_error( make_error(parser_error::e_syntax, - "ERR000 - Empty expression!", + "ERR001 - Empty expression!", exprtk_error_location)); return false; @@ -19976,7 +21027,7 @@ namespace exprtk { set_error( make_error(parser_error::e_syntax, - "ERR001 - Empty expression!", + "ERR002 - Empty expression!", exprtk_error_location)); return false; @@ -20005,7 +21056,7 @@ namespace exprtk dec_.return_present_ = true; e = expression_generator_ - .return_envelope(e,results_context_,retinvk_ptr); + .return_envelope(e, results_context_, retinvk_ptr); } expr.set_expression(e); @@ -20023,32 +21074,32 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR002 - Invalid expression encountered", + "ERR003 - Invalid expression encountered", exprtk_error_location)); } - dec_.clear (); - sem_.cleanup (); - return_cleanup(); - if ((0 != e) && branch_deletable(e)) { destroy_node(e); } + dec_.clear (); + sem_.cleanup (); + return_cleanup(); + return false; } } inline expression_t compile(const std::string& expression_string, symbol_table_t& symtab) { - expression_t expr; + expression_t expression; - expr.register_symbol_table(symtab); + expression.register_symbol_table(symtab); - compile(expression_string,expr); + compile(expression_string,expression); - return expr; + return expression; } void process_lexer_errors() @@ -20057,7 +21108,7 @@ namespace exprtk { if (lexer()[i].is_error()) { - std::string diagnostic = "ERR003 - "; + std::string diagnostic = "ERR004 - "; switch (lexer()[i].type) { @@ -20115,16 +21166,17 @@ 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::sequence_validator* sequence_validator_ptr = 0; + lexer::helper::bracket_checker* bracket_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; if (0 != (bracket_checker_ptr = dynamic_cast(helper_assembly_.error_token_scanner))) { set_error( make_error(parser_error::e_token, bracket_checker_ptr->error_token(), - "ERR004 - Mismatched brackets: '" + bracket_checker_ptr->error_token().value + "'", + "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))) @@ -20136,7 +21188,7 @@ namespace exprtk set_error( make_error(parser_error::e_token, error_token, - "ERR005 - Invalid numeric token: '" + error_token.value + "'", + "ERR006 - Invalid numeric token: '" + error_token.value + "'", exprtk_error_location)); } @@ -20154,7 +21206,7 @@ namespace exprtk set_error( make_error(parser_error::e_token, error_token.first, - "ERR006 - Invalid token sequence: '" + + "ERR007 - Invalid token sequence: '" + error_token.first.value + "' and '" + error_token.second.value + "'", exprtk_error_location)); @@ -20165,6 +21217,26 @@ namespace exprtk sequence_validator_ptr->clear_errors(); } } + else if (0 != (sequence_validator3_ptr = dynamic_cast(helper_assembly_.error_token_scanner))) + { + for (std::size_t i = 0; i < sequence_validator3_ptr->error_count(); ++i) + { + std::pair error_token = sequence_validator3_ptr->error(i); + + set_error( + make_error(parser_error::e_token, + error_token.first, + "ERR008 - Invalid token sequence: '" + + error_token.first.value + "' and '" + + error_token.second.value + "'", + exprtk_error_location)); + } + + if (sequence_validator3_ptr->error_count()) + { + sequence_validator3_ptr->clear_errors(); + } + } } return false; @@ -20179,7 +21251,7 @@ namespace exprtk return settings_; } - inline parser_error::type get_error(const std::size_t& index) + inline parser_error::type get_error(const std::size_t& index) const { if (index < error_list_.size()) return error_list_[index]; @@ -20248,9 +21320,19 @@ namespace exprtk unknown_symbol_resolver_ = &default_usr_; } + inline void register_loop_runtime_check(loop_runtime_check& lrtchk) + { + loop_runtime_check_ = &lrtchk; + } + + inline void clear_loop_runtime_check() + { + loop_runtime_check_ = loop_runtime_check_ptr(0); + } + private: - inline bool valid_base_operation(const std::string& symbol) + inline bool valid_base_operation(const std::string& symbol) const { const std::size_t length = symbol.size(); @@ -20264,7 +21346,7 @@ namespace exprtk (base_ops_map_.end() != base_ops_map_.find(symbol)); } - inline bool valid_vararg_operation(const std::string& symbol) + inline bool valid_vararg_operation(const std::string& symbol) const { static const std::string s_sum = "sum" ; static const std::string s_mul = "mul" ; @@ -20291,17 +21373,22 @@ namespace exprtk settings_.function_enabled(symbol); } - bool is_invalid_arithmetic_operation(const details::operator_type operation) + bool is_invalid_logic_operation(const details::operator_type operation) const + { + return settings_.logic_disabled(operation); + } + + bool is_invalid_arithmetic_operation(const details::operator_type operation) const { return settings_.arithmetic_disabled(operation); } - bool is_invalid_assignment_operation(const details::operator_type operation) + bool is_invalid_assignment_operation(const details::operator_type operation) const { return settings_.assignment_disabled(operation); } - bool is_invalid_inequality_operation(const details::operator_type operation) + bool is_invalid_inequality_operation(const details::operator_type operation) const { return settings_.inequality_disabled(operation); } @@ -20309,14 +21396,18 @@ namespace exprtk #ifdef exprtk_enable_debugging inline void next_token() { - std::string ct_str = current_token().value; + const std::string ct_str = current_token().value; + const std::size_t ct_pos = current_token().position; parser_helper::next_token(); - std::string depth(2 * state_.scope_depth,' '); + const std::string depth(2 * state_.scope_depth,' '); exprtk_debug(("%s" - "prev[%s] --> curr[%s]\n", + "prev[%s | %04d] --> curr[%s | %04d] stack_level: %3d\n", depth.c_str(), ct_str.c_str(), - current_token().value.c_str())); + static_cast(ct_pos), + current_token().value.c_str(), + static_cast(current_token().position), + static_cast(state_.stack_depth))); } #endif @@ -20325,8 +21416,6 @@ namespace exprtk std::vector arg_list; std::vector side_effect_list; - expression_node_ptr result = error_node(); - scoped_vec_delete sdd((*this),arg_list); lexer::token begin_token; @@ -20347,7 +21436,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR007 - Invalid expression encountered", + "ERR009 - Invalid expression encountered", exprtk_error_location)); } @@ -20361,7 +21450,7 @@ namespace exprtk end_token = current_token(); - std::string sub_expr = construct_subexpr(begin_token,end_token); + const std::string sub_expr = construct_subexpr(begin_token, end_token); exprtk_debug(("parse_corpus(%02d) Subexpr: %s\n", static_cast(arg_list.size() - 1), @@ -20393,7 +21482,7 @@ namespace exprtk dec_.final_stmt_return_ = true; } - result = simplify(arg_list,side_effect_list); + const expression_node_ptr result = simplify(arg_list,side_effect_list); sdd.delete_ptr = (0 == result); @@ -20439,6 +21528,13 @@ namespace exprtk inline expression_node_ptr parse_expression(precedence_level precedence = e_level00) { + stack_limit_handler slh(*this); + + if (!slh) + { + return error_node(); + } + expression_node_ptr expression = parse_branch(precedence); if (0 == expression) @@ -20456,25 +21552,25 @@ namespace exprtk switch (current_token().type) { - case token_t::e_assign : current_state.set(e_level00,e_level00,details::e_assign); break; - case token_t::e_addass : current_state.set(e_level00,e_level00,details::e_addass); break; - case token_t::e_subass : current_state.set(e_level00,e_level00,details::e_subass); break; - case token_t::e_mulass : current_state.set(e_level00,e_level00,details::e_mulass); break; - case token_t::e_divass : current_state.set(e_level00,e_level00,details::e_divass); break; - case token_t::e_modass : current_state.set(e_level00,e_level00,details::e_modass); break; - case token_t::e_swap : current_state.set(e_level00,e_level00,details::e_swap ); break; - case token_t::e_lt : current_state.set(e_level05,e_level06,details:: e_lt); break; - case token_t::e_lte : current_state.set(e_level05,e_level06,details:: e_lte); break; - case token_t::e_eq : current_state.set(e_level05,e_level06,details:: e_eq); break; - case token_t::e_ne : current_state.set(e_level05,e_level06,details:: e_ne); break; - case token_t::e_gte : current_state.set(e_level05,e_level06,details:: e_gte); break; - case token_t::e_gt : current_state.set(e_level05,e_level06,details:: e_gt); break; - case token_t::e_add : current_state.set(e_level07,e_level08,details:: e_add); break; - case token_t::e_sub : current_state.set(e_level07,e_level08,details:: e_sub); break; - case token_t::e_div : current_state.set(e_level10,e_level11,details:: e_div); break; - case token_t::e_mul : current_state.set(e_level10,e_level11,details:: e_mul); break; - case token_t::e_mod : current_state.set(e_level10,e_level11,details:: e_mod); break; - case token_t::e_pow : current_state.set(e_level12,e_level12,details:: e_pow); break; + case token_t::e_assign : current_state.set(e_level00,e_level00, details::e_assign); break; + case token_t::e_addass : current_state.set(e_level00,e_level00, details::e_addass); break; + case token_t::e_subass : current_state.set(e_level00,e_level00, details::e_subass); break; + case token_t::e_mulass : current_state.set(e_level00,e_level00, details::e_mulass); break; + case token_t::e_divass : current_state.set(e_level00,e_level00, details::e_divass); break; + case token_t::e_modass : current_state.set(e_level00,e_level00, details::e_modass); break; + case token_t::e_swap : current_state.set(e_level00,e_level00, details::e_swap ); break; + case token_t::e_lt : current_state.set(e_level05,e_level06, details:: e_lt); break; + case token_t::e_lte : current_state.set(e_level05,e_level06, details:: e_lte); break; + case token_t::e_eq : current_state.set(e_level05,e_level06, details:: e_eq); break; + case token_t::e_ne : current_state.set(e_level05,e_level06, details:: e_ne); break; + case token_t::e_gte : current_state.set(e_level05,e_level06, details:: e_gte); break; + case token_t::e_gt : current_state.set(e_level05,e_level06, details:: e_gt); break; + case token_t::e_add : current_state.set(e_level07,e_level08, details:: e_add); break; + case token_t::e_sub : current_state.set(e_level07,e_level08, details:: e_sub); break; + case token_t::e_div : current_state.set(e_level10,e_level11, details:: e_div); break; + case token_t::e_mul : current_state.set(e_level10,e_level11, details:: e_mul); break; + case token_t::e_mod : current_state.set(e_level10,e_level11, details:: e_mod); break; + case token_t::e_pow : current_state.set(e_level12,e_level12, details:: e_pow); break; default : if (token_t::e_symbol == current_token().type) { static const std::string s_and = "and"; @@ -20570,21 +21666,33 @@ namespace exprtk else if (current_state.left < precedence) break; - lexer::token prev_token = current_token(); + const lexer::token prev_token = current_token(); next_token(); expression_node_ptr right_branch = error_node(); expression_node_ptr new_expression = error_node(); - if (is_invalid_arithmetic_operation(current_state.operation)) + if (is_invalid_logic_operation(current_state.operation)) + { + free_node(node_allocator_,expression); + + set_error( + make_error(parser_error::e_syntax, + prev_token, + "ERR010 - Invalid or disabled logic operation '" + details::to_str(current_state.operation) + "'", + exprtk_error_location)); + + return error_node(); + } + else if (is_invalid_arithmetic_operation(current_state.operation)) { free_node(node_allocator_,expression); set_error( make_error(parser_error::e_syntax, prev_token, - "ERR008 - Invalid arithmetic operation '" + details::to_str(current_state.operation) + "'", + "ERR011 - Invalid or disabled arithmetic operation '" + details::to_str(current_state.operation) + "'", exprtk_error_location)); return error_node(); @@ -20596,7 +21704,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, prev_token, - "ERR009 - Invalid inequality operation '" + details::to_str(current_state.operation) + "'", + "ERR012 - Invalid inequality operation '" + details::to_str(current_state.operation) + "'", exprtk_error_location)); return error_node(); @@ -20608,7 +21716,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, prev_token, - "ERR010 - Invalid assignment operation '" + details::to_str(current_state.operation) + "'", + "ERR013 - Invalid or disabled assignment operation '" + details::to_str(current_state.operation) + "'", exprtk_error_location)); return error_node(); @@ -20621,13 +21729,13 @@ namespace exprtk details::is_return_node(right_branch) ) { - free_node(node_allocator_, expression); - free_node(node_allocator_,right_branch); + free_node(node_allocator_, expression); + free_node(node_allocator_, right_branch); set_error( make_error(parser_error::e_syntax, prev_token, - "ERR011 - Return statements cannot be part of sub-expressions", + "ERR014 - Return statements cannot be part of sub-expressions", exprtk_error_location)); return error_node(); @@ -20650,11 +21758,12 @@ namespace exprtk prev_token, !synthesis_error_.empty() ? synthesis_error_ : - "ERR012 - General parsing error at token: '" + prev_token.value + "'", + "ERR015 - General parsing error at token: '" + prev_token.value + "'", exprtk_error_location)); } - free_node(node_allocator_,expression); + free_node(node_allocator_, expression); + free_node(node_allocator_, right_branch); return error_node(); } @@ -20674,6 +21783,20 @@ namespace exprtk } } + if ((0 != expression) && (expression->node_depth() > settings_.max_node_depth_)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR016 - Expression depth of " + details::to_str(static_cast(expression->node_depth())) + + " exceeds maximum allowed expression depth of " + details::to_str(static_cast(settings_.max_node_depth_)), + exprtk_error_location)); + + free_node(node_allocator_,expression); + + return error_node(); + } + return expression; } @@ -20719,7 +21842,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR013 - Failed to find variable node in symbol table", + "ERR017 - Failed to find variable node in symbol table", exprtk_error_location)); free_node(node_allocator_,node); @@ -20737,6 +21860,31 @@ namespace exprtk return reinterpret_cast(0); } + struct scoped_expression_delete + { + scoped_expression_delete(parser& pr, expression_node_ptr& expression) + : delete_ptr(true), + parser_(pr), + expression_(expression) + {} + + ~scoped_expression_delete() + { + if (delete_ptr) + { + free_node(parser_.node_allocator_, expression_); + } + } + + bool delete_ptr; + parser& parser_; + expression_node_ptr& expression_; + + private: + + scoped_expression_delete& operator=(const scoped_expression_delete&); + }; + template struct scoped_delete { @@ -20760,7 +21908,7 @@ namespace exprtk { for (std::size_t i = 0; i < N; ++i) { - free_node(parser_.node_allocator_,p_[i]); + free_node(parser_.node_allocator_, p_[i]); } } } @@ -20842,7 +21990,7 @@ namespace exprtk struct scoped_bool_negator { - scoped_bool_negator(bool& bb) + explicit scoped_bool_negator(bool& bb) : b(bb) { b = !b; } @@ -20854,7 +22002,7 @@ namespace exprtk struct scoped_bool_or_restorer { - scoped_bool_or_restorer(bool& bb) + explicit scoped_bool_or_restorer(bool& bb) : b(bb), original_value_(bb) {} @@ -20868,6 +22016,21 @@ namespace exprtk bool original_value_; }; + struct scoped_inc_dec + { + explicit scoped_inc_dec(std::size_t& v) + : v_(v) + { ++v_; } + + ~scoped_inc_dec() + { + assert(v_ > 0); + --v_; + } + + std::size_t& v_; + }; + inline expression_node_ptr parse_function_invocation(ifunction* function, const std::string& function_name) { expression_node_ptr func_node = reinterpret_cast(0); @@ -20899,7 +22062,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR014 - Invalid number of parameters for function: '" + function_name + "'", + "ERR018 - Invalid number of parameters for function: '" + function_name + "'", exprtk_error_location)); return error_node(); @@ -20913,7 +22076,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR015 - Failed to generate call to function: '" + function_name + "'", + "ERR019 - Failed to generate call to function: '" + function_name + "'", exprtk_error_location)); return error_node(); @@ -20932,7 +22095,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR016 - Expecting ifunction '" + function_name + "' to have non-zero parameter count", + "ERR020 - Expecting ifunction '" + function_name + "' to have non-zero parameter count", exprtk_error_location)); return error_node(); @@ -20955,7 +22118,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR017 - Expecting argument list for function: '" + function_name + "'", + "ERR021 - Expecting argument list for function: '" + function_name + "'", exprtk_error_location)); return error_node(); @@ -20970,7 +22133,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR018 - Failed to parse argument " + details::to_str(i) + " for function: '" + function_name + "'", + "ERR022 - Failed to parse argument " + details::to_str(i) + " for function: '" + function_name + "'", exprtk_error_location)); return error_node(); @@ -20982,7 +22145,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR019 - Invalid number of arguments for function: '" + function_name + "'", + "ERR023 - Invalid number of arguments for function: '" + function_name + "'", exprtk_error_location)); return error_node(); @@ -20995,7 +22158,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR020 - Invalid number of arguments for function: '" + function_name + "'", + "ERR024 - Invalid number of arguments for function: '" + function_name + "'", exprtk_error_location)); return error_node(); @@ -21024,7 +22187,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR021 - Expecting '()' to proceed call to function: '" + function_name + "'", + "ERR025 - Expecting '()' to proceed call to function: '" + function_name + "'", exprtk_error_location)); free_node(node_allocator_,result); @@ -21049,7 +22212,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR022 - Expected a '(' at start of function call to '" + function_name + + "ERR026 - Expected a '(' at start of function call to '" + function_name + "', instead got: '" + current_token().value + "'", exprtk_error_location)); @@ -21061,7 +22224,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR023 - Expected at least one input parameter for function call '" + function_name + "'", + "ERR027 - Expected at least one input parameter for function call '" + function_name + "'", exprtk_error_location)); return 0; @@ -21087,7 +22250,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR024 - Expected a ',' between function input parameters, instead got: '" + current_token().value + "'", + "ERR028 - Expected a ',' between function input parameters, instead got: '" + current_token().value + "'", exprtk_error_location)); return 0; @@ -21099,7 +22262,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR025 - Invalid number of input parameters passed to function '" + function_name + "'", + "ERR029 - Invalid number of input parameters passed to function '" + function_name + "'", exprtk_error_location)); return 0; @@ -21122,7 +22285,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, diagnostic_token, - "ERR026 - No entry found for base operation: " + operation_name, + "ERR030 - No entry found for base operation: " + operation_name, exprtk_error_location)); return error_node(); @@ -21137,7 +22300,7 @@ namespace exprtk { for (base_ops_map_t::iterator itr = itr_range.first; itr != itr_range.second; ++itr) { - details::base_operation_t& operation = itr->second; + const details::base_operation_t& operation = itr->second; if (operation.num_params == parameter_count) { @@ -21169,7 +22332,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, diagnostic_token, - "ERR027 - Invalid number of input parameters for call to function: '" + operation_name + "'", + "ERR031 - Invalid number of input parameters for call to function: '" + operation_name + "'", exprtk_error_location)); return error_node(); @@ -21189,7 +22352,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR028 - Expected ',' between if-statement condition and consequent", + "ERR032 - Expected ',' between if-statement condition and consequent", exprtk_error_location)); result = false; } @@ -21198,7 +22361,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR029 - Failed to parse consequent for if-statement", + "ERR033 - Failed to parse consequent for if-statement", exprtk_error_location)); result = false; } @@ -21207,7 +22370,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR030 - Expected ',' between if-statement consequent and alternative", + "ERR034 - Expected ',' between if-statement consequent and alternative", exprtk_error_location)); result = false; } @@ -21216,7 +22379,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR031 - Failed to parse alternative for if-statement", + "ERR035 - Failed to parse alternative for if-statement", exprtk_error_location)); result = false; } @@ -21225,7 +22388,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR032 - Expected ')' at the end of if-statement", + "ERR036 - Expected ')' at the end of if-statement", exprtk_error_location)); result = false; } @@ -21241,13 +22404,13 @@ namespace exprtk if (consq_is_str && alter_is_str) { return expression_generator_ - .conditional_string(condition,consequent,alternative); + .conditional_string(condition, consequent, alternative); } set_error( make_error(parser_error::e_syntax, current_token(), - "ERR033 - Return types of ternary if-statement differ", + "ERR037 - Return types of ternary if-statement differ", exprtk_error_location)); result = false; @@ -21257,15 +22420,15 @@ namespace exprtk if (!result) { - free_node(node_allocator_, condition); - free_node(node_allocator_, consequent); - free_node(node_allocator_,alternative); + free_node(node_allocator_, condition ); + free_node(node_allocator_, consequent ); + free_node(node_allocator_, alternative); return error_node(); } else return expression_generator_ - .conditional(condition,consequent,alternative); + .conditional(condition, consequent, alternative); } inline expression_node_ptr parse_conditional_statement_02(expression_node_ptr condition) @@ -21282,7 +22445,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR034 - Failed to parse body of consequent for if-statement", + "ERR038 - Failed to parse body of consequent for if-statement", exprtk_error_location)); result = false; @@ -21305,7 +22468,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR035 - Expected ';' at the end of the consequent for if-statement", + "ERR039 - Expected ';' at the end of the consequent for if-statement", exprtk_error_location)); result = false; @@ -21316,7 +22479,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR036 - Failed to parse body of consequent for if-statement", + "ERR040 - Failed to parse body of consequent for if-statement", exprtk_error_location)); result = false; @@ -21336,7 +22499,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR037 - Failed to parse body of the 'else' for if-statement", + "ERR041 - Failed to parse body of the 'else' for if-statement", exprtk_error_location)); result = false; @@ -21349,7 +22512,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR038 - Failed to parse body of if-else statement", + "ERR042 - Failed to parse body of if-else statement", exprtk_error_location)); result = false; @@ -21362,7 +22525,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR039 - Expected ';' at the end of the 'else-if' for the if-statement", + "ERR043 - Expected ';' at the end of the 'else-if' for the if-statement", exprtk_error_location)); result = false; @@ -21373,7 +22536,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR040 - Failed to parse body of the 'else' for if-statement", + "ERR044 - Failed to parse body of the 'else' for if-statement", exprtk_error_location)); result = false; @@ -21392,13 +22555,13 @@ namespace exprtk if (consq_is_str && alter_is_str) { return expression_generator_ - .conditional_string(condition,consequent,alternative); + .conditional_string(condition, consequent, alternative); } set_error( make_error(parser_error::e_syntax, current_token(), - "ERR041 - Return types of ternary if-statement differ", + "ERR045 - Return types of ternary if-statement differ", exprtk_error_location)); result = false; @@ -21408,15 +22571,15 @@ namespace exprtk if (!result) { - free_node(node_allocator_, condition); - free_node(node_allocator_, consequent); - free_node(node_allocator_,alternative); + free_node(node_allocator_, condition); + free_node(node_allocator_, consequent); + free_node(node_allocator_, alternative); return error_node(); } else return expression_generator_ - .conditional(condition,consequent,alternative); + .conditional(condition, consequent, alternative); } inline expression_node_ptr parse_conditional_statement() @@ -21430,7 +22593,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR042 - Expected '(' at start of if-statement, instead got: '" + current_token().value + "'", + "ERR046 - Expected '(' at start of if-statement, instead got: '" + current_token().value + "'", exprtk_error_location)); return error_node(); @@ -21440,7 +22603,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR043 - Failed to parse condition for if-statement", + "ERR047 - Failed to parse condition for if-statement", exprtk_error_location)); return error_node(); @@ -21472,7 +22635,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR044 - Invalid if-statement", + "ERR048 - Invalid if-statement", exprtk_error_location)); free_node(node_allocator_,condition); @@ -21493,7 +22656,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR045 - Encountered invalid condition branch for ternary if-statement", + "ERR049 - Encountered invalid condition branch for ternary if-statement", exprtk_error_location)); return error_node(); @@ -21503,7 +22666,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR046 - Expected '?' after condition of ternary if-statement", + "ERR050 - Expected '?' after condition of ternary if-statement", exprtk_error_location)); result = false; @@ -21513,7 +22676,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR047 - Failed to parse consequent for ternary if-statement", + "ERR051 - Failed to parse consequent for ternary if-statement", exprtk_error_location)); result = false; @@ -21523,7 +22686,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR048 - Expected ':' between ternary if-statement consequent and alternative", + "ERR052 - Expected ':' between ternary if-statement consequent and alternative", exprtk_error_location)); result = false; @@ -21533,7 +22696,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR049 - Failed to parse alternative for ternary if-statement", + "ERR053 - Failed to parse alternative for ternary if-statement", exprtk_error_location)); result = false; @@ -21556,7 +22719,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR050 - Return types of ternary if-statement differ", + "ERR054 - Return types of ternary if-statement differ", exprtk_error_location)); result = false; @@ -21577,6 +22740,22 @@ namespace exprtk .conditional(condition, consequent, alternative); } + inline expression_node_ptr parse_not_statement() + { + if (settings_.logic_disabled("not")) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR055 - Invalid or disabled logic operation 'not'", + exprtk_error_location)); + + return error_node(); + } + + return parse_base_operation(); + } + inline expression_node_ptr parse_while_loop() { // Parse: [while][(][test expr][)][{][expression][}] @@ -21593,7 +22772,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR051 - Expected '(' at start of while-loop condition statement", + "ERR056 - Expected '(' at start of while-loop condition statement", exprtk_error_location)); return error_node(); @@ -21603,7 +22782,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR052 - Failed to parse condition for while-loop", + "ERR057 - Failed to parse condition for while-loop", exprtk_error_location)); return error_node(); @@ -21613,7 +22792,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR053 - Expected ')' at end of while-loop condition statement", + "ERR058 - Expected ')' at end of while-loop condition statement", exprtk_error_location)); result = false; @@ -21623,12 +22802,14 @@ namespace exprtk if (result) { + scoped_inc_dec sid(state_.parsing_loop_stmt_count); + if (0 == (branch = parse_multi_sequence("while-loop"))) { set_error( make_error(parser_error::e_syntax, current_token(), - "ERR054 - Failed to parse body of while-loop")); + "ERR059 - Failed to parse body of while-loop")); result = false; } else if (0 == (result_node = expression_generator_.while_loop(condition, @@ -21638,7 +22819,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR055 - Failed to synthesize while-loop", + "ERR060 - Failed to synthesize while-loop", exprtk_error_location)); result = false; @@ -21647,9 +22828,9 @@ namespace exprtk if (!result) { - free_node(node_allocator_, branch); - free_node(node_allocator_, condition); - free_node(node_allocator_,result_node); + free_node(node_allocator_, branch); + free_node(node_allocator_, condition); + free_node(node_allocator_, result_node); brkcnt_list_.pop_front(); @@ -21680,12 +22861,14 @@ namespace exprtk } else { - token_t::token_type seperator = token_t::e_eof; + const token_t::token_type seperator = token_t::e_eof; scope_handler sh(*this); scoped_bool_or_restorer sbr(state_.side_effect_present); + scoped_inc_dec sid(state_.parsing_loop_stmt_count); + for ( ; ; ) { state_.side_effect_present = false; @@ -21706,15 +22889,15 @@ namespace exprtk break; } - bool is_next_until = peek_token_is(token_t::e_symbol) && - peek_token_is("until"); + const bool is_next_until = peek_token_is(token_t::e_symbol) && + peek_token_is("until"); if (!token_is(seperator) && is_next_until) { set_error( make_error(parser_error::e_syntax, current_token(), - "ERR056 - Expected '" + token_t::to_str(seperator) + "' in body of repeat until loop", + "ERR061 - Expected '" + token_t::to_str(seperator) + "' in body of repeat until loop", exprtk_error_location)); return error_node(); @@ -21738,7 +22921,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR057 - Failed to parse body of repeat until loop", + "ERR062 - Failed to parse body of repeat until loop", exprtk_error_location)); return error_node(); @@ -21752,7 +22935,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR058 - Expected '(' before condition statement of repeat until loop", + "ERR063 - Expected '(' before condition statement of repeat until loop", exprtk_error_location)); free_node(node_allocator_,branch); @@ -21766,7 +22949,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR059 - Failed to parse condition for repeat until loop", + "ERR064 - Failed to parse condition for repeat until loop", exprtk_error_location)); free_node(node_allocator_,branch); @@ -21778,7 +22961,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR060 - Expected ')' after condition of repeat until loop", + "ERR065 - Expected ')' after condition of repeat until loop", exprtk_error_location)); free_node(node_allocator_, branch); @@ -21799,7 +22982,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR061 - Failed to synthesize repeat until loop", + "ERR066 - Failed to synthesize repeat until loop", exprtk_error_location)); free_node(node_allocator_,condition); @@ -21824,7 +23007,6 @@ namespace exprtk scope_element* se = 0; bool result = true; - std::string loop_counter_symbol; next_token(); @@ -21835,7 +23017,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR062 - Expected '(' at start of for-loop", + "ERR067 - Expected '(' at start of for-loop", exprtk_error_location)); return error_node(); @@ -21855,7 +23037,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR063 - Expected a variable at the start of initialiser section of for-loop", + "ERR068 - Expected a variable at the start of initialiser section of for-loop", exprtk_error_location)); return error_node(); @@ -21865,13 +23047,13 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR064 - Expected variable assignment of initialiser section of for-loop", + "ERR069 - Expected variable assignment of initialiser section of for-loop", exprtk_error_location)); return error_node(); } - loop_counter_symbol = current_token().value; + const std::string loop_counter_symbol = current_token().value; se = &sem_.get_element(loop_counter_symbol); @@ -21880,7 +23062,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR065 - For-loop variable '" + loop_counter_symbol+ "' is being shadowed by a previous declaration", + "ERR070 - For-loop variable '" + loop_counter_symbol+ "' is being shadowed by a previous declaration", exprtk_error_location)); return error_node(); @@ -21912,7 +23094,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR066 - Failed to add new local variable '" + loop_counter_symbol + "' to SEM", + "ERR071 - Failed to add new local variable '" + loop_counter_symbol + "' to SEM", exprtk_error_location)); sem_.free_element(nse); @@ -21934,7 +23116,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR067 - Failed to parse initialiser of for-loop", + "ERR072 - Failed to parse initialiser of for-loop", exprtk_error_location)); result = false; @@ -21944,7 +23126,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR068 - Expected ';' after initialiser of for-loop", + "ERR073 - Expected ';' after initialiser of for-loop", exprtk_error_location)); result = false; @@ -21958,7 +23140,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR069 - Failed to parse condition of for-loop", + "ERR074 - Failed to parse condition of for-loop", exprtk_error_location)); result = false; @@ -21968,7 +23150,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR070 - Expected ';' after condition section of for-loop", + "ERR075 - Expected ';' after condition section of for-loop", exprtk_error_location)); result = false; @@ -21982,7 +23164,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR071 - Failed to parse incrementor of for-loop", + "ERR076 - Failed to parse incrementor of for-loop", exprtk_error_location)); result = false; @@ -21992,7 +23174,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR072 - Expected ')' after incrementor section of for-loop", + "ERR077 - Expected ')' after incrementor section of for-loop", exprtk_error_location)); result = false; @@ -22003,12 +23185,14 @@ namespace exprtk { brkcnt_list_.push_front(false); + scoped_inc_dec sid(state_.parsing_loop_stmt_count); + if (0 == (loop_body = parse_multi_sequence("for-loop"))) { set_error( make_error(parser_error::e_syntax, current_token(), - "ERR073 - Failed to parse body of for-loop", + "ERR078 - Failed to parse body of for-loop", exprtk_error_location)); result = false; @@ -22022,8 +23206,6 @@ namespace exprtk se->ref_count--; } - sem_.cleanup(); - free_node(node_allocator_, initialiser); free_node(node_allocator_, condition); free_node(node_allocator_, incrementor); @@ -22060,7 +23242,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR074 - Expected keyword 'switch'", + "ERR079 - Expected keyword 'switch'", exprtk_error_location)); return error_node(); @@ -22075,85 +23257,100 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR075 - Expected '{' for call to switch statement", + "ERR080 - Expected '{' for call to switch statement", exprtk_error_location)); return error_node(); } + expression_node_ptr default_statement = error_node(); + + scoped_expression_delete defstmt_delete((*this), default_statement); + for ( ; ; ) { - if (!details::imatch("case",current_token().value)) + if (details::imatch("case",current_token().value)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR076 - Expected either a 'case' or 'default' statement", - exprtk_error_location)); + next_token(); - return error_node(); - } + expression_node_ptr condition = parse_expression(); - next_token(); + if (0 == condition) + return error_node(); + else if (!token_is(token_t::e_colon)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR081 - Expected ':' for case of switch statement", + exprtk_error_location)); - expression_node_ptr condition = parse_expression(); + free_node(node_allocator_, condition); - if (0 == condition) - return error_node(); - else if (!token_is(token_t::e_colon)) - { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR077 - Expected ':' for case of switch statement", - exprtk_error_location)); + return error_node(); + } - return error_node(); - } + expression_node_ptr consequent = parse_expression(); - expression_node_ptr consequent = parse_expression(); + if (0 == consequent) + { + free_node(node_allocator_, condition); - if (0 == consequent) - return error_node(); - else if (!token_is(token_t::e_eof)) - { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR078 - Expected ';' at end of case for switch statement", - exprtk_error_location)); + return error_node(); + } + else if (!token_is(token_t::e_eof)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR082 - Expected ';' at end of case for switch statement", + exprtk_error_location)); - return error_node(); - } + free_node(node_allocator_, condition); + free_node(node_allocator_, consequent); + + return error_node(); + } + + // Can we optimise away the case statement? + if (is_constant_node(condition) && is_false(condition)) + { + free_node(node_allocator_, condition); + free_node(node_allocator_, consequent); + } + else + { + arg_list.push_back( condition); + arg_list.push_back(consequent); + } - // Can we optimise away the case statement? - if (is_constant_node(condition) && is_false(condition)) - { - free_node(node_allocator_, condition); - free_node(node_allocator_, consequent); } - else + else if (details::imatch("default",current_token().value)) { - arg_list.push_back( condition); - arg_list.push_back(consequent); - } + if (0 != default_statement) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR083 - Multiple default cases for switch statement", + exprtk_error_location)); + + return error_node(); + } - if (details::imatch("default",current_token().value)) - { next_token(); + if (!token_is(token_t::e_colon)) { set_error( make_error(parser_error::e_syntax, current_token(), - "ERR079 - Expected ':' for default of switch statement", + "ERR084 - Expected ':' for default of switch statement", exprtk_error_location)); return error_node(); } - expression_node_ptr default_statement = error_node(); - if (token_is(token_t::e_lcrlbracket,prsrhlpr_t::e_hold)) default_statement = parse_multi_sequence("switch-default"); else @@ -22163,36 +23360,40 @@ namespace exprtk return error_node(); else if (!token_is(token_t::e_eof)) { - free_node(node_allocator_,default_statement); - set_error( make_error(parser_error::e_syntax, current_token(), - "ERR080 - Expected ';' at end of default for switch statement", + "ERR085 - Expected ';' at end of default for switch statement", exprtk_error_location)); return error_node(); } - - arg_list.push_back(default_statement); + } + else if (token_is(token_t::e_rcrlbracket)) break; + else + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR086 - Expected '}' at end of switch statement", + exprtk_error_location)); + + return error_node(); } } - if (!token_is(token_t::e_rcrlbracket)) - { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR081 - Expected '}' at end of switch statement", - exprtk_error_location)); + const bool default_statement_present = (0 != default_statement); - return error_node(); + if (default_statement_present) + { + arg_list.push_back(default_statement); } - result = expression_generator_.switch_statement(arg_list); + result = expression_generator_.switch_statement(arg_list, (0 != default_statement)); svd.delete_ptr = (0 == result); + defstmt_delete.delete_ptr = (0 == result); return result; } @@ -22200,14 +23401,13 @@ namespace exprtk inline expression_node_ptr parse_multi_switch_statement() { std::vector arg_list; - expression_node_ptr result = error_node(); if (!details::imatch(current_token().value,"[*]")) { set_error( make_error(parser_error::e_syntax, current_token(), - "ERR082 - Expected token '[*]'", + "ERR087 - Expected token '[*]'", exprtk_error_location)); return error_node(); @@ -22222,7 +23422,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR083 - Expected '{' for call to [*] statement", + "ERR088 - Expected '{' for call to [*] statement", exprtk_error_location)); return error_node(); @@ -22235,7 +23435,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR084 - Expected a 'case' statement for multi-switch", + "ERR089 - Expected a 'case' statement for multi-switch", exprtk_error_location)); return error_node(); @@ -22253,7 +23453,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR085 - Expected ':' for case of [*] statement", + "ERR090 - Expected ':' for case of [*] statement", exprtk_error_location)); return error_node(); @@ -22269,7 +23469,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR086 - Expected ';' at end of case for [*] statement", + "ERR091 - Expected ';' at end of case for [*] statement", exprtk_error_location)); return error_node(); @@ -22283,7 +23483,7 @@ namespace exprtk } else { - arg_list.push_back(condition); + arg_list.push_back( condition); arg_list.push_back(consequent); } @@ -22298,13 +23498,13 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR087 - Expected '}' at end of [*] statement", + "ERR092 - Expected '}' at end of [*] statement", exprtk_error_location)); return error_node(); } - result = expression_generator_.multi_switch_statement(arg_list); + const expression_node_ptr result = expression_generator_.multi_switch_statement(arg_list); svd.delete_ptr = (0 == result); @@ -22314,7 +23514,6 @@ namespace exprtk inline expression_node_ptr parse_vararg_function() { std::vector arg_list; - expression_node_ptr result = error_node(); details::operator_type opt_type = details::e_default; const std::string symbol = current_token().value; @@ -22328,19 +23527,19 @@ namespace exprtk { return parse_multi_switch_statement(); } - else if (details::imatch(symbol,"avg" )) opt_type = details::e_avg ; - else if (details::imatch(symbol,"mand")) opt_type = details::e_mand; - else if (details::imatch(symbol,"max" )) opt_type = details::e_max ; - else if (details::imatch(symbol,"min" )) opt_type = details::e_min ; - else if (details::imatch(symbol,"mor" )) opt_type = details::e_mor ; - else if (details::imatch(symbol,"mul" )) opt_type = details::e_prod; - else if (details::imatch(symbol,"sum" )) opt_type = details::e_sum ; + else if (details::imatch(symbol, "avg" )) opt_type = details::e_avg ; + else if (details::imatch(symbol, "mand")) opt_type = details::e_mand; + else if (details::imatch(symbol, "max" )) opt_type = details::e_max ; + else if (details::imatch(symbol, "min" )) opt_type = details::e_min ; + else if (details::imatch(symbol, "mor" )) opt_type = details::e_mor ; + else if (details::imatch(symbol, "mul" )) opt_type = details::e_prod; + else if (details::imatch(symbol, "sum" )) opt_type = details::e_sum ; else { set_error( make_error(parser_error::e_syntax, current_token(), - "ERR088 - Unsupported vararg function: " + symbol, + "ERR093 - Unsupported vararg function: " + symbol, exprtk_error_location)); return error_node(); @@ -22348,7 +23547,7 @@ namespace exprtk scoped_vec_delete sdd((*this),arg_list); - lodge_symbol(symbol,e_st_function); + lodge_symbol(symbol, e_st_function); next_token(); @@ -22357,7 +23556,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR089 - Expected '(' for call to vararg function: " + symbol, + "ERR094 - Expected '(' for call to vararg function: " + symbol, exprtk_error_location)); return error_node(); @@ -22379,14 +23578,14 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR090 - Expected ',' for call to vararg function: " + symbol, + "ERR095 - Expected ',' for call to vararg function: " + symbol, exprtk_error_location)); return error_node(); } } - result = expression_generator_.vararg_function(opt_type,arg_list); + const expression_node_ptr result = expression_generator_.vararg_function(opt_type,arg_list); sdd.delete_ptr = (0 == result); return result; @@ -22400,7 +23599,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR091 - Expected '[' as start of string range definition", + "ERR096 - Expected '[' as start of string range definition", exprtk_error_location)); free_node(node_allocator_,expression); @@ -22428,7 +23627,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR092 - Failed to generate string range node", + "ERR097 - Failed to generate string range node", exprtk_error_location)); free_node(node_allocator_,expression); @@ -22467,7 +23666,7 @@ namespace exprtk template class Sequence> + template class Sequence> inline expression_node_ptr simplify(Sequence& expression_list, Sequence& side_effect_list, const bool specialise_on_final_type = false) @@ -22564,7 +23763,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR093 - Expected '" + token_t::to_str(close_bracket) + "' for call to multi-sequence" + + "ERR098 - Expected '" + token_t::to_str(close_bracket) + "' for call to multi-sequence" + ((!source.empty()) ? std::string(" section of " + source): ""), exprtk_error_location)); @@ -22604,14 +23803,14 @@ namespace exprtk if (token_is(close_bracket)) break; - bool is_next_close = peek_token_is(close_bracket); + const bool is_next_close = peek_token_is(close_bracket); if (!token_is(seperator) && is_next_close) { set_error( make_error(parser_error::e_syntax, current_token(), - "ERR094 - Expected '" + details::to_str(seperator) + "' for call to multi-sequence section of " + source, + "ERR099 - Expected '" + details::to_str(seperator) + "' for call to multi-sequence section of " + source, exprtk_error_location)); return error_node(); @@ -22645,7 +23844,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR095 - Expected '[' for start of range", + "ERR100 - Expected '[' for start of range", exprtk_error_location)); return false; @@ -22666,11 +23865,10 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR096 - Failed parse begin section of range", + "ERR101 - Failed parse begin section of range", exprtk_error_location)); return false; - } else if (is_constant_node(r0)) { @@ -22690,7 +23888,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR097 - Range lower bound less than zero! Constraint: r0 >= 0", + "ERR102 - Range lower bound less than zero! Constraint: r0 >= 0", exprtk_error_location)); return false; @@ -22707,7 +23905,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR098 - Expected ':' for break in range", + "ERR103 - Expected ':' for break in range", exprtk_error_location)); rp.free(); @@ -22730,13 +23928,12 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR099 - Failed parse end section of range", + "ERR104 - Failed parse end section of range", exprtk_error_location)); rp.free(); return false; - } else if (is_constant_node(r1)) { @@ -22756,7 +23953,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR100 - Range upper bound less than zero! Constraint: r1 >= 0", + "ERR105 - Range upper bound less than zero! Constraint: r1 >= 0", exprtk_error_location)); return false; @@ -22773,7 +23970,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR101 - Expected ']' for start of range", + "ERR106 - Expected ']' for start of range", exprtk_error_location)); rp.free(); @@ -22787,14 +23984,21 @@ namespace exprtk std::size_t r0 = 0; std::size_t r1 = 0; - const bool rp_result = rp(r0,r1); + bool rp_result = false; + + try + { + rp_result = rp(r0, r1); + } + catch (std::runtime_error&) + {} if (!rp_result || (r0 > r1)) { set_error( make_error(parser_error::e_syntax, current_token(), - "ERR102 - Invalid range, Constraint: r0 <= r1", + "ERR107 - Invalid range, Constraint: r0 <= r1", exprtk_error_location)); return false; @@ -22826,7 +24030,7 @@ namespace exprtk { se.active = true; result = se.str_node; - lodge_symbol(symbol,e_st_local_string); + lodge_symbol(symbol, e_st_local_string); } else { @@ -22835,7 +24039,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR103 - Unknown string symbol", + "ERR108 - Unknown string symbol", exprtk_error_location)); return error_node(); @@ -22849,7 +24053,7 @@ namespace exprtk result = expression_generator_(const_str_node->str()); } - lodge_symbol(symbol,e_st_string); + lodge_symbol(symbol, e_st_string); } if (peek_token_is(token_t::e_lsqrbracket)) @@ -22929,6 +24133,7 @@ namespace exprtk if (!parse_range(rp)) { free_node(node_allocator_,result); + rp.free(); return error_node(); } @@ -22949,11 +24154,13 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR104 - Overflow in range for string: '" + const_str + "'[" + + "ERR109 - 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)); + rp.free(); + return error_node(); } @@ -22993,7 +24200,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR105 - Symbol '" + symbol+ " not a vector", + "ERR110 - Symbol '" + symbol+ " not a vector", exprtk_error_location)); return error_node(); @@ -23019,7 +24226,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR106 - Failed to parse index for vector: '" + symbol + "'", + "ERR111 - Failed to parse index for vector: '" + symbol + "'", exprtk_error_location)); return error_node(); @@ -23029,7 +24236,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR107 - Expected ']' for index of vector: '" + symbol + "'", + "ERR112 - Expected ']' for index of vector: '" + symbol + "'", exprtk_error_location)); free_node(node_allocator_,index_expr); @@ -23048,7 +24255,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR108 - Index of " + details::to_str(index) + " out of range for " + "ERR113 - Index of " + details::to_str(index) + " out of range for " "vector '" + symbol + "' of size " + details::to_str(vec_size), exprtk_error_location)); @@ -23058,7 +24265,7 @@ namespace exprtk } } - return expression_generator_.vector_element(symbol,vec,index_expr); + return expression_generator_.vector_element(symbol, vec, index_expr); } inline expression_node_ptr parse_vararg_function_call(ivararg_function* vararg_function, const std::string& vararg_function_name) @@ -23080,7 +24287,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR109 - Zero parameter call to vararg function: " + "ERR114 - Zero parameter call to vararg function: " + vararg_function_name + " not allowed", exprtk_error_location)); @@ -23105,7 +24312,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR110 - Expected ',' for call to vararg function: " + "ERR115 - Expected ',' for call to vararg function: " + vararg_function_name, exprtk_error_location)); @@ -23119,7 +24326,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR111 - Zero parameter call to vararg function: " + "ERR116 - Zero parameter call to vararg function: " + vararg_function_name + " not allowed", exprtk_error_location)); @@ -23131,7 +24338,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR112 - Invalid number of parameters to call to vararg function: " + "ERR117 - 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)); @@ -23143,7 +24350,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR113 - Invalid number of parameters to call to vararg function: " + "ERR118 - 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)); @@ -23162,34 +24369,54 @@ namespace exprtk { public: + enum return_type_t + { + e_overload = ' ', + e_numeric = 'T', + e_string = 'S' + }; + + struct function_prototype_t + { + return_type_t return_type; + std::string param_seq; + }; + typedef parser parser_t; - typedef std::vector param_seq_list_t; + typedef std::vector function_definition_list_t; type_checker(parser_t& p, const std::string& func_name, - const std::string& param_seq) + const std::string& func_prototypes, + const return_type_t default_return_type) : invalid_state_(true), parser_(p), - function_name_(func_name) + function_name_(func_name), + default_return_type_(default_return_type) + { + parse_function_prototypes(func_prototypes); + } + + void set_default_return_type(const std::string& return_type) { - split(param_seq); + default_return_type_ = return_type; } bool verify(const std::string& param_seq, std::size_t& pseq_index) { - if (param_seq_list_.empty()) + if (function_definition_list_.empty()) return true; std::vector > error_list; - for (std::size_t i = 0; i < param_seq_list_.size(); ++i) + for (std::size_t i = 0; i < function_definition_list_.size(); ++i) { details::char_t diff_value = 0; std::size_t diff_index = 0; - bool result = details::sequence_match(param_seq_list_[i], - param_seq, - diff_index,diff_value); + const bool result = details::sequence_match(function_definition_list_[i].param_seq, + param_seq, + diff_index, diff_value); if (result) { @@ -23197,7 +24424,7 @@ namespace exprtk return true; } else - error_list.push_back(std::make_pair(diff_index,diff_value)); + error_list.push_back(std::make_pair(diff_index, diff_value)); } if (1 == error_list.size()) @@ -23206,8 +24433,9 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, parser_.current_token(), - "ERR114 - Failed parameter type check for function '" + function_name_ + "', " - "Expected '" + param_seq_list_[0] + "' call set: '" + param_seq +"'", + "ERR119 - Failed parameter type check for function '" + function_name_ + "', " + "Expected '" + function_definition_list_[0].param_seq + + "' call set: '" + param_seq + "'", exprtk_error_location)); } else @@ -23227,8 +24455,9 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, parser_.current_token(), - "ERR115 - Failed parameter type check for function '" + function_name_ + "', " - "Best match: '" + param_seq_list_[max_diff_index] + "' call set: '" + param_seq +"'", + "ERR120 - 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)); } @@ -23237,12 +24466,17 @@ namespace exprtk std::size_t paramseq_count() const { - return param_seq_list_.size(); + return function_definition_list_.size(); } std::string paramseq(const std::size_t& index) const { - return param_seq_list_[index]; + return function_definition_list_[index].param_seq; + } + + return_type_t return_type(const std::size_t& index) const + { + return function_definition_list_[index].return_type; } bool invalid() const @@ -23252,93 +24486,142 @@ namespace exprtk bool allow_zero_parameters() const { - return - param_seq_list_.end() != std::find(param_seq_list_.begin(), - param_seq_list_.end(), - "Z"); + + for (std::size_t i = 0; i < function_definition_list_.size(); ++i) + { + if (std::string::npos != function_definition_list_[i].param_seq.find("Z")) + { + return true; + } + } + + return false; } private: - void split(const std::string& s) + std::vector split_param_seq(const std::string& param_seq, const details::char_t delimiter = '|') const { - if (s.empty()) - return; + std::string::const_iterator current_begin = param_seq.begin(); + std::string::const_iterator iter = param_seq.begin(); + + std::vector result; - std::size_t start = 0; - std::size_t end = 0; + while (iter != param_seq.end()) + { + if (*iter == delimiter) + { + result.push_back(std::string(current_begin, iter)); + current_begin = ++iter; + } + else + ++iter; + } - param_seq_list_t param_seq_list; + if (current_begin != iter) + { + result.push_back(std::string(current_begin, iter)); + } - struct token_validator + return result; + } + + inline bool is_valid_token(std::string param_seq, + function_prototype_t& funcproto) const + { + // Determine return type + funcproto.return_type = default_return_type_; + + if (param_seq.size() > 2) { - static inline bool process(const std::string& str, - std::size_t s, std::size_t e, - param_seq_list_t& psl) + if (':' == param_seq[1]) { - if ( - (e - s) && - (std::string::npos == str.find("?*")) && - (std::string::npos == str.find("**")) - ) + // Note: Only overloaded igeneric functions can have return + // type definitions. + if (type_checker::e_overload != default_return_type_) + return false; + + switch (param_seq[0]) { - const std::string curr_str = str.substr(s, e - s); + case 'T' : funcproto.return_type = type_checker::e_numeric; + break; - if ("Z" == curr_str) - { - psl.push_back(curr_str); - return true; - } - else if (std::string::npos == curr_str.find_first_not_of("STV*?|")) - { - psl.push_back(curr_str); - return true; - } + case 'S' : funcproto.return_type = type_checker::e_string; + break; + + default : return false; } - return false; + param_seq.erase(0,2); } - }; + } - while (std::string::npos != (end = s.find('|',start))) + if ( + (std::string::npos != param_seq.find("?*")) || + (std::string::npos != param_seq.find("**")) + ) + { + return false; + } + else if ( + (std::string::npos == param_seq.find_first_not_of("STV*?|")) || + ("Z" == param_seq) + ) { - if (!token_validator::process(s, start, end, param_seq_list)) + funcproto.param_seq = param_seq; + return true; + } + + return false; + } + + void parse_function_prototypes(const std::string& func_prototypes) + { + if (func_prototypes.empty()) + return; + + std::vector param_seq_list = split_param_seq(func_prototypes); + + typedef std::map param_seq_map_t; + param_seq_map_t param_seq_map; + + for (std::size_t i = 0; i < param_seq_list.size(); ++i) + { + function_prototype_t func_proto; + + if (!is_valid_token(param_seq_list[i], func_proto)) { invalid_state_ = false; - const std::string err_param_seq = s.substr(start, end - start); - parser_. set_error( make_error(parser_error::e_syntax, parser_.current_token(), - "ERR116 - Invalid parameter sequence of '" + err_param_seq + - "' for function: " + function_name_, + "ERR121 - Invalid parameter sequence of '" + param_seq_list[i] + + "' for function: " + function_name_, exprtk_error_location)); - return; } - else - start = end + 1; - } - if (start < s.size()) - { - if (token_validator::process(s, start, s.size(), param_seq_list)) - param_seq_list_ = param_seq_list; - else + param_seq_map_t::const_iterator seq_itr = param_seq_map.find(param_seq_list[i]); + + if (param_seq_map.end() != seq_itr) { - const std::string err_param_seq = s.substr(start, s.size() - start); + invalid_state_ = false; parser_. set_error( make_error(parser_error::e_syntax, parser_.current_token(), - "ERR117 - Invalid parameter sequence of '" + err_param_seq + - "' for function: " + function_name_, + "ERR122 - 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], exprtk_error_location)); return; } + + function_definition_list_.push_back(func_proto); } } @@ -23348,7 +24631,8 @@ namespace exprtk bool invalid_state_; parser_t& parser_; std::string function_name_; - param_seq_list_t param_seq_list_; + const return_type_t default_return_type_; + function_definition_list_t function_definition_list_; }; inline expression_node_ptr parse_generic_function_call(igeneric_function* function, const std::string& function_name) @@ -23361,30 +24645,14 @@ namespace exprtk std::string param_type_list; - type_checker tc((*this), function_name, function->parameter_sequence); + 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(), - "ERR118 - Type checker instantiation failure for generic function: " + function_name, - exprtk_error_location)); - - return error_node(); - } - - if ( - !function->parameter_sequence.empty() && - function->allow_zero_parameters () && - !tc .allow_zero_parameters () - ) - { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR119 - Mismatch in zero parameter condition for generic function: " - + function_name, + "ERR123 - Type checker instantiation failure for generic function: " + function_name, exprtk_error_location)); return error_node(); @@ -23402,7 +24670,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR120 - Zero parameter call to generic function: " + "ERR124 - Zero parameter call to generic function: " + function_name + " not allowed", exprtk_error_location)); @@ -23434,7 +24702,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR121 - Expected ',' for call to generic function: " + function_name, + "ERR125 - Expected ',' for call to generic function: " + function_name, exprtk_error_location)); return error_node(); @@ -23451,7 +24719,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR122 - Zero parameter call to generic function: " + "ERR126 - Zero parameter call to generic function: " + function_name + " not allowed", exprtk_error_location)); @@ -23468,7 +24736,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR123 - Expected ',' for call to generic function: " + function_name, + "ERR127 - Invalid input parameter sequence for call to generic function: " + function_name, exprtk_error_location)); return error_node(); @@ -23488,37 +24756,39 @@ namespace exprtk return result; } - #ifndef exprtk_disable_string_capabilities - inline expression_node_ptr parse_string_function_call(igeneric_function* function, const std::string& function_name) + inline bool parse_igeneric_function_params(std::string& param_type_list, + std::vector& arg_list, + const std::string& function_name, + igeneric_function* function, + const type_checker& tc) { - std::vector arg_list; - - scoped_vec_delete sdd((*this),arg_list); - - next_token(); - - std::string param_type_list; - - type_checker tc((*this), function_name, function->parameter_sequence); - - if ( - (!function->parameter_sequence.empty()) && - (0 == tc.paramseq_count()) - ) - { - return error_node(); - } - if (token_is(token_t::e_lbracket)) { - if (!token_is(token_t::e_rbracket)) + if (token_is(token_t::e_rbracket)) + { + if ( + !function->allow_zero_parameters() && + !tc .allow_zero_parameters() + ) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR128 - Zero parameter call to generic function: " + + function_name + " not allowed", + exprtk_error_location)); + + return false; + } + } + else { for ( ; ; ) { expression_node_ptr arg = parse_expression(); if (0 == arg) - return error_node(); + return false; if (is_ivector_node(arg)) param_type_list += 'V'; @@ -23536,13 +24806,44 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR124 - Expected ',' for call to string function: " + function_name, + "ERR129 - Expected ',' for call to string function: " + function_name, exprtk_error_location)); - return error_node(); + return false; } } } + + return true; + } + else + return false; + } + + #ifndef exprtk_disable_string_capabilities + inline expression_node_ptr parse_string_function_call(igeneric_function* function, const std::string& function_name) + { + // Move pass the function name + next_token(); + + std::string param_type_list; + + type_checker tc((*this), function_name, function->parameter_sequence, type_checker::e_string); + + if ( + (!function->parameter_sequence.empty()) && + (0 == tc.paramseq_count()) + ) + { + return error_node(); + } + + std::vector arg_list; + scoped_vec_delete sdd((*this),arg_list); + + if (!parse_igeneric_function_params(param_type_list, arg_list, function_name, function, tc)) + { + return error_node(); } std::size_t param_seq_index = 0; @@ -23552,7 +24853,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR125 - Expected ',' for call to string function: " + function_name, + "ERR130 - Invalid input parameter sequence for call to string function: " + function_name, exprtk_error_location)); return error_node(); @@ -23571,17 +24872,88 @@ namespace exprtk return result; } + + inline expression_node_ptr parse_overload_function_call(igeneric_function* function, const std::string& function_name) + { + // Move pass the function name + next_token(); + + std::string param_type_list; + + type_checker tc((*this), function_name, function->parameter_sequence, type_checker::e_overload); + + if ( + (!function->parameter_sequence.empty()) && + (0 == tc.paramseq_count()) + ) + { + return error_node(); + } + + std::vector arg_list; + scoped_vec_delete sdd((*this),arg_list); + + if (!parse_igeneric_function_params(param_type_list, arg_list, function_name, function, tc)) + { + return error_node(); + } + + std::size_t param_seq_index = 0; + + if (!tc.verify(param_type_list, param_seq_index)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR131 - Invalid input parameter sequence for call to overloaded function: " + function_name, + exprtk_error_location)); + + return error_node(); + } + + expression_node_ptr result = error_node(); + + if (type_checker::e_numeric == tc.return_type(param_seq_index)) + { + if (tc.paramseq_count() <= 1) + result = expression_generator_ + .generic_function_call(function, arg_list); + else + result = expression_generator_ + .generic_function_call(function, arg_list, param_seq_index); + } + else if (type_checker::e_string == tc.return_type(param_seq_index)) + { + if (tc.paramseq_count() <= 1) + result = expression_generator_ + .string_function_call(function, arg_list); + else + result = expression_generator_ + .string_function_call(function, arg_list, param_seq_index); + } + else + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR132 - Invalid return type for call to overloaded function: " + function_name, + exprtk_error_location)); + } + + sdd.delete_ptr = (0 == result); + return result; + } #endif template struct parse_special_function_impl { - static inline expression_node_ptr process(parser& p,const details::operator_type opt_type) + static inline expression_node_ptr process(parser& p, const details::operator_type opt_type, const std::string& sf_name) { expression_node_ptr branch[NumberOfParameters]; - expression_node_ptr result = error_node(); + expression_node_ptr result = error_node(); - std::fill_n(branch,NumberOfParameters,reinterpret_cast(0)); + std::fill_n(branch, NumberOfParameters, reinterpret_cast(0)); scoped_delete sd(p,branch); @@ -23592,7 +24964,7 @@ namespace exprtk p.set_error( make_error(parser_error::e_syntax, p.current_token(), - "ERR126 - Expected '(' for special function", + "ERR133 - Expected '(' for special function '" + sf_name + "'", exprtk_error_location)); return error_node(); @@ -23613,7 +24985,7 @@ namespace exprtk p.set_error( make_error(parser_error::e_syntax, p.current_token(), - "ERR127 - Expected ',' before next parameter of special function", + "ERR134 - Expected ',' before next parameter of special function '" + sf_name + "'", exprtk_error_location)); return p.error_node(); @@ -23622,7 +24994,15 @@ namespace exprtk } if (!p.token_is(token_t::e_rbracket)) + { + p.set_error( + make_error(parser_error::e_syntax, + p.current_token(), + "ERR135 - Invalid number of parameters for special function '" + sf_name + "'", + exprtk_error_location)); + return p.error_node(); + } else result = p.expression_generator_.special_function(opt_type,branch); @@ -23634,30 +25014,32 @@ namespace exprtk inline expression_node_ptr parse_special_function() { + const std::string sf_name = current_token().value; + // Expect: $fDD(expr0,expr1,expr2) or $fDD(expr0,expr1,expr2,expr3) if ( - !details::is_digit(current_token().value[2]) || - !details::is_digit(current_token().value[3]) + !details::is_digit(sf_name[2]) || + !details::is_digit(sf_name[3]) ) { set_error( make_error(parser_error::e_token, current_token(), - "ERR128 - Invalid special function[1]: " + current_token().value, + "ERR136 - Invalid special function[1]: " + sf_name, exprtk_error_location)); return error_node(); } - const int id = (current_token().value[2] - '0') * 10 + - (current_token().value[3] - '0'); + const int id = (sf_name[2] - '0') * 10 + + (sf_name[3] - '0'); if (id >= details::e_sffinal) { set_error( make_error(parser_error::e_token, current_token(), - "ERR129 - Invalid special function[2]: " + current_token().value, + "ERR137 - Invalid special function[2]: " + sf_name, exprtk_error_location)); return error_node(); @@ -23669,8 +25051,8 @@ namespace exprtk switch (NumberOfParameters) { - case 3 : return parse_special_function_impl::process((*this),opt_type); - case 4 : return parse_special_function_impl::process((*this),opt_type); + case 3 : return parse_special_function_impl::process((*this), opt_type, sf_name); + case 4 : return parse_special_function_impl::process((*this), opt_type, sf_name); default : return error_node(); } } @@ -23689,7 +25071,17 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR130 - Break call within a break call is not allowed", + "ERR138 - Invoking 'break' within a break call is not allowed", + exprtk_error_location)); + + return error_node(); + } + else if (0 == state_.parsing_loop_stmt_count) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR139 - Invalid use of 'break', allowed only in the scope of a loop", exprtk_error_location)); return error_node(); @@ -23712,7 +25104,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR131 - Failed to parse return expression for 'break' statement", + "ERR140 - Failed to parse return expression for 'break' statement", exprtk_error_location)); return error_node(); @@ -23722,7 +25114,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR132 - Expected ']' at the completion of break's return expression", + "ERR141 - Expected ']' at the completion of break's return expression", exprtk_error_location)); free_node(node_allocator_,return_expr); @@ -23740,7 +25132,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR133 - Invalid use of 'break', allowed only in the scope of a loop", + "ERR142 - Invalid use of 'break', allowed only in the scope of a loop", exprtk_error_location)); } @@ -23749,25 +25141,25 @@ namespace exprtk inline expression_node_ptr parse_continue_statement() { - if (!brkcnt_list_.empty()) - { - next_token(); - - brkcnt_list_.front() = true; - state_.activate_side_effect("parse_continue_statement()"); - - return node_allocator_.allocate >(); - } - else + if (0 == state_.parsing_loop_stmt_count) { set_error( make_error(parser_error::e_syntax, current_token(), - "ERR134 - Invalid use of 'continue', allowed only in the scope of a loop", + "ERR143 - Invalid use of 'continue', allowed only in the scope of a loop", exprtk_error_location)); return error_node(); } + else + { + next_token(); + + brkcnt_list_.front() = true; + state_.activate_side_effect("parse_continue_statement()"); + + return node_allocator_.allocate >(); + } } #endif @@ -23780,7 +25172,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR135 - Expected '[' as part of vector size definition", + "ERR144 - Expected '[' as part of vector size definition", exprtk_error_location)); return error_node(); @@ -23790,7 +25182,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR136 - Failed to determine size of vector '" + vec_name + "'", + "ERR145 - Failed to determine size of vector '" + vec_name + "'", exprtk_error_location)); return error_node(); @@ -23802,26 +25194,29 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR137 - Expected a literal number as size of vector '" + vec_name + "'", + "ERR146 - Expected a literal number as size of vector '" + vec_name + "'", exprtk_error_location)); return error_node(); } - T vector_size = size_expr->value(); + const T vector_size = size_expr->value(); free_node(node_allocator_,size_expr); + const T max_vector_size = T(2000000000.0); + if ( (vector_size <= T(0)) || std::not_equal_to() - (T(0),vector_size - details::numeric::trunc(vector_size)) + (T(0),vector_size - details::numeric::trunc(vector_size)) || + (vector_size > max_vector_size) ) { set_error( make_error(parser_error::e_syntax, current_token(), - "ERR138 - Invalid vector size. Must be an integer greater than zero, size: " + + "ERR147 - 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)); @@ -23841,7 +25236,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR139 - Expected ']' as part of vector size definition", + "ERR148 - Expected ']' as part of vector size definition", exprtk_error_location)); return error_node(); @@ -23853,7 +25248,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR140 - Expected ':=' as part of vector definition", + "ERR149 - Expected ':=' as part of vector definition", exprtk_error_location)); return error_node(); @@ -23867,7 +25262,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR141 - Failed to parse single vector initialiser", + "ERR150 - Failed to parse single vector initialiser", exprtk_error_location)); return error_node(); @@ -23880,7 +25275,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR142 - Expected ']' to close single value vector initialiser", + "ERR151 - Expected ']' to close single value vector initialiser", exprtk_error_location)); return error_node(); @@ -23896,7 +25291,7 @@ namespace exprtk if (token_t::e_symbol == current_token().type) { // Is it a locally defined vector? - scope_element& se = sem_.get_active_element(current_token().value); + const scope_element& se = sem_.get_active_element(current_token().value); if (scope_element::e_vector == se.type) { @@ -23908,7 +25303,7 @@ namespace exprtk // Are we dealing with a user defined vector? else if (symtab_store_.is_vector(current_token().value)) { - lodge_symbol(current_token().value,e_st_vector); + lodge_symbol(current_token().value, e_st_vector); if (0 != (initialiser = parse_expression())) vec_initilizer_list.push_back(initialiser); @@ -23927,7 +25322,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR143 - Expected '{' as part of vector initialiser list", + "ERR152 - Expected '{' as part of vector initialiser list", exprtk_error_location)); return error_node(); @@ -23947,7 +25342,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR144 - Expected '{' as part of vector initialiser list", + "ERR153 - Expected '{' as part of vector initialiser list", exprtk_error_location)); return error_node(); @@ -23958,14 +25353,14 @@ namespace exprtk if (token_is(token_t::e_rcrlbracket)) break; - bool is_next_close = peek_token_is(token_t::e_rcrlbracket); + const bool is_next_close = peek_token_is(token_t::e_rcrlbracket); if (!token_is(token_t::e_comma) && is_next_close) { set_error( make_error(parser_error::e_syntax, current_token(), - "ERR145 - Expected ',' between vector initialisers", + "ERR154 - Expected ',' between vector initialisers", exprtk_error_location)); return error_node(); @@ -23977,9 +25372,9 @@ namespace exprtk } if ( - !token_is(token_t::e_rbracket ,prsrhlpr_t::e_hold) && - !token_is(token_t::e_rcrlbracket,prsrhlpr_t::e_hold) && - !token_is(token_t::e_rsqrbracket,prsrhlpr_t::e_hold) + !token_is(token_t::e_rbracket , prsrhlpr_t::e_hold) && + !token_is(token_t::e_rcrlbracket, prsrhlpr_t::e_hold) && + !token_is(token_t::e_rsqrbracket, prsrhlpr_t::e_hold) ) { if (!token_is(token_t::e_eof)) @@ -23987,7 +25382,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR146 - Expected ';' at end of vector definition", + "ERR155 - Expected ';' at end of vector definition", exprtk_error_location)); return error_node(); @@ -23999,7 +25394,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR147 - Initialiser list larger than the number of elements in the vector: '" + vec_name + "'", + "ERR156 - Initialiser list larger than the number of elements in the vector: '" + vec_name + "'", exprtk_error_location)); return error_node(); @@ -24019,7 +25414,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR148 - Illegal redefinition of local vector: '" + vec_name + "'", + "ERR157 - Illegal redefinition of local vector: '" + vec_name + "'", exprtk_error_location)); return error_node(); @@ -24053,7 +25448,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR149 - Failed to add new local vector '" + vec_name + "' to SEM", + "ERR158 - Failed to add new local vector '" + vec_name + "' to SEM", exprtk_error_location)); sem_.free_element(nse); @@ -24070,17 +25465,21 @@ namespace exprtk state_.activate_side_effect("parse_define_vector_statement()"); - lodge_symbol(vec_name,e_st_local_vector); + lodge_symbol(vec_name, e_st_local_vector); expression_node_ptr result = error_node(); if (null_initialisation) result = expression_generator_(T(0.0)); else if (vec_to_vec_initialiser) + { + expression_node_ptr vec_node = node_allocator_.allocate(vec_holder); + result = expression_generator_( details::e_assign, - node_allocator_.allocate(vec_holder), + vec_node, vec_initilizer_list[0]); + } else result = node_allocator_ .allocate >( @@ -24108,7 +25507,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR150 - Illegal redefinition of local variable: '" + str_name + "'", + "ERR159 - Illegal redefinition of local variable: '" + str_name + "'", exprtk_error_location)); free_node(node_allocator_,initialisation_expression); @@ -24140,7 +25539,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR151 - Failed to add new local string variable '" + str_name + "' to SEM", + "ERR160 - Failed to add new local string variable '" + str_name + "' to SEM", exprtk_error_location)); free_node(node_allocator_,initialisation_expression); @@ -24155,7 +25554,7 @@ namespace exprtk exprtk_debug(("parse_define_string_statement() - INFO - Added new local string variable: %s\n",nse.name.c_str())); } - lodge_symbol(str_name,e_st_local_string); + lodge_symbol(str_name, e_st_local_string); state_.activate_side_effect("parse_define_string_statement()"); @@ -24186,7 +25585,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR152 - Illegal variable definition", + "ERR161 - Illegal variable definition", exprtk_error_location)); return error_node(); @@ -24207,7 +25606,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR153 - Expected a symbol for variable definition", + "ERR162 - Expected a symbol for variable definition", exprtk_error_location)); return error_node(); @@ -24217,7 +25616,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR154 - Illegal redefinition of reserved keyword: '" + var_name + "'", + "ERR163 - Illegal redefinition of reserved keyword: '" + var_name + "'", exprtk_error_location)); return error_node(); @@ -24227,7 +25626,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR155 - Illegal redefinition of variable '" + var_name + "'", + "ERR164 - Illegal redefinition of variable '" + var_name + "'", exprtk_error_location)); return error_node(); @@ -24237,7 +25636,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR156 - Illegal redefinition of local variable: '" + var_name + "'", + "ERR165 - Illegal redefinition of local variable: '" + var_name + "'", exprtk_error_location)); return error_node(); @@ -24257,7 +25656,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR157 - Failed to parse initialisation expression", + "ERR166 - Failed to parse initialisation expression", exprtk_error_location)); return error_node(); @@ -24265,9 +25664,9 @@ namespace exprtk } if ( - !token_is(token_t::e_rbracket ,prsrhlpr_t::e_hold) && - !token_is(token_t::e_rcrlbracket,prsrhlpr_t::e_hold) && - !token_is(token_t::e_rsqrbracket,prsrhlpr_t::e_hold) + !token_is(token_t::e_rbracket , prsrhlpr_t::e_hold) && + !token_is(token_t::e_rcrlbracket, prsrhlpr_t::e_hold) && + !token_is(token_t::e_rsqrbracket, prsrhlpr_t::e_hold) ) { if (!token_is(token_t::e_eof,prsrhlpr_t::e_hold)) @@ -24275,7 +25674,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR158 - Expected ';' after variable definition", + "ERR167 - Expected ';' after variable definition", exprtk_error_location)); free_node(node_allocator_,initialisation_expression); @@ -24303,7 +25702,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR159 - Illegal redefinition of local variable: '" + var_name + "'", + "ERR168 - Illegal redefinition of local variable: '" + var_name + "'", exprtk_error_location)); free_node(node_allocator_, initialisation_expression); @@ -24335,7 +25734,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR160 - Failed to add new local variable '" + var_name + "' to SEM", + "ERR169 - Failed to add new local variable '" + var_name + "' to SEM", exprtk_error_location)); free_node(node_allocator_, initialisation_expression); @@ -24352,7 +25751,7 @@ namespace exprtk state_.activate_side_effect("parse_define_var_statement()"); - lodge_symbol(var_name,e_st_local_variable); + lodge_symbol(var_name, e_st_local_variable); expression_node_ptr branch[2] = {0}; @@ -24372,7 +25771,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR161 - Expected a '{}' for uninitialised var definition", + "ERR170 - Expected a '{}' for uninitialised var definition", exprtk_error_location)); return error_node(); @@ -24382,7 +25781,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR162 - Expected ';' after uninitialised variable definition", + "ERR171 - Expected ';' after uninitialised variable definition", exprtk_error_location)); return error_node(); @@ -24399,7 +25798,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR163 - Illegal redefinition of local variable: '" + var_name + "'", + "ERR172 - Illegal redefinition of local variable: '" + var_name + "'", exprtk_error_location)); return error_node(); @@ -24429,7 +25828,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR164 - Failed to add new local variable '" + var_name + "' to SEM", + "ERR173 - Failed to add new local variable '" + var_name + "' to SEM", exprtk_error_location)); sem_.free_element(nse); @@ -24441,7 +25840,7 @@ namespace exprtk nse.name.c_str())); } - lodge_symbol(var_name,e_st_local_variable); + lodge_symbol(var_name, e_st_local_variable); state_.activate_side_effect("parse_uninitialised_var_statement()"); @@ -24462,7 +25861,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR165 - Expected '(' at start of swap statement", + "ERR174 - Expected '(' at start of swap statement", exprtk_error_location)); return error_node(); @@ -24481,7 +25880,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR166 - Expected a symbol for variable or vector element definition", + "ERR175 - Expected a symbol for variable or vector element definition", exprtk_error_location)); return error_node(); @@ -24493,7 +25892,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR167 - First parameter to swap is an invalid vector element: '" + var0_name + "'", + "ERR176 - First parameter to swap is an invalid vector element: '" + var0_name + "'", exprtk_error_location)); return error_node(); @@ -24508,7 +25907,7 @@ namespace exprtk variable0 = symtab_store_.get_variable(var0_name); } - scope_element& se = sem_.get_element(var0_name); + const scope_element& se = sem_.get_element(var0_name); if ( (se.active) && @@ -24519,14 +25918,14 @@ namespace exprtk variable0 = se.var_node; } - lodge_symbol(var0_name,e_st_variable); + lodge_symbol(var0_name, e_st_variable); if (0 == variable0) { set_error( make_error(parser_error::e_syntax, current_token(), - "ERR168 - First parameter to swap is an invalid variable: '" + var0_name + "'", + "ERR177 - First parameter to swap is an invalid variable: '" + var0_name + "'", exprtk_error_location)); return error_node(); @@ -24540,7 +25939,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR169 - Expected ',' between parameters to swap", + "ERR178 - Expected ',' between parameters to swap", exprtk_error_location)); if (variable0_generated) @@ -24558,7 +25957,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR170 - Expected a symbol for variable or vector element definition", + "ERR179 - Expected a symbol for variable or vector element definition", exprtk_error_location)); if (variable0_generated) @@ -24575,7 +25974,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR171 - Second parameter to swap is an invalid vector element: '" + var1_name + "'", + "ERR180 - Second parameter to swap is an invalid vector element: '" + var1_name + "'", exprtk_error_location)); if (variable0_generated) @@ -24595,7 +25994,7 @@ namespace exprtk variable1 = symtab_store_.get_variable(var1_name); } - scope_element& se = sem_.get_element(var1_name); + const scope_element& se = sem_.get_element(var1_name); if ( (se.active) && @@ -24606,14 +26005,14 @@ namespace exprtk variable1 = se.var_node; } - lodge_symbol(var1_name,e_st_variable); + lodge_symbol(var1_name, e_st_variable); if (0 == variable1) { set_error( make_error(parser_error::e_syntax, current_token(), - "ERR172 - Second parameter to swap is an invalid variable: '" + var1_name + "'", + "ERR181 - Second parameter to swap is an invalid variable: '" + var1_name + "'", exprtk_error_location)); if (variable0_generated) @@ -24632,7 +26031,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR173 - Expected ')' at end of swap statement", + "ERR182 - Expected ')' at end of swap statement", exprtk_error_location)); if (variable0_generated) @@ -24689,7 +26088,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR174 - Return call within a return call is not allowed", + "ERR183 - Return call within a return call is not allowed", exprtk_error_location)); return error_node(); @@ -24713,7 +26112,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR175 - Expected '[' at start of return statement", + "ERR184 - Expected '[' at start of return statement", exprtk_error_location)); return error_node(); @@ -24736,7 +26135,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR176 - Expected ',' between values during call to return", + "ERR185 - Expected ',' between values during call to return", exprtk_error_location)); return error_node(); @@ -24748,13 +26147,13 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR177 - Zero parameter return statement not allowed", + "ERR186 - Zero parameter return statement not allowed", exprtk_error_location)); return error_node(); } - lexer::token prev_token = current_token(); + const lexer::token prev_token = current_token(); if (token_is(token_t::e_rsqrbracket)) { @@ -24763,7 +26162,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, prev_token, - "ERR178 - Invalid ']' found during return call", + "ERR187 - Invalid ']' found during return call", exprtk_error_location)); return error_node(); @@ -24816,7 +26215,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR179 - Invalid sequence of variable '"+ symbol + "' and bracket", + "ERR188 - Invalid sequence of variable '"+ symbol + "' and bracket", exprtk_error_location)); return false; @@ -24864,7 +26263,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR180 - Invalid sequence of brackets", + "ERR189 - Invalid sequence of brackets", exprtk_error_location)); return false; @@ -24897,7 +26296,7 @@ namespace exprtk if (!post_variable_process(symbol)) return error_node(); - lodge_symbol(symbol,e_st_variable); + lodge_symbol(symbol, e_st_variable); next_token(); return variable; @@ -24913,7 +26312,7 @@ namespace exprtk if (scope_element::e_variable == se.type) { se.active = true; - lodge_symbol(symbol,e_st_local_variable); + lodge_symbol(symbol, e_st_local_variable); if (!post_variable_process(symbol)) return error_node(); @@ -24949,7 +26348,7 @@ namespace exprtk if (function) { - lodge_symbol(symbol,e_st_function); + lodge_symbol(symbol, e_st_function); expression_node_ptr func_node = parse_function_invocation(function,symbol); @@ -24961,7 +26360,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR181 - Failed to generate node for function: '" + symbol + "'", + "ERR190 - Failed to generate node for function: '" + symbol + "'", exprtk_error_location)); return error_node(); @@ -24975,7 +26374,7 @@ namespace exprtk if (vararg_function) { - lodge_symbol(symbol,e_st_function); + lodge_symbol(symbol, e_st_function); expression_node_ptr vararg_func_node = parse_vararg_function_call(vararg_function, symbol); @@ -24987,7 +26386,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR182 - Failed to generate node for vararg function: '" + symbol + "'", + "ERR191 - Failed to generate node for vararg function: '" + symbol + "'", exprtk_error_location)); return error_node(); @@ -25001,7 +26400,7 @@ namespace exprtk if (generic_function) { - lodge_symbol(symbol,e_st_function); + lodge_symbol(symbol, e_st_function); expression_node_ptr genericfunc_node = parse_generic_function_call(generic_function, symbol); @@ -25013,7 +26412,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR183 - Failed to generate node for generic function: '" + symbol + "'", + "ERR192 - Failed to generate node for generic function: '" + symbol + "'", exprtk_error_location)); return error_node(); @@ -25028,7 +26427,7 @@ namespace exprtk if (string_function) { - lodge_symbol(symbol,e_st_function); + lodge_symbol(symbol, e_st_function); expression_node_ptr stringfunc_node = parse_string_function_call(string_function, symbol); @@ -25040,7 +26439,33 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR184 - Failed to generate node for string function: '" + symbol + "'", + "ERR193 - Failed to generate node for string function: '" + symbol + "'", + exprtk_error_location)); + + return error_node(); + } + } + } + + { + // Are we dealing with a vararg overloaded scalar/string returning function? + igeneric_function* overload_function = symtab_store_.get_overload_function(symbol); + + if (overload_function) + { + lodge_symbol(symbol, e_st_function); + + expression_node_ptr overloadfunc_node = + parse_overload_function_call(overload_function, symbol); + + if (overloadfunc_node) + return overloadfunc_node; + else + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR194 - Failed to generate node for overload function: '" + symbol + "'", exprtk_error_location)); return error_node(); @@ -25052,7 +26477,7 @@ namespace exprtk // Are we dealing with a vector? if (symtab_store_.is_vector(symbol)) { - lodge_symbol(symbol,e_st_vector); + lodge_symbol(symbol, e_st_vector); return parse_vector(); } @@ -25066,7 +26491,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR185 - Invalid use of reserved symbol '" + symbol + "'", + "ERR195 - Invalid use of reserved symbol '" + symbol + "'", exprtk_error_location)); return error_node(); @@ -25086,7 +26511,7 @@ namespace exprtk { T default_value = T(0); - typename unknown_symbol_resolver::usr_symbol_type usr_symbol_type; + typename unknown_symbol_resolver::usr_symbol_type usr_symbol_type = unknown_symbol_resolver::e_usr_unknown_type; if (unknown_symbol_resolver_->process(symbol, usr_symbol_type, default_value, error_message)) { @@ -25114,7 +26539,7 @@ namespace exprtk var = expression_generator_(var->value()); } - lodge_symbol(symbol,e_st_variable); + lodge_symbol(symbol, e_st_variable); if (!post_variable_process(symbol)) return error_node(); @@ -25129,7 +26554,7 @@ namespace exprtk set_error( make_error(parser_error::e_symtab, current_token(), - "ERR186 - Failed to create variable: '" + symbol + "'" + + "ERR196 - Failed to create variable: '" + symbol + "'" + (error_message.empty() ? "" : " - " + error_message), exprtk_error_location)); @@ -25149,7 +26574,7 @@ namespace exprtk set_error( make_error(parser_error::e_symtab, current_token(), - "ERR187 - Failed to resolve symbol: '" + symbol + "'" + + "ERR197 - Failed to resolve symbol: '" + symbol + "'" + (error_message.empty() ? "" : " - " + error_message), exprtk_error_location)); } @@ -25161,7 +26586,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR188 - Undefined symbol: '" + symbol + "'", + "ERR198 - Undefined symbol: '" + symbol + "'", exprtk_error_location)); return error_node(); @@ -25180,11 +26605,16 @@ namespace exprtk static const std::string symbol_var = "var" ; static const std::string symbol_swap = "swap" ; static const std::string symbol_return = "return" ; + static const std::string symbol_not = "not" ; if (valid_vararg_operation(current_token().value)) { return parse_vararg_function(); } + else if (details::imatch(current_token().value, symbol_not)) + { + return parse_not_statement(); + } else if (valid_base_operation(current_token().value)) { return parse_base_operation(); @@ -25268,7 +26698,7 @@ namespace exprtk set_error( make_error(parser_error::e_symtab, current_token(), - "ERR189 - Variable or function detected, yet symbol-table is invalid, Symbol: " + current_token().value, + "ERR199 - Variable or function detected, yet symbol-table is invalid, Symbol: " + current_token().value, exprtk_error_location)); return error_node(); @@ -25277,6 +26707,13 @@ namespace exprtk inline expression_node_ptr parse_branch(precedence_level precedence = e_level00) { + stack_limit_handler slh(*this); + + if (!slh) + { + return error_node(); + } + expression_node_ptr branch = error_node(); if (token_t::e_number == current_token().type) @@ -25292,7 +26729,7 @@ namespace exprtk set_error( make_error(parser_error::e_numeric, current_token(), - "ERR190 - Failed generate node for scalar: '" + current_token().value + "'", + "ERR200 - Failed generate node for scalar: '" + current_token().value + "'", exprtk_error_location)); return error_node(); @@ -25306,7 +26743,7 @@ namespace exprtk set_error( make_error(parser_error::e_numeric, current_token(), - "ERR191 - Failed to convert '" + current_token().value + "' to a number", + "ERR201 - Failed to convert '" + current_token().value + "' to a number", exprtk_error_location)); return error_node(); @@ -25333,7 +26770,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR192 - Expected ')' instead of: '" + current_token().value + "'", + "ERR202 - Expected ')' instead of: '" + current_token().value + "'", exprtk_error_location)); free_node(node_allocator_,branch); @@ -25358,7 +26795,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR193 - Expected ']' instead of: '" + current_token().value + "'", + "ERR203 - Expected ']' instead of: '" + current_token().value + "'", exprtk_error_location)); free_node(node_allocator_,branch); @@ -25383,7 +26820,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR194 - Expected '}' instead of: '" + current_token().value + "'", + "ERR204 - Expected '}' instead of: '" + current_token().value + "'", exprtk_error_location)); free_node(node_allocator_,branch); @@ -25410,7 +26847,16 @@ namespace exprtk ) ) { - branch = expression_generator_(details::e_neg,branch); + expression_node_ptr result = expression_generator_(details::e_neg,branch); + + if (0 == result) + { + free_node(node_allocator_,branch); + + return error_node(); + } + else + branch = result; } } else if (token_t::e_add == current_token().type) @@ -25423,7 +26869,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR195 - Premature end of expression[1]", + "ERR205 - Premature end of expression[1]", exprtk_error_location)); return error_node(); @@ -25433,7 +26879,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR196 - Premature end of expression[2]", + "ERR206 - Premature end of expression[2]", exprtk_error_location)); return error_node(); @@ -25607,7 +27053,7 @@ namespace exprtk return true; } - inline details::operator_type get_operator(const binary_functor_t& bop) + inline details::operator_type get_operator(const binary_functor_t& bop) const { return (*inv_binary_op_map_).find(bop)->second; } @@ -25666,9 +27112,9 @@ namespace exprtk (details::e_frac == operation) || (details::e_trunc == operation) ; } - inline bool sf3_optimisable(const std::string& sf3id, trinary_functor_t& tfunc) + inline bool sf3_optimisable(const std::string& sf3id, trinary_functor_t& tfunc) const { - typename sf3_map_t::iterator itr = sf3_map_->find(sf3id); + typename sf3_map_t::const_iterator itr = sf3_map_->find(sf3id); if (sf3_map_->end() == itr) return false; @@ -25678,9 +27124,9 @@ namespace exprtk return true; } - inline bool sf4_optimisable(const std::string& sf4id, quaternary_functor_t& qfunc) + inline bool sf4_optimisable(const std::string& sf4id, quaternary_functor_t& qfunc) const { - typename sf4_map_t::iterator itr = sf4_map_->find(sf4id); + typename sf4_map_t::const_iterator itr = sf4_map_->find(sf4id); if (sf4_map_->end() == itr) return false; @@ -25690,9 +27136,9 @@ namespace exprtk return true; } - inline bool sf3_optimisable(const std::string& sf3id, details::operator_type& operation) + inline bool sf3_optimisable(const std::string& sf3id, details::operator_type& operation) const { - typename sf3_map_t::iterator itr = sf3_map_->find(sf3id); + typename sf3_map_t::const_iterator itr = sf3_map_->find(sf3id); if (sf3_map_->end() == itr) return false; @@ -25702,9 +27148,9 @@ namespace exprtk return true; } - inline bool sf4_optimisable(const std::string& sf4id, details::operator_type& operation) + inline bool sf4_optimisable(const std::string& sf4id, details::operator_type& operation) const { - typename sf4_map_t::iterator itr = sf4_map_->find(sf4id); + typename sf4_map_t::const_iterator itr = sf4_map_->find(sf4id); if (sf4_map_->end() == itr) return false; @@ -25832,7 +27278,7 @@ namespace exprtk (details::e_xnor == operation) ; } - inline std::string branch_to_id(expression_node_ptr branch) + inline std::string branch_to_id(expression_node_ptr branch) const { static const std::string null_str ("(null)" ); static const std::string const_str ("(c)" ); @@ -25873,7 +27319,7 @@ namespace exprtk return "ERROR"; } - inline std::string branch_to_id(expression_node_ptr (&branch)[2]) + inline std::string branch_to_id(expression_node_ptr (&branch)[2]) const { return branch_to_id(branch[0]) + std::string("o") + branch_to_id(branch[1]); } @@ -25991,7 +27437,7 @@ namespace exprtk !details::is_constant_node(branch[1]) ; } - inline bool is_invalid_assignment_op(const details::operator_type& operation, expression_node_ptr (&branch)[2]) + inline bool is_invalid_assignment_op(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const { if (is_assignment_operation(operation)) { @@ -26013,14 +27459,14 @@ namespace exprtk return false; } - inline bool is_constpow_operation(const details::operator_type& operation, expression_node_ptr(&branch)[2]) + inline bool is_constpow_operation(const details::operator_type& operation, expression_node_ptr(&branch)[2]) const { if ( - !is_constant_node(branch[1]) || - is_constant_node(branch[0]) || - is_variable_node(branch[0]) || - is_vector_node (branch[0]) || - is_generally_string_node(branch[0]) + !details::is_constant_node(branch[1]) || + details::is_constant_node(branch[0]) || + details::is_variable_node(branch[0]) || + details::is_vector_node (branch[0]) || + details::is_generally_string_node(branch[0]) ) return false; @@ -26029,7 +27475,7 @@ namespace exprtk return cardinal_pow_optimisable(operation, c); } - inline bool is_invalid_break_continue_op(expression_node_ptr (&branch)[2]) + inline bool is_invalid_break_continue_op(expression_node_ptr (&branch)[2]) const { return ( details::is_break_node (branch[0]) || @@ -26039,7 +27485,7 @@ namespace exprtk ); } - inline bool is_invalid_string_op(const details::operator_type& operation, expression_node_ptr (&branch)[2]) + inline bool is_invalid_string_op(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const { const bool b0_string = is_generally_string_node(branch[0]); const bool b1_string = is_generally_string_node(branch[1]); @@ -26059,7 +27505,7 @@ namespace exprtk return result; } - inline bool is_invalid_string_op(const details::operator_type& operation, expression_node_ptr (&branch)[3]) + inline bool is_invalid_string_op(const details::operator_type& operation, expression_node_ptr (&branch)[3]) const { const bool b0_string = is_generally_string_node(branch[0]); const bool b1_string = is_generally_string_node(branch[1]); @@ -26080,7 +27526,7 @@ namespace exprtk return result; } - inline bool is_string_operation(const details::operator_type& operation, expression_node_ptr (&branch)[2]) + inline bool is_string_operation(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const { const bool b0_string = is_generally_string_node(branch[0]); const bool b1_string = is_generally_string_node(branch[1]); @@ -26088,7 +27534,7 @@ namespace exprtk return (b0_string && b1_string && valid_string_operation(operation)); } - inline bool is_string_operation(const details::operator_type& operation, expression_node_ptr (&branch)[3]) + inline bool is_string_operation(const details::operator_type& operation, expression_node_ptr (&branch)[3]) const { const bool b0_string = is_generally_string_node(branch[0]); const bool b1_string = is_generally_string_node(branch[1]); @@ -26098,7 +27544,7 @@ namespace exprtk } #ifndef exprtk_disable_sc_andor - inline bool is_shortcircuit_expression(const details::operator_type& operation) + inline bool is_shortcircuit_expression(const details::operator_type& operation) const { return ( (details::e_scand == operation) || @@ -26106,13 +27552,13 @@ namespace exprtk ); } #else - inline bool is_shortcircuit_expression(const details::operator_type&) + inline bool is_shortcircuit_expression(const details::operator_type&) const { return false; } #endif - inline bool is_null_present(expression_node_ptr (&branch)[2]) + inline bool is_null_present(expression_node_ptr (&branch)[2]) const { return ( details::is_null_node(branch[0]) || @@ -26120,29 +27566,29 @@ namespace exprtk ); } - inline bool is_vector_eqineq_logic_operation(const details::operator_type& operation, expression_node_ptr (&branch)[2]) + inline bool is_vector_eqineq_logic_operation(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const { if (!is_ivector_node(branch[0]) && !is_ivector_node(branch[1])) return false; else return ( - (details::e_lt == operation) || - (details::e_lte == operation) || - (details::e_gt == operation) || - (details::e_gte == operation) || - (details::e_eq == operation) || - (details::e_ne == operation) || - (details::e_equal == operation) || - (details::e_and == operation) || - (details::e_nand == operation) || - (details:: e_or == operation) || - (details:: e_nor == operation) || - (details:: e_xor == operation) || - (details::e_xnor == operation) + (details::e_lt == operation) || + (details::e_lte == operation) || + (details::e_gt == operation) || + (details::e_gte == operation) || + (details::e_eq == operation) || + (details::e_ne == operation) || + (details::e_equal == operation) || + (details::e_and == operation) || + (details::e_nand == operation) || + (details:: e_or == operation) || + (details:: e_nor == operation) || + (details:: e_xor == operation) || + (details::e_xnor == operation) ); } - inline bool is_vector_arithmetic_operation(const details::operator_type& operation, expression_node_ptr (&branch)[2]) + inline bool is_vector_arithmetic_operation(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const { if (!is_ivector_node(branch[0]) && !is_ivector_node(branch[1])) return false; @@ -26315,15 +27761,19 @@ namespace exprtk return (*this)(operation,branch); } - inline expression_node_ptr operator() (const details::operator_type& operation, expression_node_ptr b0, expression_node_ptr b1) + inline expression_node_ptr operator() (const details::operator_type& operation, expression_node_ptr& b0, expression_node_ptr& b1) { - if ((0 == b0) || (0 == b1)) - return error_node(); - else + expression_node_ptr result = error_node(); + + if ((0 != b0) && (0 != b1)) { expression_node_ptr branch[2] = { b0, b1 }; - return expression_generator::operator()(operation,branch); + result = expression_generator::operator()(operation, branch); + b0 = branch[0]; + b1 = branch[1]; } + + return result; } inline expression_node_ptr conditional(expression_node_ptr condition, @@ -26332,8 +27782,8 @@ namespace exprtk { if ((0 == condition) || (0 == consequent)) { - free_node(*node_allocator_, condition ); - free_node(*node_allocator_, consequent ); + free_node(*node_allocator_, condition); + free_node(*node_allocator_, consequent); free_node(*node_allocator_, alternative); return error_node(); @@ -26344,7 +27794,7 @@ namespace exprtk // True branch if (details::is_true(condition)) { - free_node(*node_allocator_, condition ); + free_node(*node_allocator_, condition); free_node(*node_allocator_, alternative); return consequent; @@ -26352,7 +27802,7 @@ namespace exprtk // False branch else { - free_node(*node_allocator_, condition ); + free_node(*node_allocator_, condition); free_node(*node_allocator_, consequent); if (alternative) @@ -26364,11 +27814,11 @@ namespace exprtk else if ((0 != consequent) && (0 != alternative)) { return node_allocator_-> - allocate(condition,consequent,alternative); + allocate(condition, consequent, alternative); } else return node_allocator_-> - allocate(condition,consequent); + allocate(condition, consequent); } #ifndef exprtk_disable_string_capabilities @@ -26378,8 +27828,8 @@ namespace exprtk { if ((0 == condition) || (0 == consequent)) { - free_node(*node_allocator_, condition ); - free_node(*node_allocator_, consequent ); + free_node(*node_allocator_, condition); + free_node(*node_allocator_, consequent); free_node(*node_allocator_, alternative); return error_node(); @@ -26390,7 +27840,7 @@ namespace exprtk // True branch if (details::is_true(condition)) { - free_node(*node_allocator_, condition ); + free_node(*node_allocator_, condition); free_node(*node_allocator_, alternative); return consequent; @@ -26398,7 +27848,7 @@ namespace exprtk // False branch else { - free_node(*node_allocator_, condition ); + free_node(*node_allocator_, condition); free_node(*node_allocator_, consequent); if (alternative) @@ -26410,7 +27860,7 @@ namespace exprtk } else if ((0 != consequent) && (0 != alternative)) return node_allocator_-> - allocate(condition,consequent,alternative); + allocate(condition, consequent, alternative); else return error_node(); } @@ -26423,6 +27873,19 @@ namespace exprtk } #endif + inline loop_runtime_check_ptr get_loop_runtime_check(const loop_runtime_check::loop_types loop_type) const + { + if ( + parser_->loop_runtime_check_ && + (loop_type == (parser_->loop_runtime_check_->loop_set & loop_type)) + ) + { + return parser_->loop_runtime_check_; + } + + return loop_runtime_check_ptr(0); + } + inline expression_node_ptr while_loop(expression_node_ptr& condition, expression_node_ptr& branch, const bool brkcont = false) const @@ -26437,7 +27900,7 @@ namespace exprtk result = node_allocator_->allocate >(); free_node(*node_allocator_, condition); - free_node(*node_allocator_, branch ); + free_node(*node_allocator_, branch); return result; } @@ -26448,10 +27911,20 @@ namespace exprtk return branch; } else if (!brkcont) - return node_allocator_->allocate(condition,branch); + return node_allocator_->allocate + ( + condition, + branch, + get_loop_runtime_check(loop_runtime_check::e_while_loop) + ); #ifndef exprtk_disable_break_continue else - return node_allocator_->allocate(condition,branch); + return node_allocator_->allocate + ( + condition, + branch, + get_loop_runtime_check(loop_runtime_check::e_while_loop) + ); #else return error_node(); #endif @@ -26474,7 +27947,7 @@ namespace exprtk } free_node(*node_allocator_, condition); - free_node(*node_allocator_, branch ); + free_node(*node_allocator_, branch); return error_node(); } @@ -26485,10 +27958,20 @@ namespace exprtk return branch; } else if (!brkcont) - return node_allocator_->allocate(condition,branch); + return node_allocator_->allocate + ( + condition, + branch, + get_loop_runtime_check(loop_runtime_check::e_repeat_until_loop) + ); #ifndef exprtk_disable_break_continue else - return node_allocator_->allocate(condition,branch); + return node_allocator_->allocate + ( + condition, + branch, + get_loop_runtime_check(loop_runtime_check::e_repeat_until_loop) + ); #else return error_node(); #endif @@ -26511,16 +27994,16 @@ namespace exprtk result = node_allocator_->allocate >(); free_node(*node_allocator_, initialiser); - free_node(*node_allocator_, condition ); + free_node(*node_allocator_, condition); free_node(*node_allocator_, incrementor); - free_node(*node_allocator_, loop_body ); + free_node(*node_allocator_, loop_body); return result; } - else if (details::is_null_node(condition)) + else if (details::is_null_node(condition) || (0 == condition)) { free_node(*node_allocator_, initialiser); - free_node(*node_allocator_, condition ); + free_node(*node_allocator_, condition); free_node(*node_allocator_, incrementor); return loop_body; @@ -26531,7 +28014,8 @@ namespace exprtk initialiser, condition, incrementor, - loop_body + loop_body, + get_loop_runtime_check(loop_runtime_check::e_for_loop) ); #ifndef exprtk_disable_break_continue @@ -26541,7 +28025,8 @@ namespace exprtk initialiser, condition, incrementor, - loop_body + loop_body, + get_loop_runtime_check(loop_runtime_check::e_for_loop) ); #else return error_node(); @@ -26549,7 +28034,7 @@ namespace exprtk } template class Sequence> + template class Sequence> inline expression_node_ptr const_optimise_switch(Sequence& arg_list) { expression_node_ptr result = error_node(); @@ -26585,7 +28070,7 @@ namespace exprtk } template class Sequence> + template class Sequence> inline expression_node_ptr const_optimise_mswitch(Sequence& arg_list) { expression_node_ptr result = error_node(); @@ -26622,10 +28107,10 @@ namespace exprtk struct switch_nodes { - typedef std::vector arg_list_t; + typedef std::vector > arg_list_t; - #define case_stmt(N) \ - if (is_true(arg[(2 * N)])) { return arg[(2 * N) + 1]->value(); } \ + #define case_stmt(N) \ + if (is_true(arg[(2 * N)].first)) { return arg[(2 * N) + 1].first->value(); } \ struct switch_1 { @@ -26633,7 +28118,7 @@ namespace exprtk { case_stmt(0) - return arg.back()->value(); + return arg.back().first->value(); } }; @@ -26643,7 +28128,7 @@ namespace exprtk { case_stmt(0) case_stmt(1) - return arg.back()->value(); + return arg.back().first->value(); } }; @@ -26654,7 +28139,7 @@ namespace exprtk case_stmt(0) case_stmt(1) case_stmt(2) - return arg.back()->value(); + return arg.back().first->value(); } }; @@ -26665,7 +28150,7 @@ namespace exprtk case_stmt(0) case_stmt(1) case_stmt(2) case_stmt(3) - return arg.back()->value(); + return arg.back().first->value(); } }; @@ -26677,7 +28162,7 @@ namespace exprtk case_stmt(2) case_stmt(3) case_stmt(4) - return arg.back()->value(); + return arg.back().first->value(); } }; @@ -26689,7 +28174,7 @@ namespace exprtk case_stmt(2) case_stmt(3) case_stmt(4) case_stmt(5) - return arg.back()->value(); + return arg.back().first->value(); } }; @@ -26702,7 +28187,7 @@ namespace exprtk case_stmt(4) case_stmt(5) case_stmt(6) - return arg.back()->value(); + return arg.back().first->value(); } }; @@ -26710,15 +28195,14 @@ namespace exprtk }; template class Sequence> - inline expression_node_ptr switch_statement(Sequence& arg_list) + template class Sequence> + inline expression_node_ptr switch_statement(Sequence& arg_list, const bool default_statement_present) { if (arg_list.empty()) return error_node(); else if ( - !all_nodes_valid(arg_list) || - (arg_list.size() < 3) || - ((arg_list.size() % 2) != 1) + !all_nodes_valid(arg_list) || + (!default_statement_present && (arg_list.size() < 2)) ) { details::free_all_nodes(*node_allocator_,arg_list); @@ -26750,7 +28234,7 @@ namespace exprtk } template class Sequence> + template class Sequence> inline expression_node_ptr multi_switch_statement(Sequence& arg_list) { if (!all_nodes_valid(arg_list)) @@ -27062,7 +28546,7 @@ namespace exprtk } template class Sequence> + template class Sequence> inline expression_node_ptr const_optimise_varargfunc(const details::operator_type& operation, Sequence& arg_list) { expression_node_ptr temp_node = error_node(); @@ -27094,7 +28578,7 @@ namespace exprtk return node_allocator_->allocate(v); } - inline bool special_one_parameter_vararg(const details::operator_type& operation) + inline bool special_one_parameter_vararg(const details::operator_type& operation) const { return ( (details::e_sum == operation) || @@ -27106,7 +28590,7 @@ namespace exprtk } template class Sequence> + template class Sequence> inline expression_node_ptr varnode_optimise_varargfunc(const details::operator_type& operation, Sequence& arg_list) { switch (operation) @@ -27129,7 +28613,7 @@ namespace exprtk } template class Sequence> + template class Sequence> inline expression_node_ptr vectorize_func(const details::operator_type& operation, Sequence& arg_list) { if (1 == arg_list.size()) @@ -27154,7 +28638,7 @@ namespace exprtk } template class Sequence> + template class Sequence> inline expression_node_ptr vararg_function(const details::operator_type& operation, Sequence& arg_list) { if (!all_nodes_valid(arg_list)) @@ -27456,7 +28940,7 @@ namespace exprtk return node_allocator_->allocate(i,vector_base); } - scope_element& se = parser_->sem_.get_element(symbol,i); + const scope_element& se = parser_->sem_.get_element(symbol,i); if (se.index == i) { @@ -27516,7 +29000,7 @@ namespace exprtk template class Sequence> + template class Sequence> inline bool is_constant_foldable(const Sequence& b) const { for (std::size_t i = 0; i < b.size(); ++i) @@ -27662,6 +29146,8 @@ namespace exprtk } else if (details::is_vector_elem_node(branch[0])) { + lodge_assignment(e_st_vecelem,branch[0]); + switch (operation) { #define case_stmt(op0,op1) \ @@ -27680,6 +29166,8 @@ namespace exprtk } else if (details::is_rebasevector_elem_node(branch[0])) { + lodge_assignment(e_st_vecelem,branch[0]); + switch (operation) { #define case_stmt(op0,op1) \ @@ -27698,6 +29186,8 @@ namespace exprtk } else if (details::is_rebasevector_celem_node(branch[0])) { + lodge_assignment(e_st_vecelem,branch[0]); + switch (operation) { #define case_stmt(op0,op1) \ @@ -28048,7 +29538,7 @@ namespace exprtk case_stmt(details::e_xnor, details::xnor_op) \ #ifndef exprtk_disable_cardinal_pow_optimisation - template class IPowNode> + template class IPowNode> inline expression_node_ptr cardinal_pow_optimisation_impl(const TType& v, const unsigned int& p) { switch (p) @@ -28098,7 +29588,7 @@ namespace exprtk } } - inline bool cardinal_pow_optimisable(const details::operator_type& operation, const T& c) + inline bool cardinal_pow_optimisable(const details::operator_type& operation, const T& c) const { return (details::e_pow == operation) && (details::numeric::abs(c) <= T(60)) && details::numeric::is_integer(c); } @@ -28302,8 +29792,9 @@ namespace exprtk { expression_node_ptr result = error_node(); - const bool synthesis_result = synthesize_sf4ext_expression::template compile_right - (expr_gen, v, operation, branch[1], result); + const bool synthesis_result = + synthesize_sf4ext_expression::template compile_right + (expr_gen, v, operation, branch[1], result); if (synthesis_result) { @@ -28376,8 +29867,9 @@ namespace exprtk { expression_node_ptr result = error_node(); - const bool synthesis_result = synthesize_sf4ext_expression::template compile_left - (expr_gen, v, operation, branch[0], result); + const bool synthesis_result = + synthesize_sf4ext_expression::template compile_left + (expr_gen, v, operation, branch[0], result); if (synthesis_result) { @@ -28536,12 +30028,12 @@ namespace exprtk { case details::e_div : new_cobnode = expr_gen.node_allocator_-> template allocate_tt > > - (c / cobnode->c(),cobnode->move_branch(0)); + (c / cobnode->c(), cobnode->move_branch(0)); break; case details::e_mul : new_cobnode = expr_gen.node_allocator_-> template allocate_tt > > - (c / cobnode->c(),cobnode->move_branch(0)); + (c / cobnode->c(), cobnode->move_branch(0)); break; default : return error_node(); @@ -28558,7 +30050,11 @@ namespace exprtk { expression_node_ptr result = error_node(); - if (synthesize_sf4ext_expression::template compile_right(expr_gen,c,operation,branch[1],result)) + const bool synthesis_result = + synthesize_sf4ext_expression::template compile_right + (expr_gen, c, operation, branch[1], result); + + if (synthesis_result) { free_node(*expr_gen.node_allocator_,branch[1]); @@ -28590,11 +30086,11 @@ namespace exprtk { const Type c = static_cast*>(branch[1])->value(); - details::free_node(*(expr_gen.node_allocator_),branch[1]); + details::free_node(*(expr_gen.node_allocator_), branch[1]); if (std::equal_to()(T(0),c) && (details::e_mul == operation)) { - free_node(*expr_gen.node_allocator_,branch[0]); + free_node(*expr_gen.node_allocator_, branch[0]); return expr_gen(T(0)); } @@ -28673,8 +30169,9 @@ namespace exprtk { expression_node_ptr result = error_node(); - const bool synthesis_result = synthesize_sf4ext_expression::template compile_left - (expr_gen, c, operation, branch[0], result); + const bool synthesis_result = + synthesize_sf4ext_expression::template compile_left + (expr_gen, c, operation, branch[0], result); if (synthesis_result) { @@ -29224,7 +30721,8 @@ namespace exprtk if (!expr_gen.sf3_optimisable(id,sf3opr)) return false; else - result = synthesize_sf3ext_expression::template process(expr_gen,sf3opr,t0,t1,t2); + result = synthesize_sf3ext_expression::template process + (expr_gen, sf3opr, t0, t1, t2); return true; } @@ -29291,7 +30789,7 @@ namespace exprtk if (!expr_gen.sf4_optimisable(id,sf4opr)) return false; else - result = synthesize_sf4ext_expression::template process + result = synthesize_sf4ext_expression::template process (expr_gen, sf4opr, t0, t1, t2, t3); return true; @@ -29311,28 +30809,28 @@ namespace exprtk typedef details::T0oT1oT2_base_node* sf3ext_base_ptr; sf3ext_base_ptr n = static_cast(sf3node); - std::string id = "t" + expr_gen.to_str(operation) + "(" + n->type_id() + ")"; + const std::string id = "t" + expr_gen.to_str(operation) + "(" + n->type_id() + ")"; switch (n->type()) { case details::expression_node::e_covoc : return compile_right_impl - + (expr_gen, id, t, sf3node, result); case details::expression_node::e_covov : return compile_right_impl - + (expr_gen, id, t, sf3node, result); case details::expression_node::e_vocov : return compile_right_impl - + (expr_gen, id, t, sf3node, result); case details::expression_node::e_vovoc : return compile_right_impl - + (expr_gen, id, t, sf3node, result); case details::expression_node::e_vovov : return compile_right_impl - + (expr_gen, id, t, sf3node, result); default : return false; @@ -29354,28 +30852,28 @@ namespace exprtk sf3ext_base_ptr n = static_cast(sf3node); - std::string id = "(" + n->type_id() + ")" + expr_gen.to_str(operation) + "t"; + const std::string id = "(" + n->type_id() + ")" + expr_gen.to_str(operation) + "t"; switch (n->type()) { case details::expression_node::e_covoc : return compile_left_impl - + (expr_gen, id, t, sf3node, result); case details::expression_node::e_covov : return compile_left_impl - + (expr_gen, id, t, sf3node, result); case details::expression_node::e_vocov : return compile_left_impl - + (expr_gen, id, t, sf3node, result); case details::expression_node::e_vovoc : return compile_left_impl - + (expr_gen, id, t, sf3node, result); case details::expression_node::e_vovov : return compile_left_impl - + (expr_gen, id, t, sf3node, result); default : return false; @@ -29397,7 +30895,7 @@ namespace exprtk T1 t1 = n->t1(); T2 t2 = n->t2(); - return synthesize_sf4ext_expression::template compile + return synthesize_sf4ext_expression::template compile (expr_gen, id, t, t0, t1, t2, result); } else @@ -29419,7 +30917,7 @@ namespace exprtk T1 t1 = n->t1(); T2 t2 = n->t2(); - return synthesize_sf4ext_expression::template compile + return synthesize_sf4ext_expression::template compile (expr_gen, id, t0, t1, t2, t, result); } else @@ -29483,7 +30981,10 @@ namespace exprtk static inline std::string id(expression_generator& expr_gen, const details::operator_type o0, const details::operator_type o1) { - return (details::build_string() << "(t" << expr_gen.to_str(o0) << "t)" << expr_gen.to_str(o1) << "t"); + return details::build_string() + << "(t" << expr_gen.to_str(o0) + << "t)" << expr_gen.to_str(o1) + << "t"; } }; @@ -29543,7 +31044,10 @@ namespace exprtk static inline std::string id(expression_generator& expr_gen, const details::operator_type o0, const details::operator_type o1) { - return (details::build_string() << "t" << expr_gen.to_str(o0) << "(t" << expr_gen.to_str(o1) << "t)"); + return details::build_string() + << "t" << expr_gen.to_str(o0) + << "(t" << expr_gen.to_str(o1) + << "t)"; } }; @@ -29604,7 +31108,10 @@ namespace exprtk static inline std::string id(expression_generator& expr_gen, const details::operator_type o0, const details::operator_type o1) { - return (details::build_string() << "(t" << expr_gen.to_str(o0) << "t)" << expr_gen.to_str(o1) << "t"); + return details::build_string() + << "(t" << expr_gen.to_str(o0) + << "t)" << expr_gen.to_str(o1) + << "t"; } }; @@ -29664,7 +31171,10 @@ namespace exprtk static inline std::string id(expression_generator& expr_gen, const details::operator_type o0, const details::operator_type o1) { - return (details::build_string() << "t" << expr_gen.to_str(o0) << "(t" << expr_gen.to_str(o1) << "t)"); + return details::build_string() + << "t" << expr_gen.to_str(o0) + << "(t" << expr_gen.to_str(o1) + << "t)"; } }; @@ -29724,7 +31234,10 @@ namespace exprtk static inline std::string id(expression_generator& expr_gen, const details::operator_type o0, const details::operator_type o1) { - return (details::build_string() << "(t" << expr_gen.to_str(o0) << "t)" << expr_gen.to_str(o1) << "t"); + return details::build_string() + << "(t" << expr_gen.to_str(o0) + << "t)" << expr_gen.to_str(o1) + << "t"; } }; @@ -29784,7 +31297,10 @@ namespace exprtk static inline std::string id(expression_generator& expr_gen, const details::operator_type o0, const details::operator_type o1) { - return (details::build_string() << "t" << expr_gen.to_str(o0) << "(t" << expr_gen.to_str(o1) << "t)"); + return details::build_string() + << "t" << expr_gen.to_str(o0) + << "(t" << expr_gen.to_str(o1) + << "t)"; } }; @@ -29844,7 +31360,10 @@ namespace exprtk static inline std::string id(expression_generator& expr_gen, const details::operator_type o0, const details::operator_type o1) { - return (details::build_string() << "(t" << expr_gen.to_str(o0) << "t)" << expr_gen.to_str(o1) << "t"); + return details::build_string() + << "(t" << expr_gen.to_str(o0) + << "t)" << expr_gen.to_str(o1) + << "t"; } }; @@ -29904,7 +31423,10 @@ namespace exprtk static inline std::string id(expression_generator& expr_gen, const details::operator_type o0, const details::operator_type o1) { - return (details::build_string() << "t" << expr_gen.to_str(o0) << "(t" << expr_gen.to_str(o1) << "t)"); + return details::build_string() + << "t" << expr_gen.to_str(o0) + << "(t" << expr_gen.to_str(o1) + << "t)"; } }; @@ -30003,7 +31525,7 @@ namespace exprtk const bool synthesis_result = synthesize_sf3ext_expression::template compile - (expr_gen, id(expr_gen, o0, o1), c0, v, c1,result); + (expr_gen, id(expr_gen, o0, o1), c0, v, c1, result); if (synthesis_result) return result; @@ -30018,7 +31540,10 @@ namespace exprtk static inline std::string id(expression_generator& expr_gen, const details::operator_type o0, const details::operator_type o1) { - return (details::build_string() << "(t" << expr_gen.to_str(o0) << "t)" << expr_gen.to_str(o1) << "t"); + return details::build_string() + << "(t" << expr_gen.to_str(o0) + << "t)" << expr_gen.to_str(o1) + << "t"; } }; @@ -30132,7 +31657,10 @@ namespace exprtk static inline std::string id(expression_generator& expr_gen, const details::operator_type o0, const details::operator_type o1) { - return (details::build_string() << "t" << expr_gen.to_str(o0) << "(t" << expr_gen.to_str(o1) << "t)"); + return details::build_string() + << "t" << expr_gen.to_str(o0) + << "(t" << expr_gen.to_str(o1) + << "t)"; } }; @@ -30255,7 +31783,10 @@ namespace exprtk static inline std::string id(expression_generator& expr_gen, const details::operator_type o0, const details::operator_type o1) { - return (details::build_string() << "t" << expr_gen.to_str(o0) << "(t" << expr_gen.to_str(o1) << "t)"); + return details::build_string() + << "t" << expr_gen.to_str(o0) + << "(t" << expr_gen.to_str(o1) + << "t)"; } }; @@ -30377,7 +31908,10 @@ namespace exprtk static inline std::string id(expression_generator& expr_gen, const details::operator_type o0, const details::operator_type o1) { - return (details::build_string() << "(t" << expr_gen.to_str(o0) << "t)" << expr_gen.to_str(o1) << "t"); + return details::build_string() + << "(t" << expr_gen.to_str(o0) + << "t)" << expr_gen.to_str(o1) + << "t"; } }; @@ -30487,7 +32021,7 @@ namespace exprtk const bool synthesis_result = synthesize_sf4ext_expression::template compile - (expr_gen, id(expr_gen, o0, o1, o2), v0, v1, v2, v3,result); + (expr_gen, id(expr_gen, o0, o1, o2), v0, v1, v2, v3, result); if (synthesis_result) return result; @@ -30506,7 +32040,11 @@ namespace exprtk const details::operator_type o1, const details::operator_type o2) { - return (details::build_string() << "(t" << expr_gen.to_str(o0) << "t)" << expr_gen.to_str(o1) << "(t" << expr_gen.to_str(o2) << "t)"); + return details::build_string() + << "(t" << expr_gen.to_str(o0) + << "t)" << expr_gen.to_str(o1) + << "(t" << expr_gen.to_str(o2) + << "t)"; } }; @@ -30590,7 +32128,11 @@ namespace exprtk const details::operator_type o1, const details::operator_type o2) { - return (details::build_string() << "(t" << expr_gen.to_str(o0) << "t)" << expr_gen.to_str(o1) << "(t" << expr_gen.to_str(o2) << "t)"); + return details::build_string() + << "(t" << expr_gen.to_str(o0) + << "t)" << expr_gen.to_str(o1) + << "(t" << expr_gen.to_str(o2) + << "t)"; } }; @@ -30674,7 +32216,11 @@ namespace exprtk const details::operator_type o1, const details::operator_type o2) { - return (details::build_string() << "(t" << expr_gen.to_str(o0) << "t)" << expr_gen.to_str(o1) << "(t" << expr_gen.to_str(o2) << "t)"); + return details::build_string() + << "(t" << expr_gen.to_str(o0) + << "t)" << expr_gen.to_str(o1) + << "(t" << expr_gen.to_str(o2) + << "t)"; } }; @@ -30758,7 +32304,11 @@ namespace exprtk const details::operator_type o1, const details::operator_type o2) { - return (details::build_string() << "(t" << expr_gen.to_str(o0) << "t)" << expr_gen.to_str(o1) << "(t" << expr_gen.to_str(o2) << "t)"); + return details::build_string() + << "(t" << expr_gen.to_str(o0) + << "t)" << expr_gen.to_str(o1) + << "(t" << expr_gen.to_str(o2) + << "t)"; } }; @@ -30842,7 +32392,11 @@ namespace exprtk const details::operator_type o1, const details::operator_type o2) { - return (details::build_string() << "(t" << expr_gen.to_str(o0) << "t)" << expr_gen.to_str(o1) << "(t" << expr_gen.to_str(o2) << "t)"); + return details::build_string() + << "(t" << expr_gen.to_str(o0) + << "t)" << expr_gen.to_str(o1) + << "(t" << expr_gen.to_str(o2) + << "t)"; } }; @@ -31031,7 +32585,11 @@ namespace exprtk const details::operator_type o1, const details::operator_type o2) { - return (details::build_string() << "(t" << expr_gen.to_str(o0) << "t)" << expr_gen.to_str(o1) << "(t" << expr_gen.to_str(o2) << "t)"); + return details::build_string() + << "(t" << expr_gen.to_str(o0) + << "t)" << expr_gen.to_str(o1) + << "(t" << expr_gen.to_str(o2) + << "t)"; } }; @@ -31270,7 +32828,11 @@ namespace exprtk const details::operator_type o1, const details::operator_type o2) { - return (details::build_string() << "(t" << expr_gen.to_str(o0) << "t)" << expr_gen.to_str(o1) << "(t" << expr_gen.to_str(o2) << "t)"); + return details::build_string() + << "(t" << expr_gen.to_str(o0) + << "t)" << expr_gen.to_str(o1) + << "(t" << expr_gen.to_str(o2) + << "t)"; } }; @@ -31459,7 +33021,11 @@ namespace exprtk const details::operator_type o1, const details::operator_type o2) { - return (details::build_string() << "(t" << expr_gen.to_str(o0) << "t)" << expr_gen.to_str(o1) << "(t" << expr_gen.to_str(o2) << "t)"); + return details::build_string() + << "(t" << expr_gen.to_str(o0) + << "t)" << expr_gen.to_str(o1) + << "(t" << expr_gen.to_str(o2) + << "t)"; } }; @@ -31647,7 +33213,11 @@ namespace exprtk const details::operator_type o1, const details::operator_type o2) { - return (details::build_string() << "(t" << expr_gen.to_str(o0) << "t)" << expr_gen.to_str(o1) << "(t" << expr_gen.to_str(o2) << "t)"); + return details::build_string() + << "(t" << expr_gen.to_str(o0) + << "t)" << expr_gen.to_str(o1) + << "(t" << expr_gen.to_str(o2) + << "t)"; } }; @@ -31699,7 +33269,11 @@ namespace exprtk const details::operator_type o1, const details::operator_type o2) { - return (details::build_string() << "t" << expr_gen.to_str(o0) << "(t" << expr_gen.to_str(o1) << "(t" << expr_gen.to_str(o2) << "t))"); + return details::build_string() + << "t" << expr_gen.to_str(o0) + << "(t" << expr_gen.to_str(o1) + << "(t" << expr_gen.to_str(o2) + << "t))"; } }; @@ -31755,7 +33329,11 @@ namespace exprtk const details::operator_type o1, const details::operator_type o2) { - return (details::build_string() << "t" << expr_gen.to_str(o0) << "(t" << expr_gen.to_str(o1) << "(t" << expr_gen.to_str(o2) << "t))"); + return details::build_string() + << "t" << expr_gen.to_str(o0) + << "(t" << expr_gen.to_str(o1) + << "(t" << expr_gen.to_str(o2) + << "t))"; } }; @@ -31811,7 +33389,11 @@ namespace exprtk const details::operator_type o1, const details::operator_type o2) { - return (details::build_string() << "t" << expr_gen.to_str(o0) << "(t" << expr_gen.to_str(o1) << "(t" << expr_gen.to_str(o2) << "t))"); + return details::build_string() + << "t" << expr_gen.to_str(o0) + << "(t" << expr_gen.to_str(o1) + << "(t" << expr_gen.to_str(o2) + << "t))"; } }; @@ -31867,7 +33449,11 @@ namespace exprtk const details::operator_type o1, const details::operator_type o2) { - return (details::build_string() << "t" << expr_gen.to_str(o0) << "(t" << expr_gen.to_str(o1) << "(t" << expr_gen.to_str(o2) << "t))"); + return details::build_string() + << "t" << expr_gen.to_str(o0) + << "(t" << expr_gen.to_str(o1) + << "(t" << expr_gen.to_str(o2) + << "t))"; } }; @@ -31924,7 +33510,11 @@ namespace exprtk const details::operator_type o1, const details::operator_type o2) { - return (details::build_string() << "t" << expr_gen.to_str(o0) << "(t" << expr_gen.to_str(o1) << "(t" << expr_gen.to_str(o2) << "t))"); + return details::build_string() + << "t" << expr_gen.to_str(o0) + << "(t" << expr_gen.to_str(o1) + << "(t" << expr_gen.to_str(o2) + << "t))"; } }; @@ -31981,7 +33571,11 @@ namespace exprtk const details::operator_type o1, const details::operator_type o2) { - return (details::build_string() << "t" << expr_gen.to_str(o0) << "(t" << expr_gen.to_str(o1) << "(t" << expr_gen.to_str(o2) << "t))"); + return details::build_string() + << "t" << expr_gen.to_str(o0) + << "(t" << expr_gen.to_str(o1) + << "(t" << expr_gen.to_str(o2) + << "t))"; } }; @@ -32037,7 +33631,11 @@ namespace exprtk const details::operator_type o1, const details::operator_type o2) { - return (details::build_string() << "t" << expr_gen.to_str(o0) << "(t" << expr_gen.to_str(o1) << "(t" << expr_gen.to_str(o2) << "t))"); + return details::build_string() + << "t" << expr_gen.to_str(o0) + << "(t" << expr_gen.to_str(o1) + << "(t" << expr_gen.to_str(o2) + << "t))"; } }; @@ -32093,7 +33691,11 @@ namespace exprtk const details::operator_type o1, const details::operator_type o2) { - return (details::build_string() << "t" << expr_gen.to_str(o0) << "(t" << expr_gen.to_str(o1) << "(t" << expr_gen.to_str(o2) << "t))"); + return details::build_string() + << "t" << expr_gen.to_str(o0) + << "(t" << expr_gen.to_str(o1) + << "(t" << expr_gen.to_str(o2) + << "t))"; } }; @@ -32149,7 +33751,11 @@ namespace exprtk const details::operator_type o1, const details::operator_type o2) { - return (details::build_string() << "t" << expr_gen.to_str(o0) << "(t" << expr_gen.to_str(o1) << "(t" << expr_gen.to_str(o2) << "t))"); + return details::build_string() + << "t" << expr_gen.to_str(o0) + << "(t" << expr_gen.to_str(o1) + << "(t" << expr_gen.to_str(o2) + << "t))"; } }; @@ -32205,7 +33811,11 @@ namespace exprtk const details::operator_type o1, const details::operator_type o2) { - return (details::build_string() << "t" << expr_gen.to_str(o0) << "((t" << expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t)"); + return details::build_string() + << "t" << expr_gen.to_str(o0) + << "((t" << expr_gen.to_str(o1) + << "t)" << expr_gen.to_str(o2) + << "t)"; } }; @@ -32261,7 +33871,11 @@ namespace exprtk const details::operator_type o1, const details::operator_type o2) { - return (details::build_string() << "t" << expr_gen.to_str(o0) << "((t" << expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t)"); + return details::build_string() + << "t" << expr_gen.to_str(o0) + << "((t" << expr_gen.to_str(o1) + << "t)" << expr_gen.to_str(o2) + << "t)"; } }; @@ -32317,7 +33931,11 @@ namespace exprtk const details::operator_type o1, const details::operator_type o2) { - return (details::build_string() << "t" << expr_gen.to_str(o0) << "((t" << expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t)"); + return details::build_string() + << "t" << expr_gen.to_str(o0) + << "((t" << expr_gen.to_str(o1) + << "t)" << expr_gen.to_str(o2) + << "t)"; } }; @@ -32373,7 +33991,11 @@ namespace exprtk const details::operator_type o1, const details::operator_type o2) { - return (details::build_string() << "t" << expr_gen.to_str(o0) << "((t" << expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t)"); + return details::build_string() + << "t" << expr_gen.to_str(o0) + << "((t" << expr_gen.to_str(o1) + << "t)" << expr_gen.to_str(o2) + << "t)"; } }; @@ -32430,7 +34052,11 @@ namespace exprtk const details::operator_type o1, const details::operator_type o2) { - return (details::build_string() << "t" << expr_gen.to_str(o0) << "((t" << expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t)"); + return details::build_string() + << "t" << expr_gen.to_str(o0) + << "((t" << expr_gen.to_str(o1) + << "t)" << expr_gen.to_str(o2) + << "t)"; } }; @@ -32487,7 +34113,11 @@ namespace exprtk const details::operator_type o1, const details::operator_type o2) { - return (details::build_string() << "t" << expr_gen.to_str(o0) << "((t" << expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t)"); + return details::build_string() + << "t" << expr_gen.to_str(o0) + << "((t" << expr_gen.to_str(o1) + << "t)" << expr_gen.to_str(o2) + << "t)"; } }; @@ -32543,7 +34173,11 @@ namespace exprtk const details::operator_type o1, const details::operator_type o2) { - return (details::build_string() << "t" << expr_gen.to_str(o0) << "((t" << expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t)"); + return details::build_string() + << "t" << expr_gen.to_str(o0) + << "((t" << expr_gen.to_str(o1) + << "t)" << expr_gen.to_str(o2) + << "t)"; } }; @@ -32600,7 +34234,11 @@ namespace exprtk const details::operator_type o1, const details::operator_type o2) { - return (details::build_string() << "t" << expr_gen.to_str(o0) << "((t" << expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t)"); + return details::build_string() + << "t" << expr_gen.to_str(o0) + << "((t" << expr_gen.to_str(o1) + << "t)" << expr_gen.to_str(o2) + << "t)"; } }; @@ -32673,7 +34311,11 @@ namespace exprtk const details::operator_type o1, const details::operator_type o2) { - return (details::build_string() << "((t" << expr_gen.to_str(o0) << "t)" << expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t"); + return details::build_string() + << "((t" << expr_gen.to_str(o0) + << "t)" << expr_gen.to_str(o1) + << "t)" << expr_gen.to_str(o2) + << "t"; } }; @@ -32730,7 +34372,11 @@ namespace exprtk const details::operator_type o1, const details::operator_type o2) { - return (details::build_string() << "((t" << expr_gen.to_str(o0) << "t)" << expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t"); + return details::build_string() + << "((t" << expr_gen.to_str(o0) + << "t)" << expr_gen.to_str(o1) + << "t)" << expr_gen.to_str(o2) + << "t"; } }; @@ -32786,7 +34432,11 @@ namespace exprtk const details::operator_type o1, const details::operator_type o2) { - return (details::build_string() << "((t" << expr_gen.to_str(o0) << "t)" << expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t"); + return details::build_string() + << "((t" << expr_gen.to_str(o0) + << "t)" << expr_gen.to_str(o1) + << "t)" << expr_gen.to_str(o2) + << "t"; } }; @@ -32842,7 +34492,11 @@ namespace exprtk const details::operator_type o1, const details::operator_type o2) { - return (details::build_string() << "((t" << expr_gen.to_str(o0) << "t)" << expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t"); + return details::build_string() + << "((t" << expr_gen.to_str(o0) + << "t)" << expr_gen.to_str(o1) + << "t)" << expr_gen.to_str(o2) + << "t"; } }; @@ -32898,7 +34552,11 @@ namespace exprtk const details::operator_type o1, const details::operator_type o2) { - return (details::build_string() << "((t" << expr_gen.to_str(o0) << "t)" << expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t"); + return details::build_string() + << "((t" << expr_gen.to_str(o0) + << "t)" << expr_gen.to_str(o1) + << "t)" << expr_gen.to_str(o2) + << "t"; } }; @@ -32954,7 +34612,11 @@ namespace exprtk const details::operator_type o1, const details::operator_type o2) { - return (details::build_string() << "((t" << expr_gen.to_str(o0) << "t)" << expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t"); + return details::build_string() + << "((t" << expr_gen.to_str(o0) + << "t)" << expr_gen.to_str(o1) + << "t)" << expr_gen.to_str(o2) + << "t"; } }; @@ -33011,7 +34673,11 @@ namespace exprtk const details::operator_type o1, const details::operator_type o2) { - return (details::build_string() << "((t" << expr_gen.to_str(o0) << "t)" << expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t"); + return details::build_string() + << "((t" << expr_gen.to_str(o0) + << "t)" << expr_gen.to_str(o1) + << "t)" << expr_gen.to_str(o2) + << "t"; } }; @@ -33068,7 +34734,11 @@ namespace exprtk const details::operator_type o1, const details::operator_type o2) { - return (details::build_string() << "((t" << expr_gen.to_str(o0) << "t)" << expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t"); + return details::build_string() + << "((t" << expr_gen.to_str(o0) + << "t)" << expr_gen.to_str(o1) + << "t)" << expr_gen.to_str(o2) + << "t"; } }; @@ -33124,7 +34794,11 @@ namespace exprtk const details::operator_type o1, const details::operator_type o2) { - return (details::build_string() << "((t" << expr_gen.to_str(o0) << "t)" << expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t"); + return details::build_string() + << "((t" << expr_gen.to_str(o0) + << "t)" << expr_gen.to_str(o1) + << "t)" << expr_gen.to_str(o2) + << "t"; } }; @@ -33180,7 +34854,11 @@ namespace exprtk const details::operator_type o1, const details::operator_type o2) { - return (details::build_string() << "(t" << expr_gen.to_str(o0) << "(t" << expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t"); + return details::build_string() + << "(t" << expr_gen.to_str(o0) + << "(t" << expr_gen.to_str(o1) + << "t)" << expr_gen.to_str(o2) + << "t"; } }; @@ -33237,7 +34915,11 @@ namespace exprtk const details::operator_type o1, const details::operator_type o2) { - return (details::build_string() << "(t" << expr_gen.to_str(o0) << "(t" << expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t"); + return details::build_string() + << "(t" << expr_gen.to_str(o0) + << "(t" << expr_gen.to_str(o1) + << "t)" << expr_gen.to_str(o2) + << "t"; } }; @@ -33293,7 +34975,11 @@ namespace exprtk const details::operator_type o1, const details::operator_type o2) { - return (details::build_string() << "(t" << expr_gen.to_str(o0) << "(t" << expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t"); + return details::build_string() + << "(t" << expr_gen.to_str(o0) + << "(t" << expr_gen.to_str(o1) + << "t)" << expr_gen.to_str(o2) + << "t"; } }; @@ -33348,7 +35034,11 @@ namespace exprtk const details::operator_type o1, const details::operator_type o2) { - return (details::build_string() << "(t" << expr_gen.to_str(o0) << "(t" << expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t"); + return details::build_string() + << "(t" << expr_gen.to_str(o0) + << "(t" << expr_gen.to_str(o1) + << "t)" << expr_gen.to_str(o2) + << "t"; } }; @@ -33404,7 +35094,11 @@ namespace exprtk const details::operator_type o1, const details::operator_type o2) { - return (details::build_string() << "(t" << expr_gen.to_str(o0) << "(t" << expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t"); + return details::build_string() + << "(t" << expr_gen.to_str(o0) + << "(t" << expr_gen.to_str(o1) + << "t)" << expr_gen.to_str(o2) + << "t"; } }; @@ -33460,7 +35154,11 @@ namespace exprtk const details::operator_type o1, const details::operator_type o2) { - return (details::build_string() << "(t" << expr_gen.to_str(o0) << "(t" << expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t"); + return details::build_string() + << "(t" << expr_gen.to_str(o0) + << "(t" << expr_gen.to_str(o1) + << "t)" << expr_gen.to_str(o2) + << "t"; } }; @@ -33517,7 +35215,11 @@ namespace exprtk const details::operator_type o1, const details::operator_type o2) { - return (details::build_string() << "(t" << expr_gen.to_str(o0) << "(t" << expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t"); + return details::build_string() + << "(t" << expr_gen.to_str(o0) + << "(t" << expr_gen.to_str(o1) + << "t)" << expr_gen.to_str(o2) + << "t"; } }; @@ -33574,7 +35276,11 @@ namespace exprtk const details::operator_type o1, const details::operator_type o2) { - return (details::build_string() << "(t" << expr_gen.to_str(o0) << "(t" << expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t"); + return details::build_string() + << "(t" << expr_gen.to_str(o0) + << "(t" << expr_gen.to_str(o1) + << "t)" << expr_gen.to_str(o2) + << "t"; } }; @@ -33941,8 +35647,8 @@ namespace exprtk { const std::string s0 = static_cast*>(branch[0])->str (); std::string& s1 = static_cast*> (branch[1])->ref (); - range_t rp0 = static_cast*>(branch[0])->range(); - range_t rp1 = static_cast*> (branch[1])->range(); + const range_t rp0 = static_cast*>(branch[0])->range(); + const range_t rp1 = static_cast*> (branch[1])->range(); static_cast*>(branch[0])->range_ref().clear(); static_cast*> (branch[1])->range_ref().clear(); @@ -33955,9 +35661,9 @@ namespace exprtk inline expression_node_ptr synthesize_csrocs_expression(const details::operator_type& opr, expression_node_ptr (&branch)[2]) { - std::string s0 = static_cast*>(branch[0])->str (); + const std::string s0 = static_cast*>(branch[0])->str (); const std::string s1 = static_cast*> (branch[1])->str (); - range_t rp0 = static_cast*>(branch[0])->range(); + const range_t rp0 = static_cast*>(branch[0])->range(); static_cast*>(branch[0])->range_ref().clear(); @@ -33968,10 +35674,10 @@ namespace exprtk inline expression_node_ptr synthesize_csrocsr_expression(const details::operator_type& opr, expression_node_ptr (&branch)[2]) { - std::string s0 = static_cast*>(branch[0])->str (); - std::string s1 = static_cast*>(branch[1])->str (); - range_t rp0 = static_cast*>(branch[0])->range(); - range_t rp1 = static_cast*>(branch[1])->range(); + const std::string s0 = static_cast*>(branch[0])->str (); + const std::string s1 = static_cast*>(branch[1])->str (); + const range_t rp0 = static_cast*>(branch[0])->range(); + const range_t rp1 = static_cast*>(branch[1])->range(); static_cast*>(branch[0])->range_ref().clear(); static_cast*>(branch[1])->range_ref().clear(); @@ -34121,9 +35827,9 @@ namespace exprtk std::string& s1 = static_cast*>(branch[1])->ref(); std::string& s2 = static_cast*>(branch[2])->ref(); - typedef typename details::sosos_node > inrange_t; + typedef typename details::sosos_node > inrange_t; - return node_allocator_->allocate_type(s0,s1,s2); + return node_allocator_->allocate_type(s0, s1, s2); } else if ( details::is_const_string_node(branch[0]) && @@ -34135,12 +35841,12 @@ namespace exprtk std::string& s1 = static_cast< details::stringvar_node*>(branch[1])->ref(); std::string s2 = static_cast*>(branch[2])->str(); - typedef typename details::sosos_node > inrange_t; + typedef typename details::sosos_node > inrange_t; details::free_node(*node_allocator_,branch[0]); details::free_node(*node_allocator_,branch[2]); - return node_allocator_->allocate_type(s0,s1,s2); + return node_allocator_->allocate_type(s0, s1, s2); } else if ( details::is_string_node(branch[0]) && @@ -34152,11 +35858,11 @@ namespace exprtk std::string s1 = static_cast*>(branch[1])->str(); std::string& s2 = static_cast< details::stringvar_node*>(branch[2])->ref(); - typedef typename details::sosos_node > inrange_t; + typedef typename details::sosos_node > inrange_t; details::free_node(*node_allocator_,branch[1]); - return node_allocator_->allocate_type(s0,s1,s2); + return node_allocator_->allocate_type(s0, s1, s2); } else if ( details::is_string_node(branch[0]) && @@ -34168,11 +35874,11 @@ namespace exprtk std::string& s1 = static_cast< details::stringvar_node*>(branch[1])->ref(); std::string s2 = static_cast*>(branch[2])->str(); - typedef typename details::sosos_node > inrange_t; + typedef typename details::sosos_node > inrange_t; details::free_node(*node_allocator_,branch[2]); - return node_allocator_->allocate_type(s0,s1,s2); + return node_allocator_->allocate_type(s0, s1, s2); } else if ( details::is_const_string_node(branch[0]) && @@ -34184,11 +35890,11 @@ namespace exprtk std::string& s1 = static_cast< details::stringvar_node*>(branch[1])->ref(); std::string& s2 = static_cast< details::stringvar_node*>(branch[2])->ref(); - typedef typename details::sosos_node > inrange_t; + typedef typename details::sosos_node > inrange_t; details::free_node(*node_allocator_,branch[0]); - return node_allocator_->allocate_type(s0,s1,s2); + return node_allocator_->allocate_type(s0, s1, s2); } else return error_node(); @@ -34216,8 +35922,8 @@ namespace exprtk typedef typename details::null_eq_node nulleq_node_t; - bool b0_null = details::is_null_node(branch[0]); - bool b1_null = details::is_null_node(branch[1]); + const bool b0_null = details::is_null_node(branch[0]); + const bool b1_null = details::is_null_node(branch[1]); if (b0_null && b1_null) { @@ -34278,21 +35984,22 @@ namespace exprtk { return branch[0]; } - else if ( - (details::e_lt == operation) || (details::e_lte == operation) || - (details::e_gt == operation) || (details::e_gte == operation) || - (details::e_and == operation) || (details::e_nand == operation) || - (details::e_or == operation) || (details::e_nor == operation) || - (details::e_xor == operation) || (details::e_xnor == operation) || - (details::e_in == operation) || (details::e_like == operation) || - (details::e_ilike == operation) - ) + + details::free_node(*node_allocator_, branch[0]); + + if ( + (details::e_lt == operation) || (details::e_lte == operation) || + (details::e_gt == operation) || (details::e_gte == operation) || + (details::e_and == operation) || (details::e_nand == operation) || + (details::e_or == operation) || (details::e_nor == operation) || + (details::e_xor == operation) || (details::e_xnor == operation) || + (details::e_in == operation) || (details::e_like == operation) || + (details::e_ilike == operation) + ) { return node_allocator_->allocate_c(T(0)); } - details::free_node(*node_allocator_,branch[0]); - return node_allocator_->allocate >(); } @@ -34322,7 +36029,7 @@ namespace exprtk if (is_constant_foldable(branch)) { - Type v = expression_point->value(); + const Type v = expression_point->value(); details::free_node(*node_allocator_,expression_point); return node_allocator_->allocate(v); @@ -34688,48 +36395,125 @@ namespace exprtk lexer::helper::helper_assembly helper_assembly_; - lexer::helper::commutative_inserter commutative_inserter_; - lexer::helper::operator_joiner operator_joiner_2_; - 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::sequence_validator sequence_validator_; + lexer::helper::commutative_inserter commutative_inserter_; + lexer::helper::operator_joiner operator_joiner_2_; + 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::sequence_validator sequence_validator_; + lexer::helper::sequence_validator_3tokens sequence_validator_3tkns_; + + loop_runtime_check_ptr loop_runtime_check_; template friend void details::disable_type_checking(ParserType& p); }; + namespace details + { + template + struct collector_helper + { + typedef exprtk::symbol_table symbol_table_t; + typedef exprtk::expression expression_t; + typedef exprtk::parser parser_t; + typedef typename parser_t::dependent_entity_collector::symbol_t symbol_t; + typedef typename parser_t::unknown_symbol_resolver usr_t; + + struct resolve_as_vector : public parser_t::unknown_symbol_resolver + { + typedef exprtk::parser parser_t; + + resolve_as_vector() + : usr_t(usr_t::e_usrmode_extended) + {} + + virtual bool process(const std::string& unknown_symbol, + symbol_table_t& symbol_table, + std::string&) + { + static T v[1]; + symbol_table.add_vector(unknown_symbol,v); + return true; + } + }; + + static inline bool collection_pass(const std::string& expression_string, + std::set& symbol_set, + const bool collect_variables, + const bool collect_functions, + const bool vector_pass, + symbol_table_t& ext_symbol_table) + { + symbol_table_t symbol_table; + expression_t expression; + parser_t parser; + + resolve_as_vector vect_resolver; + + expression.register_symbol_table(symbol_table ); + expression.register_symbol_table(ext_symbol_table); + + if (vector_pass) + parser.enable_unknown_symbol_resolver(&vect_resolver); + else + parser.enable_unknown_symbol_resolver(); + + if (collect_variables) + parser.dec().collect_variables() = true; + + if (collect_functions) + parser.dec().collect_functions() = true; + + bool pass_result = false; + + details::disable_type_checking(parser); + + if (parser.compile(expression_string, expression)) + { + pass_result = true; + + std::deque symb_list; + parser.dec().symbols(symb_list); + + for (std::size_t i = 0; i < symb_list.size(); ++i) + { + symbol_set.insert(symb_list[i].first); + } + } + + return pass_result; + } + }; + } + template class Sequence> - inline bool collect_variables(const std::string& expr_str, + inline bool collect_variables(const std::string& expression, Sequence& symbol_list) { typedef double T; - typedef exprtk::symbol_table symbol_table_t; - typedef exprtk::expression expression_t; - typedef exprtk::parser parser_t; - typedef parser_t::dependent_entity_collector::symbol_t symbol_t; + typedef details::collector_helper collect_t; - symbol_table_t symbol_table; - expression_t expression; - parser_t parser; + collect_t::symbol_table_t null_symbol_table; - expression.register_symbol_table(symbol_table); + std::set symbol_set; - parser.enable_unknown_symbol_resolver(); - parser.dec().collect_variables() = true; + const bool variable_pass = collect_t::collection_pass + (expression, symbol_set, true, false, false, null_symbol_table); + const bool vector_pass = collect_t::collection_pass + (expression, symbol_set, true, false, true, null_symbol_table); - if (!parser.compile(expr_str, expression)) + if (!variable_pass && !vector_pass) return false; - std::deque symb_list; + std::set::iterator itr = symbol_set.begin(); - parser.dec().symbols(symb_list); - - for (std::size_t i = 0; i < symb_list.size(); ++i) + while (symbol_set.end() != itr) { - symbol_list.push_back(symb_list[i].first); + symbol_list.push_back(*itr); + ++itr; } return true; @@ -34738,37 +36522,28 @@ namespace exprtk template class Sequence> - inline bool collect_variables(const std::string& expr_str, + inline bool collect_variables(const std::string& expression, exprtk::symbol_table& extrnl_symbol_table, Sequence& symbol_list) { - typedef exprtk::symbol_table symbol_table_t; - typedef exprtk::expression expression_t; - typedef exprtk::parser parser_t; - typedef typename parser_t::dependent_entity_collector::symbol_t symbol_t; - - symbol_table_t symbol_table; - expression_t expression; - parser_t parser; - - expression.register_symbol_table(symbol_table); - expression.register_symbol_table(extrnl_symbol_table); + typedef details::collector_helper collect_t; - parser.enable_unknown_symbol_resolver(); - parser.dec().collect_variables() = true; + std::set symbol_set; - details::disable_type_checking(parser); + const bool variable_pass = collect_t::collection_pass + (expression, symbol_set, true, false, false, extrnl_symbol_table); + const bool vector_pass = collect_t::collection_pass + (expression, symbol_set, true, false, true, extrnl_symbol_table); - if (!parser.compile(expr_str, expression)) + if (!variable_pass && !vector_pass) return false; - std::deque symb_list; - - parser.dec().symbols(symb_list); + std::set::iterator itr = symbol_set.begin(); - for (std::size_t i = 0; i < symb_list.size(); ++i) + while (symbol_set.end() != itr) { - symbol_list.push_back(symb_list[i].first); + symbol_list.push_back(*itr); + ++itr; } return true; @@ -34776,34 +36551,30 @@ namespace exprtk template class Sequence> - inline bool collect_functions(const std::string& expr_str, + inline bool collect_functions(const std::string& expression, Sequence& symbol_list) { typedef double T; - typedef exprtk::symbol_table symbol_table_t; - typedef exprtk::expression expression_t; - typedef exprtk::parser parser_t; - typedef parser_t::dependent_entity_collector::symbol_t symbol_t; + typedef details::collector_helper collect_t; - symbol_table_t symbol_table; - expression_t expression; - parser_t parser; + collect_t::symbol_table_t null_symbol_table; - expression.register_symbol_table(symbol_table); + std::set symbol_set; - parser.enable_unknown_symbol_resolver(); - parser.dec().collect_functions() = true; + const bool variable_pass = collect_t::collection_pass + (expression, symbol_set, false, true, false, null_symbol_table); + const bool vector_pass = collect_t::collection_pass + (expression, symbol_set, false, true, true, null_symbol_table); - if (!parser.compile(expr_str, expression)) + if (!variable_pass && !vector_pass) return false; - std::deque symb_list; + std::set::iterator itr = symbol_set.begin(); - parser.dec().symbols(symb_list); - - for (std::size_t i = 0; i < symb_list.size(); ++i) + while (symbol_set.end() != itr) { - symbol_list.push_back(symb_list[i].first); + symbol_list.push_back(*itr); + ++itr; } return true; @@ -34812,37 +36583,28 @@ namespace exprtk template class Sequence> - inline bool collect_functions(const std::string& expr_str, + inline bool collect_functions(const std::string& expression, exprtk::symbol_table& extrnl_symbol_table, Sequence& symbol_list) { - typedef exprtk::symbol_table symbol_table_t; - typedef exprtk::expression expression_t; - typedef exprtk::parser parser_t; - typedef typename parser_t::dependent_entity_collector::symbol_t symbol_t; - - symbol_table_t symbol_table; - expression_t expression; - parser_t parser; - - expression.register_symbol_table(symbol_table); - expression.register_symbol_table(extrnl_symbol_table); + typedef details::collector_helper collect_t; - parser.enable_unknown_symbol_resolver(); - parser.dec().collect_functions() = true; + std::set symbol_set; - details::disable_type_checking(parser); + const bool variable_pass = collect_t::collection_pass + (expression, symbol_set, false, true, false, extrnl_symbol_table); + const bool vector_pass = collect_t::collection_pass + (expression, symbol_set, false, true, true, extrnl_symbol_table); - if (!parser.compile(expr_str, expression)) + if (!variable_pass && !vector_pass) return false; - std::deque symb_list; - - parser.dec().symbols(symb_list); + std::set::iterator itr = symbol_set.begin(); - for (std::size_t i = 0; i < symb_list.size(); ++i) + while (symbol_set.end() != itr) { - symbol_list.push_back(symb_list[i].first); + symbol_list.push_back(*itr); + ++itr; } return true; @@ -34888,8 +36650,8 @@ namespace exprtk if (var) { T& x = var->ref(); - T x_original = x; - T result = integrate(e,x,r0,r1,number_of_intervals); + const T x_original = x; + const T result = integrate(e, x, r0, r1, number_of_intervals); x = x_original; return result; @@ -34979,8 +36741,8 @@ namespace exprtk if (var) { T& x = var->ref(); - T x_original = x; - T result = derivative(e,x,h); + const T x_original = x; + const T result = derivative(e, x, h); x = x_original; return result; @@ -35007,7 +36769,7 @@ namespace exprtk { T& x = var->ref(); const T x_original = x; - const T result = second_derivative(e,x,h); + const T result = second_derivative(e, x, h); x = x_original; return result; @@ -35034,7 +36796,7 @@ namespace exprtk { T& x = var->ref(); const T x_original = x; - const T result = third_derivative(e,x,h); + const T result = third_derivative(e, x, h); x = x_original; return result; @@ -35327,62 +37089,62 @@ namespace exprtk inline virtual T operator() (const T& x, const T& c1, const T& c0) { - poly_rtrn(1) poly_impl::evaluate(x,c1,c0); + poly_rtrn(1) (poly_impl::evaluate(x, c1, c0)); } inline virtual T operator() (const T& x, const T& c2, const T& c1, const T& c0) { - poly_rtrn(2) poly_impl::evaluate(x,c2,c1,c0); + poly_rtrn(2) (poly_impl::evaluate(x, c2, c1, c0)); } inline virtual T operator() (const T& x, const T& c3, const T& c2, const T& c1, const T& c0) { - poly_rtrn(3) poly_impl::evaluate(x,c3,c2,c1,c0); + poly_rtrn(3) (poly_impl::evaluate(x, c3, c2, c1, c0)); } inline virtual T operator() (const T& x, const T& c4, const T& c3, const T& c2, const T& c1, const T& c0) { - poly_rtrn(4) poly_impl::evaluate(x,c4,c3,c2,c1,c0); + poly_rtrn(4) (poly_impl::evaluate(x, c4, c3, c2, c1, c0)); } inline virtual T operator() (const T& x, const T& c5, const T& c4, const T& c3, const T& c2, const T& c1, const T& c0) { - poly_rtrn(5) poly_impl::evaluate(x,c5,c4,c3,c2,c1,c0); + poly_rtrn(5) (poly_impl::evaluate(x, c5, c4, c3, c2, c1, c0)); } inline virtual T operator() (const T& x, const T& c6, const T& c5, const T& c4, const T& c3, const T& c2, const T& c1, const T& c0) { - poly_rtrn(6) poly_impl::evaluate(x,c6,c5,c4,c3,c2,c1,c0); + poly_rtrn(6) (poly_impl::evaluate(x, c6, c5, c4, c3, c2, c1, c0)); } inline virtual T operator() (const T& x, const T& c7, const T& c6, const T& c5, const T& c4, const T& c3, const T& c2, const T& c1, const T& c0) { - poly_rtrn(7) poly_impl::evaluate(x,c7,c6,c5,c4,c3,c2,c1,c0); + poly_rtrn(7) (poly_impl::evaluate(x, c7, c6, c5, c4, c3, c2, c1, c0)); } inline virtual T operator() (const T& x, const T& c8, const T& c7, const T& c6, const T& c5, const T& c4, const T& c3, const T& c2, const T& c1, const T& c0) { - poly_rtrn(8) poly_impl::evaluate(x,c8,c7,c6,c5,c4,c3,c2,c1,c0); + poly_rtrn(8) (poly_impl::evaluate(x, c8, c7, c6, c5, c4, c3, c2, c1, c0)); } inline virtual T operator() (const T& x, const T& c9, const T& c8, const T& c7, const T& c6, const T& c5, const T& c4, const T& c3, const T& c2, const T& c1, const T& c0) { - poly_rtrn(9) poly_impl::evaluate(x,c9,c8,c7,c6,c5,c4,c3,c2,c1,c0); + poly_rtrn(9) (poly_impl::evaluate(x, c9, c8, c7, c6, c5, c4, c3, c2, c1, c0)); } inline virtual T operator() (const T& x, const T& c10, const T& c9, const T& c8, const T& c7, const T& c6, const T& c5, const T& c4, const T& c3, const T& c2, const T& c1, const T& c0) { - poly_rtrn(10) poly_impl::evaluate(x,c10,c9,c8,c7,c6,c5,c4,c3,c2,c1,c0); + poly_rtrn(10) (poly_impl::evaluate(x, c10, c9, c8, c7, c6, c5, c4, c3, c2, c1, c0)); } inline virtual T operator() (const T& x, const T& c11, const T& c10, const T& c9, const T& c8, const T& c7, const T& c6, const T& c5, const T& c4, const T& c3, const T& c2, const T& c1, const T& c0) { - poly_rtrn(11) poly_impl::evaluate(x,c11,c10,c9,c8,c7,c6,c5,c4,c3,c2,c1,c0); + poly_rtrn(11) (poly_impl::evaluate(x, c11, c10, c9, c8, c7, c6, c5, c4, c3, c2, c1, c0)); } inline virtual T operator() (const T& x, const T& c12, const T& c11, const T& c10, const T& c9, const T& c8, const T& c7, const T& c6, const T& c5, const T& c4, const T& c3, const T& c2, const T& c1, const T& c0) { - poly_rtrn(12) poly_impl::evaluate(x,c12,c11,c10,c9,c8,c7,c6,c5,c4,c3,c2,c1,c0); + poly_rtrn(12) (poly_impl::evaluate(x, c12, c11, c10, c9, c8, c7, c6, c5, c4, c3, c2, c1, c0)); } #undef poly_rtrn @@ -35570,7 +37332,7 @@ namespace exprtk typedef typename expression_t::control_block::local_data_list_t ldl_t; - ldl_t ldl = expr.local_data_list(); + const ldl_t ldl = expr.local_data_list(); std::vector index_list; @@ -35840,7 +37602,7 @@ namespace exprtk typedef typename results_context_t::type_store_t type_t; typedef typename type_t::scalar_view scalar_t; - T result = e.value(); + const T result = e.value(); if (e.return_invoked()) { @@ -35871,7 +37633,7 @@ namespace exprtk def_fp_retval(6) template class Sequence> + template class Sequence> inline bool add(const std::string& name, const std::string& expression, const Sequence& var_list, @@ -35967,7 +37729,7 @@ namespace exprtk private: template class Sequence> + template class Sequence> bool compile_expression(const std::string& name, const std::string& expression, const Sequence& input_var_list, @@ -36149,89 +37911,90 @@ namespace exprtk 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::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); @@ -36286,8 +38049,8 @@ namespace exprtk { static const T lower_bound = T(-20); static const T upper_bound = T(+20); + static const T delta = T(0.1); - T delta = T(0.1); T total = T(0); for (x = lower_bound; x <= upper_bound; x += delta) @@ -36311,7 +38074,7 @@ namespace exprtk { for (std::size_t i = 0; i < 10000; ++i) { - T v = T(123.456 + 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; @@ -36416,14 +38179,14 @@ namespace exprtk { if (stop_time_.tv_sec >= start_time_.tv_sec) { - return 1000000LLU * static_cast(stop_time_.tv_sec - start_time_.tv_sec ) + - static_cast(stop_time_.tv_usec - start_time_.tv_usec) ; + return 1000000LLU * static_cast(stop_time_.tv_sec - start_time_.tv_sec ) + + static_cast(stop_time_.tv_usec - start_time_.tv_usec) ; } else - return std::numeric_limits::max(); + return std::numeric_limits::max(); } else - return std::numeric_limits::max(); + return std::numeric_limits::max(); } inline double time() const @@ -36585,8 +38348,8 @@ namespace exprtk return false; \ } \ - exprtk_register_function("print" , p) - exprtk_register_function("println" ,pl) + exprtk_register_function("print" , p) + exprtk_register_function("println", pl) #undef exprtk_register_function return true; @@ -36754,7 +38517,7 @@ namespace exprtk } } - bool eof() + bool eof() const { switch (mode) { @@ -36765,7 +38528,7 @@ namespace exprtk } } - file_mode get_file_mode(const std::string& access) + file_mode get_file_mode(const std::string& access) const { if (access.empty() || access.size() > 2) return e_error; @@ -36843,11 +38606,9 @@ namespace exprtk inline T operator() (const std::size_t& ps_index, parameter_list_t parameters) { - std::string file_name; + std::string file_name = to_str(string_t(parameters[0])); std::string access; - file_name = to_str(string_t(parameters[0])); - if (file_name.empty()) return T(0); @@ -36928,27 +38689,27 @@ namespace exprtk case 0 : { const string_t buffer(parameters[1]); amount = buffer.size(); - return T(fd->write(buffer,amount) ? 1 : 0); + return T(fd->write(buffer, amount) ? 1 : 0); } case 1 : { const string_t buffer(parameters[1]); amount = std::min(buffer.size(), static_cast(scalar_t(parameters[2])())); - return T(fd->write(buffer,amount) ? 1 : 0); + return T(fd->write(buffer, amount) ? 1 : 0); } case 2 : { const vector_t vec(parameters[1]); amount = vec.size(); - return T(fd->write(vec,amount) ? 1 : 0); + return T(fd->write(vec, amount) ? 1 : 0); } case 3 : { const vector_t vec(parameters[1]); amount = std::min(vec.size(), static_cast(scalar_t(parameters[2])())); - return T(fd->write(vec,amount) ? 1 : 0); + return T(fd->write(vec, amount) ? 1 : 0); } } @@ -37149,10 +38910,10 @@ namespace exprtk namespace details { template - inline void kahan_sum(T& sum, T& error, T v) + inline void kahan_sum(T& sum, T& error, const T v) { - T x = v - error; - T y = sum + x; + const T x = v - error; + const T y = sum + x; error = (y - sum) - x; sum = y; } @@ -37477,10 +39238,13 @@ namespace exprtk ) return T(0); - std::size_t dist = r1 - r0 + 1; - std::size_t shift = n % dist; + const std::size_t dist = r1 - r0 + 1; + const std::size_t shift = n % dist; - std::rotate(vec.begin() + r0, vec.begin() + r0 + shift, vec.begin() + r1 + 1); + std::rotate( + vec.begin() + r0, + vec.begin() + r0 + shift, + vec.begin() + r1 + 1); return T(1); } @@ -37528,7 +39292,10 @@ namespace exprtk std::size_t dist = r1 - r0 + 1; std::size_t shift = (dist - (n % dist)) % dist; - std::rotate(vec.begin() + r0, vec.begin() + r0 + shift, vec.begin() + r1 + 1); + std::rotate( + vec.begin() + r0, + vec.begin() + r0 + shift, + vec.begin() + r1 + 1); return T(1); } @@ -37573,12 +39340,15 @@ namespace exprtk ) return T(0); - std::size_t dist = r1 - r0 + 1; + const std::size_t dist = r1 - r0 + 1; if (n > dist) return T(0); - std::rotate(vec.begin() + r0, vec.begin() + r0 + n, vec.begin() + r1 + 1); + std::rotate( + vec.begin() + r0, + vec.begin() + r0 + n, + vec.begin() + r1 + 1); for (std::size_t i = r1 - n + 1; i <= r1; ++i) { @@ -37628,14 +39398,17 @@ namespace exprtk ) return T(0); - std::size_t dist = r1 - r0 + 1; + const std::size_t dist = r1 - r0 + 1; if (n > dist) return T(0); - std::size_t shift = (dist - (n % dist)) % dist; + const std::size_t shift = (dist - (n % dist)) % dist; - std::rotate(vec.begin() + r0, vec.begin() + r0 + shift, vec.begin() + r1 + 1); + std::rotate( + vec.begin() + r0, + vec.begin() + r0 + shift, + vec.begin() + r1 + 1); for (std::size_t i = r0; i < r0 + n; ++i) { @@ -37873,10 +39646,10 @@ namespace exprtk if ((1 == ps_index) && !helper::load_vector_range::process(parameters, r0, r1, 3, 4, 1)) return std::numeric_limits::quiet_NaN(); - else if (helper::invalid_range(y,r0,r1)) + else if (helper::invalid_range(y, r0, r1)) return std::numeric_limits::quiet_NaN(); - T a = scalar_t(parameters[0])(); + const T a = scalar_t(parameters[0])(); for (std::size_t i = r0; i <= r1; ++i) { @@ -37920,7 +39693,7 @@ namespace exprtk if ((1 == ps_index) && !helper::load_vector_range::process(parameters, r0, r1, 4, 5, 1)) return std::numeric_limits::quiet_NaN(); - else if (helper::invalid_range(y,r0,r1)) + else if (helper::invalid_range(y, r0, r1)) return std::numeric_limits::quiet_NaN(); const T a = scalar_t(parameters[0])(); @@ -37969,12 +39742,12 @@ namespace exprtk if ((1 == ps_index) && !helper::load_vector_range::process(parameters, r0, r1, 3, 4, 1)) return std::numeric_limits::quiet_NaN(); - else if (helper::invalid_range(y,r0,r1)) + else if (helper::invalid_range(y, r0, r1)) return std::numeric_limits::quiet_NaN(); - else if (helper::invalid_range(z,r0,r1)) + else if (helper::invalid_range(z, r0, r1)) return std::numeric_limits::quiet_NaN(); - T a = scalar_t(parameters[0])(); + const T a = scalar_t(parameters[0])(); for (std::size_t i = r0; i <= r1; ++i) { @@ -38019,9 +39792,9 @@ namespace exprtk if ((1 == ps_index) && !helper::load_vector_range::process(parameters, r0, r1, 4, 5, 1)) return std::numeric_limits::quiet_NaN(); - else if (helper::invalid_range(y,r0,r1)) + else if (helper::invalid_range(y, r0, r1)) return std::numeric_limits::quiet_NaN(); - else if (helper::invalid_range(z,r0,r1)) + else if (helper::invalid_range(z, r0, r1)) return std::numeric_limits::quiet_NaN(); const T a = scalar_t(parameters[0])(); @@ -38069,7 +39842,7 @@ namespace exprtk if ((1 == ps_index) && !helper::load_vector_range::process(parameters, r0, r1, 4, 5, 1)) return std::numeric_limits::quiet_NaN(); - else if (helper::invalid_range(z,r0,r1)) + else if (helper::invalid_range(z, r0, r1)) return std::numeric_limits::quiet_NaN(); const T a = scalar_t(parameters[0])(); @@ -38116,7 +39889,7 @@ namespace exprtk if ((1 == ps_index) && !helper::load_vector_range::process(parameters, r0, r1, 2, 3, 0)) return std::numeric_limits::quiet_NaN(); - else if (helper::invalid_range(y,r0,r1)) + else if (helper::invalid_range(y, r0, r1)) return std::numeric_limits::quiet_NaN(); T result = T(0); @@ -38162,7 +39935,7 @@ namespace exprtk if ((1 == ps_index) && !helper::load_vector_range::process(parameters, r0, r1, 2, 3, 0)) return std::numeric_limits::quiet_NaN(); - else if (helper::invalid_range(y,r0,r1)) + else if (helper::invalid_range(y, r0, r1)) return std::numeric_limits::quiet_NaN(); T result = T(0); @@ -38218,7 +39991,7 @@ namespace exprtk exprtk_register_function("any_true" ,nt) exprtk_register_function("any_false" ,nf) exprtk_register_function("count" , c) - exprtk_register_function("copy" , cp) + exprtk_register_function("copy" ,cp) exprtk_register_function("rotate_left" ,rl) exprtk_register_function("rol" ,rl) exprtk_register_function("rotate_right" ,rr) @@ -38252,9 +40025,11 @@ namespace exprtk namespace information { static const char* library = "Mathematical Expression Toolkit"; - static const char* version = "2.71828182845904523536028747135266249775724709369" - "9959574966967627724076630353547594571382178525166"; - static const char* date = "20180101"; + static const char* version = "2.71828182845904523536028747135" + "2662497757247093699959574966967" + "6277240766303535475945713821785" + "2516642742746639193200305992181"; + static const char* date = "20200101"; static inline std::string data() { diff --git a/exprtk_benchmark.cpp b/exprtk_benchmark.cpp index e219765..8e9c5fa 100644 --- a/exprtk_benchmark.cpp +++ b/exprtk_benchmark.cpp @@ -3,7 +3,7 @@ * C++ Mathematical Expression Toolkit Library * * * * ExprTk vs Native Benchmarks * - * Author: Arash Partow (1999-2018) * + * Author: Arash Partow (1999-2020) * * URL: http://www.partow.net/programming/exprtk/index.html * * * * Copyright notice: * diff --git a/exprtk_simple_example_01.cpp b/exprtk_simple_example_01.cpp index 04656bd..80eafe1 100644 --- a/exprtk_simple_example_01.cpp +++ b/exprtk_simple_example_01.cpp @@ -3,7 +3,7 @@ * C++ Mathematical Expression Toolkit Library * * * * Simple Example 1 * - * Author: Arash Partow (1999-2018) * + * Author: Arash Partow (1999-2020) * * URL: http://www.partow.net/programming/exprtk/index.html * * * * Copyright notice: * @@ -18,6 +18,7 @@ #include #include + #include "exprtk.hpp" @@ -28,7 +29,8 @@ void trig_function() typedef exprtk::expression expression_t; typedef exprtk::parser parser_t; - std::string expression_string = "clamp(-1.0,sin(2 * pi * x) + cos(x / 2 * pi),+1.0)"; + const std::string expression_string = + "clamp(-1.0,sin(2 * pi * x) + cos(x / 2 * pi),+1.0)"; T x; @@ -44,8 +46,8 @@ void trig_function() for (x = T(-5); x <= T(+5); x += T(0.001)) { - T y = expression.value(); - printf("%19.15f\t%19.15f\n",x,y); + const T y = expression.value(); + printf("%19.15f\t%19.15f\n", x, y); } } diff --git a/exprtk_simple_example_02.cpp b/exprtk_simple_example_02.cpp index 0dedde1..56b9c9b 100644 --- a/exprtk_simple_example_02.cpp +++ b/exprtk_simple_example_02.cpp @@ -3,7 +3,7 @@ * C++ Mathematical Expression Toolkit Library * * * * Simple Example 2 * - * Author: Arash Partow (1999-2018) * + * Author: Arash Partow (1999-2020) * * URL: http://www.partow.net/programming/exprtk/index.html * * * * Copyright notice: * @@ -18,6 +18,7 @@ #include #include + #include "exprtk.hpp" @@ -28,14 +29,15 @@ void square_wave() typedef exprtk::expression expression_t; typedef exprtk::parser parser_t; - std::string expr_string = "a*(4/pi)*" - "((1 /1)*sin( 2*pi*f*t)+(1 /3)*sin( 6*pi*f*t)+" - " (1 /5)*sin(10*pi*f*t)+(1 /7)*sin(14*pi*f*t)+" - " (1 /9)*sin(18*pi*f*t)+(1/11)*sin(22*pi*f*t)+" - " (1/13)*sin(26*pi*f*t)+(1/15)*sin(30*pi*f*t)+" - " (1/17)*sin(34*pi*f*t)+(1/19)*sin(38*pi*f*t)+" - " (1/21)*sin(42*pi*f*t)+(1/23)*sin(46*pi*f*t)+" - " (1/25)*sin(50*pi*f*t)+(1/27)*sin(54*pi*f*t))"; + const std::string expr_string = + "a*(4/pi)*" + "((1 /1)*sin( 2*pi*f*t)+(1 /3)*sin( 6*pi*f*t)+" + " (1 /5)*sin(10*pi*f*t)+(1 /7)*sin(14*pi*f*t)+" + " (1 /9)*sin(18*pi*f*t)+(1/11)*sin(22*pi*f*t)+" + " (1/13)*sin(26*pi*f*t)+(1/15)*sin(30*pi*f*t)+" + " (1/17)*sin(34*pi*f*t)+(1/19)*sin(38*pi*f*t)+" + " (1/21)*sin(42*pi*f*t)+(1/23)*sin(46*pi*f*t)+" + " (1/25)*sin(50*pi*f*t)+(1/27)*sin(54*pi*f*t))"; static const T pi = T(3.141592653589793238462643383279502); @@ -59,8 +61,8 @@ void square_wave() for (t = (T(-2) * pi); t <= (T(+2) * pi); t += delta) { - T result = expression.value(); - printf("%19.15f\t%19.15f\n",t,result); + const T result = expression.value(); + printf("%19.15f\t%19.15f\n", t, result); } } diff --git a/exprtk_simple_example_03.cpp b/exprtk_simple_example_03.cpp index b1abe63..8e5a164 100644 --- a/exprtk_simple_example_03.cpp +++ b/exprtk_simple_example_03.cpp @@ -3,7 +3,7 @@ * C++ Mathematical Expression Toolkit Library * * * * Simple Example 3 * - * Author: Arash Partow (1999-2018) * + * Author: Arash Partow (1999-2020) * * URL: http://www.partow.net/programming/exprtk/index.html * * * * Copyright notice: * @@ -18,6 +18,7 @@ #include #include + #include "exprtk.hpp" @@ -28,7 +29,8 @@ void polynomial() typedef exprtk::expression expression_t; typedef exprtk::parser parser_t; - std::string expression_string = "25x^5 - 35x^4 - 15x^3 + 40x^2 - 15x + 1"; + const std::string expression_string = + "25x^5 - 35x^4 - 15x^3 + 40x^2 - 15x + 1"; const T r0 = T(0); const T r1 = T(1); @@ -47,7 +49,7 @@ void polynomial() for (x = r0; x <= r1; x += delta) { - printf("%19.15f\t%19.15f\n",x,expression.value()); + printf("%19.15f\t%19.15f\n", x, expression.value()); } } diff --git a/exprtk_simple_example_04.cpp b/exprtk_simple_example_04.cpp index f394d7e..aca7014 100644 --- a/exprtk_simple_example_04.cpp +++ b/exprtk_simple_example_04.cpp @@ -3,7 +3,7 @@ * C++ Mathematical Expression Toolkit Library * * * * Simple Example 4 * - * Author: Arash Partow (1999-2018) * + * Author: Arash Partow (1999-2020) * * URL: http://www.partow.net/programming/exprtk/index.html * * * * Copyright notice: * @@ -18,6 +18,7 @@ #include #include + #include "exprtk.hpp" @@ -72,7 +73,7 @@ void fibonacci() { x = static_cast(i); - T result = expression.value(); + const T result = expression.value(); printf("fibonacci(%3d) = %10.0f\n", static_cast(i), diff --git a/exprtk_simple_example_05.cpp b/exprtk_simple_example_05.cpp index f563a4c..50d7987 100644 --- a/exprtk_simple_example_05.cpp +++ b/exprtk_simple_example_05.cpp @@ -3,7 +3,7 @@ * C++ Mathematical Expression Toolkit Library * * * * Simple Example 5 * - * Author: Arash Partow (1999-2018) * + * Author: Arash Partow (1999-2020) * * URL: http://www.partow.net/programming/exprtk/index.html * * * * Copyright notice: * @@ -18,6 +18,7 @@ #include #include + #include "exprtk.hpp" @@ -49,7 +50,7 @@ void custom_function() typedef exprtk::expression expression_t; typedef exprtk::parser parser_t; - std::string expression_string = + const std::string expression_string = "myfunc(sin(x / pi), otherfunc(3 * y, x / 2, x * y))"; T x = T(1); @@ -69,7 +70,7 @@ void custom_function() parser_t parser; parser.compile(expression_string,expression); - T result = expression.value(); + const T result = expression.value(); printf("Result: %10.5f\n",result); } diff --git a/exprtk_simple_example_06.cpp b/exprtk_simple_example_06.cpp index 15ae070..0af6f8b 100644 --- a/exprtk_simple_example_06.cpp +++ b/exprtk_simple_example_06.cpp @@ -3,7 +3,7 @@ * C++ Mathematical Expression Toolkit Library * * * * Simple Example 6 * - * Author: Arash Partow (1999-2018) * + * Author: Arash Partow (1999-2020) * * URL: http://www.partow.net/programming/exprtk/index.html * * * * Copyright notice: * @@ -18,6 +18,7 @@ #include #include + #include "exprtk.hpp" @@ -28,7 +29,7 @@ void vector_function() typedef exprtk::expression expression_t; typedef exprtk::parser parser_t; - std::string expression_string = + const std::string expression_string = " for (var i := 0; i < min(x[],y[],z[]); i += 1) " " { " " z[i] := 3sin(x[i]) + 2log(y[i]); " diff --git a/exprtk_simple_example_07.cpp b/exprtk_simple_example_07.cpp index ecaa08a..bdf3c3b 100644 --- a/exprtk_simple_example_07.cpp +++ b/exprtk_simple_example_07.cpp @@ -3,7 +3,7 @@ * C++ Mathematical Expression Toolkit Library * * * * Simple Example 7 * - * Author: Arash Partow (1999-2018) * + * Author: Arash Partow (1999-2020) * * URL: http://www.partow.net/programming/exprtk/index.html * * * * Copyright notice: * @@ -18,6 +18,7 @@ #include #include + #include "exprtk.hpp" @@ -28,7 +29,7 @@ void logic() typedef exprtk::expression expression_t; typedef exprtk::parser parser_t; - std::string expression_string = "not(A and B) or C"; + const std::string expression_string = "not(A and B) or C"; symbol_table_t symbol_table; symbol_table.create_variable("A"); @@ -52,7 +53,7 @@ void logic() symbol_table.get_variable("B")->ref() = T((i & 0x02) ? 1 : 0); symbol_table.get_variable("C")->ref() = T((i & 0x04) ? 1 : 0); - int result = static_cast(expression.value()); + const int result = static_cast(expression.value()); printf(" %d | %d | %d | %d | %d \n", i, diff --git a/exprtk_simple_example_08.cpp b/exprtk_simple_example_08.cpp index cd21bb9..4565098 100644 --- a/exprtk_simple_example_08.cpp +++ b/exprtk_simple_example_08.cpp @@ -3,7 +3,7 @@ * C++ Mathematical Expression Toolkit Library * * * * Simple Example 8 * - * Author: Arash Partow (1999-2018) * + * Author: Arash Partow (1999-2020) * * URL: http://www.partow.net/programming/exprtk/index.html * * * * Copyright notice: * @@ -18,6 +18,7 @@ #include #include + #include "exprtk.hpp" @@ -27,7 +28,7 @@ void composite() typedef exprtk::symbol_table symbol_table_t; typedef exprtk::expression expression_t; typedef exprtk::parser parser_t; - typedef exprtk::parser_error::type error_t; + typedef exprtk::parser_error::type err_t; typedef exprtk::function_compositor compositor_t; typedef typename compositor_t::function function_t; @@ -64,7 +65,7 @@ void composite() for (std::size_t i = 0; i < parser.error_count(); ++i) { - error_t error = parser.get_error(i); + const err_t error = parser.get_error(i); printf("Error: %02d Position: %02d Type: [%14s] Msg: %s\tExpression: %s\n", static_cast(i), @@ -77,7 +78,7 @@ void composite() return; } - T result = expression.value(); + const T result = expression.value(); printf("%s = %e\n", expression_string.c_str(), result); } diff --git a/exprtk_simple_example_09.cpp b/exprtk_simple_example_09.cpp index 4b61efe..b11f193 100644 --- a/exprtk_simple_example_09.cpp +++ b/exprtk_simple_example_09.cpp @@ -3,7 +3,7 @@ * C++ Mathematical Expression Toolkit Library * * * * Simple Example 9 * - * Author: Arash Partow (1999-2018) * + * Author: Arash Partow (1999-2020) * * URL: http://www.partow.net/programming/exprtk/index.html * * * * Copyright notice: * @@ -18,6 +18,7 @@ #include #include + #include "exprtk.hpp" @@ -132,9 +133,9 @@ void primes() { x = static_cast(i); - T result1 = expression1.value(); - T result2 = expression2.value(); - T result3 = expression3.value(); + const T result1 = expression1.value(); + const T result2 = expression2.value(); + const T result3 = expression3.value(); printf("%03d Result1: %c Result2: %c Result3: %c\n", static_cast(i), diff --git a/exprtk_simple_example_10.cpp b/exprtk_simple_example_10.cpp index 1d75dc1..13728da 100644 --- a/exprtk_simple_example_10.cpp +++ b/exprtk_simple_example_10.cpp @@ -3,7 +3,7 @@ * C++ Mathematical Expression Toolkit Library * * * * Simple Example 10 * - * Author: Arash Partow (1999-2018) * + * Author: Arash Partow (1999-2020) * * URL: http://www.partow.net/programming/exprtk/index.html * * * * Copyright notice: * @@ -19,6 +19,7 @@ #include #include #include + #include "exprtk.hpp" @@ -44,25 +45,26 @@ void newton_sqrt() .add( function_t( // define function: newton_sqrt(x) "newton_sqrt", - " switch " - " { " - " case x < 0 : -inf; " - " case x == 0 : 0; " - " case x == 1 : 1; " - " default: " - " ~{ " - " var z := 100; " - " var sqrt_x := x / 2; " - " repeat " - " sqrt_x := (1 / 2) * (sqrt_x + (x / sqrt_x)); " - " if (equal(sqrt_x^2, x)) " - " break[sqrt_x]; " - " until ((z -= 1) <= 0); " - " }; " - " } ", + " switch " + " { " + " case x < 0 : null; " + " case x == 0 : 0; " + " case x == 1 : 1; " + " default: " + " ~{ " + " var z := 100; " + " var sqrt_x := x / 2; " + " repeat " + " if (equal(sqrt_x^2, x)) " + " break[sqrt_x]; " + " else " + " sqrt_x := (1 / 2) * (sqrt_x + (x / sqrt_x)); " + " until ((z -= 1) <= 0); " + " }; " + " } ", "x")); - std::string expression_str = "newton_sqrt(x)"; + const std::string expression_str = "newton_sqrt(x)"; expression_t expression; expression.register_symbol_table(symbol_table); @@ -74,9 +76,9 @@ void newton_sqrt() { x = static_cast(i); - T result = expression.value(); + const T result = expression.value(); - printf("sqrt(%03d) - Result: %12.10f\tReal: %12.10f\n", + printf("sqrt(%03d) - Result: %15.13f\tReal: %15.13f\n", static_cast(i), result, std::sqrt(x)); diff --git a/exprtk_simple_example_11.cpp b/exprtk_simple_example_11.cpp index e280611..454c8f0 100644 --- a/exprtk_simple_example_11.cpp +++ b/exprtk_simple_example_11.cpp @@ -3,7 +3,7 @@ * C++ Mathematical Expression Toolkit Library * * * * Simple Example 11 * - * Author: Arash Partow (1999-2018) * + * Author: Arash Partow (1999-2020) * * URL: http://www.partow.net/programming/exprtk/index.html * * * * Copyright notice: * @@ -18,6 +18,7 @@ #include #include + #include "exprtk.hpp" @@ -28,7 +29,7 @@ void square_wave2() typedef exprtk::expression expression_t; typedef exprtk::parser parser_t; - std::string wave_program = + const std::string wave_program = " var r := 0; " " for (var i := 0; i < 1000; i += 1) " " { " @@ -58,8 +59,8 @@ void square_wave2() for (t = (T(-2) * pi); t <= (T(+2) * pi); t += delta) { - T result = expression.value(); - printf("%19.15f\t%19.15f\n",t,result); + const T result = expression.value(); + printf("%19.15f\t%19.15f\n", t, result); } } diff --git a/exprtk_simple_example_12.cpp b/exprtk_simple_example_12.cpp index dd63592..ce398bd 100644 --- a/exprtk_simple_example_12.cpp +++ b/exprtk_simple_example_12.cpp @@ -3,7 +3,7 @@ * C++ Mathematical Expression Toolkit Library * * * * Simple Example 12 * - * Author: Arash Partow (1999-2018) * + * Author: Arash Partow (1999-2020) * * URL: http://www.partow.net/programming/exprtk/index.html * * * * Copyright notice: * @@ -18,6 +18,7 @@ #include #include + #include "exprtk.hpp" @@ -28,7 +29,7 @@ void bubble_sort() typedef exprtk::expression expression_t; typedef exprtk::parser parser_t; - std::string bubblesort_program = + const std::string bubblesort_program = " var upper_bound := v[]; " " var swapped := false; " " repeat " diff --git a/exprtk_simple_example_13.cpp b/exprtk_simple_example_13.cpp index df68035..e1922e8 100644 --- a/exprtk_simple_example_13.cpp +++ b/exprtk_simple_example_13.cpp @@ -3,7 +3,7 @@ * C++ Mathematical Expression Toolkit Library * * * * Simple Example 13 * - * Author: Arash Partow (1999-2018) * + * Author: Arash Partow (1999-2020) * * URL: http://www.partow.net/programming/exprtk/index.html * * * * Copyright notice: * @@ -20,6 +20,7 @@ #include #include #include + #include "exprtk.hpp" @@ -30,7 +31,7 @@ void savitzky_golay_filter() typedef exprtk::expression expression_t; typedef exprtk::parser parser_t; - std::string sgfilter_program = + const std::string sgfilter_program = " var weight[9] := " " { " " -21, 14, 39, " @@ -88,7 +89,7 @@ void savitzky_golay_filter() for (std::size_t i = 0; i < v_out.size(); ++i) { - printf("%10.6f\t%10.6f\n",v_in[i],v_out[i]); + printf("%10.6f\t%10.6f\n", v_in[i], v_out[i]); } } diff --git a/exprtk_simple_example_14.cpp b/exprtk_simple_example_14.cpp index 7f7f8d3..bc508a2 100644 --- a/exprtk_simple_example_14.cpp +++ b/exprtk_simple_example_14.cpp @@ -3,7 +3,7 @@ * C++ Mathematical Expression Toolkit Library * * * * Simple Example 14 * - * Author: Arash Partow (1999-2018) * + * Author: Arash Partow (1999-2020) * * URL: http://www.partow.net/programming/exprtk/index.html * * * * Copyright notice: * @@ -18,6 +18,7 @@ #include #include + #include "exprtk.hpp" @@ -27,7 +28,7 @@ void stddev_example() typedef exprtk::expression expression_t; typedef exprtk::parser parser_t; - std::string stddev_program = + const std::string stddev_program = " var x[25] := { " " 1, 2, 3, 4, 5, " " 6, 7, 8, 9, 10, " @@ -43,7 +44,7 @@ void stddev_example() parser_t parser; parser.compile(stddev_program,expression); - T stddev = expression.value(); + const T stddev = expression.value(); printf("stddev(1..25) = %10.6f\n",stddev); } diff --git a/exprtk_simple_example_15.cpp b/exprtk_simple_example_15.cpp index b70c2c0..f7364fd 100644 --- a/exprtk_simple_example_15.cpp +++ b/exprtk_simple_example_15.cpp @@ -3,7 +3,7 @@ * C++ Mathematical Expression Toolkit Library * * * * Simple Example 15 * - * Author: Arash Partow (1999-2018) * + * Author: Arash Partow (1999-2020) * * URL: http://www.partow.net/programming/exprtk/index.html * * * * Copyright notice: * @@ -18,6 +18,7 @@ #include #include + #include "exprtk.hpp" @@ -28,7 +29,7 @@ void black_scholes_merton_model() typedef exprtk::expression expression_t; typedef exprtk::parser parser_t; - std::string bsm_model_program = + const std::string bsm_model_program = " var d1 := (log(s / x) + (r + v^2 / 2) * t) / (v * sqrt(t)); " " var d2 := d1 - v * sqrt(t); " " " @@ -70,7 +71,7 @@ void black_scholes_merton_model() printf("BSM(%s,%5.3f,%5.3f,%5.3f,%5.3f,%5.3f) = %10.6f\n", callput_flag.c_str(), - s,x,t,r,v, + s, x, t, r, v, bsm); } @@ -81,7 +82,7 @@ void black_scholes_merton_model() printf("BSM(%s,%5.3f,%5.3f,%5.3f,%5.3f,%5.3f) = %10.6f\n", callput_flag.c_str(), - s,x,t,r,v, + s, x, t, r, v, bsm); } } diff --git a/exprtk_simple_example_16.cpp b/exprtk_simple_example_16.cpp index 1483c50..cd76f84 100644 --- a/exprtk_simple_example_16.cpp +++ b/exprtk_simple_example_16.cpp @@ -3,7 +3,7 @@ * C++ Mathematical Expression Toolkit Library * * * * Simple Example 16 * - * Author: Arash Partow (1999-2018) * + * Author: Arash Partow (1999-2020) * * URL: http://www.partow.net/programming/exprtk/index.html * * * * Copyright notice: * @@ -19,6 +19,7 @@ #include #include #include + #include "exprtk.hpp" @@ -29,7 +30,7 @@ void linear_least_squares() typedef exprtk::expression expression_t; typedef exprtk::parser parser_t; - std::string linear_least_squares_program = + const std::string linear_least_squares_program = " if (x[] == y[]) " " { " " beta := (sum(x * y) - sum(x) * sum(y) / x[]) / " diff --git a/exprtk_simple_example_17.cpp b/exprtk_simple_example_17.cpp index a80e0ca..50263aa 100644 --- a/exprtk_simple_example_17.cpp +++ b/exprtk_simple_example_17.cpp @@ -3,7 +3,7 @@ * C++ Mathematical Expression Toolkit Library * * * * Simple Example 17 * - * Author: Arash Partow (1999-2018) * + * Author: Arash Partow (1999-2020) * * URL: http://www.partow.net/programming/exprtk/index.html * * * * Copyright notice: * @@ -47,7 +47,7 @@ void monte_carlo_pi() typedef exprtk::expression expression_t; typedef exprtk::parser parser_t; - std::string monte_carlo_pi_program = + const std::string monte_carlo_pi_program = " var experiments[5 * 10^7] := [(rnd_01^2 + rnd_01^2) <= 1]; " " 4 * sum(experiments) / experiments[]; "; diff --git a/exprtk_simple_example_18.cpp b/exprtk_simple_example_18.cpp index c5bdf04..4fabc72 100644 --- a/exprtk_simple_example_18.cpp +++ b/exprtk_simple_example_18.cpp @@ -3,7 +3,7 @@ * C++ Mathematical Expression Toolkit Library * * * * Simple Example 18 * - * Author: Arash Partow (1999-2018) * + * Author: Arash Partow (1999-2020) * * URL: http://www.partow.net/programming/exprtk/index.html * * * * Copyright notice: * @@ -29,7 +29,7 @@ void file_io() typedef exprtk::expression expression_t; typedef exprtk::parser parser_t; - std::string fileio_program = + const std::string fileio_program = " var file_name := 'file.txt'; " " var stream := null; " " " diff --git a/exprtk_simple_example_19.cpp b/exprtk_simple_example_19.cpp index d317559..5d0fc20 100644 --- a/exprtk_simple_example_19.cpp +++ b/exprtk_simple_example_19.cpp @@ -3,7 +3,7 @@ * C++ Mathematical Expression Toolkit Library * * * * Simple Example 19 * - * Author: Arash Partow (1999-2018) * + * Author: Arash Partow (1999-2020) * * URL: http://www.partow.net/programming/exprtk/index.html * * * * Copyright notice: * @@ -55,7 +55,7 @@ class randu : public exprtk::igeneric_function if ( (1 == ps_index) && !exprtk::rtl::vecops::helper:: - load_vector_range::process(parameters,r0,r1,1,2,0) + load_vector_range::process(parameters, r0, r1, 1, 2, 0) ) return T(0); @@ -84,7 +84,7 @@ void vector_randu() typedef exprtk::expression expression_t; typedef exprtk::parser parser_t; - std::string vecrandu_program = + const std::string vecrandu_program = " var noise[6] := [0]; " " " " if (randu(noise,0,5) == false) " diff --git a/exprtk_test.cpp b/exprtk_test.cpp index aaf3901..91e7593 100644 --- a/exprtk_test.cpp +++ b/exprtk_test.cpp @@ -3,7 +3,7 @@ * C++ Mathematical Expression Toolkit Library * * * * Examples and Unit-Tests * - * Author: Arash Partow (1999-2018) * + * Author: Arash Partow (1999-2020) * * URL: http://www.partow.net/programming/exprtk/index.html * * * * Copyright notice: * @@ -23,6 +23,7 @@ #include #include #include +#include #include #include @@ -2450,7 +2451,92 @@ inline bool run_test02() test_ab("var x := 'XXXXX'; var y := '01234567890'; var i := 0; x[0:i+1] <=> y[:]; (x == '01XXX') and (y == 'XX234567890')", "","",T(1.0)), test_ab("var x := 'XXXXX'; var y := '01234567890'; var i := 0; x[0:i+2] <=> y[:]; (x == '012XX') and (y == 'XXX34567890')", "","",T(1.0)), test_ab("var x := 'XXXXX'; var y := '01234567890'; var i := 0; x[0:i+3] <=> y[:]; (x == '0123X') and (y == 'XXXX4567890')", "","",T(1.0)), - test_ab("var x := 'XXXXX'; var y := '01234567890'; var i := 0; x[0:i+4] <=> y[:]; (x == '01234') and (y == 'XXXXX567890')", "","",T(1.0)) + test_ab("var x := 'XXXXX'; var y := '01234567890'; var i := 0; x[0:i+4] <=> y[:]; (x == '01234') and (y == 'XXXXX567890')", "","",T(1.0)), + + test_ab("var v[4] := {1,2,3,4}; for (var i := 0; i < v[]; i += 1) { v[i] += 10; v[i] == 0 }; sum(v) == (1 + 2 + 3 + 4) + (v[] * 10)", "","",T(1.0)), + test_ab("var v[4] := {1,2,3,4}; for (var i := 0; i < v[]; i += 1) { v[i] -= 10; v[i] == 0 }; sum(v) == (1 + 2 + 3 + 4) - (v[] * 10)", "","",T(1.0)), + test_ab("var v[4] := {1,2,3,4}; for (var i := 0; i < v[]; i += 1) { v[i] *= 10; v[i] == 0 }; sum(v) == (1 + 2 + 3 + 4) * 10", "","",T(1.0)), + test_ab("var v[4] := {1,2,3,4}; for (var i := 0; i < v[]; i += 1) { v[i] /= 10; v[i] == 0 }; sum(v) == (1 + 2 + 3 + 4) / 10", "","",T(1.0)), + + test_ab("a like b", "abcd", "abcd*", T(1.0)), + test_ab("a like b", "abcd", "abcd" , T(1.0)), + test_ab("a like b", "abcd", "abc*" , T(1.0)), + test_ab("a like b", "abcd", "*bcd" , T(1.0)), + test_ab("a like b", "abcd", "abc?" , T(1.0)), + test_ab("a like b", "abcd", "?bcd" , T(1.0)), + test_ab("a like b", "abcd", "ab?d" , T(1.0)), + test_ab("a like b", "abcd", "ab*d" , T(1.0)), + test_ab("a like b", "abcd", "a?cd" , T(1.0)), + test_ab("a like b", "abcd", "a*cd" , T(1.0)), + test_ab("a like b", "abcd", "a??d" , T(1.0)), + test_ab("a like b", "abcd", "a*?d" , T(1.0)), + test_ab("a like b", "abcd", "*bc*" , T(1.0)), + test_ab("a like b", "abcd", "?bc?" , T(1.0)), + test_ab("a like b", "abcd", "????" , T(1.0)), + test_ab("a like b", "abcd", "a???" , T(1.0)), + test_ab("a like b", "abcd", "ab??" , T(1.0)), + test_ab("a like b", "abcd", "abc?" , T(1.0)), + test_ab("a like b", "abcd", "???d" , T(1.0)), + test_ab("a like b", "abcd", "??cd" , T(1.0)), + test_ab("a like b", "abcd", "?bcd" , T(1.0)), + test_ab("a like b", "abcd", "?b?d" , T(1.0)), + test_ab("a like b", "abcd", "a?c?" , T(1.0)), + test_ab("a like b", "abcd", "a??d" , T(1.0)), + test_ab("a like b", "abcd", "?bc?" , T(1.0)), + test_ab("a like b", "abcd", "ab**" , T(1.0)), + test_ab("a like b", "abcd", "ab*?" , T(1.0)), + test_ab("a like b", "abcd", "a***" , T(1.0)), + test_ab("a like b", "abcd", "**cd" , T(1.0)), + test_ab("a like b", "abcd", "*?cd" , T(1.0)), + test_ab("a like b", "abcd", "***d" , T(1.0)), + test_ab("a like b", "abcd", "*bc*" , T(1.0)), + test_ab("a like b", "abcd", "*bc?" , T(1.0)), + test_ab("a like b", "abcd", "*b??" , T(1.0)), + test_ab("a like b", "abcd", "?bc*" , T(1.0)), + test_ab("a like b", "abcd", "??c*" , T(1.0)), + test_ab("a like b", "abcd", "*b?*" , T(1.0)), + test_ab("a like b", "ab" , "a*" , T(1.0)), + test_ab("a like b", "ab" , "a?" , T(1.0)), + + test_ab("a ilike b", "aBcD", "abcd*", T(1.0)), + test_ab("a ilike b", "aBcD", "abcd" , T(1.0)), + test_ab("a ilike b", "aBcD", "abc*" , T(1.0)), + test_ab("a ilike b", "aBcD", "*bcd" , T(1.0)), + test_ab("a ilike b", "aBcD", "abc?" , T(1.0)), + test_ab("a ilike b", "aBcD", "?bcd" , T(1.0)), + test_ab("a ilike b", "aBcD", "ab?d" , T(1.0)), + test_ab("a ilike b", "aBcD", "ab*d" , T(1.0)), + test_ab("a ilike b", "aBcD", "a?cd" , T(1.0)), + test_ab("a ilike b", "aBcD", "a*cd" , T(1.0)), + test_ab("a ilike b", "aBcD", "a??d" , T(1.0)), + test_ab("a ilike b", "aBcD", "a*?d" , T(1.0)), + test_ab("a ilike b", "aBcD", "*bc*" , T(1.0)), + test_ab("a ilike b", "aBcD", "?bc?" , T(1.0)), + test_ab("a ilike b", "aBcD", "????" , T(1.0)), + test_ab("a ilike b", "aBcD", "a???" , T(1.0)), + test_ab("a ilike b", "aBcD", "ab??" , T(1.0)), + test_ab("a ilike b", "aBcD", "abc?" , T(1.0)), + test_ab("a ilike b", "aBcD", "???d" , T(1.0)), + test_ab("a ilike b", "aBcD", "??cd" , T(1.0)), + test_ab("a ilike b", "aBcD", "?bcd" , T(1.0)), + test_ab("a ilike b", "aBcD", "?b?d" , T(1.0)), + test_ab("a ilike b", "aBcD", "a?c?" , T(1.0)), + test_ab("a ilike b", "aBcD", "a??d" , T(1.0)), + test_ab("a ilike b", "aBcD", "?bc?" , T(1.0)), + test_ab("a ilike b", "aBcD", "ab**" , T(1.0)), + test_ab("a ilike b", "aBcD", "ab*?" , T(1.0)), + test_ab("a ilike b", "aBcD", "a***" , T(1.0)), + test_ab("a ilike b", "aBcD", "**cd" , T(1.0)), + test_ab("a ilike b", "aBcD", "*?cd" , T(1.0)), + test_ab("a ilike b", "aBcD", "***d" , T(1.0)), + test_ab("a ilike b", "aBcD", "*bc*" , T(1.0)), + test_ab("a ilike b", "aBcD", "*bc?" , T(1.0)), + test_ab("a ilike b", "aBcD", "*b??" , T(1.0)), + test_ab("a ilike b", "aBcD", "?bc*" , T(1.0)), + test_ab("a ilike b", "aBcD", "??c*" , T(1.0)), + test_ab("a ilike b", "aBcD", "*b?*" , T(1.0)), + test_ab("a ilike b", "aB" , "a*" , T(1.0)), + test_ab("a ilike b", "aB" , "a?" , T(1.0)) }; static const std::size_t test_list_size = sizeof(test_list) / sizeof(test_ab); @@ -2589,6 +2675,10 @@ inline bool run_test02() template inline bool run_test03() { + typedef exprtk::symbol_table symbol_table_t; + typedef exprtk::expression expression_t; + typedef exprtk::parser parser_t; + std::string expression_string = "A+A0+aA+Aa0+b+B1+Bb+bB1+A+A0+AA+AA0+B+B1+BB+BB1+a+a0+aa+aa0+b+b1+bb+bb1+" "c+C2+Cc+Cc2+D+D3+dD+dD3+C+C2+CC+CC2+D+D3+DD+DD3+c+c2+cc+cc2+d+d3+dd+dd3+" "E+E4+eE+Ee4+f+F5+Ff+fF5+E+E4+EE+EE4+F+F5+FF+FF5+e+e4+ee+ee4+f+f5+ff+ff5+" @@ -2626,9 +2716,9 @@ inline bool run_test03() for (std::size_t r = 0; r < rounds; ++r) { - exprtk::symbol_table symbol_table_0; - exprtk::symbol_table symbol_table_1; - exprtk::expression expression; + symbol_table_t symbol_table_0; + symbol_table_t symbol_table_1; + expression_t expression; std::vector v; v.resize(variable_list_size); @@ -2726,7 +2816,38 @@ inline bool run_test03() "1 v x", "1 v y", "x v 1", - "y v 1" + "y v 1", + + "(x == 'a string' )", + "(x == 'a string'[1:2] )", + "(x == 'a string' + 'b string' )", + "(x == ('a string' + 'b string')[3:5])", + "('a string' == x )", + "('a string'[1:2] == x )", + "('a string' + 'b string' == x )", + "(('a string' + 'b string')[3:5] == x)", + + "var a; var b; 3in(a)+sin(b) ", + "var a; var b; sin(a)+3in(b) ", + "var a; var b; sqrt(a)<3in(8) ", + "var a; var b; (1.99-3in((b-b))) ", + "var a; var b; ((3in(sin((b+b)))/1.06)-a) ", + "var a; var b; ((sin(3in((b+b)))/1.06)-a) ", + "var a; var b; (3in(x*(y+z))+cos(x*(y-z))) ", + "var a; var b; (cos(x*(y+z))+3in(x*(y-z))) ", + + "1++++", + "1+-+-+", + "1===", + "1====", + "[*][*][*][*][*]", + + "var v[1] := {}; var s0appe0 := false; repeat s0appe0 false for(){(){}}", + "var v[2] := {}; repeat var s0appe0 := false; s0appe0 false for(){(){}}", + "var v[3] := {}; repeat var s0appe0 := false; for(){(){}} s0appe0 false", + "var v[4] := {}; repeat var s0appe0 := false; s0appe0 for(){(){}} false", + "var v[5] := {}; repeat for(){(){}} var s0appe0 := false; s0appe0 false", + "var v{};v ;v 60;v 60;v o5" }; const std::size_t invalid_expr_size = sizeof(invalid_expr) / sizeof(std::string); @@ -2734,9 +2855,9 @@ inline bool run_test03() { for (std::size_t i = 0; i < invalid_expr_size; ++i) { - exprtk::symbol_table symbol_table; - - exprtk::expression expression; + symbol_table_t symbol_table; + expression_t expression; + parser_t parser; T x = T(0); std::string s; @@ -2746,8 +2867,6 @@ inline bool run_test03() symbol_table.add_stringvar("s",s); symbol_table.add_vector ("v",v); - exprtk::parser parser; - if (parser.compile(invalid_expr[i],expression)) { printf("run_test03() - Error: [1] Invalid expression compiled successfuly. Expression: %s\n", @@ -2763,14 +2882,13 @@ inline bool run_test03() std::string s; std::vector v(10, T(1.234)); - exprtk::symbol_table symbol_table; + symbol_table_t symbol_table; + parser_t parser; symbol_table.add_variable ("x",x); symbol_table.add_stringvar("s",s); symbol_table.add_vector ("v",v); - exprtk::parser parser; - for (std::size_t i = 0; i < invalid_expr_size; ++i) { exprtk::expression expression; @@ -2784,6 +2902,64 @@ inline bool run_test03() } } } + + { + const std::string base_expression = + "1+(2+2(3+3(4+4cos(((((a+((x*(e-tan((cos((((((b/(tan(((1.60*a)-0.34))-0.76))-x)+y)-3.27)+a))/pi))))^a))+y)*b)-e))+e)/z)+w)+" + "(((b+(a/((((tan((b*((((((a-(cos((cos(tan(((a+a)*3.33)))-b))/2.52))*x)/b)+3.07)^0.86)+b)))*3.95)/0.39)*y)+a)))*a)*z)"; + + const std::string mod = + "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789^+-/*,;:<>=%?[]{}() #&'\"\\\t\r\n"; + + symbol_table_t symbol_table; + expression_t expression; + parser_t parser; + + T a = T(1.1 ); + T b = T(2.2 ); + T c = T(3.3 ); + T d = T(4.5 ); + T e = T(4.5 ); + T x = T(2.123456); + T y = T(3.123456); + T z = T(4.123456); + T w = T(5.123456); + + symbol_table.add_variable("a", a); + symbol_table.add_variable("b", b); + symbol_table.add_variable("c", c); + symbol_table.add_variable("d", d); + symbol_table.add_variable("e", e); + + symbol_table.add_variable("x", x); + symbol_table.add_variable("y", y); + symbol_table.add_variable("z", z); + symbol_table.add_variable("w", w); + + expression.register_symbol_table(symbol_table); + + T total = T(0); + + for (std::size_t j = 0; j < base_expression.size(); ++j) + { + std::string expression_str = base_expression; + const char old_c = base_expression[j]; + + for (std::size_t i = 0; i < mod.size(); ++i) + { + expression_str[j] = mod[i]; + + if (parser.compile(expression_str, expression)) + { + total += expression.value(); + } + } + + expression_str[j] = old_c; + } + + if (total == T(12345.6789)) { printf(" "); } + } } return true; @@ -4074,6 +4250,62 @@ inline bool run_test10() } } + { + const std::string expression = + "for (var i := 0; i < min(x[],y[],z[]); i += 1)" + "{ z[i] := 3sin(x[i]) + 2log(y[i]); }"; + + std::vector var_symbol_list; + std::vector func_symbol_list; + + if (!exprtk::collect_variables(expression, var_symbol_list)) + { + printf("run_test10() - Failed to collect variables.\n"); + return false; + } + + if (!exprtk::collect_functions(expression, func_symbol_list)) + { + printf("run_test10() - Failed to collect functions.\n"); + return false; + } + + std::sort(var_symbol_list .begin(), var_symbol_list .end()); + std::sort(func_symbol_list.begin(), func_symbol_list.end()); + + std::vector expected_var_symbol_list; + std::vector expected_func_symbol_list; + + expected_var_symbol_list.push_back("i"); + expected_var_symbol_list.push_back("x"); + expected_var_symbol_list.push_back("y"); + expected_var_symbol_list.push_back("z"); + + expected_func_symbol_list.push_back("log"); + expected_func_symbol_list.push_back("min"); + expected_func_symbol_list.push_back("sin"); + + const bool var_result = (var_symbol_list.size() == expected_var_symbol_list.size()) && + std::equal(var_symbol_list.begin(), + var_symbol_list.end(), + expected_var_symbol_list.begin()); + if (!var_result) + { + printf("run_test10() - Failed collected variable comparison between recieved and expected variables\n"); + return false; + } + + const bool func_result = (func_symbol_list.size() == expected_func_symbol_list.size()) && + std::equal(func_symbol_list.begin(), + func_symbol_list.end(), + expected_func_symbol_list.begin()); + if (!func_result) + { + printf("run_test10() - Failed collected fuctions comparison between recieved and expected functions\n"); + return false; + } + } + { std::string expression_list[] = { @@ -5578,6 +5810,109 @@ struct vararg_func : public exprtk::igeneric_function } }; +template +struct vecrebase_func : public exprtk::igeneric_function +{ + typedef typename exprtk::igeneric_function::parameter_list_t + parameter_list_t; + + typedef typename exprtk::igeneric_function::generic_type + generic_type; + + typedef typename generic_type::vector_view vector_t; + + using exprtk::igeneric_function::operator(); + + vecrebase_func() + : exprtk::igeneric_function("V") + {} + + inline T operator()(parameter_list_t params) + { + vector_t v(params[0]); + return std::accumulate(v.begin(), v.end(), T(0)); + } +}; + +template +struct overload_func : exprtk::igeneric_function +{ + typedef typename exprtk::igeneric_function igfun_t; + typedef typename igfun_t::parameter_list_t parameter_list_t; + typedef typename igfun_t::generic_type generic_type; + typedef typename generic_type::vector_view vector_t; + + using exprtk::igeneric_function::operator(); + + overload_func(const std::string& param_seq_list) + : exprtk::igeneric_function(param_seq_list, igfun_t::e_rtrn_overload), + current_ps_index(std::numeric_limits::max()) + { + clear(); + } + + void clear() + { + current_ps_index = std::numeric_limits::max(); + current_param_seq = ""; + } + + inline T operator()(const std::size_t& ps_index, + parameter_list_t parameters) + { + current_ps_index = ps_index; + determine_param_seq(parameters); + return T(1); + } + + inline T operator()(const std::size_t& ps_index, + std::string& result, + parameter_list_t parameters) + { + current_ps_index = ps_index; + determine_param_seq(parameters); + result = "string result"; + return T(1); + } + + void determine_param_seq(parameter_list_t parameters) + { + current_param_seq = ""; + + for (std::size_t i = 0; i < parameters.size(); ++i) + { + generic_type& gt = parameters[i]; + + switch (gt.type) + { + case generic_type::e_scalar : current_param_seq += "T"; + break; + + case generic_type::e_vector : current_param_seq += "V"; + break; + + case generic_type::e_string : current_param_seq += "S"; + break; + + default : continue; + } + } + } + + std::size_t current_ps_index; + std::string current_param_seq; + + struct test_result_t + { + test_result_t(const std::size_t psi, const std::string& ps) + : ps_index(psi), + param_seq(ps) + {} + + std::size_t ps_index; + std::string param_seq; + }; +}; template inline bool run_test18() @@ -6516,6 +6851,68 @@ inline bool run_test18() return false; } + { + typedef exprtk::symbol_table symbol_table_t; + typedef exprtk::expression expression_t; + typedef exprtk::parser parser_t; + + T v0[] = { T(0), T(1), T(2), T(3), T(4) }; + T v1[] = { T(5), T(6), T(7), T(8), T(9) }; + + const std::size_t v0_size = sizeof(v0) / sizeof (T); + const std::size_t v1_size = sizeof(v1) / sizeof (T); + + exprtk::vector_view v = exprtk::make_vector_view(v0, v0_size); + + vecrebase_func vec_sum; + + symbol_table_t symbol_table; + symbol_table.add_vector("v",v); + symbol_table.add_function("vec_sum",vec_sum); + + expression_t expression; + expression.register_symbol_table(symbol_table); + + parser_t parser; + + const std::string expr_string = "vec_sum(v)"; + + if (!parser.compile(expr_string,expression)) + { + printf("run_test18() - Error: %s\tExpression: %s\n", + parser.error().c_str(), + expr_string.c_str()); + + return false; + } + + const T expected_result0 = std::accumulate(v0, v0 + v0_size,T(0)); + + if (expression.value() != expected_result0) + { + printf("run_test18() - Error in evaluation! (10.1) Expression: %s Expected: %5.3f Computed: %5.3f\n", + expr_string.c_str(), + expected_result0, + expression.value()); + + return false; + } + + v.rebase(v1); + + const T expected_result1 = std::accumulate(v1, v1 + v1_size,T(0)); + + if (expression.value() != expected_result1) + { + printf("run_test18() - Error in evaluation! (10.2) Expression: %s Expected: %5.3f Computed: %5.3f\n", + expr_string.c_str(), + expected_result1, + expression.value()); + + return false; + } + } + { bool failure = false; @@ -6648,7 +7045,7 @@ inline bool run_test18() if (result != T(1)) { - printf("run_test18() - Error in evaluation! (10) Expression: %s\n", + printf("run_test18() - Error in evaluation! (11) Expression: %s\n", expr_str_list[i].c_str()); failure = true; @@ -6659,6 +7056,295 @@ inline bool run_test18() return false; } + { + typedef exprtk::expression expression_t; + + std::string a = "a"; + std::string b = "b"; + std::string c = "c"; + std::string d = "d"; + + T x = T(1.1); + T y = T(2.2); + T z = T(3.3); + T w = T(4.4); + + overload_func ovrld_func + ( + "T:T|T:TT|T:TTT|T:TTTT|" + "T:S|T:SS|T:SSS|T:SSSS|" + "T:ST|T:STS|T:STST|" + "T:TS|T:TST|T:TSTS|" + "T:TTSS|T:SSTT|T:STTS|T:TSST" + ); + + 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_stringvar("a",a); + symbol_table.add_stringvar("b",b); + symbol_table.add_stringvar("c",c); + symbol_table.add_stringvar("d",d); + + symbol_table.add_function("foo",ovrld_func); + + typedef typename overload_func::test_result_t test_result_t; + typedef std::pair::test_result_t> test_pack_t; + + static const test_pack_t test_pack_list[] = + { + test_pack_t("foo(x)" , test_result_t( 0, "T" )), + test_pack_t("foo(x, y)" , test_result_t( 1, "TT" )), + test_pack_t("foo(x, y, z)" , test_result_t( 2, "TTT" )), + test_pack_t("foo(x, y, z, w)" , test_result_t( 3, "TTTT")), + test_pack_t("foo(x + y)" , test_result_t( 0, "T" )), + test_pack_t("foo(x + y, y + z)" , test_result_t( 1, "TT" )), + test_pack_t("foo(x + y, y + z, z + w)" , test_result_t( 2, "TTT" )), + test_pack_t("foo(x + y, y + z, z + w, w)" , test_result_t( 3, "TTTT")), + test_pack_t("foo(a)" , test_result_t( 4, "S" )), + test_pack_t("foo(a, b)" , test_result_t( 5, "SS" )), + test_pack_t("foo(a, b, c)" , test_result_t( 6, "SSS" )), + test_pack_t("foo(a, b, c, d)" , test_result_t( 7, "SSSS")), + test_pack_t("foo(a + b)" , test_result_t( 4, "S" )), + test_pack_t("foo(a + b, b + c)" , test_result_t( 5, "SS" )), + test_pack_t("foo(a + b, b + c, c + d)" , test_result_t( 6, "SSS" )), + test_pack_t("foo(a + b, b + c, c + d, d)" , test_result_t( 7, "SSSS")), + test_pack_t("foo(a, x)" , test_result_t( 8, "ST" )), + test_pack_t("foo(a, x, b)" , test_result_t( 9, "STS" )), + test_pack_t("foo(a, x, b, y)" , test_result_t(10, "STST")), + test_pack_t("foo(a + b, x + y)" , test_result_t( 8, "ST" )), + test_pack_t("foo(a + b, x + y, b + c)" , test_result_t( 9, "STS" )), + test_pack_t("foo(a + b, x + y, b + c, y + z)" , test_result_t(10, "STST")), + test_pack_t("foo(x, a)" , test_result_t(11, "TS" )), + test_pack_t("foo(x, a, y)" , test_result_t(12, "TST" )), + test_pack_t("foo(x, a, y, b)" , test_result_t(13, "TSTS")), + test_pack_t("foo(x + y, a + b)" , test_result_t(11, "TS" )), + test_pack_t("foo(x + y, a + b, y + z)" , test_result_t(12, "TST" )), + test_pack_t("foo(x + y, a + b, y + z, b + c)" , test_result_t(13, "TSTS")), + test_pack_t("foo(x, y, a, b)" , test_result_t(14, "TTSS")), + test_pack_t("foo(a, b, x, y)" , test_result_t(15, "SSTT")), + test_pack_t("foo(a, x, y, b)" , test_result_t(16, "STTS")), + test_pack_t("foo(x, a, b, y)" , test_result_t(17, "TSST")), + test_pack_t("foo(x + y, y + z, a + b, b + c)" , test_result_t(14, "TTSS")), + test_pack_t("foo(a + b, b + c, x + y, y + z)" , test_result_t(15, "SSTT")), + test_pack_t("foo(a + b, x + y, y + z, b + c)" , test_result_t(16, "STTS")), + test_pack_t("foo(x + y, a + b, b + c, y + z)" , test_result_t(17, "TSST")) + }; + + static const std::size_t test_pack_list_size = sizeof(test_pack_list) / sizeof(test_pack_t); + + std::deque expression_list; + + for (std::size_t i = 0; i < test_pack_list_size; ++i) + { + expression_t expression; + expression.register_symbol_table(symbol_table); + + exprtk::parser parser; + + if (!parser.compile(test_pack_list[i].first, expression)) + { + printf("run_test18() - (12) Overload VarArg Error: %s Expression: %s\n", + parser.error().c_str(), + test_pack_list[i].first.c_str()); + + return false; + } + else + expression_list.push_back(expression); + } + + bool failure = false; + + for (std::size_t i = 0; i < expression_list.size(); ++i) + { + ovrld_func.clear(); + + if (T(1) != expression_list[i].value()) + { + printf("run_test18() - Error in evaluation! (12) Expression: %s\n", + test_pack_list[i].first.c_str()); + + failure = true; + } + + if (ovrld_func.current_ps_index != test_pack_list[i].second.ps_index) + { + printf("run_test18() - Error with ps_index (12) Expression: %s Expected: %d Got: %d\n", + test_pack_list[i].first.c_str(), + static_cast(test_pack_list[i].second.ps_index), + static_cast(ovrld_func.current_ps_index)); + + failure = true; + } + + if (ovrld_func.current_param_seq != test_pack_list[i].second.param_seq) + { + printf("run_test18() - Error with parameter seq (12) Expression: %s Expected: %s Got: %s\n", + test_pack_list[i].first.c_str(), + test_pack_list[i].second.param_seq.c_str(), + ovrld_func.current_param_seq.c_str()); + + failure = true; + } + ::fflush(stdout); + } + + if (failure) + return false; + } + + { + typedef exprtk::expression expression_t; + + std::string a = "a"; + std::string b = "b"; + std::string c = "c"; + std::string d = "d"; + std::string result = ""; + + T x = T(1.1); + T y = T(2.2); + T z = T(3.3); + T w = T(4.4); + + overload_func ovrld_func + ( + "S:T|S:TT|S:TTT|S:TTTT|" + "S:S|S:SS|S:SSS|S:SSSS|" + "S:ST|S:STS|S:STST|" + "S:TS|S:TST|S:TSTS|" + "S:TTSS|S:SSTT|S:STTS|S:TSST" + ); + + 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_stringvar("a",a); + symbol_table.add_stringvar("b",b); + symbol_table.add_stringvar("c",c); + symbol_table.add_stringvar("d",d); + symbol_table.add_stringvar("result",result); + + symbol_table.add_function("foo",ovrld_func); + + typedef typename overload_func::test_result_t test_result_t; + typedef std::pair::test_result_t> test_pack_t; + + static const test_pack_t test_pack_list[] = + { + test_pack_t("result := foo(x)" , test_result_t( 0, "T" )), + test_pack_t("result := foo(x, y)" , test_result_t( 1, "TT" )), + test_pack_t("result := foo(x, y, z)" , test_result_t( 2, "TTT" )), + test_pack_t("result := foo(x, y, z, w)" , test_result_t( 3, "TTTT")), + test_pack_t("result := foo(x + y)" , test_result_t( 0, "T" )), + test_pack_t("result := foo(x + y, y + z)" , test_result_t( 1, "TT" )), + test_pack_t("result := foo(x + y, y + z, z + w)" , test_result_t( 2, "TTT" )), + test_pack_t("result := foo(x + y, y + z, z + w, w)" , test_result_t( 3, "TTTT")), + test_pack_t("result := foo(a)" , test_result_t( 4, "S" )), + test_pack_t("result := foo(a, b)" , test_result_t( 5, "SS" )), + test_pack_t("result := foo(a, b, c)" , test_result_t( 6, "SSS" )), + test_pack_t("result := foo(a, b, c, d)" , test_result_t( 7, "SSSS")), + test_pack_t("result := foo(a + b)" , test_result_t( 4, "S" )), + test_pack_t("result := foo(a + b, b + c)" , test_result_t( 5, "SS" )), + test_pack_t("result := foo(a + b, b + c, c + d)" , test_result_t( 6, "SSS" )), + test_pack_t("result := foo(a + b, b + c, c + d, d)" , test_result_t( 7, "SSSS")), + test_pack_t("result := foo(a, x)" , test_result_t( 8, "ST" )), + test_pack_t("result := foo(a, x, b)" , test_result_t( 9, "STS" )), + test_pack_t("result := foo(a, x, b, y)" , test_result_t(10, "STST")), + test_pack_t("result := foo(a + b, x + y)" , test_result_t( 8, "ST" )), + test_pack_t("result := foo(a + b, x + y, b + c)" , test_result_t( 9, "STS" )), + test_pack_t("result := foo(a + b, x + y, b + c, y + z)" , test_result_t(10, "STST")), + test_pack_t("result := foo(x, a)" , test_result_t(11, "TS" )), + test_pack_t("result := foo(x, a, y)" , test_result_t(12, "TST" )), + test_pack_t("result := foo(x, a, y, b)" , test_result_t(13, "TSTS")), + test_pack_t("result := foo(x + y, a + b)" , test_result_t(11, "TS" )), + test_pack_t("result := foo(x + y, a + b, y + z)" , test_result_t(12, "TST" )), + test_pack_t("result := foo(x + y, a + b, y + z, b + c)" , test_result_t(13, "TSTS")), + test_pack_t("result := foo(x, y, a, b)" , test_result_t(14, "TTSS")), + test_pack_t("result := foo(a, b, x, y)" , test_result_t(15, "SSTT")), + test_pack_t("result := foo(a, x, y, b)" , test_result_t(16, "STTS")), + test_pack_t("result := foo(x, a, b, y)" , test_result_t(17, "TSST")), + test_pack_t("result := foo(x + y, y + z, a + b, b + c)" , test_result_t(14, "TTSS")), + test_pack_t("result := foo(a + b, b + c, x + y, y + z)" , test_result_t(15, "SSTT")), + test_pack_t("result := foo(a + b, x + y, y + z, b + c)" , test_result_t(16, "STTS")), + test_pack_t("result := foo(x + y, a + b, b + c, y + z)" , test_result_t(17, "TSST")) + }; + + static const std::size_t test_pack_list_size = sizeof(test_pack_list) / sizeof(test_pack_t); + + std::deque expression_list; + + for (std::size_t i = 0; i < test_pack_list_size; ++i) + { + expression_t expression; + expression.register_symbol_table(symbol_table); + + exprtk::parser parser; + + if (!parser.compile(test_pack_list[i].first, expression)) + { + printf("run_test18() - (13) Overload VarArg Error: %s Expression: %s\n", + parser.error().c_str(), + test_pack_list[i].first.c_str()); + + return false; + } + else + expression_list.push_back(expression); + } + + bool failure = false; + + for (std::size_t i = 0; i < expression_list.size(); ++i) + { + ovrld_func.clear(); + result = ""; + expression_list[i].value(); + + if (result != "string result") + { + printf("run_test18() - Error in evaluation! (13) Expression: %s\n", + test_pack_list[i].first.c_str()); + + failure = true; + } + + if (ovrld_func.current_ps_index != test_pack_list[i].second.ps_index) + { + printf("run_test18() - Error with ps_index (13) Expression: %s Expected: %d Got: %d\n", + test_pack_list[i].first.c_str(), + static_cast(test_pack_list[i].second.ps_index), + static_cast(ovrld_func.current_ps_index)); + + failure = true; + } + + if (ovrld_func.current_param_seq != test_pack_list[i].second.param_seq) + { + printf("run_test18() - Error with parameter seq (13) Expression: %s Expected: %s Got: %s\n", + test_pack_list[i].first.c_str(), + test_pack_list[i].second.param_seq.c_str(), + ovrld_func.current_param_seq.c_str()); + + failure = true; + } + } + + if (failure) + return false; + } + return true; } @@ -7826,6 +8512,126 @@ inline bool run_test20() } } + { + T var; + std::string str; + std::vector vec(10,0.0); + + typedef exprtk::symbol_table symbol_table_t; + + bool result = true; + + { + symbol_table_t symbol_table; + + symbol_table.add_variable ("val",var); + symbol_table.add_stringvar("str",str); + symbol_table.add_vector ("vec",vec); + + if (symbol_table.get_variable("val") == 0 || !symbol_table.symbol_exists("val")) + { + printf("run_test20() - [3] Failed to get 'val' from symbol_table\n"); + result = false; + } + + if (symbol_table.get_stringvar("str") == 0 || !symbol_table.symbol_exists("str")) + { + printf("run_test20() - [3] Failed to get 'str' from symbol_table\n"); + result = false; + } + + if (symbol_table.get_vector("vec") == 0 || !symbol_table.symbol_exists("vec")) + { + printf("run_test20() - [3] Failed to get 'vec' from symbol_table\n"); + result = false; + } + } + + if (!result) + return result; + + { + symbol_table_t symbol_table; + + symbol_table.add_variable("val",var); + + if (symbol_table.get_variable("val") == 0 || !symbol_table.symbol_exists("val")) + { + printf("run_test20() - [4] Failed to get 'val' from symbol_table\n"); + result = false; + } + + if (symbol_table.get_stringvar("str") != 0 || symbol_table.symbol_exists("str")) + { + printf("run_test20() - [4] Failed to get 'str' from symbol_table\n"); + result = false; + } + + if (symbol_table.get_vector("vec") != 0 || symbol_table.symbol_exists("vec")) + { + printf("run_test20() - [4] Failed to get 'vec' from symbol_table\n"); + result = false; + } + } + + if (!result) + return result; + + { + symbol_table_t symbol_table; + + symbol_table.add_stringvar("str",str); + + if (symbol_table.get_stringvar("str") == 0 || !symbol_table.symbol_exists("str")) + { + printf("run_test20() - [5] Failed to get 'str' from symbol_table\n"); + result = false; + } + + if (symbol_table.get_variable("val") != 0 || symbol_table.symbol_exists("val")) + { + printf("run_test20() - [5] Failed to get 'val' from symbol_table\n"); + result = false; + } + + if (symbol_table.get_vector("vec") != 0 || symbol_table.symbol_exists("vec")) + { + printf("run_test20() - [5] Failed to get 'vec' from symbol_table\n"); + result = false; + } + } + + if (!result) + return result; + + { + symbol_table_t symbol_table; + + symbol_table.add_vector("vec",vec); + + if (symbol_table.get_vector("vec") == 0 || !symbol_table.symbol_exists("vec")) + { + printf("run_test20() - [6] Failed to get 'vec' from symbol_table\n"); + result = false; + } + + if (symbol_table.get_variable("val") != 0 || symbol_table.symbol_exists("val")) + { + printf("run_test20() - [6] Failed to get 'val' from symbol_table\n"); + result = false; + } + + if (symbol_table.get_stringvar("str") != 0 || symbol_table.symbol_exists("str")) + { + printf("run_test20() - [6] Failed to get 'str' from symbol_table\n"); + result = false; + } + } + + if (!result) + return result; + } + return true; } diff --git a/readme.txt b/readme.txt index a819125..8e4dc46 100644 --- a/readme.txt +++ b/readme.txt @@ -428,8 +428,8 @@ of C++ compilers: | [r0:r1] | The closed interval [r0,r1] of the specified string. | | | eg: Given a string x with a value of 'abcdefgh' then: | | | 1. x[1:4] == 'bcde' | -| | 2. x[ :5] == x[:5] == 'abcdef' | -| | 3. x[3: ] == x[3:] =='cdefgh' | +| | 2. x[ :5] == x[:10 / 2] == 'abcdef' | +| | 3. x[2 + 1: ] == x[3:] =='defgh' | | | 4. x[ : ] == x[:] == 'abcdefgh' | | | 5. x[4/2:3+2] == x[2:5] == 'cdef' | | | | @@ -706,6 +706,61 @@ This allows for the original element to be modified independently of 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 +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 +evaluations or variable referencing via the symbol_table instance will +result in undefined behaviour. + +The following bit of code instantiates a symbol_table and expression +instance, then proceeds to demonstrate various ways in which +references to variables can be added to the symbol_table, and how +those references are subsequently invalidated resulting in various +forms of undefined behaviour. + + typedef exprtk::symbol_table symbol_table_t; + + symbol_table_t symbol_table; + expression_t expression; + + { + double x = 123.4567; + symbol_table.add_variable("x", x); + } // Reference to variable x has been invalidated + + std::deque y {1.1, 2.2, 3.3}; + + symbol_table.add_variable("y", y.back()); + + y.pop_back(); // Reference to variable y has been invalidated + + std::vector z {4.4, 5.5, 6.6}; + + symbol_table.add_variable("z", z.front()); + + z.erase(z.begin()); + // Reference to variable z has been invalidated + + double* w = new double(123.456); + + symbol_table.add_variable("w", *w); + + delete w; // Reference to variable w has been invalidated + + const std::string expression_str = "x + y / z * w"; + + // Compilation of expression will succeed + parser.compile(expression_str,expression); + + expression.value(); + // Evaluation will result in undefined behaviour + + symbol_table.get_variable("x")->ref() = 135.791; + // Assignment will result in undefined behaviour + + The example below demonstrates the relationship between variables, symbol_table and expression. Note the variables are modified as they normally would in a program, and when the expression is evaluated the @@ -865,7 +920,7 @@ The above denoted AST will be evaluated in the following order: Generally an expression in ExprTk can be thought of as a free function similar to those found in imperative languages. This form of pseudo function will have a name, it may have a set of one or more inputs and -will return at least one value as its result. Futhermore the function +will return at least one value as its result. Furthermore the function when invoked, may cause a side-effect that changes the state of the host program. @@ -968,7 +1023,7 @@ copied, it will then result in two or more identical expressions utilizing the exact same references for variables. This obviously is not the default assumed scenario and will give rise to non-obvious behaviours when using the expressions in various contexts such as -muli-threading et al. +multi-threading et al. The prescribed method for cloning an expression is to compile it from its string form. Doing so will allow the 'user' to properly consider @@ -1260,7 +1315,7 @@ in a statement will cause it to have a side-effect: (b) Invoking a user-defined function that has side-effects The following are examples of expressions where the side-effect status -of the statements (or sub-exressions) within the expressions have been +of the statements (sub-expressions) within the expressions have been noted: +-+----------------------+------------------------------+ @@ -1537,7 +1592,7 @@ zero. The following are examples of variable definitions: var y := 3; (c) Initialise z to the expression - var z := if (max(1,x + y) > 2,w,v); + var z := if (max(1, x + y) > 2, w, v); (2) Vector Definition @@ -1552,7 +1607,7 @@ zero. The following are examples of vector definitions: var x[3] := {}; (c) Initialise all values to given expression - var x[3] := [123 + 3y + sin(w/z)]; + var x[3] := [123 + 3y + sin(w / z)]; (d) Initialise the first two values, all other elements to zero var x[3] := { 1 + x[2], sin(y[0] / x[]) + 3 }; @@ -1814,15 +1869,16 @@ embedded into the expression. There are five types of function interface: - +---+----------------------+-------------+----------------------+ - | # | Name | Return Type | Input Types | - +---+----------------------+-------------+----------------------+ - | 1 | ifunction | Scalar | Scalar | - | 2 | ivararg_function | Scalar | Scalar | - | 3 | igeneric_function | Scalar | Scalar,Vector,String | - | 4 | igeneric_function II | String | Scalar,Vector,String | - | 5 | function_compositor | Scalar | Scalar | - +---+----------------------+-------------+----------------------+ + +---+----------------------+--------------+----------------------+ + | # | Name | Return Type | Input Types | + +---+----------------------+--------------+----------------------+ + | 1 | ifunction | Scalar | Scalar | + | 2 | ivararg_function | Scalar | Scalar | + | 3 | igeneric_function | Scalar | Scalar,Vector,String | + | 4 | igeneric_function II | String | Scalar,Vector,String | + | 5 | igeneric_function III| String/Scalar| Scalar,Vector,String | + | 6 | function_compositor | Scalar | Scalar | + +---+----------------------+--------------+----------------------+ (1) ifunction This interface supports zero to 20 input parameters of only the scalar @@ -2198,7 +2254,60 @@ as follows: (4) Scalar (4) String -(5) function_compositor +(5) igeneric_function III +In this section we will discuss an extension of the igeneric_function +interface that will allow for the overloading of a user defined custom +function, where by it can return either a scalar or string value type +depending on the input parameter sequence with which the function is +invoked. + + template + struct foo : public exprtk::igeneric_function + { + typedef typename exprtk::igeneric_function::parameter_list_t + parameter_list_t; + + foo() + : exprtk::igeneric_function + ( + "T:T|S:TS", + igfun_t::e_rtrn_overload + ) + {} + + // Scalar value returning invocations + inline T operator()(const std::size_t& ps_index, + parameter_list_t parameters) + { + ... + } + + // String value returning invocations + inline T operator()(const std::size_t& ps_index, + std::string& result, + parameter_list_t& parameters) + { + ... + } + }; + + +In the example above the custom user defined function "foo" can be +invoked by using either one of two input parameter sequences, which +are defined as follows: + + Sequence-0 Sequence-1 + 'T' -> T 'TS' -> S + (1) Scalar (1) Scalar + (2) String + + +The parameter sequence definitions are identical to the previously +define igeneric_function, with the exception of the inclusion of the +return type - which can only be either a scalar T or a string S. + + +(6) function_compositor The function compositor is a factory that allows one to define and construct a function using ExprTk syntax. The functions are limited to returning a single scalar value and consuming up to six parameters as @@ -2355,11 +2464,11 @@ default be assumed to have side-effects and hence will not participate in constant folding optimisations. In the following example, a two input parameter free function named -'compute', and a three input parameter lambda will be registered with -the given symbol_table instance: +'compute1', and a three input parameter lambda named 'compute2' will +be registered with the given symbol_table instance: - double compute(double v0, double v1) + double compute1(double v0, double v1) { return 2.0 * v0 + v1 / 3.0; } @@ -2372,12 +2481,12 @@ the given symbol_table instance: symbol_table_t symbol_table; - symbol_table.add_function("compute", compute); - - symbol_table.add_function("lambda", - [](double v0, double v1, double v2) -> double - { return v0 / v1 + v2; }); + symbol_table.add_function("compute1", compute1); + symbol_table.add_function( + "compute2", + [](double v0, double v1, double v2) -> double + { return v0 / v1 + v2; }); ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -2715,7 +2824,7 @@ expression being compiled. This can become problematic, as in the default scenario it is assumed the symbol_table that is registered with the expression instance will -already posses the externally available variables, functions and +already possess the externally available variables, functions and constants needed during the compilation of the expression. In the event there are symbols in the expression that can't be mapped @@ -2838,7 +2947,7 @@ after which the expression itself can be evaluated. for (auto& var_name : variable_list) { - T& v = symbol_table.variable_ref(var_name); + T& v = unknown_var_symbol_table.variable_ref(var_name); v = ...; } @@ -2999,6 +3108,24 @@ constructor of the user defined USR. Note: The primary symbol table for an expression is the first symbol table to be registered with that instance of the expression. +Note: For a successful symbol resolution using the normal USR all of +the following are required: + + (1) Only if successful shall the process method return TRUE + (2) The default_value parameter will have been set + (3) The error_message parameter will be empty + (4) usr_symbol_type input parameter field will be set to either: + (*) e_usr_variable_type + (*) e_usr_constant_type + +Note: For a successful symbol resolution using the extended USR all of +the following are required: + + (1) Only if successful shall the process method return TRUE + (2) symbol_table parameter will have had the newly resolved + variable or string added to it + (3) error_message parameter will be empty + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ [SECTION 19 - ENABLING & DISABLING FEATURES] @@ -3710,13 +3837,13 @@ follows: if (exprtk::collect_variables(expression, variable_list)) { - for (auto var : variable_list) + for (const auto& var : variable_list) { ... } } else - printf("An error occured."); + printf("An error occurred."); (b) collect_functions @@ -3734,13 +3861,13 @@ follows: if (exprtk::collect_functions(expression, function_list)) { - for (auto func : function_list) + for (const auto& func : function_list) { ... } } else - printf("An error occured."); + printf("An error occurred."); Note: When either the 'collect_variables' or 'collect_functions' free @@ -3752,10 +3879,10 @@ true. Note: The default interface provided for both the collect_variables and collect_functions free_functions, assumes that expressions will -only be utilising the ExprTk reserved funnctions (eg: abs, cos, min +only be utilising the ExprTk reserved functions (eg: abs, cos, min etc). When user defined functions are to be used in an expression, a symbol_table instance containing said functions can be passed to -either routine, and will be incorparated during the compilation and +either routine, and will be incorporated during the compilation and Dependent Entity Collection processes. In the following example, a user defined free function named 'foo' is registered with a symbol_table. Finally the symbol_table instance and associated @@ -3779,13 +3906,13 @@ expression string are passed to the exprtk::collect_functions routine. if (exprtk::collect_functions(expression, sym_tab, function_list)) { - for (auto func : function_list) + for (const auto& func : function_list) { ... } } else - printf("An error occured."); + printf("An error occurred."); (c) compute @@ -3910,7 +4037,7 @@ function is as follows: // Differentiate expression at value of x = 12.3 using a reference // to the x variable x = T(12.3); - T derivative1 = exprtk::derivative(expression,x); + T derivative1 = exprtk::derivative(expression, x); // Differentiate expression where value x = 45.6 using name // of the x variable @@ -3988,7 +4115,7 @@ is as follows: // Third derivative of expression where value of x = 12.3 using a // reference to the x variable x = T(12.3); - T derivative1 = exprtk::third_derivative(expression,x); + T derivative1 = exprtk::third_derivative(expression, x); // Third derivative of expression where value of x = 45.6 using // name of the x variable @@ -4168,9 +4295,11 @@ into account when using ExprTk: function names are case-insensitive. (07) Variable, vector, string variable and function names must begin - with a letter (A-Z or a-z), then can be comprised of any - combination of letters, digits, underscores and dots. (eg: x, - var1 or power_func99, person.age, item.size.0) + with a letter (A-Z or a-z), then can be comprised of any + combination of letters, digits, underscores and dots, ending in + either a letter (A-Z or a-z), digit or underscore. (eg: x, y2, + var1, power_func99, person.age, item.size.0). The associated + regex pattern is: [a-zA-Z]([a-zA-Z0-9_.]*|[a-zA-Z0-9_]) (08) Expression lengths and sub-expression lists are limited only by storage capacity.