From 42de8b70ad034d01027d10e6f5e0820e42669345 Mon Sep 17 00:00:00 2001 From: Arash Partow Date: Tue, 26 Jan 2021 13:10:27 +1100 Subject: [PATCH] Update the ExprTk library --- Color/ChannelMath/exprtk.hpp | 38647 +++++++++++++++++++++------------ 1 file changed, 24263 insertions(+), 14384 deletions(-) diff --git a/Color/ChannelMath/exprtk.hpp b/Color/ChannelMath/exprtk.hpp index 057895b..cb65b5f 100644 --- a/Color/ChannelMath/exprtk.hpp +++ b/Color/ChannelMath/exprtk.hpp @@ -1,18 +1,15 @@ /* - MODIFICATIONS BY N CARROLL - 1. Clamp from clamp(a,b,c) to clamp(b,a,c) - ****************************************************************** * C++ Mathematical Expression Toolkit Library * * * - * Author: Arash Partow (1999-2015) * + * Author: Arash Partow (1999-2021) * * URL: http://www.partow.net/programming/exprtk/index.html * * * * Copyright notice: * * Free use of the C++ Mathematical Expression Toolkit Library is * * permitted under the guidelines and in accordance with the most * - * current version of the Common Public License. * - * http://www.opensource.org/licenses/cpl1.0.php * + * current version of the MIT License. * + * http://www.opensource.org/licenses/MIT * * * * Example expressions: * * (00) (y + x / y) * (x - y / x) * @@ -25,7 +22,6 @@ * (07) z := x + sin(2 * pi / y) * * (08) u := 2 * (pi * z) / (w := x + cos(y / pi)) * * (09) clamp(-1,sin(2 * pi * x) + cos(y / 2 * pi),+1) * - * CLAMP MODIFIED * (10) inrange(-2,m,+2) == if(({-2 <= m} and [m <= +2]),1,0) * * (11) (2sin(x)cos(2y)7 + 1) == (2 * sin(x) * cos(2*y) * 7 + 1) * * (12) (x ilike 's*ri?g') and [y < (3 z^7 + w)] * @@ -39,10 +35,13 @@ #include +#include #include #include +#include #include #include +#include #include #include #include @@ -60,15 +59,41 @@ namespace exprtk { - #if exprtk_enable_debugging + #ifdef exprtk_enable_debugging #define exprtk_debug(params) printf params #else #define exprtk_debug(params) (void)0 #endif + #define exprtk_error_location \ + "exprtk.hpp:" + details::to_str(__LINE__) \ + + #if defined(__GNUC__) && (__GNUC__ >= 7) + + #define exprtk_disable_fallthrough_begin \ + _Pragma ("GCC diagnostic push") \ + _Pragma ("GCC diagnostic ignored \"-Wimplicit-fallthrough\"") \ + + #define exprtk_disable_fallthrough_end \ + _Pragma ("GCC diagnostic pop") \ + + #else + #define exprtk_disable_fallthrough_begin (void)0; + #define exprtk_disable_fallthrough_end (void)0; + #endif + namespace details { - inline bool is_whitespace(const char c) + 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) { return (' ' == c) || ('\n' == c) || ('\r' == c) || ('\t' == c) || @@ -76,7 +101,7 @@ namespace exprtk ('\f' == c) ; } - inline bool is_operator_char(const char c) + inline bool is_operator_char(const char_t c) { return ('+' == c) || ('-' == c) || ('*' == c) || ('/' == c) || @@ -91,43 +116,43 @@ namespace exprtk ('|' == c) || (';' == c) ; } - inline bool is_letter(const char c) + inline bool is_letter(const char_t c) { return (('a' <= c) && (c <= 'z')) || (('A' <= c) && (c <= 'Z')) ; } - inline bool is_digit(const char c) + inline bool is_digit(const char_t c) { return ('0' <= c) && (c <= '9'); } - inline bool is_letter_or_digit(const char c) + inline bool is_letter_or_digit(const char_t c) { return is_letter(c) || is_digit(c); } - inline bool is_left_bracket(const char c) + inline bool is_left_bracket(const char_t c) { return ('(' == c) || ('[' == c) || ('{' == c); } - inline bool is_right_bracket(const char c) + inline bool is_right_bracket(const char_t c) { return (')' == c) || (']' == c) || ('}' == c); } - inline bool is_bracket(const char c) + inline bool is_bracket(const char_t c) { return is_left_bracket(c) || is_right_bracket(c); } - inline bool is_sign(const char c) + inline bool is_sign(const char_t c) { return ('+' == c) || ('-' == c); } - inline bool is_invalid(const char c) + inline bool is_invalid(const char_t c) { return !is_whitespace (c) && !is_operator_char(c) && @@ -140,7 +165,22 @@ namespace exprtk ('\'' != c); } - inline bool imatch(const char c1, const char c2) + 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) + { + for (std::size_t i = 0; i < s.size(); ++i) + { + s[i] = static_cast(std::tolower(s[i])); + } + } + + inline bool imatch(const char_t c1, const char_t c2) { return std::tolower(c1) == std::tolower(c2); } @@ -163,6 +203,50 @@ namespace exprtk return false; } + struct ilesscompare + { + inline bool operator() (const std::string& s1, const std::string& s2) const + { + const std::size_t length = std::min(s1.size(),s2.size()); + + for (std::size_t i = 0; i < length; ++i) + { + const char_t c1 = static_cast(std::tolower(s1[i])); + const char_t c2 = static_cast(std::tolower(s2[i])); + + if (c1 > c2) + return false; + else if (c1 < c2) + return true; + } + + return s1.size() < s2.size(); + } + }; + + #else + inline void case_normalise(std::string&) + {} + + inline bool imatch(const char_t c1, const char_t c2) + { + return c1 == c2; + } + + inline bool imatch(const std::string& s1, const std::string& s2) + { + return s1 == s2; + } + + struct ilesscompare + { + inline bool operator() (const std::string& s1, const std::string& s2) const + { + return s1 < s2; + } + }; + #endif + inline bool is_valid_sf_symbol(const std::string& symbol) { // Special function: $f12 or $F34 @@ -173,29 +257,50 @@ namespace exprtk is_digit(symbol[3]); } + inline const char_t& front(const std::string& s) + { + return s[0]; + } + + inline const char_t& back(const std::string& s) + { + return s[s.size() - 1]; + } + inline std::string to_str(int i) { if (0 == i) return std::string("0"); std::string result; - bool negative = (i < 0); - if (negative) i *= -1; + if (i < 0) + { + for ( ; i; i /= 10) + { + result += '0' + char(-(i % 10)); + } - while (i) + result += '-'; + } + else { - char digit = '0' + char(i % 10); - result = (digit + result); - i /= 10; + for ( ; i; i /= 10) + { + result += '0' + char(i % 10); + } } - if (negative) - result = "-" + result; + std::reverse(result.begin(), result.end()); return result; } + inline std::string to_str(std::size_t i) + { + return to_str(static_cast(i)); + } + inline bool is_hex_digit(const std::string::value_type digit) { return (('0' <= digit) && (digit <= '9')) || @@ -203,79 +308,87 @@ namespace exprtk (('a' <= digit) && (digit <= 'f')) ; } - inline unsigned char hex_to_bin(unsigned char h) + inline uchar_t hex_to_bin(uchar_t h) { if (('0' <= h) && (h <= '9')) return (h - '0'); else - return (std::toupper(h) - 'A'); + return static_cast(std::toupper(h) - 'A'); } 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(*(itr + 2)) << 4 | hex_to_bin(*(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) { - std::string::iterator itr1 = s.begin(); - std::string::iterator itr2 = s.begin(); - std::string::iterator end = s.end (); + typedef std::string::iterator str_itr_t; + + str_itr_t itr1 = s.begin(); + str_itr_t itr2 = s.begin(); + str_itr_t end = s.end (); + std::size_t removal_count = 0; while (end != itr1) { 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 @@ -293,7 +406,7 @@ namespace exprtk return (*this); } - inline build_string& operator << (const char* s) + inline build_string& operator << (char_cptr s) { data_ += std::string(s); return (*this); @@ -314,34 +427,13 @@ namespace exprtk std::string data_; }; - struct ilesscompare - { - inline bool operator()(const std::string& s1, const std::string& s2) const - { - const std::size_t length = std::min(s1.size(),s2.size()); - - for (std::size_t i = 0; i < length; ++i) - { - const char c1 = static_cast(std::tolower(s1[i])); - const char c2 = static_cast(std::tolower(s2[i])); - - if (c1 > c2) - return false; - else if (c1 < c2) - return true; - } - - return s1.size() < s2.size(); - } - }; - static const std::string reserved_words[] = { "break", "case", "continue", "default", "false", "for", "if", "else", "ilike", "in", "like", "and", "nand", "nor", - "not", "null", "or", "repeat", "shl", "shr", "swap", - "switch", "true", "until", "var", "while", "xnor", "xor", - "&", "|" + "not", "null", "or", "repeat", "return", "shl", "shr", + "swap", "switch", "true", "until", "var", "while", "xnor", + "xor", "&", "|" }; static const std::size_t reserved_words_size = sizeof(reserved_words) / sizeof(std::string); @@ -357,19 +449,72 @@ namespace exprtk "like", "log", "log10", "log2", "logn", "log1p", "mand", "max", "min", "mod", "mor", "mul", "ncdf", "nand", "nor", "not", "not_equal", "null", "or", "pow", "rad2deg", - "repeat", "root", "round", "roundn", "sec", "sgn", "shl", - "shr", "sin", "sinc", "sinh", "sqrt", "sum", "swap", + "repeat", "return", "root", "round", "roundn", "sec", "sgn", + "shl", "shr", "sin", "sinc", "sinh", "sqrt", "sum", "swap", "switch", "tan", "tanh", "true", "trunc", "until", "var", "while", "xnor", "xor", "&", "|" }; static const std::size_t reserved_symbols_size = sizeof(reserved_symbols) / sizeof(std::string); + static const std::string base_function_list[] = + { + "abs", "acos", "acosh", "asin", "asinh", "atan", "atanh", + "atan2", "avg", "ceil", "clamp", "cos", "cosh", "cot", + "csc", "equal", "erf", "erfc", "exp", "expm1", "floor", + "frac", "hypot", "iclamp", "like", "log", "log10", "log2", + "logn", "log1p", "mand", "max", "min", "mod", "mor", "mul", + "ncdf", "pow", "root", "round", "roundn", "sec", "sgn", + "sin", "sinc", "sinh", "sqrt", "sum", "swap", "tan", "tanh", + "trunc", "not_equal", "inrange", "deg2grad", "deg2rad", + "rad2deg", "grad2deg" + }; + + static const std::size_t base_function_list_size = sizeof(base_function_list) / sizeof(std::string); + + static const std::string logic_ops_list[] = + { + "and", "nand", "nor", "not", "or", "xnor", "xor", "&", "|" + }; + + static const std::size_t logic_ops_list_size = sizeof(logic_ops_list) / sizeof(std::string); + + static const std::string cntrl_struct_list[] = + { + "if", "switch", "for", "while", "repeat", "return" + }; + + static const std::size_t cntrl_struct_list_size = sizeof(cntrl_struct_list) / sizeof(std::string); + + static const std::string arithmetic_ops_list[] = + { + "+", "-", "*", "/", "%", "^" + }; + + static const std::size_t arithmetic_ops_list_size = sizeof(arithmetic_ops_list) / sizeof(std::string); + + static const std::string assignment_ops_list[] = + { + ":=", "+=", "-=", + "*=", "/=", "%=" + }; + + static const std::size_t assignment_ops_list_size = sizeof(assignment_ops_list) / sizeof(std::string); + + static const std::string inequality_ops_list[] = + { + "<", "<=", "==", + "=", "!=", "<>", + ">=", ">" + }; + + static const std::size_t inequality_ops_list_size = sizeof(inequality_ops_list) / sizeof(std::string); + inline bool is_reserved_word(const std::string& symbol) { for (std::size_t i = 0; i < reserved_words_size; ++i) { - if (imatch(symbol,reserved_words[i])) + if (imatch(symbol, reserved_words[i])) { return true; } @@ -382,7 +527,46 @@ namespace exprtk { for (std::size_t i = 0; i < reserved_symbols_size; ++i) { - if (imatch(symbol,reserved_symbols[i])) + if (imatch(symbol, reserved_symbols[i])) + { + return true; + } + } + + return false; + } + + inline bool is_base_function(const std::string& function_name) + { + for (std::size_t i = 0; i < base_function_list_size; ++i) + { + if (imatch(function_name, base_function_list[i])) + { + return true; + } + } + + return false; + } + + inline bool is_control_struct(const std::string& cntrl_strct) + { + for (std::size_t i = 0; i < cntrl_struct_list_size; ++i) + { + if (imatch(cntrl_strct, cntrl_struct_list[i])) + { + return true; + } + } + + return false; + } + + inline bool is_logic_opr(const std::string& lgc_opr) + { + for (std::size_t i = 0; i < logic_ops_list_size; ++i) + { + if (imatch(lgc_opr, logic_ops_list[i])) { return true; } @@ -393,7 +577,7 @@ namespace exprtk struct cs_match { - static inline bool cmp(const char c0, const char c1) + static inline bool cmp(const char_t c0, const char_t c1) { return (c0 == c1); } @@ -401,7 +585,7 @@ namespace exprtk struct cis_match { - static inline bool cmp(const char c0, const char c1) + static inline bool cmp(const char_t c0, const char_t c1) { return (std::tolower(c0) == std::tolower(c1)); } @@ -409,92 +593,93 @@ 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, const std::string& str, std::size_t& diff_index, - char& diff_value) + char_t& diff_value) { - if (str.empty() || pattern.empty()) - return false; + if (str.empty()) + { + return ("Z" == pattern); + } else if ('*' == pattern[0]) return false; @@ -510,12 +695,12 @@ namespace exprtk { if ('*' == (*p_itr)) { - const char target = std::toupper(*(p_itr - 1)); + const char_t target = static_cast(std::toupper(*(p_itr - 1))); if ('*' == target) { - diff_index = std::distance(str.begin(),s_itr); - diff_value = std::toupper(*p_itr); + diff_index = static_cast(std::distance(str.begin(),s_itr)); + diff_value = static_cast(std::toupper(*p_itr)); return false; } @@ -537,8 +722,8 @@ namespace exprtk std::toupper(*p_itr) != std::toupper(*s_itr) ) { - diff_index = std::distance(str.begin(),s_itr); - diff_value = std::toupper(*p_itr); + diff_index = static_cast(std::distance(str.begin(),s_itr)); + diff_value = static_cast(std::toupper(*p_itr)); return false; } @@ -557,89 +742,93 @@ namespace exprtk } static const double pow10[] = { - 1.0, - 1.0E+001, 1.0E+002, 1.0E+003, 1.0E+004, - 1.0E+005, 1.0E+006, 1.0E+007, 1.0E+008, - 1.0E+009, 1.0E+010, 1.0E+011, 1.0E+012, - 1.0E+013, 1.0E+014, 1.0E+015, 1.0E+016 + 1.0, + 1.0E+001, 1.0E+002, 1.0E+003, 1.0E+004, + 1.0E+005, 1.0E+006, 1.0E+007, 1.0E+008, + 1.0E+009, 1.0E+010, 1.0E+011, 1.0E+012, + 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 { namespace constant { - static const double e = 2.718281828459045235360; - static const double pi = 3.141592653589793238462; - static const double pi_2 = 1.570796326794896619231; - static const double pi_4 = 0.785398163397448309616; - static const double pi_180 = 0.017453292519943295769; - static const double _1_pi = 0.318309886183790671538; - static const double _2_pi = 0.636619772367581343076; - static const double _180_pi = 57.295779513082320876798; - static const double log2 = 0.693147180559945309417; - static const double sqrt2 = 1.414213562373095048801; + static const double e = 2.71828182845904523536028747135266249775724709369996; + static const double pi = 3.14159265358979323846264338327950288419716939937510; + static const double pi_2 = 1.57079632679489661923132169163975144209858469968755; + static const double pi_4 = 0.78539816339744830961566084581987572104929234984378; + static const double pi_180 = 0.01745329251994329576923690768488612713442871888542; + static const double _1_pi = 0.31830988618379067153776752674502872406891929148091; + static const double _2_pi = 0.63661977236758134307553505349005744813783858296183; + static const double _180_pi = 57.29577951308232087679815481410517033240547246656443; + static const double log2 = 0.69314718055994530941723212145817656807550013436026; + static const double sqrt2 = 1.41421356237309504880168872420969807856967187537695; } namespace details { - struct unknown_type_tag {}; - struct real_type_tag {}; - struct int_type_tag {}; + struct unknown_type_tag { unknown_type_tag() {} }; + struct real_type_tag { real_type_tag () {} }; + struct complex_type_tag { complex_type_tag() {} }; + struct int_type_tag { int_type_tag () {} }; template - struct number_type { typedef unknown_type_tag type; }; + struct number_type + { + typedef unknown_type_tag type; + number_type() {} + }; - #define exprtk_register_real_type_tag(T) \ - template<> struct number_type { typedef real_type_tag type; }; \ + #define exprtk_register_real_type_tag(T) \ + template <> struct number_type \ + { typedef real_type_tag type; number_type() {} }; \ - #define exprtk_register_int_type_tag(T) \ - template<> struct number_type { typedef int_type_tag type; }; \ + #define exprtk_register_complex_type_tag(T) \ + template <> struct number_type > \ + { typedef complex_type_tag type; number_type() {} }; \ + + #define exprtk_register_int_type_tag(T) \ + template <> struct number_type \ + { typedef int_type_tag type; number_type() {} }; \ exprtk_register_real_type_tag(double ) exprtk_register_real_type_tag(long double) exprtk_register_real_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_complex_type_tag(double ) + exprtk_register_complex_type_tag(long double) + exprtk_register_complex_type_tag(float ) + + exprtk_register_int_type_tag(short ) + exprtk_register_int_type_tag(int ) + exprtk_register_int_type_tag(_int64_t ) + 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 template - struct epsilon_type - { - static inline T value() - { - const T epsilon = T(0.0000000001); - return epsilon; - } - }; + struct epsilon_type {}; - template <> - struct epsilon_type - { - static inline float value() - { - const float epsilon = float(0.000001f); - return epsilon; - } - }; + #define exprtk_define_epsilon_type(Type, Epsilon) \ + template <> struct epsilon_type \ + { \ + static inline Type value() \ + { \ + const Type epsilon = static_cast(Epsilon); \ + return epsilon; \ + } \ + }; \ - template <> - struct epsilon_type - { - static inline long double value() - { - const long double epsilon = (long double)(0.000000000001); - return epsilon; - } - }; + exprtk_define_epsilon_type(float , 0.000001f) + exprtk_define_epsilon_type(double , 0.0000000001) + exprtk_define_epsilon_type(long double, 0.000000000001) + + #undef exprtk_define_epsilon_type template inline bool is_nan_impl(const T v, real_type_tag) @@ -654,9 +843,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 @@ -674,7 +863,7 @@ namespace exprtk template inline T abs_impl(const T v, real_type_tag) { - return ((v >= T(0)) ? v : -v); + return ((v < T(0)) ? -v : v); } template @@ -727,14 +916,16 @@ namespace exprtk template inline T nequal_impl(const T v0, const T v1, real_type_tag) { + typedef real_type_tag rtg; const T epsilon = epsilon_type::value(); - return (abs_impl(v0 - v1,real_type_tag()) > (std::max(T(1),std::max(abs_impl(v0,real_type_tag()),abs_impl(v1,real_type_tag()))) * epsilon)) ? T(1) : T(0); + return (abs_impl(v0 - v1,rtg()) > (std::max(T(1),std::max(abs_impl(v0,rtg()),abs_impl(v1,rtg()))) * epsilon)) ? T(1) : T(0); } inline float nequal_impl(const float v0, const float v1, real_type_tag) { + typedef real_type_tag rtg; const float epsilon = epsilon_type::value(); - return (abs_impl(v0 - v1,real_type_tag()) > (std::max(1.0f,std::max(abs_impl(v0,real_type_tag()),abs_impl(v1,real_type_tag()))) * epsilon)) ? 1.0f : 0.0f; + return (abs_impl(v0 - v1,rtg()) > (std::max(1.0f,std::max(abs_impl(v0,rtg()),abs_impl(v1,rtg()))) * epsilon)) ? 1.0f : 0.0f; } template @@ -809,7 +1000,15 @@ namespace exprtk template inline T root_impl(const T v0, const T v1, real_type_tag) { - return std::pow(v0,T(1) / v1); + if (v1 < T(0)) + return std::numeric_limits::quiet_NaN(); + + const std::size_t n = static_cast(v1); + + if ((v0 < T(0)) && (0 == (n % 2))) + return std::numeric_limits::quiet_NaN(); + + return std::pow(v0, T(1) / n); } template @@ -827,8 +1026,9 @@ namespace exprtk template inline T roundn_impl(const T v0, const T v1, real_type_tag) { - const int index = std::max(0, std::min(pow10_size - 1, (int)std::floor(v1))); + const int index = std::max(0, std::min(pow10_size - 1, static_cast(std::floor(v1)))); const T p10 = T(pow10[index]); + if (v0 < T(0)) return T(std::ceil ((v0 * p10) - T(0.5)) / p10); else @@ -970,6 +1170,7 @@ namespace exprtk { const bool v0_true = is_true_impl(v0); const bool v1_true = is_true_impl(v1); + if ((v0_true && v1_true) || (!v0_true && !v1_true)) return T(1); else @@ -981,18 +1182,28 @@ namespace exprtk { const bool v0_true = is_true_impl(v0); const bool v1_true = is_true_impl(v1); + if ((v0_true && v1_true) || (!v0_true && !v1_true)) return T(1); else return T(0); } + #if (defined(_MSC_VER) && (_MSC_VER >= 1900)) || !defined(_MSC_VER) + #define exprtk_define_erf(TT,impl) \ + inline TT erf_impl(TT v) { return impl(v); } \ + + exprtk_define_erf( float,::erff) + exprtk_define_erf( double,::erf ) + exprtk_define_erf(long double,::erfl) + #undef exprtk_define_erf + #endif + template inline T erf_impl(T v, real_type_tag) { - #if defined(_WIN32) || defined(__WIN32__) || defined(WIN32) + #if defined(_MSC_VER) && (_MSC_VER < 1900) // Credits: Abramowitz & Stegun Equations 7.1.25-28 - const T t = T(1) / (T(1) + T(0.5) * abs_impl(v,real_type_tag())); static const T c[] = { T( 1.26551223), T(1.00002368), T( 0.37409196), T(0.09678418), @@ -1000,15 +1211,19 @@ namespace exprtk T(-1.13520398), T(1.48851587), T(-0.82215223), T(0.17087277) }; + + const T t = T(1) / (T(1) + T(0.5) * abs_impl(v,real_type_tag())); + T result = T(1) - t * std::exp((-v * v) - c[0] + t * (c[1] + t * (c[2] + t * (c[3] + t * (c[4] + t * (c[5] + t * (c[6] + t * (c[7] + t * (c[8] + t * (c[9])))))))))); + return (v >= T(0)) ? result : -result; #else - return ::erf(v); + return erf_impl(v); #endif } @@ -1018,13 +1233,23 @@ namespace exprtk return erf_impl(static_cast(v),real_type_tag()); } + #if (defined(_MSC_VER) && (_MSC_VER >= 1900)) || !defined(_MSC_VER) + #define exprtk_define_erfc(TT,impl) \ + inline TT erfc_impl(TT v) { return impl(v); } \ + + exprtk_define_erfc( float,::erfcf) + exprtk_define_erfc( double,::erfc ) + exprtk_define_erfc(long double,::erfcl) + #undef exprtk_define_erfc + #endif + template inline T erfc_impl(T v, real_type_tag) { - #if defined(_WIN32) || defined(__WIN32__) || defined(WIN32) + #if defined(_MSC_VER) && (_MSC_VER < 1900) return T(1) - erf_impl(v,real_type_tag()); #else - return ::erfc(v); + return erfc_impl(v); #endif } @@ -1069,7 +1294,7 @@ namespace exprtk template inline T asin_impl(const T v, real_type_tag) { return std::asin (v); } template inline T asinh_impl(const T v, real_type_tag) { return std::log(v + std::sqrt((v * v) + T(1))); } template inline T atan_impl(const T v, real_type_tag) { return std::atan (v); } - template inline T atanh_impl(const T v, real_type_tag) { return (std::log(T(1) + v) - log(T(1) - v)) / T(2); } + template inline T atanh_impl(const T v, real_type_tag) { return (std::log(T(1) + v) - std::log(T(1) - v)) / T(2); } template inline T ceil_impl(const T v, real_type_tag) { return std::ceil (v); } template inline T cos_impl(const T v, real_type_tag) { return std::cos (v); } template inline T cosh_impl(const T v, real_type_tag) { return std::cosh (v); } @@ -1096,6 +1321,9 @@ 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 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); } template inline T log_impl(const T v, int_type_tag) { return std::log (v); } @@ -1142,170 +1370,170 @@ namespace exprtk template struct numeric_info { enum { length = 0, size = 32, bound_length = 0, min_exp = 0, max_exp = 0 }; }; - template<> struct numeric_info { enum { length = 10, size = 16, bound_length = 9}; }; - template<> struct numeric_info { enum { min_exp = -38, max_exp = +38}; }; - template<> struct numeric_info { enum { min_exp = -308, max_exp = +308}; }; - template<> struct numeric_info { enum { min_exp = -308, max_exp = +308}; }; + template <> struct numeric_info { enum { length = 10, size = 16, bound_length = 9}; }; + template <> struct numeric_info { enum { min_exp = -38, max_exp = +38}; }; + template <> struct numeric_info { enum { min_exp = -308, max_exp = +308}; }; + template <> struct numeric_info { enum { min_exp = -308, max_exp = +308}; }; template inline int to_int32(const T v) { - typename details::number_type::type num_type; - return to_int32_impl(v,num_type); + const typename details::number_type::type num_type; + return to_int32_impl(v, num_type); } template - inline long long int to_int64(const T v) + inline _int64_t to_int64(const T v) { - typename details::number_type::type num_type; - return to_int64_impl(v,num_type); + const typename details::number_type::type num_type; + return to_int64_impl(v, num_type); } template inline bool is_nan(const T v) { - typename details::number_type::type num_type; - return is_nan_impl(v,num_type); + const typename details::number_type::type num_type; + return is_nan_impl(v, num_type); } template inline T min(const T v0, const T v1) { - typename details::number_type::type num_type; - return min_impl(v0,v1,num_type); + const typename details::number_type::type num_type; + return min_impl(v0, v1, num_type); } template inline T max(const T v0, const T v1) { - typename details::number_type::type num_type; - return max_impl(v0,v1,num_type); + const typename details::number_type::type num_type; + return max_impl(v0, v1, num_type); } template inline T equal(const T v0, const T v1) { - typename details::number_type::type num_type; - return equal_impl(v0,v1,num_type); + const typename details::number_type::type num_type; + return equal_impl(v0, v1, num_type); } template inline T nequal(const T v0, const T v1) { - typename details::number_type::type num_type; - return nequal_impl(v0,v1,num_type); + const typename details::number_type::type num_type; + return nequal_impl(v0, v1, num_type); } template inline T modulus(const T v0, const T v1) { - typename details::number_type::type num_type; - return modulus_impl(v0,v1,num_type); + const typename details::number_type::type num_type; + return modulus_impl(v0, v1, num_type); } template inline T pow(const T v0, const T v1) { - typename details::number_type::type num_type; - return pow_impl(v0,v1,num_type); + const typename details::number_type::type num_type; + return pow_impl(v0, v1, num_type); } template inline T logn(const T v0, const T v1) { - typename details::number_type::type num_type; - return logn_impl(v0,v1,num_type); + const typename details::number_type::type num_type; + return logn_impl(v0, v1, num_type); } template inline T root(const T v0, const T v1) { - typename details::number_type::type num_type; - return root_impl(v0,v1,num_type); + const typename details::number_type::type num_type; + return root_impl(v0, v1, num_type); } template inline T roundn(const T v0, const T v1) { - typename details::number_type::type num_type; - return roundn_impl(v0,v1,num_type); + const typename details::number_type::type num_type; + return roundn_impl(v0, v1, num_type); } template inline T hypot(const T v0, const T v1) { - typename details::number_type::type num_type; - return hypot_impl(v0,v1,num_type); + const typename details::number_type::type num_type; + return hypot_impl(v0, v1, num_type); } template inline T atan2(const T v0, const T v1) { - typename details::number_type::type num_type; - return atan2_impl(v0,v1,num_type); + const typename details::number_type::type num_type; + return atan2_impl(v0, v1, num_type); } template inline T shr(const T v0, const T v1) { - typename details::number_type::type num_type; - return shr_impl(v0,v1,num_type); + const typename details::number_type::type num_type; + return shr_impl(v0, v1, num_type); } template inline T shl(const T v0, const T v1) { - typename details::number_type::type num_type; - return shl_impl(v0,v1,num_type); + const typename details::number_type::type num_type; + return shl_impl(v0, v1, num_type); } template inline T and_opr(const T v0, const T v1) { - typename details::number_type::type num_type; - return and_impl(v0,v1,num_type); + const typename details::number_type::type num_type; + return and_impl(v0, v1, num_type); } template inline T nand_opr(const T v0, const T v1) { - typename details::number_type::type num_type; - return nand_impl(v0,v1,num_type); + const typename details::number_type::type num_type; + return nand_impl(v0, v1, num_type); } template inline T or_opr(const T v0, const T v1) { - typename details::number_type::type num_type; - return or_impl(v0,v1,num_type); + const typename details::number_type::type num_type; + return or_impl(v0, v1, num_type); } template inline T nor_opr(const T v0, const T v1) { - typename details::number_type::type num_type; - return nor_impl(v0,v1,num_type); + const typename details::number_type::type num_type; + return nor_impl(v0, v1, num_type); } template inline T xor_opr(const T v0, const T v1) { - typename details::number_type::type num_type; - return xor_impl(v0,v1,num_type); + const typename details::number_type::type num_type; + return xor_impl(v0, v1, num_type); } template inline T xnor_opr(const T v0, const T v1) { - typename details::number_type::type num_type; - return xnor_impl(v0,v1,num_type); + const typename details::number_type::type num_type; + return xnor_impl(v0, v1, num_type); } template inline bool is_integer(const T v) { - typename details::number_type::type num_type; - return is_integer_impl(v,num_type); + const typename details::number_type::type num_type; + return is_integer_impl(v, num_type); } template @@ -1344,13 +1572,13 @@ namespace exprtk template struct fast_exp { static inline T result(T v) { return v; } }; template struct fast_exp { static inline T result(T ) { return T(1); } }; - #define exprtk_define_unary_function(FunctionName) \ - template \ - inline T FunctionName (const T v) \ - { \ - typename details::number_type::type num_type; \ - return FunctionName##_impl(v,num_type); \ - } \ + #define exprtk_define_unary_function(FunctionName) \ + template \ + inline T FunctionName (const T v) \ + { \ + const typename details::number_type::type num_type; \ + return FunctionName##_impl(v,num_type); \ + } \ exprtk_define_unary_function(abs ) exprtk_define_unary_function(acos ) @@ -1400,38 +1628,38 @@ namespace exprtk { static const double fract10[] = { - 0.0, - 1.0E+001, 1.0E+002, 1.0E+003, 1.0E+004, 1.0E+005, 1.0E+006, 1.0E+007, 1.0E+008, 1.0E+009, 1.0E+010, - 1.0E+011, 1.0E+012, 1.0E+013, 1.0E+014, 1.0E+015, 1.0E+016, 1.0E+017, 1.0E+018, 1.0E+019, 1.0E+020, - 1.0E+021, 1.0E+022, 1.0E+023, 1.0E+024, 1.0E+025, 1.0E+026, 1.0E+027, 1.0E+028, 1.0E+029, 1.0E+030, - 1.0E+031, 1.0E+032, 1.0E+033, 1.0E+034, 1.0E+035, 1.0E+036, 1.0E+037, 1.0E+038, 1.0E+039, 1.0E+040, - 1.0E+041, 1.0E+042, 1.0E+043, 1.0E+044, 1.0E+045, 1.0E+046, 1.0E+047, 1.0E+048, 1.0E+049, 1.0E+050, - 1.0E+051, 1.0E+052, 1.0E+053, 1.0E+054, 1.0E+055, 1.0E+056, 1.0E+057, 1.0E+058, 1.0E+059, 1.0E+060, - 1.0E+061, 1.0E+062, 1.0E+063, 1.0E+064, 1.0E+065, 1.0E+066, 1.0E+067, 1.0E+068, 1.0E+069, 1.0E+070, - 1.0E+071, 1.0E+072, 1.0E+073, 1.0E+074, 1.0E+075, 1.0E+076, 1.0E+077, 1.0E+078, 1.0E+079, 1.0E+080, - 1.0E+081, 1.0E+082, 1.0E+083, 1.0E+084, 1.0E+085, 1.0E+086, 1.0E+087, 1.0E+088, 1.0E+089, 1.0E+090, - 1.0E+091, 1.0E+092, 1.0E+093, 1.0E+094, 1.0E+095, 1.0E+096, 1.0E+097, 1.0E+098, 1.0E+099, 1.0E+100, - 1.0E+101, 1.0E+102, 1.0E+103, 1.0E+104, 1.0E+105, 1.0E+106, 1.0E+107, 1.0E+108, 1.0E+109, 1.0E+110, - 1.0E+111, 1.0E+112, 1.0E+113, 1.0E+114, 1.0E+115, 1.0E+116, 1.0E+117, 1.0E+118, 1.0E+119, 1.0E+120, - 1.0E+121, 1.0E+122, 1.0E+123, 1.0E+124, 1.0E+125, 1.0E+126, 1.0E+127, 1.0E+128, 1.0E+129, 1.0E+130, - 1.0E+131, 1.0E+132, 1.0E+133, 1.0E+134, 1.0E+135, 1.0E+136, 1.0E+137, 1.0E+138, 1.0E+139, 1.0E+140, - 1.0E+141, 1.0E+142, 1.0E+143, 1.0E+144, 1.0E+145, 1.0E+146, 1.0E+147, 1.0E+148, 1.0E+149, 1.0E+150, - 1.0E+151, 1.0E+152, 1.0E+153, 1.0E+154, 1.0E+155, 1.0E+156, 1.0E+157, 1.0E+158, 1.0E+159, 1.0E+160, - 1.0E+161, 1.0E+162, 1.0E+163, 1.0E+164, 1.0E+165, 1.0E+166, 1.0E+167, 1.0E+168, 1.0E+169, 1.0E+170, - 1.0E+171, 1.0E+172, 1.0E+173, 1.0E+174, 1.0E+175, 1.0E+176, 1.0E+177, 1.0E+178, 1.0E+179, 1.0E+180, - 1.0E+181, 1.0E+182, 1.0E+183, 1.0E+184, 1.0E+185, 1.0E+186, 1.0E+187, 1.0E+188, 1.0E+189, 1.0E+190, - 1.0E+191, 1.0E+192, 1.0E+193, 1.0E+194, 1.0E+195, 1.0E+196, 1.0E+197, 1.0E+198, 1.0E+199, 1.0E+200, - 1.0E+201, 1.0E+202, 1.0E+203, 1.0E+204, 1.0E+205, 1.0E+206, 1.0E+207, 1.0E+208, 1.0E+209, 1.0E+210, - 1.0E+211, 1.0E+212, 1.0E+213, 1.0E+214, 1.0E+215, 1.0E+216, 1.0E+217, 1.0E+218, 1.0E+219, 1.0E+220, - 1.0E+221, 1.0E+222, 1.0E+223, 1.0E+224, 1.0E+225, 1.0E+226, 1.0E+227, 1.0E+228, 1.0E+229, 1.0E+230, - 1.0E+231, 1.0E+232, 1.0E+233, 1.0E+234, 1.0E+235, 1.0E+236, 1.0E+237, 1.0E+238, 1.0E+239, 1.0E+240, - 1.0E+241, 1.0E+242, 1.0E+243, 1.0E+244, 1.0E+245, 1.0E+246, 1.0E+247, 1.0E+248, 1.0E+249, 1.0E+250, - 1.0E+251, 1.0E+252, 1.0E+253, 1.0E+254, 1.0E+255, 1.0E+256, 1.0E+257, 1.0E+258, 1.0E+259, 1.0E+260, - 1.0E+261, 1.0E+262, 1.0E+263, 1.0E+264, 1.0E+265, 1.0E+266, 1.0E+267, 1.0E+268, 1.0E+269, 1.0E+270, - 1.0E+271, 1.0E+272, 1.0E+273, 1.0E+274, 1.0E+275, 1.0E+276, 1.0E+277, 1.0E+278, 1.0E+279, 1.0E+280, - 1.0E+281, 1.0E+282, 1.0E+283, 1.0E+284, 1.0E+285, 1.0E+286, 1.0E+287, 1.0E+288, 1.0E+289, 1.0E+290, - 1.0E+291, 1.0E+292, 1.0E+293, 1.0E+294, 1.0E+295, 1.0E+296, 1.0E+297, 1.0E+298, 1.0E+299, 1.0E+300, - 1.0E+301, 1.0E+302, 1.0E+303, 1.0E+304, 1.0E+305, 1.0E+306, 1.0E+307, 1.0E+308 + 0.0, + 1.0E+001, 1.0E+002, 1.0E+003, 1.0E+004, 1.0E+005, 1.0E+006, 1.0E+007, 1.0E+008, 1.0E+009, 1.0E+010, + 1.0E+011, 1.0E+012, 1.0E+013, 1.0E+014, 1.0E+015, 1.0E+016, 1.0E+017, 1.0E+018, 1.0E+019, 1.0E+020, + 1.0E+021, 1.0E+022, 1.0E+023, 1.0E+024, 1.0E+025, 1.0E+026, 1.0E+027, 1.0E+028, 1.0E+029, 1.0E+030, + 1.0E+031, 1.0E+032, 1.0E+033, 1.0E+034, 1.0E+035, 1.0E+036, 1.0E+037, 1.0E+038, 1.0E+039, 1.0E+040, + 1.0E+041, 1.0E+042, 1.0E+043, 1.0E+044, 1.0E+045, 1.0E+046, 1.0E+047, 1.0E+048, 1.0E+049, 1.0E+050, + 1.0E+051, 1.0E+052, 1.0E+053, 1.0E+054, 1.0E+055, 1.0E+056, 1.0E+057, 1.0E+058, 1.0E+059, 1.0E+060, + 1.0E+061, 1.0E+062, 1.0E+063, 1.0E+064, 1.0E+065, 1.0E+066, 1.0E+067, 1.0E+068, 1.0E+069, 1.0E+070, + 1.0E+071, 1.0E+072, 1.0E+073, 1.0E+074, 1.0E+075, 1.0E+076, 1.0E+077, 1.0E+078, 1.0E+079, 1.0E+080, + 1.0E+081, 1.0E+082, 1.0E+083, 1.0E+084, 1.0E+085, 1.0E+086, 1.0E+087, 1.0E+088, 1.0E+089, 1.0E+090, + 1.0E+091, 1.0E+092, 1.0E+093, 1.0E+094, 1.0E+095, 1.0E+096, 1.0E+097, 1.0E+098, 1.0E+099, 1.0E+100, + 1.0E+101, 1.0E+102, 1.0E+103, 1.0E+104, 1.0E+105, 1.0E+106, 1.0E+107, 1.0E+108, 1.0E+109, 1.0E+110, + 1.0E+111, 1.0E+112, 1.0E+113, 1.0E+114, 1.0E+115, 1.0E+116, 1.0E+117, 1.0E+118, 1.0E+119, 1.0E+120, + 1.0E+121, 1.0E+122, 1.0E+123, 1.0E+124, 1.0E+125, 1.0E+126, 1.0E+127, 1.0E+128, 1.0E+129, 1.0E+130, + 1.0E+131, 1.0E+132, 1.0E+133, 1.0E+134, 1.0E+135, 1.0E+136, 1.0E+137, 1.0E+138, 1.0E+139, 1.0E+140, + 1.0E+141, 1.0E+142, 1.0E+143, 1.0E+144, 1.0E+145, 1.0E+146, 1.0E+147, 1.0E+148, 1.0E+149, 1.0E+150, + 1.0E+151, 1.0E+152, 1.0E+153, 1.0E+154, 1.0E+155, 1.0E+156, 1.0E+157, 1.0E+158, 1.0E+159, 1.0E+160, + 1.0E+161, 1.0E+162, 1.0E+163, 1.0E+164, 1.0E+165, 1.0E+166, 1.0E+167, 1.0E+168, 1.0E+169, 1.0E+170, + 1.0E+171, 1.0E+172, 1.0E+173, 1.0E+174, 1.0E+175, 1.0E+176, 1.0E+177, 1.0E+178, 1.0E+179, 1.0E+180, + 1.0E+181, 1.0E+182, 1.0E+183, 1.0E+184, 1.0E+185, 1.0E+186, 1.0E+187, 1.0E+188, 1.0E+189, 1.0E+190, + 1.0E+191, 1.0E+192, 1.0E+193, 1.0E+194, 1.0E+195, 1.0E+196, 1.0E+197, 1.0E+198, 1.0E+199, 1.0E+200, + 1.0E+201, 1.0E+202, 1.0E+203, 1.0E+204, 1.0E+205, 1.0E+206, 1.0E+207, 1.0E+208, 1.0E+209, 1.0E+210, + 1.0E+211, 1.0E+212, 1.0E+213, 1.0E+214, 1.0E+215, 1.0E+216, 1.0E+217, 1.0E+218, 1.0E+219, 1.0E+220, + 1.0E+221, 1.0E+222, 1.0E+223, 1.0E+224, 1.0E+225, 1.0E+226, 1.0E+227, 1.0E+228, 1.0E+229, 1.0E+230, + 1.0E+231, 1.0E+232, 1.0E+233, 1.0E+234, 1.0E+235, 1.0E+236, 1.0E+237, 1.0E+238, 1.0E+239, 1.0E+240, + 1.0E+241, 1.0E+242, 1.0E+243, 1.0E+244, 1.0E+245, 1.0E+246, 1.0E+247, 1.0E+248, 1.0E+249, 1.0E+250, + 1.0E+251, 1.0E+252, 1.0E+253, 1.0E+254, 1.0E+255, 1.0E+256, 1.0E+257, 1.0E+258, 1.0E+259, 1.0E+260, + 1.0E+261, 1.0E+262, 1.0E+263, 1.0E+264, 1.0E+265, 1.0E+266, 1.0E+267, 1.0E+268, 1.0E+269, 1.0E+270, + 1.0E+271, 1.0E+272, 1.0E+273, 1.0E+274, 1.0E+275, 1.0E+276, 1.0E+277, 1.0E+278, 1.0E+279, 1.0E+280, + 1.0E+281, 1.0E+282, 1.0E+283, 1.0E+284, 1.0E+285, 1.0E+286, 1.0E+287, 1.0E+288, 1.0E+289, 1.0E+290, + 1.0E+291, 1.0E+292, 1.0E+293, 1.0E+294, 1.0E+295, 1.0E+296, 1.0E+297, 1.0E+298, 1.0E+299, 1.0E+300, + 1.0E+301, 1.0E+302, 1.0E+303, 1.0E+304, 1.0E+305, 1.0E+306, 1.0E+307, 1.0E+308 }; static const int fract10_size = static_cast(sizeof(fract10) / sizeof(double)); @@ -1463,7 +1691,7 @@ namespace exprtk if (itr == end) return false; - bool negative = ('-' == (*itr)); + const bool negative = ('-' == (*itr)); if (negative || ('+' == (*itr))) { @@ -1471,34 +1699,51 @@ namespace exprtk return false; } - while ((end != itr) && ('0' == (*itr))) ++itr; + static const uchar_t zero = static_cast('0'); + + while ((end != itr) && (zero == (*itr))) ++itr; bool return_result = true; unsigned int digit = 0; - const std::size_t length = std::distance(itr,end); + const std::size_t length = static_cast(std::distance(itr,end)); if (length <= 4) { + exprtk_disable_fallthrough_begin switch (length) { #ifdef exprtk_use_lut - #define exprtk_process_digit \ - if ((digit = details::digit_table[(int)*itr++]) < 10) result = result * 10 + (digit); else { return_result = false; break; } + #define exprtk_process_digit \ + if ((digit = details::digit_table[(int)*itr++]) < 10) \ + result = result * 10 + (digit); \ + else \ + { \ + return_result = false; \ + break; \ + } \ #else - #define exprtk_process_digit \ - if ((digit = (*itr++ - '0')) < 10) result = result * 10 + (digit); else { return_result = false; break; } + + #define exprtk_process_digit \ + if ((digit = (*itr++ - zero)) < 10) \ + result = result * T(10) + digit; \ + else \ + { \ + return_result = false; \ + break; \ + } \ #endif case 4 : exprtk_process_digit case 3 : exprtk_process_digit case 2 : exprtk_process_digit - case 1 : if ((digit = (*itr - '0'))>= 10) { digit = 0; return_result = false; } + case 1 : if ((digit = (*itr - zero))>= 10) { digit = 0; return_result = false; } #undef exprtk_process_digit } + exprtk_disable_fallthrough_end } else return_result = false; @@ -1517,9 +1762,12 @@ namespace exprtk static inline bool parse_nan(Iterator& itr, const Iterator end, T& t) { typedef typename std::iterator_traits::value_type type; + static const std::size_t nan_length = 3; + if (std::distance(itr,end) != static_cast(nan_length)) return false; + if (static_cast('n') == (*itr)) { if ( @@ -1537,20 +1785,26 @@ namespace exprtk { return false; } + t = std::numeric_limits::quiet_NaN(); + return true; } template static inline bool parse_inf(Iterator& itr, const Iterator end, T& t, bool negative) { - static const char inf_uc[] = "INFINITY"; - static const char inf_lc[] = "infinity"; + static const char_t inf_uc[] = "INFINITY"; + static const char_t inf_lc[] = "infinity"; static const std::size_t inf_length = 8; - const std::size_t length = std::distance(itr,end); + + const std::size_t length = static_cast(std::distance(itr,end)); + if ((3 != length) && (inf_length != length)) return false; - const char* inf_itr = ('i' == (*itr)) ? inf_lc : inf_uc; + + char_cptr inf_itr = ('i' == (*itr)) ? inf_lc : inf_uc; + while (end != itr) { if (*inf_itr == static_cast(*itr)) @@ -1562,15 +1816,24 @@ namespace exprtk else return false; } + if (negative) t = -std::numeric_limits::infinity(); else t = std::numeric_limits::infinity(); + return true; } - template - inline bool string_to_real(Iterator& itr_external, const Iterator end, T& t, numeric::details::real_type_tag) + template + inline bool valid_exponent(const int exponent, numeric::details::real_type_tag) + { + using namespace details::numeric; + return (numeric_info::min_exp <= exponent) && (exponent <= numeric_info::max_exp); + } + + template + inline bool string_to_real(Iterator& itr_external, const Iterator end, T& t, numeric::details::real_type_tag) { if (end == itr_external) return false; @@ -1578,7 +1841,7 @@ namespace exprtk T d = T(0); - bool negative = ('-' == (*itr)); + const bool negative = ('-' == (*itr)); if (negative || '+' == (*itr)) { @@ -1588,26 +1851,30 @@ namespace exprtk bool instate = false; - #define parse_digit_1(d) \ - if ((digit = (*itr - '0')) < 10) { d = d * T(10) + digit; } else break; if (end == ++itr) break; \ + static const char_t zero = static_cast('0'); - #define parse_digit_2(d) \ - if ((digit = (*itr - '0')) < 10) { d = d * T(10) + digit; } else break; ++itr; \ + #define parse_digit_1(d) \ + if ((digit = (*itr - zero)) < 10) \ + { d = d * T(10) + digit; } \ + else \ + { break; } \ + if (end == ++itr) break; \ + + #define parse_digit_2(d) \ + if ((digit = (*itr - zero)) < 10) \ + { d = d * T(10) + digit; } \ + else { break; } \ + ++itr; \ if ('.' != (*itr)) { const Iterator curr = itr; - while ((end != itr) && ('0' == (*itr))) ++itr; - unsigned int digit; + + while ((end != itr) && (zero == (*itr))) ++itr; while (end != itr) { - // Note: For 'physical' superscalar architectures it - // is advised that the following loop be: 4xPD1 and 1xPD2 - #ifdef exprtk_enable_superscalar - parse_digit_1(d) - parse_digit_1(d) - #endif + unsigned int digit; parse_digit_1(d) parse_digit_1(d) parse_digit_2(d) @@ -1623,16 +1890,11 @@ namespace exprtk if ('.' == (*itr)) { const Iterator curr = ++itr; - unsigned int digit; T tmp_d = T(0); while (end != itr) { - #ifdef exprtk_enable_superscalar - parse_digit_1(tmp_d) - parse_digit_1(tmp_d) - parse_digit_1(tmp_d) - #endif + unsigned int digit; parse_digit_1(tmp_d) parse_digit_1(tmp_d) parse_digit_2(tmp_d) @@ -1641,7 +1903,13 @@ namespace exprtk if (curr != itr) { instate = true; - d += compute_pow10(tmp_d,-std::distance(curr,itr)); + + const int frac_exponent = static_cast(-std::distance(curr, itr)); + + if (!valid_exponent(frac_exponent, numeric::details::real_type_tag())) + return false; + + d += compute_pow10(tmp_d, frac_exponent); } #undef parse_digit_1 @@ -1656,7 +1924,7 @@ namespace exprtk { int exp = 0; - if (!details::string_to_type_converter_impl_ref(++itr,end,exp)) + if (!details::string_to_type_converter_impl_ref(++itr, end, exp)) { if (end == itr) return false; @@ -1679,11 +1947,11 @@ namespace exprtk { if (('i' == (*itr)) || ('I' == (*itr))) { - return parse_inf(itr,end,t,negative); + return parse_inf(itr, end, t, negative); } else if (('n' == (*itr)) || ('N' == (*itr))) { - return parse_nan(itr,end,t); + return parse_nan(itr, end, t); } else return false; @@ -1695,11 +1963,11 @@ namespace exprtk { if (('i' == (*itr)) || ('I' == (*itr))) { - return parse_inf(itr,end,t,negative); + return parse_inf(itr, end, t, negative); } else if (('n' == (*itr)) || ('N' == (*itr))) { - return parse_nan(itr,end,t); + return parse_nan(itr, end, t); } else return false; @@ -1712,6 +1980,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); @@ -1722,10 +1992,12 @@ namespace exprtk template inline bool string_to_real(const std::string& s, T& t) { - const char* begin = s.data(); - const char* end = s.data() + s.size(); - typename numeric::details::number_type::type num_type; - return string_to_real(begin,end,t,num_type); + const typename numeric::details::number_type::type num_type; + + char_cptr begin = s.data(); + char_cptr end = s.data() + s.size(); + + return string_to_real(begin, end, t, num_type); } template @@ -1739,6 +2011,7 @@ namespace exprtk //typedef T Type; //typedef const T Type; typedef const T& Type; + typedef T& RefType; typedef T (*qfunc_t)(Type t0, Type t1, Type t2, Type t3); typedef T (*tfunc_t)(Type t0, Type t1, Type t2); typedef T (*bfunc_t)(Type t0, Type t1); @@ -1747,6 +2020,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 @@ -1783,13 +2100,15 @@ namespace exprtk } template - inline token& set_operator(const token_type tt, const Iterator begin, const Iterator end, const Iterator base_begin = Iterator(0)) + inline token& set_operator(const token_type tt, + const Iterator begin, const Iterator end, + const Iterator base_begin = Iterator(0)) { type = tt; value.assign(begin,end); if (base_begin) - position = std::distance(base_begin,begin); - return *this; + position = static_cast(std::distance(base_begin,begin)); + return (*this); } template @@ -1798,8 +2117,8 @@ namespace exprtk type = e_symbol; value.assign(begin,end); if (base_begin) - position = std::distance(base_begin,begin); - return *this; + position = static_cast(std::distance(base_begin,begin)); + return (*this); } template @@ -1808,8 +2127,8 @@ namespace exprtk type = e_number; value.assign(begin,end); if (base_begin) - position = std::distance(base_begin,begin); - return *this; + position = static_cast(std::distance(base_begin,begin)); + return (*this); } template @@ -1818,8 +2137,8 @@ namespace exprtk type = e_string; value.assign(begin,end); if (base_begin) - position = std::distance(base_begin,begin); - return *this; + position = static_cast(std::distance(base_begin,begin)); + return (*this); } inline token& set_string(const std::string& s, const std::size_t p) @@ -1827,11 +2146,13 @@ namespace exprtk type = e_string; value = s; position = p; - return *this; + return (*this); } template - inline token& set_error(const token_type et, const Iterator begin, const Iterator end, const Iterator base_begin = Iterator(0)) + inline token& set_error(const token_type et, + const Iterator begin, const Iterator end, + const Iterator base_begin = Iterator(0)) { if ( (e_error == et) || @@ -1849,9 +2170,9 @@ namespace exprtk value.assign(begin,end); if (base_begin) - position = std::distance(base_begin,begin); + position = static_cast(std::distance(base_begin,begin)); - return *this; + return (*this); } static inline std::string to_str(token_type t) @@ -1923,7 +2244,8 @@ 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() : base_itr_(0), @@ -1956,12 +2278,8 @@ namespace exprtk { scan_token(); - if (token_list_.empty()) - return true; - else if (token_list_.back().is_error()) - { + if (!token_list_.empty() && token_list_.back().is_error()) return false; - } } return true; @@ -2048,13 +2366,53 @@ namespace exprtk } } + inline std::string substr(const std::size_t& begin, const std::size_t& 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); + } + + inline std::string remaining() const + { + if (finished()) + return ""; + else if (token_list_.begin() != token_itr_) + return std::string(base_itr_ + (token_itr_ - 1)->position, s_end_); + else + return std::string(base_itr_ + token_itr_->position, s_end_); + } + private: - inline bool is_end(const char* itr) + inline bool is_end(details::char_cptr itr) { return (s_end_ == itr); } + #ifndef exprtk_disable_comments + inline bool is_comment_start(details::char_cptr itr) + { + const char_t c0 = *(itr + 0); + const char_t c1 = *(itr + 1); + + if ('#' == c0) + return true; + else if (!is_end(itr + 1)) + { + if (('/' == c0) && ('/' == c1)) return true; + if (('/' == c0) && ('*' == c1)) return true; + } + return false; + } + #else + inline bool is_comment_start(details::char_cptr) + { + return false; + } + #endif + inline void skip_whitespace() { while (!is_end(s_itr_) && details::is_whitespace(*s_itr_)) @@ -2072,7 +2430,7 @@ namespace exprtk // 3. /* .... */ struct test { - static inline bool comment_start(const char c0, const char c1, int& mode, int& incr) + static inline bool comment_start(const char_t c0, const char_t c1, int& mode, int& incr) { mode = 0; if ('#' == c0) { mode = 1; incr = 1; } @@ -2084,45 +2442,72 @@ namespace exprtk return (0 != mode); } - static inline bool comment_end(const char c0, const char c1, const int mode) + static inline bool comment_end(const char_t c0, const char_t c1, int& mode) { - return ( - ((1 == mode) && ('\n' == c0)) || - ((2 == mode) && ( '*' == c0) && ('/' == c1)) - ); + if ( + ((1 == mode) && ('\n' == c0)) || + ((2 == mode) && ( '*' == c0) && ('/' == c1)) + ) + { + mode = 0; + return true; + } + else + return false; } }; - int mode = 0; + int mode = 0; int increment = 0; - if (is_end(s_itr_) || is_end((s_itr_ + 1))) + if (is_end(s_itr_)) return; - else if (!test::comment_start(*s_itr_,*(s_itr_ + 1),mode,increment)) + else if (!test::comment_start(*s_itr_, *(s_itr_ + 1), mode, increment)) return; + details::char_cptr cmt_start = s_itr_; + s_itr_ += increment; - while (!is_end(s_itr_) && !test::comment_end(*s_itr_,*(s_itr_ + 1),mode)) + while (!is_end(s_itr_)) { - ++s_itr_; + if ((1 == mode) && test::comment_end(*s_itr_, 0, mode)) + { + ++s_itr_; + return; + } + + if ((2 == mode)) + { + if (!is_end((s_itr_ + 1)) && test::comment_end(*s_itr_, *(s_itr_ + 1), mode)) + { + s_itr_ += 2; + return; + } + } + + ++s_itr_; } - if (!is_end(s_itr_)) + if (2 == mode) { - s_itr_ += mode; - skip_whitespace(); - skip_comments(); + token_t t; + t.set_error(token::e_error, cmt_start, cmt_start + mode, base_itr_); + token_list_.push_back(t); } #endif } inline void scan_token() { - skip_whitespace(); - skip_comments(); - if (is_end(s_itr_)) + if (details::is_whitespace(*s_itr_)) + { + skip_whitespace(); + return; + } + else if (is_comment_start(s_itr_)) { + skip_comments(); return; } else if (details::is_operator_char(*s_itr_)) @@ -2155,7 +2540,7 @@ namespace exprtk else if ('~' == (*s_itr_)) { token_t t; - t.set_symbol(s_itr_,s_itr_ + 1,base_itr_); + t.set_symbol(s_itr_, s_itr_ + 1, base_itr_); token_list_.push_back(t); ++s_itr_; return; @@ -2163,7 +2548,7 @@ namespace exprtk else { token_t t; - t.set_error(token::e_error,s_itr_,s_itr_ + 2,base_itr_); + t.set_error(token::e_error, s_itr_, s_itr_ + 2, base_itr_); token_list_.push_back(t); ++s_itr_; } @@ -2173,19 +2558,19 @@ namespace exprtk { token_t t; - const char c0 = s_itr_[0]; + const char_t c0 = s_itr_[0]; if (!is_end(s_itr_ + 1)) { - const char c1 = s_itr_[1]; + const char_t c1 = s_itr_[1]; if (!is_end(s_itr_ + 2)) { - const char c2 = s_itr_[2]; + const char_t c2 = s_itr_[2]; if ((c0 == '<') && (c1 == '=') && (c2 == '>')) { - t.set_operator(token_t::e_swap,s_itr_,s_itr_ + 3,base_itr_); + t.set_operator(token_t::e_swap, s_itr_, s_itr_ + 3, base_itr_); token_list_.push_back(t); s_itr_ += 3; return; @@ -2210,7 +2595,7 @@ namespace exprtk if (token_t::e_none != ttype) { - t.set_operator(ttype,s_itr_,s_itr_ + 2,base_itr_); + t.set_operator(ttype, s_itr_, s_itr_ + 2, base_itr_); token_list_.push_back(t); s_itr_ += 2; return; @@ -2218,17 +2603,17 @@ namespace exprtk } if ('<' == c0) - t.set_operator(token_t::e_lt ,s_itr_,s_itr_ + 1,base_itr_); + t.set_operator(token_t::e_lt , s_itr_, s_itr_ + 1, base_itr_); else if ('>' == c0) - t.set_operator(token_t::e_gt ,s_itr_,s_itr_ + 1,base_itr_); + t.set_operator(token_t::e_gt , s_itr_, s_itr_ + 1, base_itr_); else if (';' == c0) - t.set_operator(token_t::e_eof,s_itr_,s_itr_ + 1,base_itr_); + t.set_operator(token_t::e_eof, s_itr_, s_itr_ + 1, base_itr_); else if ('&' == c0) - t.set_symbol(s_itr_,s_itr_ + 1,base_itr_); + t.set_symbol(s_itr_, s_itr_ + 1, base_itr_); else if ('|' == c0) - t.set_symbol(s_itr_,s_itr_ + 1,base_itr_); + t.set_symbol(s_itr_, s_itr_ + 1, base_itr_); else - t.set_operator(token_t::token_type(c0),s_itr_,s_itr_ + 1,base_itr_); + t.set_operator(token_t::token_type(c0), s_itr_, s_itr_ + 1, base_itr_); token_list_.push_back(t); ++s_itr_; @@ -2236,13 +2621,28 @@ namespace exprtk inline void scan_symbol() { - const char* initial_itr = s_itr_; + details::char_cptr initial_itr = s_itr_; - while ( - (!is_end(s_itr_)) && - (details::is_letter_or_digit(*s_itr_) || ((*s_itr_) == '_')) - ) + while (!is_end(s_itr_)) { + if (!details::is_letter_or_digit(*s_itr_) && ('_' != (*s_itr_))) + { + if ('.' != (*s_itr_)) + break; + /* + Permit symbols that contain a 'dot' + Allowed : abc.xyz, a123.xyz, abc.123, abc_.xyz a123_.xyz abc._123 + Disallowed: .abc, abc., abc., abc. + */ + if ( + (s_itr_ != initial_itr) && + !is_end(s_itr_ + 1) && + !details::is_letter_or_digit(*(s_itr_ + 1)) && + ('_' != (*(s_itr_ + 1))) + ) + break; + } + ++s_itr_; } @@ -2255,19 +2655,28 @@ namespace exprtk { /* Attempt to match a valid numeric value in one of the following formats: - 1. 123456 - 2. 123.456 - 3. 123.456e3 - 4. 123.456E3 - 5. 123.456e+3 - 6. 123.456E+3 - 7. 123.456e-3 - 8. 123.456E-3 + (01) 123456 + (02) 123456. + (03) 123.456 + (04) 123.456e3 + (05) 123.456E3 + (06) 123.456e+3 + (07) 123.456E+3 + (08) 123.456e-3 + (09) 123.456E-3 + (00) .1234 + (11) .1234e3 + (12) .1234E+3 + (13) .1234e+3 + (14) .1234E-3 + (15) .1234e-3 */ - const char* initial_itr = s_itr_; - bool dot_found = false; - bool e_found = false; - bool post_e_sign_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_)) @@ -2276,8 +2685,9 @@ namespace exprtk { if (dot_found) { - t.set_error(token::e_err_number,initial_itr,s_itr_,base_itr_); + t.set_error(token::e_err_number, initial_itr, s_itr_, base_itr_); token_list_.push_back(t); + return; } @@ -2286,13 +2696,13 @@ namespace exprtk continue; } - else if (details::imatch('e',(*s_itr_))) + else if ('e' == std::tolower(*s_itr_)) { - const char& c = *(s_itr_ + 1); + const char_t& c = *(s_itr_ + 1); if (is_end(s_itr_ + 1)) { - t.set_error(token::e_err_number,initial_itr,s_itr_,base_itr_); + t.set_error(token::e_err_number, initial_itr, s_itr_, base_itr_); token_list_.push_back(t); return; @@ -2303,7 +2713,7 @@ namespace exprtk !details::is_digit(c) ) { - t.set_error(token::e_err_number,initial_itr,s_itr_,base_itr_); + t.set_error(token::e_err_number, initial_itr, s_itr_, base_itr_); token_list_.push_back(t); return; @@ -2311,13 +2721,14 @@ namespace exprtk e_found = true; ++s_itr_; + continue; } - else if (e_found && details::is_sign(*s_itr_)) + else if (e_found && details::is_sign(*s_itr_) && !post_e_digit_found) { if (post_e_sign_found) { - t.set_error(token::e_err_number,initial_itr,s_itr_,base_itr_); + t.set_error(token::e_err_number, initial_itr, s_itr_, base_itr_); token_list_.push_back(t); return; @@ -2325,6 +2736,14 @@ namespace exprtk post_e_sign_found = true; ++s_itr_; + + continue; + } + else if (e_found && details::is_digit(*s_itr_)) + { + post_e_digit_found = true; + ++s_itr_; + continue; } else if (('.' != (*s_itr_)) && !details::is_digit(*s_itr_)) @@ -2333,7 +2752,7 @@ namespace exprtk ++s_itr_; } - t.set_numeric(initial_itr,s_itr_,base_itr_); + t.set_numeric(initial_itr, s_itr_, base_itr_); token_list_.push_back(t); return; @@ -2341,13 +2760,16 @@ namespace exprtk inline void scan_special_function() { - const char* initial_itr = s_itr_; + details::char_cptr initial_itr = s_itr_; token_t t; // $fdd(x,x,x) = at least 11 chars if (std::distance(s_itr_,s_end_) < 11) { - t.set_error(token::e_err_sfunc,initial_itr,s_itr_,base_itr_); + t.set_error( + token::e_err_sfunc, + initial_itr, std::min(initial_itr + 11, s_end_), + base_itr_); token_list_.push_back(t); return; @@ -2360,7 +2782,10 @@ namespace exprtk (details::is_digit(*(s_itr_ + 3)))) ) { - t.set_error(token::e_err_sfunc,initial_itr,s_itr_,base_itr_); + t.set_error( + token::e_err_sfunc, + initial_itr, std::min(initial_itr + 4, s_end_), + base_itr_); token_list_.push_back(t); return; @@ -2368,7 +2793,7 @@ namespace exprtk s_itr_ += 4; // $fdd = 4chars - t.set_symbol(initial_itr,s_itr_,base_itr_); + t.set_symbol(initial_itr, s_itr_, base_itr_); token_list_.push_back(t); return; @@ -2377,13 +2802,14 @@ namespace exprtk #ifndef exprtk_disable_string_capabilities inline void scan_string() { - const char* 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_); + t.set_error(token::e_err_string, s_itr_, s_end_, base_itr_); token_list_.push_back(t); + return; } @@ -2394,7 +2820,14 @@ namespace exprtk while (!is_end(s_itr_)) { - if ('\\' == *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; @@ -2409,22 +2842,21 @@ 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_) + ) { - if ( - is_end(s_itr_ + 1) || - is_end(s_itr_ + 2) || - is_end(s_itr_ + 3) || - ( - ('x' != *(s_itr_ + 1)) && - ('X' != *(s_itr_ + 1)) - ) || - (!details::is_hex_digit(*(s_itr_ + 2))) || - (!details::is_hex_digit(*(s_itr_ + 3))) - ) + 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)) ; + + if (!(x_seperator && both_digits)) { - t.set_error(token::e_err_string,initial_itr,s_itr_,base_itr_); + t.set_error(token::e_err_string, initial_itr, s_itr_, base_itr_); token_list_.push_back(t); + return; } else @@ -2439,19 +2871,29 @@ namespace exprtk if (is_end(s_itr_)) { - t.set_error(token::e_err_string,initial_itr,s_itr_,base_itr_); + t.set_error(token::e_err_string, initial_itr, s_itr_, base_itr_); token_list_.push_back(t); return; } if (!escaped_found) - t.set_string(initial_itr,s_itr_,base_itr_); + t.set_string(initial_itr, s_itr_, base_itr_); else { std::string parsed_string(initial_itr,s_itr_); - details::cleanup_escapes(parsed_string); - t.set_string(parsed_string, std::distance(base_itr_,initial_itr)); + + 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, + static_cast(std::distance(base_itr_,initial_itr))); } token_list_.push_back(t); @@ -2463,13 +2905,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* base_itr_; - const char* s_itr_; - const char* 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; @@ -2530,7 +2972,7 @@ namespace exprtk const token& t0 = g.token_list_[i ]; const token& t1 = g.token_list_[i + 1]; - if (!operator()(t0,t1)) + if (!operator()(t0, t1)) { return i; } @@ -2543,7 +2985,7 @@ namespace exprtk const token& t1 = g.token_list_[i + 1]; const token& t2 = g.token_list_[i + 2]; - if (!operator()(t0,t1,t2)) + if (!operator()(t0, t1, t2)) { return i; } @@ -2557,7 +2999,7 @@ namespace exprtk const token& t2 = g.token_list_[i + 2]; const token& t3 = g.token_list_[i + 3]; - if (!operator()(t0,t1,t2,t3)) + if (!operator()(t0, t1, t2, t3)) { return i; } @@ -2570,29 +3012,29 @@ namespace exprtk return (g.token_list_.size() - stride_ + 1); } - virtual bool operator()(const token&) + virtual bool operator() (const token&) { return false; } - virtual bool operator()(const token&, const token&) + virtual bool operator() (const token&, const token&) { return false; } - virtual bool operator()(const token&, const token&, const token&) + virtual bool operator() (const token&, const token&, const token&) { return false; } - virtual bool operator()(const token&, const token&, const token&, const token&) + virtual bool operator() (const token&, const token&, const token&, const token&) { return false; } private: - std::size_t stride_; + const std::size_t stride_; }; class token_modifier : public helper_interface @@ -2636,6 +3078,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; @@ -2646,64 +3092,84 @@ namespace exprtk case 1 : insert_index = insert(g.token_list_[i],t); break; - case 2 : insert_index = insert(g.token_list_[i],g.token_list_[i + 1],t); + case 2 : insert_index = insert(g.token_list_[i], g.token_list_[i + 1], t); break; - case 3 : insert_index = insert(g.token_list_[i],g.token_list_[i + 1],g.token_list_[i + 2],t); + case 3 : insert_index = insert(g.token_list_[i], g.token_list_[i + 1], g.token_list_[i + 2], t); break; - case 4 : insert_index = insert(g.token_list_[i],g.token_list_[i + 1],g.token_list_[i + 2],g.token_list_[i + 3],t); + case 4 : insert_index = insert(g.token_list_[i], g.token_list_[i + 1], g.token_list_[i + 2], g.token_list_[i + 3], t); break; - case 5 : insert_index = insert(g.token_list_[i],g.token_list_[i + 1],g.token_list_[i + 2],g.token_list_[i + 3],g.token_list_[i + 4],t); + case 5 : insert_index = insert(g.token_list_[i], g.token_list_[i + 1], g.token_list_[i + 2], g.token_list_[i + 3], g.token_list_[i + 4], t); break; } if ((insert_index >= 0) && (insert_index <= (static_cast(stride_) + 1))) { - g.token_list_.insert(g.token_list_.begin() + (i + 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; } - inline virtual int insert(const token&, token& ) - { - return -1; - } + #define token_inserter_empty_body \ + { \ + return -1; \ + } \ + + inline virtual int insert(const token&, token&) + token_inserter_empty_body inline virtual int insert(const token&, const token&, token&) - { - return -1; - } + token_inserter_empty_body inline virtual int insert(const token&, const token&, const token&, token&) - { - return -1; - } + token_inserter_empty_body inline virtual int insert(const token&, const token&, const token&, const token&, token&) - { - return -1; - } + token_inserter_empty_body inline virtual int insert(const token&, const token&, const token&, const token&, const token&, token&) - { - return -1; - } + token_inserter_empty_body + + #undef token_inserter_empty_body private: - std::size_t stride_; + const std::size_t stride_; }; class token_joiner : public helper_interface { public: - token_joiner(const std::size_t& stride) + explicit token_joiner(const std::size_t& stride) : stride_(stride) {} @@ -2720,7 +3186,7 @@ namespace exprtk } } - virtual bool join(const token&, const token&, token&) { return false; } + virtual bool join(const token&, const token&, token&) { return false; } virtual bool join(const token&, const token&, const token&, token&) { return false; } private: @@ -2732,18 +3198,36 @@ namespace exprtk 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.token_list_[i],g.token_list_[i + 1],t)) + for ( ; ; ) { - g.token_list_[i] = t; - g.token_list_.erase(g.token_list_.begin() + (i + 1)); + if (!join(g[i], g[i + 1], t)) + { + token_list.push_back(g[i]); + break; + } + + 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; } @@ -2754,33 +3238,51 @@ namespace exprtk 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.token_list_[i],g.token_list_[i + 1],g.token_list_[i + 2],t)) + for ( ; ; ) { - g.token_list_[i] = t; - g.token_list_.erase(g.token_list_.begin() + (i + 1), - g.token_list_.begin() + (i + 3)); + if (!join(g[i], g[i + 1], g[i + 2], t)) + { + token_list.push_back(g[i]); + break; + } + + token_list.push_back(t); + ++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; } - std::size_t stride_; + const std::size_t stride_; }; 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), @@ -2793,6 +3295,8 @@ namespace exprtk { public: + using lexer::token_inserter::insert; + commutative_inserter() : lexer::token_inserter(2) {} @@ -2839,6 +3343,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; } @@ -2852,7 +3357,7 @@ namespace exprtk { public: - operator_joiner(const std::size_t& stride) + explicit operator_joiner(const std::size_t& stride) : token_joiner(stride) {} @@ -2864,6 +3369,7 @@ namespace exprtk t.type = lexer::token::e_assign; t.value = ":="; t.position = t0.position; + return true; } // '+ =' --> '+=' @@ -2872,6 +3378,7 @@ namespace exprtk t.type = lexer::token::e_addass; t.value = "+="; t.position = t0.position; + return true; } // '- =' --> '-=' @@ -2880,6 +3387,7 @@ namespace exprtk t.type = lexer::token::e_subass; t.value = "-="; t.position = t0.position; + return true; } // '* =' --> '*=' @@ -2888,6 +3396,7 @@ namespace exprtk t.type = lexer::token::e_mulass; t.value = "*="; t.position = t0.position; + return true; } // '/ =' --> '/=' @@ -2896,6 +3405,7 @@ namespace exprtk t.type = lexer::token::e_divass; t.value = "/="; t.position = t0.position; + return true; } // '% =' --> '%=' @@ -2904,6 +3414,7 @@ namespace exprtk t.type = lexer::token::e_modass; t.value = "%="; t.position = t0.position; + return true; } // '> =' --> '>=' @@ -2912,6 +3423,7 @@ namespace exprtk t.type = lexer::token::e_gte; t.value = ">="; t.position = t0.position; + return true; } // '< =' --> '<=' @@ -2920,6 +3432,7 @@ namespace exprtk t.type = lexer::token::e_lte; t.value = "<="; t.position = t0.position; + return true; } // '= =' --> '==' @@ -2928,6 +3441,7 @@ namespace exprtk t.type = lexer::token::e_eq; t.value = "=="; t.position = t0.position; + return true; } // '! =' --> '!=' @@ -2936,6 +3450,7 @@ namespace exprtk t.type = lexer::token::e_ne; t.value = "!="; t.position = t0.position; + return true; } // '< >' --> '<>' @@ -2944,6 +3459,7 @@ namespace exprtk t.type = lexer::token::e_ne; t.value = "<>"; t.position = t0.position; + return true; } // '<= >' --> '<=>' @@ -2952,6 +3468,38 @@ namespace exprtk t.type = lexer::token::e_swap; t.value = "<=>"; t.position = t0.position; + + return true; + } + // '+ -' --> '-' + else if ((t0.type == lexer::token::e_add) && (t1.type == lexer::token::e_sub)) + { + t.type = lexer::token::e_sub; + t.value = "-"; + t.position = t0.position; + + return true; + } + // '- +' --> '-' + else if ((t0.type == lexer::token::e_sub) && (t1.type == lexer::token::e_add)) + { + t.type = lexer::token::e_sub; + t.value = "-"; + t.position = t0.position; + + return true; + } + // '- -' --> '+' + else if ((t0.type == lexer::token::e_sub) && (t1.type == lexer::token::e_sub)) + { + /* + Note: May need to reconsider this when wanting to implement + pre/postfix decrement operator + */ + t.type = lexer::token::e_add; + t.value = "+"; + t.position = t0.position; + return true; } else @@ -2982,6 +3530,8 @@ namespace exprtk { public: + using lexer::token_scanner::operator(); + bracket_checker() : token_scanner(1), state_(true) @@ -3016,7 +3566,7 @@ namespace exprtk error_token_.clear(); } - bool operator()(const lexer::token& t) + bool operator() (const lexer::token& t) { if ( !t.value.empty() && @@ -3025,23 +3575,23 @@ namespace exprtk exprtk::details::is_bracket(t.value[0]) ) { - char c = t.value[0]; + details::char_t c = t.value[0]; - if (t.type == lexer::token::e_lbracket) stack_.push(std::make_pair(')',t.position)); + if (t.type == lexer::token::e_lbracket ) stack_.push(std::make_pair(')',t.position)); else if (t.type == lexer::token::e_lcrlbracket) stack_.push(std::make_pair('}',t.position)); else if (t.type == lexer::token::e_lsqrbracket) stack_.push(std::make_pair(']',t.position)); else if (exprtk::details::is_right_bracket(c)) { if (stack_.empty()) { - state_ = false; + state_ = false; error_token_ = t; return false; } else if (c != stack_.top().first) { - state_ = false; + state_ = false; error_token_ = t; return false; @@ -3065,6 +3615,8 @@ namespace exprtk { public: + using lexer::token_scanner::operator(); + numeric_checker() : token_scanner (1), current_index_(0) @@ -3081,7 +3633,7 @@ namespace exprtk current_index_ = 0; } - bool operator()(const lexer::token& t) + bool operator() (const lexer::token& t) { if (token::e_number == t.type) { @@ -3132,7 +3684,7 @@ namespace exprtk bool remove(const std::string& target_symbol) { - replace_map_t::iterator itr = replace_map_.find(target_symbol); + const replace_map_t::iterator itr = replace_map_.find(target_symbol); if (replace_map_.end() == itr) return false; @@ -3146,7 +3698,7 @@ namespace exprtk const std::string& replace_symbol, const lexer::token::token_type token_type = lexer::token::e_symbol) { - replace_map_t::iterator itr = replace_map_.find(target_symbol); + const replace_map_t::iterator itr = replace_map_.find(target_symbol); if (replace_map_.end() != itr) { @@ -3172,7 +3724,7 @@ namespace exprtk if (replace_map_.empty()) return false; - replace_map_t::iterator itr = replace_map_.find(t.value); + const replace_map_t::iterator itr = replace_map_.find(t.value); if (replace_map_.end() != itr) { @@ -3198,17 +3750,16 @@ namespace exprtk public: + using lexer::token_scanner::operator(); + 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_string ,lexer::token::e_colon ); - add_invalid(lexer::token::e_string ,lexer::token::e_ternary); - add_invalid(lexer::token::e_colon ,lexer::token::e_string ); - add_invalid(lexer::token::e_ternary,lexer::token::e_string ); + 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 ); @@ -3234,9 +3785,9 @@ namespace exprtk return error_list_.empty(); } - bool operator()(const lexer::token& t0, const lexer::token& t1) + 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)) { @@ -3250,7 +3801,7 @@ namespace exprtk return true; } - std::size_t error_count() + std::size_t error_count() const { return error_list_.size(); } @@ -3282,21 +3833,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) @@ -3306,7 +3857,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; } } @@ -3327,7 +3878,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 ; } } } @@ -3341,7 +3892,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))) @@ -3362,64 +3913,152 @@ namespace exprtk std::vector > error_list_; }; - struct helper_assembly + class sequence_validator_3tokens : public lexer::token_scanner { - inline bool register_scanner(lexer::token_scanner* 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) { - if (token_scanner_list.end() != std::find(token_scanner_list.begin(), - token_scanner_list.end(), - scanner)) + 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()) { - return false; + error_list_.push_back(std::make_pair(t0,t1)); } - token_scanner_list.push_back(scanner); return true; } - inline bool register_modifier(lexer::token_modifier* modifier) + 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) + { + if (token_scanner_list.end() != std::find(token_scanner_list.begin(), + token_scanner_list.end (), + scanner)) + { + return false; + } + + token_scanner_list.push_back(scanner); + + return true; + } + + inline bool register_modifier(lexer::token_modifier* modifier) { if (token_modifier_list.end() != std::find(token_modifier_list.begin(), - token_modifier_list.end(), + token_modifier_list.end (), modifier)) { return false; } token_modifier_list.push_back(modifier); + return true; } inline bool register_joiner(lexer::token_joiner* joiner) { if (token_joiner_list.end() != std::find(token_joiner_list.begin(), - token_joiner_list.end(), + token_joiner_list.end (), joiner)) { return false; } token_joiner_list.push_back(joiner); + return true; } inline bool register_inserter(lexer::token_inserter* inserter) { if (token_inserter_list.end() != std::find(token_inserter_list.begin(), - token_inserter_list.end(), + token_inserter_list.end (), inserter)) { return false; } token_inserter_list.push_back(inserter); + return true; } inline bool run_modifiers(lexer::generator& g) { error_token_modifier = reinterpret_cast(0); - bool result = true; for (std::size_t i = 0; i < token_modifier_list.size(); ++i) { @@ -3431,17 +4070,17 @@ namespace exprtk if (!modifier.result()) { error_token_modifier = token_modifier_list[i]; + return false; } } - return result; + return true; } inline bool run_joiners(lexer::generator& g) { error_token_joiner = reinterpret_cast(0); - bool result = true; for (std::size_t i = 0; i < token_joiner_list.size(); ++i) { @@ -3453,17 +4092,17 @@ namespace exprtk if (!joiner.result()) { error_token_joiner = token_joiner_list[i]; + return false; } } - return result; + return true; } inline bool run_inserters(lexer::generator& g) { error_token_inserter = reinterpret_cast(0); - bool result = true; for (std::size_t i = 0; i < token_inserter_list.size(); ++i) { @@ -3475,17 +4114,17 @@ namespace exprtk if (!inserter.result()) { error_token_inserter = token_inserter_list[i]; + return false; } } - return result; + return true; } inline bool run_scanners(lexer::generator& g) { error_token_scanner = reinterpret_cast(0); - bool result = true; for (std::size_t i = 0; i < token_scanner_list.size(); ++i) { @@ -3497,11 +4136,12 @@ namespace exprtk if (!scanner.result()) { error_token_scanner = token_scanner_list[i]; + return false; } } - return result; + return true; } std::vector token_scanner_list; @@ -3515,34 +4155,232 @@ namespace exprtk lexer::token_inserter* error_token_inserter; }; } + + class parser_helper + { + public: + + typedef token token_t; + typedef generator generator_t; + + inline bool init(const std::string& str) + { + if (!lexer_.process(str)) + { + return false; + } + + lexer_.begin(); + + next_token(); + + return true; + } + + inline generator_t& lexer() + { + return lexer_; + } + + inline const generator_t& lexer() const + { + return lexer_; + } + + inline void store_token() + { + lexer_.store(); + store_current_token_ = current_token_; + } + + inline void restore_token() + { + lexer_.restore(); + current_token_ = store_current_token_; + } + + inline void next_token() + { + current_token_ = lexer_.next_token(); + } + + inline const token_t& current_token() const + { + return current_token_; + } + + enum token_advance_mode + { + e_hold = 0, + e_advance = 1 + }; + + inline void advance_token(const token_advance_mode mode) + { + if (e_advance == mode) + { + next_token(); + } + } + + inline bool token_is(const token_t::token_type& ttype, const token_advance_mode mode = e_advance) + { + if (current_token().type != ttype) + { + return false; + } + + advance_token(mode); + + return true; + } + + inline bool token_is(const token_t::token_type& ttype, + const std::string& value, + const token_advance_mode mode = e_advance) + { + if ( + (current_token().type != ttype) || + !exprtk::details::imatch(value,current_token().value) + ) + { + return false; + } + + advance_token(mode); + + return true; + } + + inline bool peek_token_is(const token_t::token_type& ttype) + { + return (lexer_.peek_next_token().type == ttype); + } + + inline bool peek_token_is(const std::string& s) + { + return (exprtk::details::imatch(lexer_.peek_next_token().value,s)); + } + + private: + + generator_t lexer_; + token_t current_token_; + token_t store_current_token_; + }; + } + + template + class vector_view + { + public: + + typedef T* data_ptr_t; + + vector_view(data_ptr_t data, const std::size_t& size) + : size_(size), + data_(data), + data_ref_(0) + {} + + vector_view(const vector_view& vv) + : size_(vv.size_), + data_(vv.data_), + data_ref_(0) + {} + + inline void rebase(data_ptr_t data) + { + data_ = data; + + if (!data_ref_.empty()) + { + for (std::size_t i = 0; i < data_ref_.size(); ++i) + { + (*data_ref_[i]) = data; + } + } + } + + inline data_ptr_t data() const + { + return data_; + } + + inline std::size_t size() const + { + return size_; + } + + inline const T& operator[](const std::size_t index) const + { + return data_[index]; + } + + inline T& operator[](const std::size_t index) + { + return data_[index]; + } + + void set_ref(data_ptr_t* data_ref) + { + data_ref_.push_back(data_ref); + } + + private: + + const std::size_t size_; + data_ptr_t data_; + std::vector data_ref_; + }; + + template + 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); + } + + 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); } + template class results_context; + template struct type_store { enum store_type { e_unknown, - e_scalar, - e_vector, + e_scalar , + e_vector , e_string }; 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 { public: - parameter_list(std::vector& pl) + explicit parameter_list(std::vector& pl) : parameter_list_(pl) {} @@ -3578,17 +4416,19 @@ namespace exprtk inline type_store& back() { - return parameter_list_[size() - 1]; + return parameter_list_.back(); } inline const type_store& back() const { - return parameter_list_[size() - 1]; + return parameter_list_.back(); } private: std::vector& parameter_list_; + + friend class results_context; }; template @@ -3597,11 +4437,16 @@ namespace exprtk typedef type_store type_store_t; typedef ViewType value_t; - type_view(type_store_t& ts) + explicit type_view(type_store_t& ts) : ts_(ts), data_(reinterpret_cast(ts_.data)) {} + explicit type_view(const type_store_t& ts) + : ts_(const_cast(ts)), + data_(reinterpret_cast(ts_.data)) + {} + inline std::size_t size() const { return ts_.size; @@ -3620,8 +4465,15 @@ namespace exprtk inline const value_t* begin() const { return data_; } inline value_t* begin() { return data_; } - inline const value_t* end() const { return data_ + ts_.size; } - inline value_t* end() { return data_ + ts_.size; } + inline const value_t* end() const + { + return static_cast(data_ + ts_.size); + } + + inline value_t* end() + { + return static_cast(data_ + ts_.size); + } type_store_t& ts_; value_t* data_; @@ -3635,20 +4487,48 @@ namespace exprtk typedef type_store type_store_t; typedef T value_t; - scalar_view(type_store_t& ts) + explicit scalar_view(type_store_t& ts) : v_(*reinterpret_cast(ts.data)) {} - value_t& operator()() + explicit scalar_view(const type_store_t& ts) + : v_(*reinterpret_cast(const_cast(ts).data)) + {} + + inline value_t& operator() () { return v_; } - const value_t& operator()() const + inline const value_t& operator() () const { return v_; } + template + inline bool to_int(IntType& i) const + { + if (!exprtk::details::numeric::is_integer(v_)) + return false; + + i = static_cast(v_); + + return true; + } + + template + inline bool to_uint(UIntType& u) const + { + if (v_ < T(0)) + return false; + else if (!exprtk::details::numeric::is_integer(v_)) + return false; + + u = static_cast(v_); + + return true; + } + T& v_; }; }; @@ -3659,6 +4539,68 @@ namespace exprtk return std::string(view.begin(),view.size()); } + #ifndef exprtk_disable_return_statement + namespace details + { + template class return_node; + template class return_envelope_node; + } + #endif + + template + class results_context + { + public: + + typedef type_store type_store_t; + + results_context() + : results_available_(false) + {} + + inline std::size_t count() const + { + if (results_available_) + return parameter_list_.size(); + else + return 0; + } + + inline type_store_t& operator[](const std::size_t& index) + { + return parameter_list_[index]; + } + + inline const type_store_t& operator[](const std::size_t& index) const + { + return parameter_list_[index]; + } + + private: + + inline void clear() + { + results_available_ = false; + } + + typedef std::vector ts_list_t; + typedef typename type_store_t::parameter_list parameter_list_t; + + inline void assign(const parameter_list_t& pl) + { + parameter_list_ = pl.parameter_list_; + results_available_ = true; + } + + bool results_available_; + ts_list_t parameter_list_; + + #ifndef exprtk_disable_return_statement + friend class details::return_node; + friend class details::return_envelope_node; + #endif + }; + namespace details { enum operator_type @@ -3685,7 +4627,8 @@ namespace exprtk e_erf , e_erfc , e_ncdf , e_frac , e_trunc , e_assign , e_addass , e_subass , e_mulass , e_divass , e_modass , e_in , - e_like , e_ilike , e_multi , e_swap , + e_like , e_ilike , e_multi , e_smulti , + e_swap , // Do not add new functions/operators after this point. e_sf00 = 1000, e_sf01 = 1001, e_sf02 = 1002, e_sf03 = 1003, @@ -3728,9 +4671,44 @@ namespace exprtk e_sf4ext44 = 2044, e_sf4ext45 = 2045, e_sf4ext46 = 2046, e_sf4ext47 = 2047, e_sf4ext48 = 2048, e_sf4ext49 = 2049, e_sf4ext50 = 2050, e_sf4ext51 = 2051, e_sf4ext52 = 2052, e_sf4ext53 = 2053, e_sf4ext54 = 2054, e_sf4ext55 = 2055, - e_sf4ext56 = 2056, e_sf4ext57 = 2057, e_sf4ext58 = 2058, e_sf4ext59 = 2059 + e_sf4ext56 = 2056, e_sf4ext57 = 2057, e_sf4ext58 = 2058, e_sf4ext59 = 2059, + e_sf4ext60 = 2060, e_sf4ext61 = 2061 }; + inline std::string to_str(const operator_type opr) + { + 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 ">" ; + 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" ; + } + } + struct base_operation_t { base_operation_t(const operator_type t, const unsigned int& np) @@ -3742,12 +4720,255 @@ namespace exprtk unsigned int num_params; }; - namespace numeric + namespace loop_unroll { - namespace details + #ifndef exprtk_disable_superscalar_unroll + const unsigned int global_loop_batch_size = 16; + #else + const unsigned int global_loop_batch_size = 4; + #endif + + struct details { - template - inline T process_impl(const operator_type operation, const T arg) + 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))) + {} + + unsigned int batch_size; + int remainder; + int upper_bound; + }; + } + + #ifdef exprtk_enable_debugging + inline void dump_ptr(const std::string& s, const void* ptr, const std::size_t size = 0) + { + if (size) + exprtk_debug(("%s - addr: %p\n",s.c_str(),ptr)); + else + exprtk_debug(("%s - addr: %p size: %d\n", + s.c_str(), + ptr, + static_cast(size))); + } + #else + inline void dump_ptr(const std::string&, const void*) {} + inline void dump_ptr(const std::string&, const void*, const std::size_t) {} + #endif + + template + class vec_data_store + { + public: + + typedef vec_data_store type; + typedef T* data_t; + + private: + + struct control_block + { + control_block() + : ref_count(1), + size (0), + data (0), + destruct (true) + {} + + explicit control_block(const std::size_t& dsize) + : ref_count(1 ), + size (dsize), + 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 ), + destruct (dstrct) + {} + + ~control_block() + { + if (data && destruct && (0 == ref_count)) + { + dump_ptr("~control_block() data",data); + delete[] data; + data = reinterpret_cast(0); + } + } + + static inline control_block* create(const std::size_t& dsize, data_t data_ptr = data_t(0), bool dstrct = false) + { + if (dsize) + { + if (0 == data_ptr) + return (new control_block(dsize)); + else + return (new control_block(dsize, data_ptr, dstrct)); + } + else + return (new control_block); + } + + static inline void destroy(control_block*& cntrl_blck) + { + if (cntrl_blck) + { + if ( + (0 != cntrl_blck->ref_count) && + (0 == --cntrl_blck->ref_count) + ) + { + delete cntrl_blck; + } + + cntrl_blck = 0; + } + } + + std::size_t ref_count; + std::size_t size; + data_t data; + bool destruct; + + private: + + control_block(const control_block&); + control_block& operator=(const control_block&); + + inline void create_data() + { + destruct = true; + data = new T[size]; + std::fill_n(data, size, T(0)); + dump_ptr("control_block::create_data() - data",data,size); + } + }; + + public: + + vec_data_store() + : control_block_(control_block::create(0)) + {} + + explicit vec_data_store(const std::size_t& size) + : control_block_(control_block::create(size,reinterpret_cast(0),true)) + {} + + vec_data_store(const std::size_t& size, data_t data, bool dstrct = false) + : control_block_(control_block::create(size, data, dstrct)) + {} + + vec_data_store(const type& vds) + { + control_block_ = vds.control_block_; + control_block_->ref_count++; + } + + ~vec_data_store() + { + control_block::destroy(control_block_); + } + + type& operator=(const type& vds) + { + if (this != &vds) + { + std::size_t final_size = min_size(control_block_, vds.control_block_); + + vds.control_block_->size = final_size; + control_block_->size = final_size; + + if (control_block_->destruct || (0 == control_block_->data)) + { + control_block::destroy(control_block_); + + control_block_ = vds.control_block_; + control_block_->ref_count++; + } + } + + return (*this); + } + + inline data_t data() + { + return control_block_->data; + } + + inline data_t data() const + { + return control_block_->data; + } + + inline std::size_t size() + { + return control_block_->size; + } + + inline std::size_t size() const + { + return control_block_->size; + } + + inline data_t& ref() + { + return control_block_->data; + } + + inline void dump() const + { + #ifdef exprtk_enable_debugging + exprtk_debug(("size: %d\taddress:%p\tdestruct:%c\n", + size(), + data(), + (control_block_->destruct ? 'T' : 'F'))); + + for (std::size_t i = 0; i < size(); ++i) + { + if (5 == i) + exprtk_debug(("\n")); + + exprtk_debug(("%15.10f ",data()[i])); + } + exprtk_debug(("\n")); + #endif + } + + static inline void match_sizes(type& vds0, type& vds1) + { + const std::size_t size = min_size(vds0.control_block_,vds1.control_block_); + vds0.control_block_->size = size; + vds1.control_block_->size = size; + } + + private: + + static inline std::size_t min_size(control_block* cb0, control_block* cb1) + { + const std::size_t size0 = cb0->size; + const std::size_t size1 = cb1->size; + + if (size0 && size1) + return std::min(size0,size1); + else + return (size0) ? size0 : size1; + } + + control_block* control_block_; + }; + + namespace numeric + { + namespace details + { + template + inline T process_impl(const operator_type operation, const T arg) { switch (operation) { @@ -3791,7 +5012,9 @@ namespace exprtk case e_ncdf : return numeric::ncdf (arg); case e_frac : return numeric::frac (arg); case e_trunc : return numeric::trunc(arg); - default : return std::numeric_limits::quiet_NaN(); + + default : exprtk_debug(("numeric::details::process_impl - Invalid unary operation.\n")); + return std::numeric_limits::quiet_NaN(); } } @@ -3816,20 +5039,22 @@ 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_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); - default : return std::numeric_limits::quiet_NaN(); + 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); + + default : exprtk_debug(("numeric::details::process_impl - Invalid binary operation.\n")); + return std::numeric_limits::quiet_NaN(); } } @@ -3865,7 +5090,9 @@ namespace exprtk case e_hypot : return hypot(arg0,arg1); case e_shr : return arg0 >> arg1; case e_shl : return arg0 << arg1; - default : return std::numeric_limits::quiet_NaN(); + + default : exprtk_debug(("numeric::details::process_impl - Invalid binary operation.\n")); + return std::numeric_limits::quiet_NaN(); } } } @@ -3879,56 +5106,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_quinary , e_senary , e_vararg , e_conditional , - e_while , e_repeat , e_for , e_switch , - e_mswitch , e_variable , e_stringvar , e_stringconst , - e_stringvarrng , e_cstringvarrng, e_strgenrange , e_strconcat , - e_stringvarsize, e_strswap , e_stringsize , e_function , - e_vafunction , e_genfunction , e_strfunction , 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_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 + 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() {} @@ -3967,18 +5215,36 @@ namespace exprtk return std::not_equal_to()(0.0f,v); } + template + inline bool is_true(const std::complex& v) + { + return std::not_equal_to >()(std::complex(0),v); + } + template inline bool is_true(const expression_node* node) { 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) { @@ -4008,8 +5274,10 @@ namespace exprtk { return node && ( - details::expression_node::e_variable == node->type() || - details::expression_node::e_vecelem == node->type() + details::expression_node::e_variable == node->type() || + details::expression_node::e_vecelem == node->type() || + details::expression_node::e_rbvecelem == node->type() || + details::expression_node::e_rbveccelem == node->type() ); } @@ -4019,6 +5287,18 @@ namespace exprtk return node && (details::expression_node::e_vecelem == node->type()); } + template + inline bool is_rebasevector_elem_node(const expression_node* node) + { + return node && (details::expression_node::e_rbvecelem == node->type()); + } + + template + inline bool is_rebasevector_celem_node(const expression_node* node) + { + return node && (details::expression_node::e_rbveccelem == node->type()); + } + template inline bool is_vector_node(const expression_node* node) { @@ -4085,6 +5365,12 @@ namespace exprtk return node && (details::expression_node::e_function == node->type()); } + template + inline bool is_return_node(const expression_node* node) + { + return node && (details::expression_node::e_return == node->type()); + } + template class unary_node; template @@ -4101,7 +5387,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) ; } @@ -4118,7 +5405,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) @@ -4145,7 +5432,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) @@ -4159,6 +5446,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]) { @@ -4171,7 +5528,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) @@ -4183,69 +5540,299 @@ 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; + return; + } - node_allocator.free(node); - node = 0; + node_collection_destructor > + ::delete_nodes(node); + } + + template + inline void destroy_node(expression_node*& node) + { + if (0 != node) + { + node_collection_destructor > + ::delete_nodes(node); } } - template - class vector_holder + template + struct node_depth_base { - private: + node_depth_base() + : depth_set(false), + depth(0) + {} - typedef Type value_type; - typedef value_type* value_ptr; - typedef const value_ptr const_value_ptr; + virtual ~node_depth_base() {} - class vector_holder_base + virtual std::size_t node_depth() const { return 1; } + + std::size_t compute_node_depth(const Node* const& node) const { - public: + if (!depth_set) + { + depth = 1 + (node ? node->node_depth() : 0); + depth_set = true; + } - virtual ~vector_holder_base(){} + return depth; + } - inline value_ptr operator[](const std::size_t& index) const + std::size_t compute_node_depth(const std::pair& branch) const + { + if (!depth_set) { - return value_at(index); + depth = 1 + (branch.first ? branch.first->node_depth() : 0); + depth_set = true; } - inline std::size_t size() const + return depth; + } + + template + std::size_t compute_node_depth(const std::pair (&branch)[N]) const + { + if (!depth_set) { - return vector_size(); + 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; } - protected: - - virtual value_ptr value_at(const std::size_t&) const = 0; - virtual std::size_t vector_size() const = 0; - }; + return depth; + } - class array_vector_impl : public vector_holder_base + template + std::size_t compute_node_depth(const BranchType& n0, const BranchType& n1) const { - public: - - array_vector_impl(const Type* vec, const std::size_t& vec_size) - : vec_(vec), - size_(vec_size) - {} + if (!depth_set) + { + depth = 1 + std::max(compute_node_depth(n0), compute_node_depth(n1)); + depth_set = true; + } - protected: + return depth; + } - value_ptr value_at(const std::size_t& index) const + template + std::size_t compute_node_depth(const BranchType& n0, const BranchType& n1, + const BranchType& n2) const + { + if (!depth_set) { - if (index < size_) - return const_cast(vec_ + index); - else - return const_value_ptr(0); + 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 + { + private: + + typedef Type value_type; + typedef value_type* value_ptr; + typedef const value_ptr const_value_ptr; + + class vector_holder_base + { + public: + + virtual ~vector_holder_base() {} + + inline value_ptr operator[](const std::size_t& index) const + { + return value_at(index); + } + + inline std::size_t size() const + { + return vector_size(); + } + + inline value_ptr data() const + { + return value_at(0); + } + + virtual inline bool rebaseable() const + { + return false; + } + + virtual void set_ref(value_ptr*) {} + + protected: + + virtual value_ptr value_at(const std::size_t&) const = 0; + virtual std::size_t vector_size() const = 0; + }; + + class array_vector_impl : public vector_holder_base + { + public: + + array_vector_impl(const Type* vec, const std::size_t& vec_size) + : vec_(vec), + size_(vec_size) + {} + + protected: + + value_ptr value_at(const std::size_t& index) const + { + if (index < size_) + return const_cast(vec_ + index); + else + return const_value_ptr(0); } std::size_t vector_size() const @@ -4262,7 +5849,7 @@ namespace exprtk }; template class Sequence> + template class Sequence> class sequence_vector_impl : public vector_holder_base { public: @@ -4292,20 +5879,64 @@ namespace exprtk sequence_t& sequence_; }; + class vector_view_impl : public vector_holder_base + { + public: + + typedef exprtk::vector_view vector_view_t; + + vector_view_impl(vector_view_t& vec_view) + : vec_view_(vec_view) + {} + + void set_ref(value_ptr* ref) + { + vec_view_.set_ref(ref); + } + + virtual inline bool rebaseable() const + { + return true; + } + + protected: + + value_ptr value_at(const std::size_t& index) const + { + return (index < vec_view_.size()) ? (&vec_view_[index]) : const_value_ptr(0); + } + + std::size_t vector_size() const + { + return vec_view_.size(); + } + + private: + + vector_view_impl operator=(const vector_view_impl&); + + vector_view_t& vec_view_; + }; + public: + typedef typename details::vec_data_store vds_t; + vector_holder(Type* vec, const std::size_t& vec_size) : vector_holder_base_(new(buffer)array_vector_impl(vec,vec_size)) {} + vector_holder(const vds_t& vds) + : vector_holder_base_(new(buffer)array_vector_impl(vds.data(),vds.size())) + {} + template vector_holder(std::vector& vec) : vector_holder_base_(new(buffer)sequence_vector_impl(vec)) {} - template - vector_holder(std::deque& deq) - : vector_holder_base_(new(buffer)sequence_vector_impl(deq)) + vector_holder(exprtk::vector_view& vec) + : vector_holder_base_(new(buffer)vector_view_impl(vec)) {} inline value_ptr operator[](const std::size_t& index) const @@ -4318,10 +5949,25 @@ namespace exprtk return vector_holder_base_->size(); } + inline value_ptr data() const + { + return vector_holder_base_->data(); + } + + void set_ref(value_ptr* ref) + { + vector_holder_base_->set_ref(ref); + } + + bool rebaseable() const + { + return vector_holder_base_->rebaseable(); + } + private: mutable vector_holder_base* vector_holder_base_; - unsigned char buffer[64]; + uchar_t buffer[64]; }; template @@ -4340,31 +5986,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_) - { - delete branch_; - branch_ = 0; - } + 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) @@ -4385,14 +6070,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_; - bool branch_deletable_; bool equality_; + branch_t branch_; }; template @@ -4422,7 +6116,7 @@ namespace exprtk private: literal_node(literal_node&) {} - literal_node& operator=(literal_node&) { return *this; } + literal_node& operator=(literal_node&) { return (*this); } const T value_; }; @@ -4440,11 +6134,15 @@ namespace exprtk typedef range_pack range_t; + virtual ~range_interface() + {} + virtual range_t& range_ref() = 0; virtual const range_t& range_ref() const = 0; }; + #ifndef exprtk_disable_string_capabilities template class string_base_node { @@ -4452,9 +6150,12 @@ namespace exprtk typedef range_data_type range_data_type_t; + virtual ~string_base_node() + {} + virtual std::string str () const = 0; - virtual const char* base() const = 0; + virtual char_cptr base() const = 0; virtual std::size_t size() const = 0; }; @@ -4497,9 +6198,9 @@ namespace exprtk return value_; } - const char* base() const + char_cptr base() const { - return value_.data(); + return value_.data(); } std::size_t size() const @@ -4525,6 +6226,7 @@ namespace exprtk const std::string value_; range_t rp_; }; + #endif template class unary_node : public expression_node @@ -4532,26 +6234,20 @@ 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_) - { - delete branch_; - branch_ = 0; - } + 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); } @@ -4567,123 +6263,54 @@ 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_); } protected: operator_type operation_; - expression_ptr branch_; - bool branch_deletable_; + branch_t branch_; }; - template - struct construct_branch_pair + template + class binary_node : public expression_node { - template - static inline void process(std::pair*,bool> (&)[N], expression_node*) - {} - }; + public: - template - struct construct_branch_pair - { - template - static inline void process(std::pair*,bool> (&branch)[N], expression_node* b) + typedef expression_node* expression_ptr; + typedef std::pair branch_t; + + binary_node(const operator_type& opr, + expression_ptr branch0, + expression_ptr branch1) + : operation_(opr) { - if (b) - { - branch[D] = 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 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]) - { - for (std::size_t i = 0; i < N; ++i) - { - if (branch[i].first && branch[i].second) - { - delete branch[i].first; - branch[i].first = 0; - } - } - } - - 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) - { - delete branch[i].first; - branch[i].first = 0; - } - } - } - }; - - template - class binary_node : public expression_node - { - public: - - typedef expression_node* expression_ptr; - typedef std::pair branch_t; - - binary_node(const operator_type& opr, - expression_ptr branch0, - expression_ptr branch1) - : operation_(opr) - { - init_branches<2>(branch_,branch0,branch1); - } - - ~binary_node() - { - cleanup_branches::execute(branch_); + init_branches<2>(branch_, branch0, branch1); } 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(); + return numeric::process(operation_,arg0,arg1); } @@ -4707,6 +6334,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_; @@ -4723,18 +6360,17 @@ namespace exprtk binary_ext_node(expression_ptr branch0, expression_ptr branch1) { - init_branches<2>(branch_,branch0,branch1); - } - - ~binary_ext_node() - { - cleanup_branches::execute(branch_); + init_branches<2>(branch_, branch0, branch1); } 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(); + return Operation::process(arg0,arg1); } @@ -4758,6 +6394,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]; @@ -4777,16 +6423,15 @@ namespace exprtk expression_ptr branch2) : operation_(opr) { - init_branches<3>(branch_,branch0,branch1,branch2); - } - - ~trinary_node() - { - cleanup_branches::execute(branch_); + init_branches<3>(branch_, branch0, branch1, branch2); } 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(); @@ -4794,14 +6439,16 @@ namespace exprtk switch (operation_) { case e_inrange : return (arg1 < arg0) ? T(0) : ((arg1 > arg2) ? T(0) : T(1)); - case e_min : return std::min(std::min(arg0,arg1),arg2); - case e_max : return std::max(std::max(arg0,arg1),arg2); - case e_clamp : return (arg0 < arg1) ? arg1 : (arg0 > arg2 ? arg2 : arg0); + + case e_clamp : return (arg1 < arg0) ? arg0 : (arg1 > arg2 ? arg2 : arg1); + case e_iclamp : if ((arg1 <= arg0) || (arg1 >= arg2)) return arg1; else return ((T(2) * arg1 <= (arg2 + arg0)) ? arg0 : arg2); - default : return std::numeric_limits::quiet_NaN(); + + default : exprtk_debug(("trinary_node::value() - Error: Invalid operation\n")); + return std::numeric_limits::quiet_NaN(); } } @@ -4810,6 +6457,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_; @@ -4831,27 +6488,12 @@ namespace exprtk expression_ptr branch3) : operation_(opr) { - init_branches<4>(branch_,branch0,branch1,branch2,branch3); - } - - ~quaternary_node() - { - cleanup_branches::execute(branch_); + init_branches<4>(branch_, branch0, branch1, branch2, branch3); } inline T value() const { - const T arg0 = branch_[0].first->value(); - const T arg1 = branch_[1].first->value(); - const T arg2 = branch_[2].first->value(); - const T arg3 = branch_[3].first->value(); - - switch (operation_) - { - case e_min : return std::min(std::min(arg0,arg1),std::min(arg2,arg3)); - case e_max : return std::max(std::max(arg0,arg1),std::max(arg2,arg3)); - default : return std::numeric_limits::quiet_NaN(); - } + return std::numeric_limits::quiet_NaN(); } inline typename expression_node::node_type type() const @@ -4859,163 +6501,74 @@ namespace exprtk return expression_node::e_quaternary; } - protected: - - operator_type operation_; - branch_t branch_[4]; - }; - - template - class quinary_node : public expression_node - { - public: - - typedef expression_node* expression_ptr; - typedef std::pair branch_t; - - quinary_node(const operator_type& opr, - expression_ptr branch0, - expression_ptr branch1, - expression_ptr branch2, - expression_ptr branch3, - expression_ptr branch4) - : operation_(opr) - { - init_branches<5>(branch_,branch0,branch1,branch2,branch3,branch4); - } - - ~quinary_node() - { - cleanup_branches::execute(branch_); - } - - inline T value() const + void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) { - const T arg0 = branch_[0].first->value(); - const T arg1 = branch_[1].first->value(); - const T arg2 = branch_[2].first->value(); - const T arg3 = branch_[3].first->value(); - const T arg4 = branch_[4].first->value(); - - switch (operation_) - { - case e_min : return std::min(std::min(std::min(arg0,arg1),std::min(arg2,arg3)),arg4); - case e_max : return std::max(std::max(std::max(arg0,arg1),std::max(arg2,arg3)),arg4); - default : return std::numeric_limits::quiet_NaN(); - } + expression_node::ndb_t::template collect(branch_, node_delete_list); } - inline typename expression_node::node_type type() const + std::size_t node_depth() const { - return expression_node::e_quinary; + return expression_node::ndb_t::template compute_node_depth<4>(branch_); } - private: + protected: operator_type operation_; - branch_t branch_[5]; + branch_t branch_[4]; }; template - class senary_node : public expression_node + class conditional_node : public expression_node { public: typedef expression_node* expression_ptr; typedef std::pair branch_t; - senary_node(const operator_type& opr, - expression_ptr branch0, - expression_ptr branch1, - expression_ptr branch2, - expression_ptr branch3, - expression_ptr branch4, - expression_ptr branch5) - : operation_(opr) - { - init_branches<6>(branch_,branch0,branch1,branch2,branch3,branch4,branch5); - } - - ~senary_node() + conditional_node(expression_ptr condition, + expression_ptr consequent, + expression_ptr alternative) { - cleanup_branches::execute(branch_); + construct_branch_pair(condition_ , condition ); + construct_branch_pair(consequent_ , consequent ); + construct_branch_pair(alternative_, alternative); } inline T value() const { - const T arg0 = branch_[0].first->value(); - const T arg1 = branch_[1].first->value(); - const T arg2 = branch_[2].first->value(); - const T arg3 = branch_[3].first->value(); - const T arg4 = branch_[4].first->value(); - const T arg5 = branch_[5].first->value(); + assert(condition_ .first); + assert(consequent_ .first); + assert(alternative_.first); - switch (operation_) - { - case e_min : return std::min(std::min(std::min(arg0,arg1),std::min(arg2,arg3)),std::min(arg4,arg5)); - case e_max : return std::max(std::max(std::max(arg0,arg1),std::max(arg2,arg3)),std::max(arg4,arg5)); - case e_default : - default : return std::numeric_limits::quiet_NaN(); - } + if (is_true(condition_)) + return consequent_.first->value(); + else + return alternative_.first->value(); } inline typename expression_node::node_type type() const { - return expression_node::e_senary; - } - - private: - - operator_type operation_; - branch_t branch_[6]; - }; - - template - class conditional_node : public expression_node - { - public: - - typedef expression_node* expression_ptr; - - conditional_node(expression_ptr test, - 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_ ) delete test_; - if (consequent_ && consequent_deletable_ ) delete consequent_; - if (alternative_ && alternative_deletable_) delete alternative_; + return expression_node::e_conditional; } - inline T value() const + void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) { - if (is_true(test_)) - return consequent_->value(); - else - return alternative_->value(); + 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); } - inline typename expression_node::node_type type() const + std::size_t node_depth() const { - return expression_node::e_conditional; + return expression_node::ndb_t::compute_node_depth + (condition_, consequent_, alternative_); } private: - expression_ptr test_; - expression_ptr consequent_; - expression_ptr alternative_; - bool test_deletable_; - bool consequent_deletable_; - bool alternative_deletable_; + branch_t condition_; + branch_t consequent_; + branch_t alternative_; }; template @@ -5025,25 +6578,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_ ) delete test_; - if (consequent_ && consequent_deletable_) delete 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(); } @@ -5053,28 +6603,38 @@ 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_; - bool test_deletable_; - bool consequent_deletable_; + branch_t condition_; + branch_t consequent_; }; #ifndef exprtk_disable_break_continue template - class break_exception : public std::exception + class break_exception { public: - break_exception(const T& v) + explicit break_exception(const T& v) : value(v) {} T value; }; - class continue_exception : public std::exception + class continue_exception {}; template @@ -5083,23 +6643,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_) - { - delete 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 @@ -5110,10 +6663,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_; - bool return_deletable_; + branch_t return_; }; template @@ -5136,40 +6698,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_) - { - delete 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) + ) { - delete 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; @@ -5180,50 +6792,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_; - bool condition_deletable_; - 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_) - { - delete condition_; - } - - if (loop_body_ && loop_body_deletable_) - { - delete 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; } @@ -5233,78 +6850,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_; - bool condition_deletable_; - 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_ )) - {} + 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) + { + construct_branch_pair(initialiser_, initialiser); + construct_branch_pair(condition_ , condition ); + construct_branch_pair(incrementor_, incrementor); + construct_branch_pair(loop_body_ , loop_body ); + } - ~for_loop_node() + inline T value() const { - if (initialiser_ && initialiser_deletable_) - { - delete initialiser_; - } + assert(condition_.first); + assert(loop_body_.first); - if (condition_ && condition_deletable_) - { - delete condition_; - } + T result = T(0); - if (incrementor_ && incrementor_deletable_) - { - delete incrementor_; - } - - if (loop_body_ && loop_body_deletable_) - { - delete loop_body_; - } - } - - inline T value() const - { - T result = T(0); + loop_runtime_checker::reset(); - if (initialiser_) - initialiser_->value(); + if (initialiser_.first) + initialiser_.first->value(); - if (incrementor_) + 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(); } } @@ -5316,54 +6925,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_ ; - bool initialiser_deletable_; - bool condition_deletable_ ; - bool incrementor_deletable_; - 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_) - { - delete condition_; - } - - if (loop_body_ && loop_body_deletable_) - { - delete 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) { @@ -5372,6 +6988,7 @@ namespace exprtk catch(const continue_exception&) {} } + return result; } @@ -5380,50 +6997,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_; - bool condition_deletable_; - 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_) - { - delete condition_; - } - - if (loop_body_ && loop_body_deletable_) - { - delete 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) { @@ -5432,7 +7054,7 @@ namespace exprtk catch(const continue_exception&) {} } - while (is_false(condition_)); + while (is_false(condition_.first) && loop_runtime_checker::check()); return result; } @@ -5442,72 +7064,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_; - bool condition_deletable_; - 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_) - { - delete initialiser_; - } - - if (condition_ && condition_deletable_) - { - delete condition_; - } - - if (incrementor_ && incrementor_deletable_) - { - delete incrementor_; - } - - if (loop_body_ && loop_body_deletable_) - { - delete 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 (initialiser_.first) + initialiser_.first->value(); - if (incrementor_) + 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) { @@ -5516,16 +7130,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) { @@ -5544,16 +7158,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_ ; - bool initialiser_deletable_; - bool condition_deletable_ ; - bool incrementor_deletable_; - bool loop_body_deletable_ ; + branch_t initialiser_; + branch_t condition_ ; + branch_t incrementor_; + branch_t loop_body_ ; }; #endif @@ -5563,45 +7187,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]) - { - delete arg_list_[i]; - arg_list_[i] = 0; - } - } - } - inline T value() const { if (!arg_list_.empty()) @@ -5610,8 +7220,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)) { @@ -5619,7 +7229,7 @@ namespace exprtk } } - return arg_list_[upper_bound]->value(); + return arg_list_[upper_bound].first->value(); } else return std::numeric_limits::quiet_NaN(); @@ -5630,10 +7240,38 @@ namespace exprtk return expression_node::e_switch; } - private: + void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) + { + expression_node::ndb_t::collect(arg_list_, node_delete_list); + } - std::vector arg_list_; - std::vector delete_branch_; + std::size_t node_depth() const + { + return expression_node::ndb_t::compute_node_depth(arg_list_); + } + + protected: + + std::vector arg_list_; + }; + + template + class switch_n_node : public switch_node + { + public: + + typedef expression_node* expression_ptr; + + template class Sequence> + explicit switch_n_node(const Sequence& arg_list) + : switch_node(arg_list) + {} + + inline T value() const + { + return Switch_N::process(switch_node::arg_list_); + } }; template @@ -5642,45 +7280,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]) - { - delete arg_list_[i]; - arg_list_[i] = 0; - } - } - } - inline T value() const { T result = T(0); @@ -5694,8 +7318,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)) { @@ -5711,10 +7335,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 @@ -5722,36 +7355,29 @@ namespace exprtk { public: + virtual ~ivariable() + {} + virtual T& ref() = 0; virtual const T& ref() const = 0; }; template class variable_node : public expression_node, - public ivariable + public ivariable { public: static T null_value; explicit variable_node() - : value_(&null_value), - delete_value_(false) + : value_(&null_value) {} - variable_node(T& v) - : value_(&v), - delete_value_(false) + explicit variable_node(T& v) + : value_(&v) {} - ~variable_node() - { - if (delete_value_) - { - delete value_; - } - } - inline bool operator <(const variable_node& v) const { return this < (&v); @@ -5777,15 +7403,9 @@ namespace exprtk return expression_node::e_variable; } - inline bool& delete_value() - { - return delete_value_; - } - private: T* value_; - bool delete_value_; }; template @@ -5825,8 +7445,7 @@ namespace exprtk !is_string_node (n0_e.second) ) { - delete n0_e.second; - n0_e.second = expression_node_ptr(0); + destroy_node(n0_e.second); } } @@ -5839,36 +7458,31 @@ namespace exprtk !is_string_node (n1_e.second) ) { - delete n1_e.second; - n1_e.second = expression_node_ptr(0); + destroy_node(n1_e.second); } } } - 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; @@ -5877,12 +7491,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; @@ -5898,7 +7507,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 @@ -5916,6 +7529,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 >= size) + { + throw std::runtime_error("range error: (r0 < 0) || (r0 >= size)"); + return false; + } + + if (r1 >= size) + { + throw std::runtime_error("range error: (r1 < 0) || (r1 >= size)"); + return false; + } + + return (r0 <= r1); + } + #endif }; template @@ -5949,20 +7583,27 @@ namespace exprtk { public: - typedef vector_node* vector_node_ptr; + typedef vector_node* vector_node_ptr; + typedef vec_data_store vds_t; virtual ~vector_interface() {} + virtual std::size_t size () const = 0; + virtual vector_node_ptr vec() const = 0; - virtual vector_node_ptr vec() = 0; + virtual vector_node_ptr vec() = 0; - virtual std::size_t size() const = 0; + virtual vds_t& vds () = 0; + + virtual const vds_t& vds () const = 0; + + virtual bool side_effect () const { return false; } }; template - class vector_node : public expression_node, + class vector_node : public expression_node , public vector_interface { public: @@ -5970,24 +7611,23 @@ namespace exprtk typedef expression_node* expression_ptr; typedef vector_holder vector_holder_t; typedef vector_node* vector_node_ptr; + typedef vec_data_store vds_t; - vector_node(vector_holder_t* vh) - : vector_holder_(vh) - {} - - inline T value() const + explicit vector_node(vector_holder_t* vh) + : vector_holder_(vh), + vds_((*vector_holder_).size(),(*vector_holder_)[0]) { - return *(ref()[0]); + vector_holder_->set_ref(&vds_.ref()); } - inline const vector_holder_t& ref() const - { - return (*vector_holder_); - } + vector_node(const vds_t& vds, vector_holder_t* vh) + : vector_holder_(vh), + vds_(vds) + {} - inline vector_holder_t& ref() + inline T value() const { - return (*vector_holder_); + return vds().data()[0]; } vector_node_ptr vec() const @@ -6007,49 +7647,61 @@ namespace exprtk std::size_t size() const { - return ref().size(); + return vds().size(); + } + + vds_t& vds() + { + return vds_; + } + + const vds_t& vds() const + { + return vds_; + } + + inline vector_holder_t& vec_holder() + { + return (*vector_holder_); } private: vector_holder_t* vector_holder_; + vds_t vds_; }; template class vector_elem_node : public expression_node, - public ivariable + public ivariable { public: - typedef expression_node* expression_ptr; - - vector_elem_node(expression_ptr index, T* vector_base) - : index_(index), - vector_base_(vector_base), - index_deletable_(branch_deletable(index_)) - {} + 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() + vector_elem_node(expression_ptr index, vector_holder_ptr vec_holder) + : vec_holder_(vec_holder), + vector_base_((*vec_holder)[0]) { - if (index_ && index_deletable_) - { - delete 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 @@ -6057,81 +7709,208 @@ namespace exprtk return expression_node::e_vecelem; } + inline vector_holder_t& vec_holder() + { + 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_; - bool index_deletable_; + branch_t index_; }; template - class vector_assignment_node : public expression_node + class rebasevector_elem_node : public expression_node, + public ivariable { public: - typedef expression_node* expression_ptr; - - vector_assignment_node(T* vector_base, - const std::size_t& size, - const std::vector& initialiser_list, - const bool single_value_initialse) - : vector_base_(vector_base), - initialiser_list_(initialiser_list), - size_(size), - single_value_initialse_(single_value_initialse) - {} + 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; - ~vector_assignment_node() + rebasevector_elem_node(expression_ptr index, vector_holder_ptr vec_holder) + : vector_holder_(vec_holder), + vds_((*vector_holder_).size(),(*vector_holder_)[0]) { - for (std::size_t i = 0; i < initialiser_list_.size(); ++i) - { - if (branch_deletable(initialiser_list_[i])) - { - delete initialiser_list_[i]; - } - } + vector_holder_->set_ref(&vds_.ref()); + construct_branch_pair(index_, index); } inline T value() const { - if (single_value_initialse_) - { - for (std::size_t i = 0; i < size_; ++i) - { - *(vector_base_ + i) = initialiser_list_[0]->value(); - } - } - else - { - std::size_t il_size = initialiser_list_.size(); - - for (std::size_t i = 0; i < il_size; ++i) - { - *(vector_base_ + i) = initialiser_list_[i]->value(); - } + return *(vds_.data() + static_cast(details::numeric::to_int64(index_.first->value()))); + } - if (il_size < size_) - { - for (std::size_t i = il_size; i < size_; ++i) - { - *(vector_base_ + i) = T(0); - } - } - } + inline T& ref() + { + return *(vds_.data() + static_cast(details::numeric::to_int64(index_.first->value()))); + } - return *(vector_base_); + inline const T& ref() const + { + return *(vds_.data() + static_cast(details::numeric::to_int64(index_.first->value()))); } inline typename expression_node::node_type type() const { - return expression_node::e_vecdefass; + return expression_node::e_rbvecelem; } - private: + inline vector_holder_t& vec_holder() + { + return (*vector_holder_); + } - vector_assignment_node& operator=(const vector_assignment_node&); + void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) + { + expression_node::ndb_t::template collect(index_, node_delete_list); + } - mutable T* vector_base_; + std::size_t node_depth() const + { + return expression_node::ndb_t::compute_node_depth(index_); + } + + private: + + vector_holder_ptr vector_holder_; + vds_t vds_; + branch_t index_; + }; + + template + class rebasevector_celem_node : public expression_node, + public ivariable + { + 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; + + rebasevector_celem_node(const std::size_t index, vector_holder_ptr vec_holder) + : index_(index), + vector_holder_(vec_holder), + vds_((*vector_holder_).size(),(*vector_holder_)[0]) + { + vector_holder_->set_ref(&vds_.ref()); + } + + inline T value() const + { + return *(vds_.data() + index_); + } + + inline T& ref() + { + return *(vds_.data() + index_); + } + + inline const T& ref() const + { + return *(vds_.data() + index_); + } + + inline typename expression_node::node_type type() const + { + return expression_node::e_rbveccelem; + } + + inline vector_holder_t& vec_holder() + { + return (*vector_holder_); + } + + private: + + const std::size_t index_; + vector_holder_ptr vector_holder_; + vds_t vds_; + }; + + template + class vector_assignment_node : public expression_node + { + public: + + typedef expression_node* expression_ptr; + + vector_assignment_node(T* vector_base, + const std::size_t& size, + const std::vector& initialiser_list, + const bool single_value_initialse) + : vector_base_(vector_base), + initialiser_list_(initialiser_list), + size_(size), + single_value_initialse_(single_value_initialse) + {} + + inline T value() const + { + if (single_value_initialse_) + { + for (std::size_t i = 0; i < size_; ++i) + { + *(vector_base_ + i) = initialiser_list_[0]->value(); + } + } + else + { + std::size_t il_size = initialiser_list_.size(); + + for (std::size_t i = 0; i < il_size; ++i) + { + *(vector_base_ + i) = initialiser_list_[i]->value(); + } + + if (il_size < size_) + { + for (std::size_t i = il_size; i < size_; ++i) + { + *(vector_base_ + i) = T(0); + } + } + } + + return *(vector_base_); + } + + inline typename expression_node::node_type type() const + { + 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&); + + mutable T* vector_base_; std::vector initialiser_list_; const std::size_t size_; const bool single_value_initialse_; @@ -6176,7 +7955,7 @@ namespace exprtk typedef ivariable* ivariable_ptr; swap_generic_node(expression_ptr var0, expression_ptr var1) - : binary_node(details::e_swap,var0,var1), + : binary_node(details::e_swap, var0, var1), var0_(dynamic_cast(var0)), var1_(dynamic_cast(var1)) {} @@ -6199,28 +7978,31 @@ namespace exprtk }; template - class swap_vecvec_node : public binary_node, + class swap_vecvec_node : public binary_node , public vector_interface { public: - typedef expression_node* expression_ptr; + typedef expression_node* expression_ptr; typedef vector_node* vector_node_ptr; + typedef vec_data_store vds_t; swap_vecvec_node(expression_ptr branch0, expression_ptr branch1) - : binary_node(details::e_swap,branch0,branch1), + : binary_node(details::e_swap, branch0, branch1), vec0_node_ptr_(0), vec1_node_ptr_(0), - vec_size_ (0) + vec_size_ (0), + initialised_ (false) { if (is_ivector_node(binary_node::branch_[0].first)) { vector_interface* vi = reinterpret_cast*>(0); - if ((vi = dynamic_cast*>(binary_node::branch_[0].first))) + if (0 != (vi = dynamic_cast*>(binary_node::branch_[0].first))) { vec0_node_ptr_ = vi->vec(); + vds() = vi->vds(); } } @@ -6228,7 +8010,7 @@ namespace exprtk { vector_interface* vi = reinterpret_cast*>(0); - if ((vi = dynamic_cast*>(binary_node::branch_[1].first))) + if (0 != (vi = dynamic_cast*>(binary_node::branch_[1].first))) { vec1_node_ptr_ = vi->vec(); } @@ -6236,24 +8018,29 @@ namespace exprtk if (vec0_node_ptr_ && vec1_node_ptr_) { - vec_size_ = std::min(vec0_node_ptr_->ref().size(), - vec1_node_ptr_->ref().size()); + vec_size_ = std::min(vec0_node_ptr_->vds().size(), + vec1_node_ptr_->vds().size()); + + initialised_ = true; } } inline T value() const { - if (vec0_node_ptr_ && vec1_node_ptr_) + assert(binary_node::branch_[0].first); + assert(binary_node::branch_[1].first); + + if (initialised_) { binary_node::branch_[0].first->value(); binary_node::branch_[1].first->value(); - vector_holder& vec0 = vec0_node_ptr_->ref(); - vector_holder& vec1 = vec1_node_ptr_->ref(); + T* vec0 = vec0_node_ptr_->vds().data(); + T* vec1 = vec1_node_ptr_->vds().data(); for (std::size_t i = 0; i < vec_size_; ++i) { - std::swap((*vec0[i]),(*vec1[i])); + std::swap(vec0[i],vec1[i]); } return vec1_node_ptr_->value(); @@ -6282,11 +8069,23 @@ namespace exprtk return vec_size_; } + vds_t& vds() + { + return vds_; + } + + const vds_t& vds() const + { + return vds_; + } + private: vector_node* vec0_node_ptr_; vector_node* vec1_node_ptr_; std::size_t vec_size_; + bool initialised_; + vds_t vds_; }; #ifndef exprtk_disable_string_capabilities @@ -6323,6 +8122,7 @@ namespace exprtk { rp_.n1_c.second = (*value_).size() - 1; rp_.cache.second = rp_.n1_c.second; + return std::numeric_limits::quiet_NaN(); } @@ -6331,9 +8131,9 @@ namespace exprtk return ref(); } - const char* base() const + char_cptr base() const { - return (*value_).data(); + return &(*value_)[0]; } std::size_t size() const @@ -6376,9 +8176,9 @@ namespace exprtk std::string stringvar_node::null_value = std::string(""); template - class string_range_node : public expression_node , - public string_base_node, - public range_interface + class string_range_node : public expression_node , + public string_base_node, + public range_interface { public: @@ -6386,12 +8186,12 @@ namespace exprtk static std::string null_value; - explicit string_range_node(std::string& v, range_t rp) + explicit string_range_node(std::string& v, const range_t& rp) : value_(&v), rp_(rp) {} - ~string_range_node() + virtual ~string_range_node() { rp_.free(); } @@ -6411,9 +8211,9 @@ namespace exprtk return (*value_); } - const char* base() const + char_cptr base() const { - return (*value_).data(); + return &(*value_)[0]; } std::size_t size() const @@ -6469,7 +8269,7 @@ namespace exprtk typedef range_pack range_t; - explicit const_string_range_node(const std::string& v, range_t rp) + explicit const_string_range_node(const std::string& v, const range_t& rp) : value_(v), rp_(rp) {} @@ -6489,9 +8289,9 @@ namespace exprtk return value_; } - const char* base() const + char_cptr base() const { - return value_.data(); + return value_.data(); } std::size_t size() const @@ -6534,19 +8334,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 typename range_t::cached_range_t cached_range_t; + 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, range_t brange) + 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) @@ -6556,14 +8355,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; @@ -6575,19 +8376,15 @@ namespace exprtk ~generic_string_range_node() { base_range_.free(); - - if (branch_ && branch_deletable_) - { - delete branch_; - branch_ = 0; - } } 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; @@ -6595,13 +8392,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; @@ -6621,9 +8418,9 @@ namespace exprtk return value_; } - const char* base() const + char_cptr base() const { - return value_.data(); + return &value_[0]; } std::size_t size() const @@ -6646,16 +8443,25 @@ 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_; - bool branch_deletable_; - str_base_ptr str_base_ptr_; - irange_ptr str_range_ptr_; - mutable range_t base_range_; - mutable range_t range_; - mutable std::string value_; + bool initialised_; + branch_t branch_; + str_base_ptr str_base_ptr_; + irange_ptr str_range_ptr_; + mutable range_t base_range_; + mutable range_t range_; + mutable std::string value_; }; template @@ -6666,18 +8472,16 @@ 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 typename range_t::cached_range_t cached_range_t; string_concat_node(const operator_type& opr, expression_ptr branch0, expression_ptr branch1) - : binary_node(opr,branch0,branch1), + : binary_node(opr, branch0, branch1), initialised_(false), str0_base_ptr_ (0), str1_base_ptr_ (0), @@ -6686,6 +8490,7 @@ namespace exprtk { range_.n0_c = std::make_pair(true,0); range_.n1_c = std::make_pair(true,0); + range_.cache.first = range_.n0_c.second; range_.cache.second = range_.n1_c.second; @@ -6725,6 +8530,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(); @@ -6734,12 +8542,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; @@ -6761,9 +8569,9 @@ namespace exprtk return value_; } - const char* base() const + char_cptr base() const { - return value_.data(); + return &value_[0]; } std::size_t size() const @@ -6811,10 +8619,9 @@ namespace exprtk typedef range_t* range_ptr; typedef range_interface irange_t; typedef irange_t* irange_ptr; - typedef typename range_t::cached_range_t cached_range_t; swap_string_node(expression_ptr branch0, expression_ptr branch1) - : binary_node(details::e_swap,branch0,branch1), + : binary_node(details::e_swap, branch0, branch1), initialised_(false), str0_node_ptr_(0), str1_node_ptr_(0) @@ -6836,10 +8643,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(); @@ -6850,7 +8660,7 @@ namespace exprtk return str0_node_ptr_->str(); } - const char* base() const + char_cptr base() const { return str0_node_ptr_->base(); } @@ -6882,6 +8692,163 @@ namespace exprtk strvar_node_ptr str1_node_ptr_; }; + template + class swap_genstrings_node : public binary_node + { + 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; + + swap_genstrings_node(expression_ptr branch0, + expression_ptr branch1) + : binary_node(details::e_default, branch0, branch1), + str0_base_ptr_ (0), + str1_base_ptr_ (0), + str0_range_ptr_(0), + str1_range_ptr_(0), + initialised_(false) + { + if (is_generally_string_node(binary_node::branch_[0].first)) + { + str0_base_ptr_ = dynamic_cast(binary_node::branch_[0].first); + + if (0 == str0_base_ptr_) + return; + + irange_ptr range = dynamic_cast(binary_node::branch_[0].first); + + if (0 == range) + return; + + str0_range_ptr_ = &(range->range_ref()); + } + + if (is_generally_string_node(binary_node::branch_[1].first)) + { + str1_base_ptr_ = dynamic_cast(binary_node::branch_[1].first); + + if (0 == str1_base_ptr_) + return; + + irange_ptr range = dynamic_cast(binary_node::branch_[1].first); + + if (0 == range) + return; + + str1_range_ptr_ = &(range->range_ref()); + } + + initialised_ = str0_base_ptr_ && + str1_base_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(); + + std::size_t str0_r0 = 0; + std::size_t str0_r1 = 0; + + std::size_t str1_r0 = 0; + std::size_t str1_r1 = 0; + + 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()) + ) + { + 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_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); + char_cptr upper_bound = s0 + lud.upper_bound; + + while (s0 < upper_bound) + { + #define exprtk_loop(N) \ + std::swap(s0[N], s1[N]); \ + + exprtk_loop( 0) exprtk_loop( 1) + exprtk_loop( 2) exprtk_loop( 3) + #ifndef exprtk_disable_superscalar_unroll + exprtk_loop( 4) exprtk_loop( 5) + exprtk_loop( 6) exprtk_loop( 7) + exprtk_loop( 8) exprtk_loop( 9) + exprtk_loop(10) exprtk_loop(11) + exprtk_loop(12) exprtk_loop(13) + exprtk_loop(14) exprtk_loop(15) + #endif + + s0 += lud.batch_size; + s1 += lud.batch_size; + } + + int i = 0; + + exprtk_disable_fallthrough_begin + switch (lud.remainder) + { + #define case_stmt(N) \ + case N : { std::swap(s0[i], s1[i]); ++i; } \ + + #ifndef exprtk_disable_superscalar_unroll + case_stmt(15) case_stmt(14) + case_stmt(13) case_stmt(12) + case_stmt(11) case_stmt(10) + case_stmt( 9) case_stmt( 8) + case_stmt( 7) case_stmt( 6) + case_stmt( 5) case_stmt( 4) + #endif + case_stmt( 3) case_stmt( 2) + case_stmt( 1) + } + exprtk_disable_fallthrough_end + + #undef exprtk_loop + #undef case_stmt + } + } + + return std::numeric_limits::quiet_NaN(); + } + + inline typename expression_node::node_type type() const + { + return expression_node::e_strswap; + } + + private: + + swap_genstrings_node(swap_genstrings_node&); + swap_genstrings_node& operator=(swap_genstrings_node&); + + str_base_ptr str0_base_ptr_; + str_base_ptr str1_base_ptr_; + range_ptr str0_range_ptr_; + range_ptr str1_range_ptr_; + bool initialised_; + }; + template class stringvar_size_node : public expression_node { @@ -6920,39 +8887,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_) - { - delete branch_; - branch_ = 0; - } - } - 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()); } @@ -6964,22 +8924,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_; - bool branch_deletable_; + branch_t branch_; str_base_ptr str_base_ptr_; }; struct asn_assignment { - static inline void execute(std::string& s, const char* 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* 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); } }; @@ -6997,12 +8966,11 @@ namespace exprtk typedef range_t* range_ptr; typedef range_interface irange_t; typedef irange_t* irange_ptr; - typedef typename range_t::cached_range_t cached_range_t; assignment_string_node(const operator_type& opr, expression_ptr branch0, expression_ptr branch1) - : binary_node(opr,branch0,branch1), + : binary_node(opr, branch0, branch1), initialised_(false), str0_base_ptr_ (0), str1_base_ptr_ (0), @@ -7023,12 +8991,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_ && @@ -7041,14 +9009,17 @@ 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())) + if (range(r0, r1, str1_base_ptr_->size())) { AssignmentProcess::execute(str0_node_ptr_->ref(), str1_base_ptr_->base() + r0, @@ -7066,7 +9037,7 @@ namespace exprtk return str0_node_ptr_->str(); } - const char* base() const + char_cptr base() const { return str0_node_ptr_->base(); } @@ -7107,38 +9078,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 typename range_t::cached_range_t cached_range_t; + 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), + : 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)) @@ -7148,25 +9119,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(); @@ -7176,19 +9150,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()) + 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)); } } @@ -7197,27 +9171,27 @@ namespace exprtk std::string str() const { - return str0_node_ptr_->str(); + return str0_base_ptr_->str(); } - const char* 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 @@ -7227,437 +9201,355 @@ 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_; }; - #endif - template - inline T axn(T a, T x) + template + class conditional_string_node : public trinary_node , + public string_base_node, + public range_interface { - // a*x^n - return a * exprtk::details::numeric::fast_exp::result(x); - } + public: - template - inline T axnb(T a, T x, T b) - { - // a*x^n+b - return a * exprtk::details::numeric::fast_exp::result(x) + b; - } + 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; - template - struct sf_base - { - typedef typename details::functor_t::Type Type; - 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; - }; + conditional_string_node(expression_ptr condition, + expression_ptr consequent, + expression_ptr alternative) + : 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), + condition_ (condition), + consequent_ (consequent), + alternative_(alternative) + { + range_.n0_c = std::make_pair(true,0); + range_.n1_c = std::make_pair(true,0); - #define define_sfop3(NN,OP0,OP1) \ - template \ - struct sf##NN##_op : public sf_base \ - { \ - typedef typename sf_base::Type Type; \ - static inline T process(Type x, Type y, Type z) \ - { \ - return (OP0); \ - } \ - static inline std::string id() \ - { \ - return OP1; \ - } \ - }; \ + range_.cache.first = range_.n0_c.second; + range_.cache.second = range_.n1_c.second; - define_sfop3(00,(x + y) / z ,"(t+t)/t") - define_sfop3(01,(x + y) * z ,"(t+t)*t") - define_sfop3(02,(x + y) - z ,"(t+t)-t") - define_sfop3(03,(x + y) + z ,"(t+t)+t") - define_sfop3(04,(x - y) + z ,"(t-t)+t") - define_sfop3(05,(x - y) / z ,"(t-t)/t") - define_sfop3(06,(x - y) * z ,"(t-t)*t") - define_sfop3(07,(x * y) + z ,"(t*t)+t") - define_sfop3(08,(x * y) - z ,"(t*t)-t") - define_sfop3(09,(x * y) / z ,"(t*t)/t") - define_sfop3(10,(x * y) * z ,"(t*t)*t") - define_sfop3(11,(x / y) + z ,"(t/t)+t") - define_sfop3(12,(x / y) - z ,"(t/t)-t") - define_sfop3(13,(x / y) / z ,"(t/t)/t") - define_sfop3(14,(x / y) * z ,"(t/t)*t") - define_sfop3(15,x / (y + z) ,"t/(t+t)") - define_sfop3(16,x / (y - z) ,"t/(t-t)") - define_sfop3(17,x / (y * z) ,"t/(t*t)") - define_sfop3(18,x / (y / z) ,"t/(t/t)") - define_sfop3(19,x * (y + z) ,"t*(t+t)") - define_sfop3(20,x * (y - z) ,"t*(t-t)") - define_sfop3(21,x * (y * z) ,"t*(t*t)") - define_sfop3(22,x * (y / z) ,"t*(t/t)") - define_sfop3(23,x - (y + z) ,"t-(t+t)") - define_sfop3(24,x - (y - z) ,"t-(t-t)") - define_sfop3(25,x - (y / z) ,"t-(t/t)") - define_sfop3(26,x - (y * z) ,"t-(t*t)") - define_sfop3(27,x + (y * z) ,"t+(t*t)") - define_sfop3(28,x + (y / z) ,"t+(t/t)") - define_sfop3(29,x + (y + z) ,"t+(t+t)") - define_sfop3(30,x + (y - z) ,"t+(t-t)") - define_sfop3(31,(axnb(x,y,z))," ") - define_sfop3(32,(axnb(x,y,z))," ") - define_sfop3(33,(axnb(x,y,z))," ") - define_sfop3(34,(axnb(x,y,z))," ") - define_sfop3(35,(axnb(x,y,z))," ") - define_sfop3(36,(axnb(x,y,z))," ") - define_sfop3(37,(axnb(x,y,z))," ") - define_sfop3(38,(axnb(x,y,z))," ") - define_sfop3(39,x * numeric::log(y) + z,"") - define_sfop3(40,x * numeric::log(y) - z,"") - define_sfop3(41,x * numeric::log10(y) + z,"") - define_sfop3(42,x * numeric::log10(y) - z,"") - define_sfop3(43,x * numeric::sin(y) + z ,"") - define_sfop3(44,x * numeric::sin(y) - z ,"") - define_sfop3(45,x * numeric::cos(y) + z ,"") - define_sfop3(46,x * numeric::cos(y) - z ,"") - define_sfop3(47,details::is_true(x) ? y : z,"") + if (is_generally_string_node(trinary_node::branch_[0].first)) + { + str0_base_ptr_ = dynamic_cast(trinary_node::branch_[0].first); - #define define_sfop4(NN,OP0,OP1) \ - template \ - struct sf##NN##_op : public sf_base \ - { \ - typedef typename sf_base::Type Type; \ - static inline T process(Type x, Type y, Type z, Type w) \ - { \ - return (OP0); \ - } \ - static inline std::string id() { return OP1; } \ - }; \ + if (0 == str0_base_ptr_) + return; - define_sfop4(48,(x + ((y + z) / w)),"t+((t+t)/t)") - define_sfop4(49,(x + ((y + z) * w)),"t+((t+t)*t)") - define_sfop4(50,(x + ((y - z) / w)),"t+((t-t)/t)") - define_sfop4(51,(x + ((y - z) * w)),"t+((t-t)*t)") - define_sfop4(52,(x + ((y * z) / w)),"t+((t*t)/t)") - define_sfop4(53,(x + ((y * z) * w)),"t+((t*t)*t)") - define_sfop4(54,(x + ((y / z) + w)),"t+((t/t)+t)") - define_sfop4(55,(x + ((y / z) / w)),"t+((t/t)/t)") - define_sfop4(56,(x + ((y / z) * w)),"t+((t/t)*t)") - define_sfop4(57,(x - ((y + z) / w)),"t-((t+t)/t)") - define_sfop4(58,(x - ((y + z) * w)),"t-((t+t)*t)") - define_sfop4(59,(x - ((y - z) / w)),"t-((t-t)/t)") - define_sfop4(60,(x - ((y - z) * w)),"t-((t-t)*t)") - define_sfop4(61,(x - ((y * z) / w)),"t-((t*t)/t)") - define_sfop4(62,(x - ((y * z) * w)),"t-((t*t)*t)") - define_sfop4(63,(x - ((y / z) / w)),"t-((t/t)/t)") - define_sfop4(64,(x - ((y / z) * w)),"t-((t/t)*t)") - define_sfop4(65,(((x + y) * z) - w),"((t+t)*t)-t") - define_sfop4(66,(((x - y) * z) - w),"((t-t)*t)-t") - define_sfop4(67,(((x * y) * z) - w),"((t*t)*t)-t") - define_sfop4(68,(((x / y) * z) - w),"((t/t)*t)-t") - define_sfop4(69,(((x + y) / z) - w),"((t+t)/t)-t") - define_sfop4(70,(((x - y) / z) - w),"((t-t)/t)-t") - define_sfop4(71,(((x * y) / z) - w),"((t*t)/t)-t") - define_sfop4(72,(((x / y) / z) - w),"((t/t)/t)-t") - define_sfop4(73,((x * y) + (z * w)),"(t*t)+(t*t)") - define_sfop4(74,((x * y) - (z * w)),"(t*t)-(t*t)") - define_sfop4(75,((x * y) + (z / w)),"(t*t)+(t/t)") - define_sfop4(76,((x * y) - (z / w)),"(t*t)-(t/t)") - define_sfop4(77,((x / y) + (z / w)),"(t/t)+(t/t)") - define_sfop4(78,((x / y) - (z / w)),"(t/t)-(t/t)") - define_sfop4(79,((x / y) - (z * w)),"(t/t)-(t*t)") - define_sfop4(80,(x / (y + (z * w))),"t/(t+(t*t))") - define_sfop4(81,(x / (y - (z * w))),"t/(t-(t*t))") - define_sfop4(82,(x * (y + (z * w))),"t*(t+(t*t))") - define_sfop4(83,(x * (y - (z * w))),"t*(t-(t*t))") + str0_range_ptr_ = dynamic_cast(trinary_node::branch_[0].first); - define_sfop4(84,(axn(x,y) + axn(z,w)),"") - define_sfop4(85,(axn(x,y) + axn(z,w)),"") - define_sfop4(86,(axn(x,y) + axn(z,w)),"") - define_sfop4(87,(axn(x,y) + axn(z,w)),"") - define_sfop4(88,(axn(x,y) + axn(z,w)),"") - define_sfop4(89,(axn(x,y) + axn(z,w)),"") - define_sfop4(90,(axn(x,y) + axn(z,w)),"") - define_sfop4(91,(axn(x,y) + axn(z,w)),"") - define_sfop4(92,((details::is_true(x) && details::is_true(y)) ? z : w),"") - define_sfop4(93,((details::is_true(x) || details::is_true(y)) ? z : w),"") - define_sfop4(94,((x < y) ? z : w),"") - define_sfop4(95,((x <= y) ? z : w),"") - define_sfop4(96,((x > y) ? z : w),"") - define_sfop4(97,((x >= y) ? z : w),"") - define_sfop4(98,(details::is_true(numeric::equal(x,y)) ? z : w),"") - define_sfop4(99,(x * numeric::sin(y) + z * numeric::cos(w)),"") + if (0 == str0_range_ptr_) + return; + } - define_sfop4(ext00,((x + y) - (z * w)),"(t+t)-(t*t)") - define_sfop4(ext01,((x + y) - (z / w)),"(t+t)-(t/t)") - define_sfop4(ext02,((x + y) + (z * w)),"(t+t)+(t*t)") - define_sfop4(ext03,((x + y) + (z / w)),"(t+t)+(t/t)") - define_sfop4(ext04,((x - y) + (z * w)),"(t-t)+(t*t)") - define_sfop4(ext05,((x - y) + (z / w)),"(t-t)+(t/t)") - define_sfop4(ext06,((x - y) - (z * w)),"(t-t)-(t*t)") - define_sfop4(ext07,((x - y) - (z / w)),"(t-t)-(t/t)") - define_sfop4(ext08,((x + y) - (z - w)),"(t+t)-(t-t)") - define_sfop4(ext09,((x + y) + (z - w)),"(t+t)+(t-t)") - define_sfop4(ext10,((x + y) * (z - w)),"(t+t)*(t-t)") - define_sfop4(ext11,((x + y) / (z - w)),"(t+t)/(t-t)") - define_sfop4(ext12,((x - y) - (z + w)),"(t-t)-(t+t)") - define_sfop4(ext13,((x - y) + (z + w)),"(t-t)+(t+t)") - define_sfop4(ext14,((x - y) * (z + w)),"(t-t)*(t+t)") - define_sfop4(ext15,((x - y) / (z + w)),"(t-t)/(t+t)") - define_sfop4(ext16,((x * y) - (z + w)),"(t*t)-(t+t)") - define_sfop4(ext17,((x / y) - (z + w)),"(t/t)-(t+t)") - define_sfop4(ext18,((x * y) + (z + w)),"(t*t)+(t+t)") - define_sfop4(ext19,((x / y) + (z + w)),"(t/t)+(t+t)") - define_sfop4(ext20,((x * y) + (z - w)),"(t*t)+(t-t)") - define_sfop4(ext21,((x / y) + (z - w)),"(t/t)+(t-t)") - define_sfop4(ext22,((x * y) - (z - w)),"(t*t)-(t-t)") - define_sfop4(ext23,((x / y) - (z - w)),"(t/t)-(t-t)") - define_sfop4(ext24,((x + y) * (z * w)),"(t+t)*(t*t)") - define_sfop4(ext25,((x + y) * (z / w)),"(t+t)*(t/t)") - define_sfop4(ext26,((x + y) / (z * w)),"(t+t)/(t*t)") - define_sfop4(ext27,((x + y) / (z / w)),"(t+t)/(t/t)") - define_sfop4(ext28,((x - y) / (z * w)),"(t-t)/(t*t)") - define_sfop4(ext29,((x - y) / (z / w)),"(t-t)/(t/t)") - define_sfop4(ext30,((x - y) * (z * w)),"(t-t)*(t*t)") - define_sfop4(ext31,((x - y) * (z / w)),"(t-t)*(t/t)") - define_sfop4(ext32,((x * y) * (z + w)),"(t*t)*(t+t)") - define_sfop4(ext33,((x / y) * (z + w)),"(t/t)*(t+t)") - define_sfop4(ext34,((x * y) / (z + w)),"(t*t)/(t+t)") - define_sfop4(ext35,((x / y) / (z + w)),"(t/t)/(t+t)") - define_sfop4(ext36,((x * y) / (z - w)),"(t*t)/(t-t)") - define_sfop4(ext37,((x / y) / (z - w)),"(t/t)/(t-t)") - define_sfop4(ext38,((x * y) * (z - w)),"(t*t)*(t-t)") - define_sfop4(ext39,((x * y) / (z * w)),"(t*t)/(t*t)") - define_sfop4(ext40,((x / y) * (z / w)),"(t/t)*(t/t)") - define_sfop4(ext41,((x / y) * (z - w)),"(t/t)*(t-t)") - define_sfop4(ext42,((x * y) * (z * w)),"(t*t)*(t*t)") - define_sfop4(ext43,(x + (y * (z / w))),"t+(t*(t/t))") - define_sfop4(ext44,(x - (y * (z / w))),"t-(t*(t/t))") - define_sfop4(ext45,(x + (y / (z * w))),"t+(t/(t*t))") - define_sfop4(ext46,(x - (y / (z * w))),"t-(t/(t*t))") - define_sfop4(ext47,(((x - y) - z) * w),"((t-t)-t)*t") - define_sfop4(ext48,(((x - y) - z) / w),"((t-t)-t)/t") - define_sfop4(ext49,(((x - y) + z) * w),"((t-t)+t)*t") - define_sfop4(ext50,(((x - y) + z) / w),"((t-t)+t)/t") - define_sfop4(ext51,((x + (y - z)) * w),"(t+(t-t))*t") - define_sfop4(ext52,((x + (y - z)) / w),"(t+(t-t))/t") - define_sfop4(ext53,((x + y) / (z + w)),"(t+t)/(t+t)") - define_sfop4(ext54,((x - y) / (z - w)),"(t-t)/(t-t)") - define_sfop4(ext55,((x + y) * (z + w)),"(t+t)*(t+t)") - define_sfop4(ext56,((x - y) * (z - w)),"(t-t)*(t-t)") - define_sfop4(ext57,((x - y) + (z - w)),"(t-t)+(t-t)") - define_sfop4(ext58,((x - y) - (z - w)),"(t-t)-(t-t)") - define_sfop4(ext59,((x / y) + (z * w)),"(t/t)+(t*t)") + if (is_generally_string_node(trinary_node::branch_[1].first)) + { + str1_base_ptr_ = dynamic_cast(trinary_node::branch_[1].first); - #undef define_sfop3 - #undef define_sfop4 + if (0 == str1_base_ptr_) + return; - template - class sf3_node : public trinary_node - { - public: + str1_range_ptr_ = dynamic_cast(trinary_node::branch_[1].first); - typedef expression_node* expression_ptr; + if (0 == str1_range_ptr_) + return; + } - sf3_node(const operator_type& opr, - expression_ptr branch0, - expression_ptr branch1, - expression_ptr branch2) - : trinary_node(opr,branch0,branch1,branch2) - {} + initialised_ = str0_base_ptr_ && + str1_base_ptr_ && + str0_range_ptr_ && + str1_range_ptr_ ; + + } inline T value() const { - 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(); + if (initialised_) + { + assert(condition_ ); + assert(consequent_ ); + assert(alternative_); - return SpecialFunction::process(x,y,z); - } - }; + std::size_t r0 = 0; + std::size_t r1 = 0; - template - class sf4_node : public quaternary_node - { - public: + if (is_true(condition_)) + { + consequent_->value(); - typedef expression_node* expression_ptr; + const range_t& range = str0_range_ptr_->range_ref(); - sf4_node(const operator_type& opr, - expression_ptr branch0, - expression_ptr branch1, - expression_ptr branch2, - expression_ptr branch3) - : quaternary_node(opr,branch0,branch1,branch2,branch3) - {} + if (range(r0, r1, str0_base_ptr_->size())) + { + const std::size_t size = (r1 - r0) + 1; - inline T value() const - { - 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(); - const T w = quaternary_node::branch_[3].first->value(); + value_.assign(str0_base_ptr_->base() + r0, size); - return SpecialFunction::process(x,y,z,w); - } - }; + range_.n1_c.second = value_.size() - 1; + range_.cache.second = range_.n1_c.second; - template - class sf3_var_node : public expression_node - { - public: + return T(1); + } + } + else + { + alternative_->value(); - typedef expression_node* expression_ptr; + const range_t& range = str1_range_ptr_->range_ref(); - sf3_var_node(const T& v0, const T& v1, const T& v2) - : v0_(v0), - v1_(v1), - v2_(v2) - {} + if (range(r0, r1, str1_base_ptr_->size())) + { + const std::size_t size = (r1 - r0) + 1; - inline T value() const - { - return SpecialFunction::process(v0_,v1_,v2_); - } + value_.assign(str1_base_ptr_->base() + r0, size); - inline typename expression_node::node_type type() const - { - return expression_node::e_trinary; - } + range_.n1_c.second = value_.size() - 1; + range_.cache.second = range_.n1_c.second; - private: + return T(0); + } + } + } - sf3_var_node(sf3_var_node&); - sf3_var_node& operator=(sf3_var_node&); + return std::numeric_limits::quiet_NaN(); + } - const T& v0_; - const T& v1_; - const T& v2_; - }; + std::string str() const + { + return value_; + } - template - class sf4_var_node : public expression_node - { - public: + char_cptr base() const + { + return &value_[0]; + } - typedef expression_node* expression_ptr; + std::size_t size() const + { + return value_.size(); + } - sf4_var_node(const T& v0, const T& v1, const T& v2, const T& v3) - : v0_(v0), - v1_(v1), - v2_(v2), - v3_(v3) - {} + range_t& range_ref() + { + return range_; + } - inline T value() const + const range_t& range_ref() const { - return SpecialFunction::process(v0_,v1_,v2_,v3_); + return range_; } inline typename expression_node::node_type type() const { - return expression_node::e_trinary; + return expression_node::e_strcondition; } private: - sf4_var_node(sf4_var_node&); - sf4_var_node& operator=(sf4_var_node&); + bool initialised_; + str_base_ptr str0_base_ptr_; + str_base_ptr str1_base_ptr_; + irange_ptr str0_range_ptr_; + irange_ptr str1_range_ptr_; + mutable range_t range_; + mutable std::string value_; - const T& v0_; - const T& v1_; - const T& v2_; - const T& v3_; + expression_ptr condition_; + expression_ptr consequent_; + expression_ptr alternative_; }; - template - class vararg_node : public expression_node + template + class cons_conditional_str_node : public binary_node , + public string_base_node, + public range_interface { public: - typedef expression_node* expression_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; - template class Sequence> - vararg_node(const Sequence& arg_list) + cons_conditional_str_node(expression_ptr condition, + expression_ptr consequent) + : binary_node(details::e_default, consequent, condition), + initialised_(false), + str0_base_ptr_ (0), + str0_range_ptr_(0), + condition_ (condition), + consequent_(consequent) { - arg_list_.resize(arg_list.size()); - delete_branch_.resize(arg_list.size()); + range_.n0_c = std::make_pair(true,0); + range_.n1_c = std::make_pair(true,0); - for (std::size_t i = 0; i < arg_list.size(); ++i) + range_.cache.first = range_.n0_c.second; + range_.cache.second = range_.n1_c.second; + + if (is_generally_string_node(binary_node::branch_[0].first)) { - if (arg_list[i]) - { - arg_list_[i] = arg_list[i]; - delete_branch_[i] = static_cast(branch_deletable(arg_list_[i]) ? 1 : 0); - } - else - { - arg_list_.clear(); - delete_branch_.clear(); + str0_base_ptr_ = dynamic_cast(binary_node::branch_[0].first); + + if (0 == str0_base_ptr_) + return; + + str0_range_ptr_ = dynamic_cast(binary_node::branch_[0].first); + + if (0 == str0_range_ptr_) return; - } } + + initialised_ = str0_base_ptr_ && str0_range_ptr_ ; } - ~vararg_node() + inline T value() const { - for (std::size_t i = 0; i < arg_list_.size(); ++i) + if (initialised_) { - if (arg_list_[i] && delete_branch_[i]) + assert(condition_ ); + assert(consequent_); + + if (is_true(condition_)) { - delete arg_list_[i]; - arg_list_[i] = 0; + consequent_->value(); + + 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())) + { + const std::size_t size = (r1 - r0) + 1; + + value_.assign(str0_base_ptr_->base() + r0, size); + + range_.n1_c.second = value_.size() - 1; + range_.cache.second = range_.n1_c.second; + + return T(1); + } } } + + return std::numeric_limits::quiet_NaN(); } - inline T value() const + std::string str() const { - if (!arg_list_.empty()) - return VarArgFunction::process(arg_list_); - else - return std::numeric_limits::quiet_NaN(); + return value_; + } + + char_cptr base() const + { + return &value_[0]; + } + + std::size_t size() const + { + return value_.size(); + } + + range_t& range_ref() + { + return range_; + } + + const range_t& range_ref() const + { + return range_; } inline typename expression_node::node_type type() const { - return expression_node::e_vararg; + return expression_node::e_strccondition; } private: - std::vector arg_list_; - std::vector delete_branch_; + bool initialised_; + str_base_ptr str0_base_ptr_; + irange_ptr str0_range_ptr_; + mutable range_t range_; + mutable std::string value_; + + expression_ptr condition_; + expression_ptr consequent_; }; template - class vararg_varnode : public expression_node + class str_vararg_node : public expression_node , + public string_base_node, + public range_interface { public: - typedef expression_node* expression_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> - vararg_varnode(const Sequence& arg_list) + template class Sequence> + explicit str_vararg_node(const Sequence& arg_list) + : initialised_(false), + str_base_ptr_ (0), + str_range_ptr_(0) { - arg_list_.resize(arg_list.size()); + construct_branch_pair(final_node_, const_cast(arg_list.back())); - for (std::size_t i = 0; i < arg_list.size(); ++i) + if (0 == final_node_.first) + return; + else if (!is_generally_string_node(final_node_.first)) + return; + + str_base_ptr_ = dynamic_cast(final_node_.first); + + if (0 == str_base_ptr_) + return; + + str_range_ptr_ = dynamic_cast(final_node_.first); + + if (0 == str_range_ptr_) + return; + + initialised_ = str_base_ptr_ && str_range_ptr_; + + if (arg_list.size() > 1) { - if (arg_list[i] && is_variable_node(arg_list[i])) - { - variable_node* var_node_ptr = static_cast*>(arg_list[i]); - arg_list_[i] = (&var_node_ptr->ref()); - } - else + const std::size_t arg_list_size = arg_list.size() - 1; + + arg_list_.resize(arg_list_size); + + for (std::size_t i = 0; i < arg_list_size; ++i) { - arg_list_.clear(); - return; + if (arg_list[i]) + { + construct_branch_pair(arg_list_[i], arg_list[i]); + } + else + { + arg_list_.clear(); + return; + } } } } @@ -7665,314 +9557,585 @@ namespace exprtk inline T value() const { if (!arg_list_.empty()) - return VarArgFunction::process(arg_list_); - else - return std::numeric_limits::quiet_NaN(); + { + VarArgFunction::process(arg_list_); + } + + final_node_.first->value(); + + return std::numeric_limits::quiet_NaN(); } - inline typename expression_node::node_type type() const + std::string str() const { - return expression_node::e_vararg; + return str_base_ptr_->str(); } - private: - - std::vector arg_list_; - }; + char_cptr base() const + { + return str_base_ptr_->base(); + } - template - class vectorize_node : public expression_node - { - public: + std::size_t size() const + { + return str_base_ptr_->size(); + } - typedef expression_node* expression_ptr; + range_t& range_ref() + { + return str_range_ptr_->range_ref(); + } - vectorize_node(const expression_ptr v) - : ivec_ptr_(0), - v_(v), - v_deletable_(branch_deletable(v_)) + const range_t& range_ref() const { - if (is_ivector_node(v)) - { - ivec_ptr_ = dynamic_cast*>(v); - } - else - ivec_ptr_ = 0; + return str_range_ptr_->range_ref(); } - ~vectorize_node() + inline typename expression_node::node_type type() const { - if (v_ && v_deletable_) - { - delete v_; - } + return expression_node::e_stringvararg; } - inline T value() const + void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) { - if (ivec_ptr_) - { - v_->value(); - return VecFunction::process(ivec_ptr_); - } - else - return std::numeric_limits::quiet_NaN(); + expression_node::ndb_t::collect(final_node_, node_delete_list); + expression_node::ndb_t::collect(arg_list_ , node_delete_list); } - inline typename expression_node::node_type type() const + std::size_t node_depth() const { - return expression_node::e_vecfunc; + return std::max( + expression_node::ndb_t::compute_node_depth(final_node_), + expression_node::ndb_t::compute_node_depth(arg_list_ )); } private: - vector_interface* ivec_ptr_; - expression_ptr v_; - bool v_deletable_; + bool initialised_; + branch_t final_node_; + str_base_ptr str_base_ptr_; + irange_ptr str_range_ptr_; + std::vector arg_list_; }; + #endif + + template + inline T axn(T a, T x) + { + // a*x^n + return a * exprtk::details::numeric::fast_exp::result(x); + } + + template + inline T axnb(T a, T x, T b) + { + // a*x^n+b + return a * exprtk::details::numeric::fast_exp::result(x) + b; + } template - class assignment_node : public binary_node + struct sf_base { - public: + typedef typename details::functor_t::Type Type; + 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 expression_node* expression_ptr; + #define define_sfop3(NN,OP0,OP1) \ + template \ + struct sf##NN##_op : public sf_base \ + { \ + 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); \ + } \ + }; \ - assignment_node(const operator_type& opr, - expression_ptr branch0, - expression_ptr branch1) - : binary_node(opr,branch0,branch1), - var_node_ptr_(0) - { - if (is_variable_node(binary_node::branch_[0].first)) - { - var_node_ptr_ = static_cast*>(binary_node::branch_[0].first); - } - } + define_sfop3(00,(x + y) / z ,"(t+t)/t") + define_sfop3(01,(x + y) * z ,"(t+t)*t") + define_sfop3(02,(x + y) - z ,"(t+t)-t") + define_sfop3(03,(x + y) + z ,"(t+t)+t") + define_sfop3(04,(x - y) + z ,"(t-t)+t") + define_sfop3(05,(x - y) / z ,"(t-t)/t") + define_sfop3(06,(x - y) * z ,"(t-t)*t") + define_sfop3(07,(x * y) + z ,"(t*t)+t") + define_sfop3(08,(x * y) - z ,"(t*t)-t") + define_sfop3(09,(x * y) / z ,"(t*t)/t") + define_sfop3(10,(x * y) * z ,"(t*t)*t") + define_sfop3(11,(x / y) + z ,"(t/t)+t") + define_sfop3(12,(x / y) - z ,"(t/t)-t") + define_sfop3(13,(x / y) / z ,"(t/t)/t") + define_sfop3(14,(x / y) * z ,"(t/t)*t") + define_sfop3(15,x / (y + z) ,"t/(t+t)") + define_sfop3(16,x / (y - z) ,"t/(t-t)") + define_sfop3(17,x / (y * z) ,"t/(t*t)") + define_sfop3(18,x / (y / z) ,"t/(t/t)") + define_sfop3(19,x * (y + z) ,"t*(t+t)") + define_sfop3(20,x * (y - z) ,"t*(t-t)") + define_sfop3(21,x * (y * z) ,"t*(t*t)") + define_sfop3(22,x * (y / z) ,"t*(t/t)") + define_sfop3(23,x - (y + z) ,"t-(t+t)") + define_sfop3(24,x - (y - z) ,"t-(t-t)") + define_sfop3(25,x - (y / z) ,"t-(t/t)") + define_sfop3(26,x - (y * z) ,"t-(t*t)") + define_sfop3(27,x + (y * z) ,"t+(t*t)") + define_sfop3(28,x + (y / z) ,"t+(t/t)") + define_sfop3(29,x + (y + z) ,"t+(t+t)") + define_sfop3(30,x + (y - z) ,"t+(t-t)") + define_sfop3(31,(axnb(x,y,z))," ") + define_sfop3(32,(axnb(x,y,z))," ") + define_sfop3(33,(axnb(x,y,z))," ") + define_sfop3(34,(axnb(x,y,z))," ") + define_sfop3(35,(axnb(x,y,z))," ") + define_sfop3(36,(axnb(x,y,z))," ") + define_sfop3(37,(axnb(x,y,z))," ") + define_sfop3(38,(axnb(x,y,z))," ") + define_sfop3(39,x * numeric::log(y) + z,"") + define_sfop3(40,x * numeric::log(y) - z,"") + define_sfop3(41,x * numeric::log10(y) + z,"") + define_sfop3(42,x * numeric::log10(y) - z,"") + define_sfop3(43,x * numeric::sin(y) + z ,"") + define_sfop3(44,x * numeric::sin(y) - z ,"") + define_sfop3(45,x * numeric::cos(y) + z ,"") + define_sfop3(46,x * numeric::cos(y) - z ,"") + define_sfop3(47,details::is_true(x) ? y : z,"") - inline T value() const - { - if (var_node_ptr_) - { - T& result = var_node_ptr_->ref(); - result = binary_node::branch_[1].first->value(); + #define define_sfop4(NN,OP0,OP1) \ + template \ + struct sf##NN##_op : public sf_base \ + { \ + 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); \ + } \ + }; \ - return result; - } - else - return std::numeric_limits::quiet_NaN(); - } + define_sfop4(48,(x + ((y + z) / w)),"t+((t+t)/t)") + define_sfop4(49,(x + ((y + z) * w)),"t+((t+t)*t)") + define_sfop4(50,(x + ((y - z) / w)),"t+((t-t)/t)") + define_sfop4(51,(x + ((y - z) * w)),"t+((t-t)*t)") + define_sfop4(52,(x + ((y * z) / w)),"t+((t*t)/t)") + define_sfop4(53,(x + ((y * z) * w)),"t+((t*t)*t)") + define_sfop4(54,(x + ((y / z) + w)),"t+((t/t)+t)") + define_sfop4(55,(x + ((y / z) / w)),"t+((t/t)/t)") + define_sfop4(56,(x + ((y / z) * w)),"t+((t/t)*t)") + define_sfop4(57,(x - ((y + z) / w)),"t-((t+t)/t)") + define_sfop4(58,(x - ((y + z) * w)),"t-((t+t)*t)") + define_sfop4(59,(x - ((y - z) / w)),"t-((t-t)/t)") + define_sfop4(60,(x - ((y - z) * w)),"t-((t-t)*t)") + define_sfop4(61,(x - ((y * z) / w)),"t-((t*t)/t)") + define_sfop4(62,(x - ((y * z) * w)),"t-((t*t)*t)") + define_sfop4(63,(x - ((y / z) / w)),"t-((t/t)/t)") + define_sfop4(64,(x - ((y / z) * w)),"t-((t/t)*t)") + define_sfop4(65,(((x + y) * z) - w),"((t+t)*t)-t") + define_sfop4(66,(((x - y) * z) - w),"((t-t)*t)-t") + define_sfop4(67,(((x * y) * z) - w),"((t*t)*t)-t") + define_sfop4(68,(((x / y) * z) - w),"((t/t)*t)-t") + define_sfop4(69,(((x + y) / z) - w),"((t+t)/t)-t") + define_sfop4(70,(((x - y) / z) - w),"((t-t)/t)-t") + define_sfop4(71,(((x * y) / z) - w),"((t*t)/t)-t") + define_sfop4(72,(((x / y) / z) - w),"((t/t)/t)-t") + define_sfop4(73,((x * y) + (z * w)),"(t*t)+(t*t)") + define_sfop4(74,((x * y) - (z * w)),"(t*t)-(t*t)") + define_sfop4(75,((x * y) + (z / w)),"(t*t)+(t/t)") + define_sfop4(76,((x * y) - (z / w)),"(t*t)-(t/t)") + define_sfop4(77,((x / y) + (z / w)),"(t/t)+(t/t)") + define_sfop4(78,((x / y) - (z / w)),"(t/t)-(t/t)") + define_sfop4(79,((x / y) - (z * w)),"(t/t)-(t*t)") + define_sfop4(80,(x / (y + (z * w))),"t/(t+(t*t))") + define_sfop4(81,(x / (y - (z * w))),"t/(t-(t*t))") + define_sfop4(82,(x * (y + (z * w))),"t*(t+(t*t))") + define_sfop4(83,(x * (y - (z * w))),"t*(t-(t*t))") - private: + define_sfop4(84,(axn(x,y) + axn(z,w)),"") + define_sfop4(85,(axn(x,y) + axn(z,w)),"") + define_sfop4(86,(axn(x,y) + axn(z,w)),"") + define_sfop4(87,(axn(x,y) + axn(z,w)),"") + define_sfop4(88,(axn(x,y) + axn(z,w)),"") + define_sfop4(89,(axn(x,y) + axn(z,w)),"") + define_sfop4(90,(axn(x,y) + axn(z,w)),"") + define_sfop4(91,(axn(x,y) + axn(z,w)),"") + define_sfop4(92,((details::is_true(x) && details::is_true(y)) ? z : w),"") + define_sfop4(93,((details::is_true(x) || details::is_true(y)) ? z : w),"") + define_sfop4(94,((x < y) ? z : w),"") + define_sfop4(95,((x <= y) ? z : w),"") + define_sfop4(96,((x > y) ? z : w),"") + define_sfop4(97,((x >= y) ? z : w),"") + define_sfop4(98,(details::is_true(numeric::equal(x,y)) ? z : w),"") + define_sfop4(99,(x * numeric::sin(y) + z * numeric::cos(w)),"") - variable_node* var_node_ptr_; - }; + define_sfop4(ext00,((x + y) - (z * w)),"(t+t)-(t*t)") + define_sfop4(ext01,((x + y) - (z / w)),"(t+t)-(t/t)") + define_sfop4(ext02,((x + y) + (z * w)),"(t+t)+(t*t)") + define_sfop4(ext03,((x + y) + (z / w)),"(t+t)+(t/t)") + define_sfop4(ext04,((x - y) + (z * w)),"(t-t)+(t*t)") + define_sfop4(ext05,((x - y) + (z / w)),"(t-t)+(t/t)") + define_sfop4(ext06,((x - y) - (z * w)),"(t-t)-(t*t)") + define_sfop4(ext07,((x - y) - (z / w)),"(t-t)-(t/t)") + define_sfop4(ext08,((x + y) - (z - w)),"(t+t)-(t-t)") + define_sfop4(ext09,((x + y) + (z - w)),"(t+t)+(t-t)") + define_sfop4(ext10,((x + y) + (z + w)),"(t+t)+(t+t)") + define_sfop4(ext11,((x + y) * (z - w)),"(t+t)*(t-t)") + define_sfop4(ext12,((x + y) / (z - w)),"(t+t)/(t-t)") + define_sfop4(ext13,((x - y) - (z + w)),"(t-t)-(t+t)") + define_sfop4(ext14,((x - y) + (z + w)),"(t-t)+(t+t)") + define_sfop4(ext15,((x - y) * (z + w)),"(t-t)*(t+t)") + define_sfop4(ext16,((x - y) / (z + w)),"(t-t)/(t+t)") + define_sfop4(ext17,((x * y) - (z + w)),"(t*t)-(t+t)") + define_sfop4(ext18,((x / y) - (z + w)),"(t/t)-(t+t)") + define_sfop4(ext19,((x * y) + (z + w)),"(t*t)+(t+t)") + define_sfop4(ext20,((x / y) + (z + w)),"(t/t)+(t+t)") + define_sfop4(ext21,((x * y) + (z - w)),"(t*t)+(t-t)") + define_sfop4(ext22,((x / y) + (z - w)),"(t/t)+(t-t)") + define_sfop4(ext23,((x * y) - (z - w)),"(t*t)-(t-t)") + define_sfop4(ext24,((x / y) - (z - w)),"(t/t)-(t-t)") + define_sfop4(ext25,((x + y) * (z * w)),"(t+t)*(t*t)") + define_sfop4(ext26,((x + y) * (z / w)),"(t+t)*(t/t)") + define_sfop4(ext27,((x + y) / (z * w)),"(t+t)/(t*t)") + define_sfop4(ext28,((x + y) / (z / w)),"(t+t)/(t/t)") + define_sfop4(ext29,((x - y) / (z * w)),"(t-t)/(t*t)") + define_sfop4(ext30,((x - y) / (z / w)),"(t-t)/(t/t)") + define_sfop4(ext31,((x - y) * (z * w)),"(t-t)*(t*t)") + define_sfop4(ext32,((x - y) * (z / w)),"(t-t)*(t/t)") + define_sfop4(ext33,((x * y) * (z + w)),"(t*t)*(t+t)") + define_sfop4(ext34,((x / y) * (z + w)),"(t/t)*(t+t)") + define_sfop4(ext35,((x * y) / (z + w)),"(t*t)/(t+t)") + define_sfop4(ext36,((x / y) / (z + w)),"(t/t)/(t+t)") + define_sfop4(ext37,((x * y) / (z - w)),"(t*t)/(t-t)") + define_sfop4(ext38,((x / y) / (z - w)),"(t/t)/(t-t)") + define_sfop4(ext39,((x * y) * (z - w)),"(t*t)*(t-t)") + define_sfop4(ext40,((x * y) / (z * w)),"(t*t)/(t*t)") + define_sfop4(ext41,((x / y) * (z / w)),"(t/t)*(t/t)") + define_sfop4(ext42,((x / y) * (z - w)),"(t/t)*(t-t)") + define_sfop4(ext43,((x * y) * (z * w)),"(t*t)*(t*t)") + define_sfop4(ext44,(x + (y * (z / w))),"t+(t*(t/t))") + define_sfop4(ext45,(x - (y * (z / w))),"t-(t*(t/t))") + define_sfop4(ext46,(x + (y / (z * w))),"t+(t/(t*t))") + define_sfop4(ext47,(x - (y / (z * w))),"t-(t/(t*t))") + define_sfop4(ext48,(((x - y) - z) * w),"((t-t)-t)*t") + define_sfop4(ext49,(((x - y) - z) / w),"((t-t)-t)/t") + define_sfop4(ext50,(((x - y) + z) * w),"((t-t)+t)*t") + define_sfop4(ext51,(((x - y) + z) / w),"((t-t)+t)/t") + define_sfop4(ext52,((x + (y - z)) * w),"(t+(t-t))*t") + define_sfop4(ext53,((x + (y - z)) / w),"(t+(t-t))/t") + define_sfop4(ext54,((x + y) / (z + w)),"(t+t)/(t+t)") + define_sfop4(ext55,((x - y) / (z - w)),"(t-t)/(t-t)") + define_sfop4(ext56,((x + y) * (z + w)),"(t+t)*(t+t)") + define_sfop4(ext57,((x - y) * (z - w)),"(t-t)*(t-t)") + define_sfop4(ext58,((x - y) + (z - w)),"(t-t)+(t-t)") + define_sfop4(ext59,((x - y) - (z - w)),"(t-t)-(t-t)") + define_sfop4(ext60,((x / y) + (z * w)),"(t/t)+(t*t)") + define_sfop4(ext61,(((x * y) * z) / w),"((t*t)*t)/t") - template - class assignment_vec_elem_node : public binary_node + #undef define_sfop3 + #undef define_sfop4 + + template + class sf3_node : public trinary_node { public: typedef expression_node* expression_ptr; - assignment_vec_elem_node(const operator_type& opr, - expression_ptr branch0, - expression_ptr branch1) - : binary_node(opr,branch0,branch1), - vec_node_ptr_(0) - { - if (is_vector_elem_node(binary_node::branch_[0].first)) - { - vec_node_ptr_ = static_cast*>(binary_node::branch_[0].first); - } - } + sf3_node(const operator_type& opr, + expression_ptr branch0, + expression_ptr branch1, + expression_ptr branch2) + : trinary_node(opr, branch0, branch1, branch2) + {} inline T value() const { - if (vec_node_ptr_) - { - T& result = vec_node_ptr_->ref(); - result = binary_node::branch_[1].first->value(); - - return result; - } - else - return std::numeric_limits::quiet_NaN(); - } + assert(trinary_node::branch_[0].first); + assert(trinary_node::branch_[1].first); + assert(trinary_node::branch_[2].first); - private: + 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(); - vector_elem_node* vec_node_ptr_; + return SpecialFunction::process(x, y, z); + } }; - template - class assignment_vec_node : public binary_node, - public vector_interface + template + class sf4_node : public quaternary_node { public: typedef expression_node* expression_ptr; - typedef vector_node* vector_node_ptr; - assignment_vec_node(const operator_type& opr, - expression_ptr branch0, - expression_ptr branch1) - : binary_node(opr,branch0,branch1), - vec_node_ptr_(0), - vec_size_ (0) - { - if (is_vector_node(binary_node::branch_[0].first)) - { - vec_node_ptr_ = static_cast*>(binary_node::branch_[0].first); - vec_size_ = vec_node_ptr_->ref().size(); - } - } + sf4_node(const operator_type& opr, + expression_ptr branch0, + expression_ptr branch1, + expression_ptr branch2, + expression_ptr branch3) + : quaternary_node(opr, branch0, branch1, branch2, branch3) + {} inline T value() const { - if (vec_node_ptr_) - { - vector_holder& vec_hldr = vec_node_ptr_->ref(); - const T v = binary_node::branch_[1].first->value(); + assert(quaternary_node::branch_[0].first); + assert(quaternary_node::branch_[1].first); + assert(quaternary_node::branch_[2].first); + assert(quaternary_node::branch_[3].first); - for (std::size_t i = 0; i < vec_size_; ++i) - { - (*vec_hldr[i]) = v; - } + 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(); + const T w = quaternary_node::branch_[3].first->value(); - return vec_node_ptr_->value(); - } - else - return std::numeric_limits::quiet_NaN(); + return SpecialFunction::process(x, y, z, w); } + }; - vector_node_ptr vec() const + template + class sf3_var_node : public expression_node + { + public: + + typedef expression_node* expression_ptr; + + sf3_var_node(const T& v0, const T& v1, const T& v2) + : v0_(v0), + v1_(v1), + v2_(v2) + {} + + inline T value() const { - return vec_node_ptr_; + return SpecialFunction::process(v0_, v1_, v2_); } - vector_node_ptr vec() + inline typename expression_node::node_type type() const { - return vec_node_ptr_; + return expression_node::e_trinary; } - inline typename expression_node::node_type type() const + private: + + sf3_var_node(sf3_var_node&); + sf3_var_node& operator=(sf3_var_node&); + + const T& v0_; + const T& v1_; + const T& v2_; + }; + + template + class sf4_var_node : public expression_node + { + public: + + typedef expression_node* expression_ptr; + + sf4_var_node(const T& v0, const T& v1, const T& v2, const T& v3) + : v0_(v0), + v1_(v1), + v2_(v2), + v3_(v3) + {} + + inline T value() const { - return expression_node::e_vecvalass; + return SpecialFunction::process(v0_, v1_, v2_, v3_); } - std::size_t size() const + inline typename expression_node::node_type type() const { - return vec_size_; + return expression_node::e_trinary; } private: - vector_node* vec_node_ptr_; - std::size_t vec_size_; + sf4_var_node(sf4_var_node&); + sf4_var_node& operator=(sf4_var_node&); + + const T& v0_; + const T& v1_; + const T& v2_; + const T& v3_; }; - template - class assignment_vecvec_node : public binary_node, - public vector_interface + template + class vararg_node : public expression_node { public: typedef expression_node* expression_ptr; - typedef vector_node* vector_node_ptr; + typedef std::pair branch_t; - assignment_vecvec_node(const operator_type& opr, - expression_ptr branch0, - expression_ptr branch1) - : binary_node(opr,branch0,branch1), - vec0_node_ptr_(0), - vec1_node_ptr_(0), - vec_size_ (0) + template class Sequence> + explicit vararg_node(const Sequence& arg_list) { - if (is_vector_node(binary_node::branch_[0].first)) - { - vec0_node_ptr_ = static_cast*>(binary_node::branch_[0].first); - } + arg_list_.resize(arg_list.size()); - if (is_vector_node(binary_node::branch_[1].first)) - { - vec1_node_ptr_ = static_cast*>(binary_node::branch_[1].first); - } - else if (is_ivector_node(binary_node::branch_[1].first)) + for (std::size_t i = 0; i < arg_list.size(); ++i) { - vector_interface* vi = reinterpret_cast*>(0); - - if ((vi = dynamic_cast*>(binary_node::branch_[1].first))) + if (arg_list[i]) { - vec1_node_ptr_ = vi->vec(); + construct_branch_pair(arg_list_[i],arg_list[i]); + } + else + { + arg_list_.clear(); + return; } - } - - if (vec0_node_ptr_ && vec1_node_ptr_) - { - vec_size_ = std::min(vec0_node_ptr_->ref().size(), - vec1_node_ptr_->ref().size()); } } inline T value() const { - binary_node::branch_[1].first->value(); + return VarArgFunction::process(arg_list_); + } - if (vec0_node_ptr_ && vec1_node_ptr_) - { - vector_holder& vec0 = vec0_node_ptr_->ref(); - vector_holder& vec1 = vec1_node_ptr_->ref(); + inline typename expression_node::node_type type() const + { + return expression_node::e_vararg; + } - for (std::size_t i = 0; i < vec_size_; ++i) + 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_; + }; + + template + class vararg_varnode : public expression_node + { + public: + + typedef expression_node* expression_ptr; + + template class Sequence> + explicit vararg_varnode(const Sequence& arg_list) + { + arg_list_.resize(arg_list.size()); + + for (std::size_t i = 0; i < arg_list.size(); ++i) + { + if (arg_list[i] && is_variable_node(arg_list[i])) { - (*vec0[i]) = (*vec1[i]); + variable_node* var_node_ptr = static_cast*>(arg_list[i]); + arg_list_[i] = (&var_node_ptr->ref()); + } + else + { + arg_list_.clear(); + return; } - - return vec0_node_ptr_->value(); } + } + + inline T value() const + { + if (!arg_list_.empty()) + return VarArgFunction::process(arg_list_); else return std::numeric_limits::quiet_NaN(); } - vector_node_ptr vec() const + inline typename expression_node::node_type type() const { - return vec0_node_ptr_; + return expression_node::e_vararg; } - vector_node_ptr vec() + private: + + std::vector arg_list_; + }; + + template + class vectorize_node : public expression_node + { + public: + + typedef expression_node* expression_ptr; + typedef std::pair branch_t; + + explicit vectorize_node(const expression_ptr v) + : ivec_ptr_(0) { - return vec0_node_ptr_; + construct_branch_pair(v_, v); + + if (is_ivector_node(v_.first)) + { + ivec_ptr_ = dynamic_cast*>(v_.first); + } + else + ivec_ptr_ = 0; + } + + inline T value() const + { + if (ivec_ptr_) + { + assert(v_.first); + + v_.first->value(); + + return VecFunction::process(ivec_ptr_); + } + else + return std::numeric_limits::quiet_NaN(); } inline typename expression_node::node_type type() const { - return expression_node::e_vecvecass; + return expression_node::e_vecfunc; } - std::size_t size() const + void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) { - return vec_size_; + 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_node* vec0_node_ptr_; - vector_node* vec1_node_ptr_; - std::size_t vec_size_; + vector_interface* ivec_ptr_; + branch_t v_; }; - template - class assignment_op_node : public binary_node + template + class assignment_node : public binary_node { public: typedef expression_node* expression_ptr; - assignment_op_node(const operator_type& opr, - expression_ptr branch0, - expression_ptr branch1) - : binary_node(opr,branch0,branch1), + assignment_node(const operator_type& opr, + expression_ptr branch0, + expression_ptr branch1) + : binary_node(opr, branch0, branch1), var_node_ptr_(0) { if (is_variable_node(binary_node::branch_[0].first)) @@ -7985,10 +10148,13 @@ namespace exprtk { if (var_node_ptr_) { - T& v = var_node_ptr_->ref(); - v = Operation::process(v,binary_node::branch_[1].first->value()); + assert(binary_node::branch_[1].first); - return v; + T& result = var_node_ptr_->ref(); + + result = binary_node::branch_[1].first->value(); + + return result; } else return std::numeric_limits::quiet_NaN(); @@ -7999,17 +10165,17 @@ namespace exprtk variable_node* var_node_ptr_; }; - template - class assignment_vec_elem_op_node : public binary_node + template + class assignment_vec_elem_node : public binary_node { public: typedef expression_node* expression_ptr; - assignment_vec_elem_op_node(const operator_type& opr, - expression_ptr branch0, - expression_ptr branch1) - : binary_node(opr,branch0,branch1), + assignment_vec_elem_node(const operator_type& opr, + expression_ptr branch0, + expression_ptr branch1) + : binary_node(opr, branch0, branch1), vec_node_ptr_(0) { if (is_vector_elem_node(binary_node::branch_[0].first)) @@ -8022,10 +10188,13 @@ namespace exprtk { if (vec_node_ptr_) { - T& v = vec_node_ptr_->ref(); - v = Operation::process(v,binary_node::branch_[1].first->value()); + assert(binary_node::branch_[1].first); - return v; + T& result = vec_node_ptr_->ref(); + + result = binary_node::branch_[1].first->value(); + + return result; } else return std::numeric_limits::quiet_NaN(); @@ -8036,135 +10205,164 @@ namespace exprtk vector_elem_node* vec_node_ptr_; }; - template - class assignment_vec_op_node : public binary_node, - public vector_interface + template + class assignment_rebasevec_elem_node : public binary_node { public: typedef expression_node* expression_ptr; - typedef vector_node* vector_node_ptr; - assignment_vec_op_node(const operator_type& opr, - expression_ptr branch0, - expression_ptr branch1) - : binary_node(opr,branch0,branch1), - vec_node_ptr_(0), - vec_size_ (0) + assignment_rebasevec_elem_node(const operator_type& opr, + expression_ptr branch0, + expression_ptr branch1) + : binary_node(opr, branch0, branch1), + rbvec_node_ptr_(0) { - if (is_vector_node(binary_node::branch_[0].first)) + if (is_rebasevector_elem_node(binary_node::branch_[0].first)) { - vec_node_ptr_ = static_cast*>(binary_node::branch_[0].first); - vec_size_ = vec_node_ptr_->ref().size(); + rbvec_node_ptr_ = static_cast*>(binary_node::branch_[0].first); } } inline T value() const { - if (vec_node_ptr_) + if (rbvec_node_ptr_) { - vector_holder& vec_hldr = vec_node_ptr_->ref(); - const T v = binary_node::branch_[1].first->value(); + assert(binary_node::branch_[1].first); - for (std::size_t i = 0; i < vec_size_; ++i) - { - T& vec_i = *vec_hldr[i]; - vec_i = Operation::process(vec_i,v); - } + T& result = rbvec_node_ptr_->ref(); - return vec_node_ptr_->value(); + result = binary_node::branch_[1].first->value(); + + return result; } else return std::numeric_limits::quiet_NaN(); } - vector_node_ptr vec() const - { - return vec_node_ptr_; - } + private: - vector_node_ptr vec() - { - return vec_node_ptr_; - } + rebasevector_elem_node* rbvec_node_ptr_; + }; - inline typename expression_node::node_type type() const + template + class assignment_rebasevec_celem_node : public binary_node + { + public: + + typedef expression_node* expression_ptr; + + assignment_rebasevec_celem_node(const operator_type& opr, + expression_ptr branch0, + expression_ptr branch1) + : binary_node(opr, branch0, branch1), + rbvec_node_ptr_(0) { - return expression_node::e_vecopvalass; + if (is_rebasevector_celem_node(binary_node::branch_[0].first)) + { + rbvec_node_ptr_ = static_cast*>(binary_node::branch_[0].first); + } } - std::size_t size() const + inline T value() const { - return vec_size_; + if (rbvec_node_ptr_) + { + assert(binary_node::branch_[1].first); + + T& result = rbvec_node_ptr_->ref(); + + result = binary_node::branch_[1].first->value(); + + return result; + } + else + return std::numeric_limits::quiet_NaN(); } private: - vector_node* vec_node_ptr_; - std::size_t vec_size_; + rebasevector_celem_node* rbvec_node_ptr_; }; - template - class assignment_vecvec_op_node : public binary_node, - public vector_interface + template + class assignment_vec_node : public binary_node , + public vector_interface { public: typedef expression_node* expression_ptr; - typedef vector_node* vector_node_ptr; + typedef vector_node* vector_node_ptr; + typedef vec_data_store vds_t; - assignment_vecvec_op_node(const operator_type& opr, - expression_ptr branch0, - expression_ptr branch1) - : binary_node(opr,branch0,branch1), - vec0_node_ptr_(0), - vec1_node_ptr_(0), - vec_size_ (0) + assignment_vec_node(const operator_type& opr, + expression_ptr branch0, + expression_ptr branch1) + : binary_node(opr, branch0, branch1), + vec_node_ptr_(0) { if (is_vector_node(binary_node::branch_[0].first)) { - vec0_node_ptr_ = static_cast*>(binary_node::branch_[0].first); - } - - if (is_vector_node(binary_node::branch_[1].first)) - { - vec1_node_ptr_ = static_cast*>(binary_node::branch_[1].first); - } - else if (is_ivector_node(binary_node::branch_[1].first)) - { - vector_interface* vi = reinterpret_cast*>(0); - - if ((vi = dynamic_cast*>(binary_node::branch_[1].first))) - { - vec1_node_ptr_ = vi->vec(); - } - } - - if (vec0_node_ptr_ && vec1_node_ptr_) - { - vec_size_ = std::min(vec0_node_ptr_->ref().size(), - vec1_node_ptr_->ref().size()); + vec_node_ptr_ = static_cast*>(binary_node::branch_[0].first); + vds() = vec_node_ptr_->vds(); } } inline T value() const { - if (vec0_node_ptr_ && vec1_node_ptr_) + if (vec_node_ptr_) { - binary_node::branch_[0].first->value(); - binary_node::branch_[1].first->value(); + assert(binary_node::branch_[1].first); - vector_holder& vec0 = vec0_node_ptr_->ref(); - vector_holder& vec1 = vec1_node_ptr_->ref(); + const T v = binary_node::branch_[1].first->value(); - for (std::size_t i = 0; i < vec_size_; ++i) + T* vec = vds().data(); + + loop_unroll::details lud(size()); + const T* upper_bound = vec + lud.upper_bound; + + while (vec < upper_bound) { - T& vec0_i = *vec0[i]; - T& vec1_i = *vec1[i]; - vec0_i = Operation::process(vec0_i,vec1_i); + #define exprtk_loop(N) \ + vec[N] = v; \ + + exprtk_loop( 0) exprtk_loop( 1) + exprtk_loop( 2) exprtk_loop( 3) + #ifndef exprtk_disable_superscalar_unroll + exprtk_loop( 4) exprtk_loop( 5) + exprtk_loop( 6) exprtk_loop( 7) + exprtk_loop( 8) exprtk_loop( 9) + exprtk_loop(10) exprtk_loop(11) + exprtk_loop(12) exprtk_loop(13) + exprtk_loop(14) exprtk_loop(15) + #endif + + vec += lud.batch_size; } - return vec0_node_ptr_->value(); + exprtk_disable_fallthrough_begin + switch (lud.remainder) + { + #define case_stmt(N) \ + case N : *vec++ = v; \ + + #ifndef exprtk_disable_superscalar_unroll + case_stmt(15) case_stmt(14) + case_stmt(13) case_stmt(12) + case_stmt(11) case_stmt(10) + case_stmt( 9) case_stmt( 8) + case_stmt( 7) case_stmt( 6) + case_stmt( 5) case_stmt( 4) + #endif + case_stmt( 3) case_stmt( 2) + case_stmt( 1) + } + exprtk_disable_fallthrough_end + + #undef exprtk_loop + #undef case_stmt + + return vec_node_ptr_->value(); } else return std::numeric_limits::quiet_NaN(); @@ -8172,103 +10370,151 @@ namespace exprtk vector_node_ptr vec() const { - return vec0_node_ptr_; + return vec_node_ptr_; } vector_node_ptr vec() { - return vec0_node_ptr_; + return vec_node_ptr_; } inline typename expression_node::node_type type() const { - return expression_node::e_vecopvecass; + return expression_node::e_vecvalass; } std::size_t size() const { - return vec_size_; + return vds().size(); + } + + vds_t& vds() + { + return vds_; + } + + const vds_t& vds() const + { + return vds_; } private: - vector_node* vec0_node_ptr_; - vector_node* vec1_node_ptr_; - std::size_t vec_size_; + vector_node* vec_node_ptr_; + vds_t vds_; }; - template - class eqineq_vecvec_node : public binary_node, - public vector_interface + template + class assignment_vecvec_node : public binary_node , + public vector_interface { public: typedef expression_node* expression_ptr; typedef vector_node* vector_node_ptr; + typedef vec_data_store vds_t; - eqineq_vecvec_node(const operator_type& opr, - expression_ptr branch0, - expression_ptr branch1) - : binary_node(opr,branch0,branch1), + assignment_vecvec_node(const operator_type& opr, + expression_ptr branch0, + expression_ptr branch1) + : binary_node(opr, branch0, branch1), vec0_node_ptr_(0), vec1_node_ptr_(0), - vec_size_ (0) + initialised_(false), + src_is_ivec_(false) { - if (is_vector_node(binary_node::branch_[0].first)) { vec0_node_ptr_ = static_cast*>(binary_node::branch_[0].first); - } - else if (is_ivector_node(binary_node::branch_[0].first)) - { - vector_interface* vi = reinterpret_cast*>(0); - - if ((vi = dynamic_cast*>(binary_node::branch_[0].first))) - { - vec0_node_ptr_ = vi->vec(); - } + vds() = vec0_node_ptr_->vds(); } if (is_vector_node(binary_node::branch_[1].first)) { vec1_node_ptr_ = static_cast*>(binary_node::branch_[1].first); + vds_t::match_sizes(vds(),vec1_node_ptr_->vds()); } else if (is_ivector_node(binary_node::branch_[1].first)) { vector_interface* vi = reinterpret_cast*>(0); - if ((vi = dynamic_cast*>(binary_node::branch_[1].first))) + if (0 != (vi = dynamic_cast*>(binary_node::branch_[1].first))) { vec1_node_ptr_ = vi->vec(); + + if (!vi->side_effect()) + { + vi->vds() = vds(); + src_is_ivec_ = true; + } + else + vds_t::match_sizes(vds(),vi->vds()); } } - if (vec0_node_ptr_ && vec1_node_ptr_) - { - vec_size_ = std::min(vec0_node_ptr_->ref().size(), - vec1_node_ptr_->ref().size()); - } + initialised_ = (vec0_node_ptr_ && vec1_node_ptr_); } inline T value() const { - if (vec0_node_ptr_ && vec1_node_ptr_) + if (initialised_) { - binary_node::branch_[0].first->value(); + assert(binary_node::branch_[1].first); + binary_node::branch_[1].first->value(); - vector_holder& vec0 = vec0_node_ptr_->ref(); - vector_holder& vec1 = vec1_node_ptr_->ref(); + if (src_is_ivec_) + return vec0_node_ptr_->value(); - for (std::size_t i = 0; i < vec_size_; ++i) + T* vec0 = vec0_node_ptr_->vds().data(); + T* vec1 = vec1_node_ptr_->vds().data(); + + loop_unroll::details lud(size()); + const T* upper_bound = vec0 + lud.upper_bound; + + while (vec0 < upper_bound) { - if (std::equal_to()(T(0),Operation::process(*vec0[i],*vec1[i]))) - { - return T(0); - } + #define exprtk_loop(N) \ + vec0[N] = vec1[N]; \ + + exprtk_loop( 0) exprtk_loop( 1) + exprtk_loop( 2) exprtk_loop( 3) + #ifndef exprtk_disable_superscalar_unroll + exprtk_loop( 4) exprtk_loop( 5) + exprtk_loop( 6) exprtk_loop( 7) + exprtk_loop( 8) exprtk_loop( 9) + exprtk_loop(10) exprtk_loop(11) + exprtk_loop(12) exprtk_loop(13) + exprtk_loop(14) exprtk_loop(15) + #endif + + vec0 += lud.batch_size; + vec1 += lud.batch_size; } - return T(1); + exprtk_disable_fallthrough_begin + switch (lud.remainder) + { + #define case_stmt(N) \ + case N : *vec0++ = *vec1++; \ + + #ifndef exprtk_disable_superscalar_unroll + case_stmt(15) case_stmt(14) + case_stmt(13) case_stmt(12) + case_stmt(11) case_stmt(10) + case_stmt( 9) case_stmt( 8) + case_stmt( 7) case_stmt( 6) + case_stmt( 5) case_stmt( 4) + #endif + case_stmt( 3) case_stmt( 2) + case_stmt( 1) + } + exprtk_disable_fallthrough_end + + #undef exprtk_loop + #undef case_stmt + + return vec0_node_ptr_->value(); } else return std::numeric_limits::quiet_NaN(); @@ -8286,160 +10532,268 @@ namespace exprtk inline typename expression_node::node_type type() const { - return expression_node::e_vecvecineq; + return expression_node::e_vecvecass; } std::size_t size() const { - return vec_size_; + return vds().size(); + } + + vds_t& vds() + { + return vds_; + } + + const vds_t& vds() const + { + return vds_; } private: vector_node* vec0_node_ptr_; vector_node* vec1_node_ptr_; - std::size_t vec_size_; + bool initialised_; + bool src_is_ivec_; + vds_t vds_; }; template - class eqineq_vecval_node : public binary_node, - public vector_interface + class assignment_op_node : public binary_node { public: - typedef expression_node* expression_ptr; - typedef vector_node* vector_node_ptr; + typedef expression_node* expression_ptr; - eqineq_vecval_node(const operator_type& opr, + assignment_op_node(const operator_type& opr, expression_ptr branch0, expression_ptr branch1) - : binary_node(opr,branch0,branch1), - vec_node_ptr_(0), - vec_size_ (0) + : binary_node(opr, branch0, branch1), + var_node_ptr_(0) { - if (is_vector_node(binary_node::branch_[0].first)) - { - vec_node_ptr_ = static_cast(binary_node::branch_[0].first); - } - else if (is_ivector_node(binary_node::branch_[0].first)) - { - vector_interface* vi = reinterpret_cast*>(0); - - if ((vi = dynamic_cast*>(binary_node::branch_[0].first))) - { - vec_node_ptr_ = vi->vec(); - } - } - - if (vec_node_ptr_) + if (is_variable_node(binary_node::branch_[0].first)) { - vec_size_ = vec_node_ptr_->ref().size(); + var_node_ptr_ = static_cast*>(binary_node::branch_[0].first); } } inline T value() const { - if (vec_node_ptr_) + if (var_node_ptr_) { - binary_node::branch_[0].first->value(); - T v = binary_node::branch_[1].first->value(); + assert(binary_node::branch_[1].first); - vector_holder& vec_hldr = vec_node_ptr_->ref(); - - for (std::size_t i = 0; i < vec_size_; ++i) - { - if (std::equal_to()(T(0),Operation::process(*vec_hldr[i],v))) - { - return T(0); - } - } + T& v = var_node_ptr_->ref(); + v = Operation::process(v,binary_node::branch_[1].first->value()); - return T(1); + return v; } else return std::numeric_limits::quiet_NaN(); } - vector_node_ptr vec() const - { - return vec_node_ptr_; - } + private: - vector_node_ptr vec() - { - return vec_node_ptr_; - } + variable_node* var_node_ptr_; + }; - inline typename expression_node::node_type type() const + template + class assignment_vec_elem_op_node : public binary_node + { + public: + + typedef expression_node* expression_ptr; + + assignment_vec_elem_op_node(const operator_type& opr, + expression_ptr branch0, + expression_ptr branch1) + : binary_node(opr, branch0, branch1), + vec_node_ptr_(0) { - return expression_node::e_vecvalineq; + if (is_vector_elem_node(binary_node::branch_[0].first)) + { + vec_node_ptr_ = static_cast*>(binary_node::branch_[0].first); + } } - std::size_t size() const + inline T value() const { - return vec_size_; + 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()); + + return v; + } + else + return std::numeric_limits::quiet_NaN(); } private: - vector_node* vec_node_ptr_; - std::size_t vec_size_; + vector_elem_node* vec_node_ptr_; }; template - class eqineq_valvec_node : public binary_node, - public vector_interface + class assignment_rebasevec_elem_op_node : public binary_node { public: - typedef expression_node* expression_ptr; - typedef vector_node* vector_node_ptr; + typedef expression_node* expression_ptr; - eqineq_valvec_node(const operator_type& opr, - expression_ptr branch0, - expression_ptr branch1) - : binary_node(opr,branch0,branch1), - vec_node_ptr_(0), - vec_size_ (0) + assignment_rebasevec_elem_op_node(const operator_type& opr, + expression_ptr branch0, + expression_ptr branch1) + : binary_node(opr, branch0, branch1), + rbvec_node_ptr_(0) { - if (is_vector_node(binary_node::branch_[1].first)) - { - vec_node_ptr_ = static_cast(binary_node::branch_[1].first); - } - else if (is_ivector_node(binary_node::branch_[1].first)) - { - vector_interface* vi = reinterpret_cast*>(0); - - if ((vi = dynamic_cast*>(binary_node::branch_[1].first))) - { - vec_node_ptr_ = vi->vec(); - } - } - - if (vec_node_ptr_) + if (is_rebasevector_elem_node(binary_node::branch_[0].first)) { - vec_size_ = vec_node_ptr_->ref().size(); + rbvec_node_ptr_ = static_cast*>(binary_node::branch_[0].first); } } inline T value() const { - if (vec_node_ptr_) + if (rbvec_node_ptr_) { - T v = binary_node::branch_[0].first->value(); - binary_node::branch_[1].first->value(); + assert(binary_node::branch_[1].first); - vector_holder& vec_hldr = vec_node_ptr_->ref(); - - for (std::size_t i = 0; i < vec_size_; ++i) - { - if (std::equal_to()(T(0),Operation::process(v,*vec_hldr[i]))) - { - return T(0); - } - } + T& v = rbvec_node_ptr_->ref(); + v = Operation::process(v,binary_node::branch_[1].first->value()); - return T(1); + return v; + } + else + return std::numeric_limits::quiet_NaN(); + } + + private: + + rebasevector_elem_node* rbvec_node_ptr_; + }; + + template + class assignment_rebasevec_celem_op_node : public binary_node + { + public: + + typedef expression_node* expression_ptr; + + assignment_rebasevec_celem_op_node(const operator_type& opr, + expression_ptr branch0, + expression_ptr branch1) + : binary_node(opr, branch0, branch1), + rbvec_node_ptr_(0) + { + if (is_rebasevector_celem_node(binary_node::branch_[0].first)) + { + rbvec_node_ptr_ = static_cast*>(binary_node::branch_[0].first); + } + } + + inline T value() const + { + 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()); + + return v; + } + else + return std::numeric_limits::quiet_NaN(); + } + + private: + + rebasevector_celem_node* rbvec_node_ptr_; + }; + + template + class assignment_vec_op_node : public binary_node , + public vector_interface + { + public: + + typedef expression_node* expression_ptr; + typedef vector_node* vector_node_ptr; + typedef vec_data_store vds_t; + + assignment_vec_op_node(const operator_type& opr, + expression_ptr branch0, + expression_ptr branch1) + : binary_node(opr, branch0, branch1), + vec_node_ptr_(0) + { + if (is_vector_node(binary_node::branch_[0].first)) + { + vec_node_ptr_ = static_cast*>(binary_node::branch_[0].first); + vds() = vec_node_ptr_->vds(); + } + } + + inline T value() const + { + if (vec_node_ptr_) + { + assert(binary_node::branch_[1].first); + + const T v = binary_node::branch_[1].first->value(); + + T* vec = vds().data(); + + loop_unroll::details lud(size()); + const T* upper_bound = vec + lud.upper_bound; + + while (vec < upper_bound) + { + #define exprtk_loop(N) \ + Operation::assign(vec[N],v); \ + + exprtk_loop( 0) exprtk_loop( 1) + exprtk_loop( 2) exprtk_loop( 3) + #ifndef exprtk_disable_superscalar_unroll + exprtk_loop( 4) exprtk_loop( 5) + exprtk_loop( 6) exprtk_loop( 7) + exprtk_loop( 8) exprtk_loop( 9) + exprtk_loop(10) exprtk_loop(11) + exprtk_loop(12) exprtk_loop(13) + exprtk_loop(14) exprtk_loop(15) + #endif + + vec += lud.batch_size; + } + + exprtk_disable_fallthrough_begin + switch (lud.remainder) + { + #define case_stmt(N) \ + case N : Operation::assign(*vec++,v); \ + + #ifndef exprtk_disable_superscalar_unroll + case_stmt(15) case_stmt(14) + case_stmt(13) case_stmt(12) + case_stmt(11) case_stmt(10) + case_stmt( 9) case_stmt( 8) + case_stmt( 7) case_stmt( 6) + case_stmt( 5) case_stmt( 4) + #endif + case_stmt( 3) case_stmt( 2) + case_stmt( 1) + } + exprtk_disable_fallthrough_end + + + #undef exprtk_loop + #undef case_stmt + + return vec_node_ptr_->value(); } else return std::numeric_limits::quiet_NaN(); @@ -8457,41 +10811,213 @@ namespace exprtk inline typename expression_node::node_type type() const { - return expression_node::e_valvecineq; + return expression_node::e_vecopvalass; } std::size_t size() const { - return vec_size_; + return vds().size(); + } + + vds_t& vds() + { + return vds_; + } + + const vds_t& vds() const + { + return vds_; + } + + bool side_effect() const + { + return true; } private: vector_node* vec_node_ptr_; - std::size_t vec_size_; + vds_t vds_; + }; + + template + class assignment_vecvec_op_node : public binary_node , + public vector_interface + { + public: + + typedef expression_node* expression_ptr; + typedef vector_node* vector_node_ptr; + typedef vec_data_store vds_t; + + assignment_vecvec_op_node(const operator_type& opr, + expression_ptr branch0, + expression_ptr branch1) + : binary_node(opr, branch0, branch1), + vec0_node_ptr_(0), + vec1_node_ptr_(0), + initialised_(false) + { + if (is_vector_node(binary_node::branch_[0].first)) + { + vec0_node_ptr_ = static_cast*>(binary_node::branch_[0].first); + vds() = vec0_node_ptr_->vds(); + } + + if (is_vector_node(binary_node::branch_[1].first)) + { + vec1_node_ptr_ = static_cast*>(binary_node::branch_[1].first); + vec1_node_ptr_->vds() = vds(); + } + else if (is_ivector_node(binary_node::branch_[1].first)) + { + vector_interface* vi = reinterpret_cast*>(0); + + if (0 != (vi = dynamic_cast*>(binary_node::branch_[1].first))) + { + vec1_node_ptr_ = vi->vec(); + vec1_node_ptr_->vds() = vds(); + } + else + vds_t::match_sizes(vds(),vec1_node_ptr_->vds()); + } + + initialised_ = (vec0_node_ptr_ && vec1_node_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(); + + 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]); \ + + exprtk_loop( 0) exprtk_loop( 1) + exprtk_loop( 2) exprtk_loop( 3) + #ifndef exprtk_disable_superscalar_unroll + exprtk_loop( 4) exprtk_loop( 5) + exprtk_loop( 6) exprtk_loop( 7) + exprtk_loop( 8) exprtk_loop( 9) + exprtk_loop(10) exprtk_loop(11) + exprtk_loop(12) exprtk_loop(13) + exprtk_loop(14) exprtk_loop(15) + #endif + + vec0 += lud.batch_size; + vec1 += lud.batch_size; + } + + int i = 0; + + exprtk_disable_fallthrough_begin + switch (lud.remainder) + { + #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) + case_stmt(13) case_stmt(12) + case_stmt(11) case_stmt(10) + case_stmt( 9) case_stmt( 8) + case_stmt( 7) case_stmt( 6) + case_stmt( 5) case_stmt( 4) + #endif + case_stmt( 3) case_stmt( 2) + case_stmt( 1) + } + exprtk_disable_fallthrough_end + + #undef exprtk_loop + #undef case_stmt + + return vec0_node_ptr_->value(); + } + else + return std::numeric_limits::quiet_NaN(); + } + + vector_node_ptr vec() const + { + return vec0_node_ptr_; + } + + vector_node_ptr vec() + { + return vec0_node_ptr_; + } + + inline typename expression_node::node_type type() const + { + return expression_node::e_vecopvecass; + } + + std::size_t size() const + { + return vds().size(); + } + + vds_t& vds() + { + return vds_; + } + + const vds_t& vds() const + { + return vds_; + } + + bool side_effect() const + { + return true; + } + + private: + + vector_node* vec0_node_ptr_; + vector_node* vec1_node_ptr_; + bool initialised_; + vds_t vds_; }; template - class vecarith_vecvec_node : public binary_node, - public vector_interface + class vec_binop_vecvec_node : public binary_node , + public vector_interface { public: typedef expression_node* expression_ptr; typedef vector_node* vector_node_ptr; typedef vector_holder* vector_holder_ptr; + typedef vec_data_store vds_t; - vecarith_vecvec_node(const operator_type& opr, - expression_ptr branch0, - expression_ptr branch1) - : binary_node(opr,branch0,branch1), + vec_binop_vecvec_node(const operator_type& opr, + expression_ptr branch0, + expression_ptr branch1) + : binary_node(opr, branch0, branch1), vec0_node_ptr_(0), vec1_node_ptr_(0), - vec_size_ (0), - data_ (0), temp_ (0), - temp_vec_node_(0) + temp_vec_node_(0), + initialised_(false) { + bool v0_is_ivec = false; + bool v1_is_ivec = false; + if (is_vector_node(binary_node::branch_[0].first)) { vec0_node_ptr_ = static_cast(binary_node::branch_[0].first); @@ -8500,9 +11026,10 @@ namespace exprtk { vector_interface* vi = reinterpret_cast*>(0); - if ((vi = dynamic_cast*>(binary_node::branch_[0].first))) + if (0 != (vi = dynamic_cast*>(binary_node::branch_[0].first))) { vec0_node_ptr_ = vi->vec(); + v0_is_ivec = true; } } @@ -8514,53 +11041,101 @@ namespace exprtk { vector_interface* vi = reinterpret_cast*>(0); - if ((vi = dynamic_cast*>(binary_node::branch_[1].first))) + if (0 != (vi = dynamic_cast*>(binary_node::branch_[1].first))) { vec1_node_ptr_ = vi->vec(); + v1_is_ivec = true; } } if (vec0_node_ptr_ && vec1_node_ptr_) { - vector_holder& vec0 = vec0_node_ptr_->ref(); - vector_holder& vec1 = vec1_node_ptr_->ref(); + vector_holder& vec0 = vec0_node_ptr_->vec_holder(); + vector_holder& vec1 = vec1_node_ptr_->vec_holder(); + + if (v0_is_ivec && (vec0.size() <= vec1.size())) + vds_ = vds_t(vec0_node_ptr_->vds()); + else if (v1_is_ivec && (vec1.size() <= vec0.size())) + vds_ = vds_t(vec1_node_ptr_->vds()); + else + vds_ = vds_t(std::min(vec0.size(),vec1.size())); + + temp_ = new vector_holder(vds().data(),vds().size()); + temp_vec_node_ = new vector_node (vds(),temp_); - vec_size_ = std::min(vec0.size(),vec1.size()); - data_ = new T[vec_size_]; - temp_ = new vector_holder(data_,vec_size_); - temp_vec_node_ = new vector_node (temp_); + initialised_ = true; } } - ~vecarith_vecvec_node() + ~vec_binop_vecvec_node() { - delete[] data_; - delete temp_; - delete temp_vec_node_; + delete temp_; + delete temp_vec_node_; } inline T value() const { - if (vec0_node_ptr_ && vec1_node_ptr_) + 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(); - vector_holder& vec0 = vec0_node_ptr_->ref(); - vector_holder& vec1 = vec1_node_ptr_->ref(); - vector_holder& vec2 = *temp_; + const T* vec0 = vec0_node_ptr_->vds().data(); + const T* vec1 = vec1_node_ptr_->vds().data(); + T* vec2 = vds().data(); - for (std::size_t i = 0; i < vec_size_; ++i) + 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]); \ + + exprtk_loop( 0) exprtk_loop( 1) + exprtk_loop( 2) exprtk_loop( 3) + #ifndef exprtk_disable_superscalar_unroll + exprtk_loop( 4) exprtk_loop( 5) + exprtk_loop( 6) exprtk_loop( 7) + exprtk_loop( 8) exprtk_loop( 9) + exprtk_loop(10) exprtk_loop(11) + exprtk_loop(12) exprtk_loop(13) + exprtk_loop(14) exprtk_loop(15) + #endif + + vec0 += lud.batch_size; + vec1 += lud.batch_size; + vec2 += lud.batch_size; + } + + int i = 0; - T& vec0_i = *vec0[i]; - T& vec1_i = *vec1[i]; - T& vec2_i = *vec2[i]; + exprtk_disable_fallthrough_begin + switch (lud.remainder) + { + #define case_stmt(N) \ + case N : { vec2[i] = Operation::process(vec0[i], vec1[i]); ++i; } \ - vec2_i = Operation::process(vec0_i,vec1_i); + #ifndef exprtk_disable_superscalar_unroll + case_stmt(15) case_stmt(14) + case_stmt(13) case_stmt(12) + case_stmt(11) case_stmt(10) + case_stmt( 9) case_stmt( 8) + case_stmt( 7) case_stmt( 6) + case_stmt( 5) case_stmt( 4) + #endif + case_stmt( 3) case_stmt( 2) + case_stmt( 1) } + exprtk_disable_fallthrough_end + + #undef exprtk_loop + #undef case_stmt - return *vec2[0]; + return (vds().data())[0]; } else return std::numeric_limits::quiet_NaN(); @@ -8583,39 +11158,50 @@ namespace exprtk std::size_t size() const { - return vec_size_; + return vds_.size(); + } + + vds_t& vds() + { + return vds_; + } + + const vds_t& vds() const + { + return vds_; } private: vector_node_ptr vec0_node_ptr_; vector_node_ptr vec1_node_ptr_; - std::size_t vec_size_; - T* data_; vector_holder_ptr temp_; vector_node_ptr temp_vec_node_; + bool initialised_; + vds_t vds_; }; template - class vecarith_vecval_node : public binary_node, - public vector_interface + class vec_binop_vecval_node : public binary_node , + public vector_interface { public: typedef expression_node* expression_ptr; typedef vector_node* vector_node_ptr; typedef vector_holder* vector_holder_ptr; + typedef vec_data_store vds_t; - vecarith_vecval_node(const operator_type& opr, - expression_ptr branch0, - expression_ptr branch1) - : binary_node(opr,branch0,branch1), + vec_binop_vecval_node(const operator_type& opr, + expression_ptr branch0, + expression_ptr branch1) + : binary_node(opr, branch0, branch1), vec0_node_ptr_(0), - vec_size_ (0), - data_ (0), temp_ (0), temp_vec_node_(0) { + bool v0_is_ivec = false; + if (is_vector_node(binary_node::branch_[0].first)) { vec0_node_ptr_ = static_cast(binary_node::branch_[0].first); @@ -8624,49 +11210,92 @@ namespace exprtk { vector_interface* vi = reinterpret_cast*>(0); - if ((vi = dynamic_cast*>(binary_node::branch_[0].first))) + if (0 != (vi = dynamic_cast*>(binary_node::branch_[0].first))) { vec0_node_ptr_ = vi->vec(); + v0_is_ivec = true; } } if (vec0_node_ptr_) { - vector_holder& vec0 = vec0_node_ptr_->ref(); + if (v0_is_ivec) + vds() = vec0_node_ptr_->vds(); + else + vds() = vds_t(vec0_node_ptr_->size()); - vec_size_ = vec0.size(); - data_ = new T[vec_size_]; - temp_ = new vector_holder(data_,vec_size_); - temp_vec_node_ = new vector_node (temp_); + temp_ = new vector_holder(vds()); + temp_vec_node_ = new vector_node (vds(),temp_); } } - ~vecarith_vecval_node() + ~vec_binop_vecval_node() { - delete[] data_; - delete temp_; - delete temp_vec_node_; + delete temp_; + delete temp_vec_node_; } inline T value() const { 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(); - vector_holder& vec0 = vec0_node_ptr_->ref(); - vector_holder& vec1 = *temp_; + const T* vec0 = vec0_node_ptr_->vds().data(); + T* vec1 = vds().data(); - for (std::size_t i = 0; i < vec_size_; ++i) + 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); \ + + exprtk_loop( 0) exprtk_loop( 1) + exprtk_loop( 2) exprtk_loop( 3) + #ifndef exprtk_disable_superscalar_unroll + exprtk_loop( 4) exprtk_loop( 5) + exprtk_loop( 6) exprtk_loop( 7) + exprtk_loop( 8) exprtk_loop( 9) + exprtk_loop(10) exprtk_loop(11) + exprtk_loop(12) exprtk_loop(13) + exprtk_loop(14) exprtk_loop(15) + #endif + + vec0 += lud.batch_size; + vec1 += lud.batch_size; + } + + int i = 0; + + exprtk_disable_fallthrough_begin + switch (lud.remainder) { - T& vec0_i = *vec0[i]; - T& vec1_i = *vec1[i]; + #define case_stmt(N) \ + case N : { vec1[i] = Operation::process(vec0[i], v); ++i; } \ - vec1_i = Operation::process(vec0_i,v); + #ifndef exprtk_disable_superscalar_unroll + case_stmt(15) case_stmt(14) + case_stmt(13) case_stmt(12) + case_stmt(11) case_stmt(10) + case_stmt( 9) case_stmt( 8) + case_stmt( 7) case_stmt( 6) + case_stmt( 5) case_stmt( 4) + #endif + case_stmt( 3) case_stmt( 2) + case_stmt( 1) } + exprtk_disable_fallthrough_end + + #undef exprtk_loop + #undef case_stmt - return *vec1[0]; + return (vds().data())[0]; } else return std::numeric_limits::quiet_NaN(); @@ -8689,38 +11318,48 @@ namespace exprtk std::size_t size() const { - return vec_size_; + return vds().size(); + } + + vds_t& vds() + { + return vds_; + } + + const vds_t& vds() const + { + return vds_; } private: vector_node_ptr vec0_node_ptr_; - std::size_t vec_size_; - T* data_; vector_holder_ptr temp_; vector_node_ptr temp_vec_node_; + vds_t vds_; }; template - class vecarith_valvec_node : public binary_node, - public vector_interface + class vec_binop_valvec_node : public binary_node , + public vector_interface { public: typedef expression_node* expression_ptr; typedef vector_node* vector_node_ptr; typedef vector_holder* vector_holder_ptr; + typedef vec_data_store vds_t; - vecarith_valvec_node(const operator_type& opr, - expression_ptr branch0, - expression_ptr branch1) - : binary_node(opr,branch0,branch1), + vec_binop_valvec_node(const operator_type& opr, + expression_ptr branch0, + expression_ptr branch1) + : binary_node(opr, branch0, branch1), vec1_node_ptr_(0), - vec_size_ (0), - data_ (0), temp_ (0), temp_vec_node_(0) { + bool v1_is_ivec = false; + if (is_vector_node(binary_node::branch_[1].first)) { vec1_node_ptr_ = static_cast(binary_node::branch_[1].first); @@ -8729,53 +11368,96 @@ namespace exprtk { vector_interface* vi = reinterpret_cast*>(0); - if ((vi = dynamic_cast*>(binary_node::branch_[1].first))) + if (0 != (vi = dynamic_cast*>(binary_node::branch_[1].first))) { vec1_node_ptr_ = vi->vec(); + v1_is_ivec = true; } } if (vec1_node_ptr_) { - vector_holder& vec0 = vec1_node_ptr_->ref(); + if (v1_is_ivec) + vds() = vec1_node_ptr_->vds(); + else + vds() = vds_t(vec1_node_ptr_->size()); - vec_size_ = vec0.size(); - data_ = new T[vec_size_]; - temp_ = new vector_holder(data_,vec_size_); - temp_vec_node_ = new vector_node (temp_); + temp_ = new vector_holder(vds()); + temp_vec_node_ = new vector_node (vds(),temp_); } } - ~vecarith_valvec_node() + ~vec_binop_valvec_node() { - delete[] data_; - delete temp_; - delete temp_vec_node_; + delete temp_; + delete temp_vec_node_; } inline T value() const { 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(); - vector_holder& vec1 = vec1_node_ptr_->ref(); - vector_holder& vec2 = *temp_; + T* vec0 = vds().data(); + const T* vec1 = vec1_node_ptr_->vds().data(); - for (std::size_t i = 0; i < vec_size_; ++i) + loop_unroll::details lud(size()); + const T* upper_bound = vec0 + lud.upper_bound; + + while (vec0 < upper_bound) { - T& vec1_i = *vec1[i]; - T& vec2_i = *vec2[i]; + #define exprtk_loop(N) \ + vec0[N] = Operation::process(v, vec1[N]); \ + + exprtk_loop( 0) exprtk_loop( 1) + exprtk_loop( 2) exprtk_loop( 3) + #ifndef exprtk_disable_superscalar_unroll + exprtk_loop( 4) exprtk_loop( 5) + exprtk_loop( 6) exprtk_loop( 7) + exprtk_loop( 8) exprtk_loop( 9) + exprtk_loop(10) exprtk_loop(11) + exprtk_loop(12) exprtk_loop(13) + exprtk_loop(14) exprtk_loop(15) + #endif - vec2_i = Operation::process(v,vec1_i); + vec0 += lud.batch_size; + vec1 += lud.batch_size; } - return *vec2[0]; - } - else - return std::numeric_limits::quiet_NaN(); - } + int i = 0; + + exprtk_disable_fallthrough_begin + switch (lud.remainder) + { + #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) + case_stmt(13) case_stmt(12) + case_stmt(11) case_stmt(10) + case_stmt( 9) case_stmt( 8) + case_stmt( 7) case_stmt( 6) + case_stmt( 5) case_stmt( 4) + #endif + case_stmt( 3) case_stmt( 2) + case_stmt( 1) + } + exprtk_disable_fallthrough_end + + #undef exprtk_loop + #undef case_stmt + + return (vds().data())[0]; + } + else + return std::numeric_limits::quiet_NaN(); + } vector_node_ptr vec() const { @@ -8794,20 +11476,29 @@ namespace exprtk std::size_t size() const { - return vec_size_; + return vds().size(); + } + + vds_t& vds() + { + return vds_; + } + + const vds_t& vds() const + { + return vds_; } private: vector_node_ptr vec1_node_ptr_; - std::size_t vec_size_; - T* data_; vector_holder_ptr temp_; vector_node_ptr temp_vec_node_; + vds_t vds_; }; template - class unary_vector_node : public unary_node, + class unary_vector_node : public unary_node , public vector_interface { public: @@ -8815,65 +11506,108 @@ namespace exprtk typedef expression_node* expression_ptr; typedef vector_node* vector_node_ptr; typedef vector_holder* vector_holder_ptr; + typedef vec_data_store vds_t; unary_vector_node(const operator_type& opr, expression_ptr branch0) - : unary_node(opr,branch0), + : unary_node(opr, branch0), vec0_node_ptr_(0), - vec_size_ (0), - data_ (0), temp_ (0), temp_vec_node_(0) { - if (is_vector_node(unary_node::branch_)) + bool vec0_is_ivec = false; + + 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 ((vi = dynamic_cast*>(unary_node::branch_))) + if (0 != (vi = dynamic_cast*>(unary_node::branch_.first))) { vec0_node_ptr_ = vi->vec(); + vec0_is_ivec = true; } } if (vec0_node_ptr_) { - vector_holder& vec0 = vec0_node_ptr_->ref(); + if (vec0_is_ivec) + vds_ = vec0_node_ptr_->vds(); + else + vds_ = vds_t(vec0_node_ptr_->size()); - vec_size_ = vec0.size(); - data_ = new T[vec_size_]; - temp_ = new vector_holder(data_,vec_size_); - temp_vec_node_ = new vector_node (temp_); + temp_ = new vector_holder(vds()); + temp_vec_node_ = new vector_node (vds(),temp_); } } ~unary_vector_node() { - delete[] data_; - delete temp_; - delete temp_vec_node_; + delete temp_; + delete temp_vec_node_; } inline T value() const { - unary_node::branch_->value(); + assert(unary_node::branch_.first); + + unary_node::branch_.first->value(); if (vec0_node_ptr_) { - vector_holder& vec0 = vec0_node_ptr_->ref(); - vector_holder& vec1 = *temp_; + const T* vec0 = vec0_node_ptr_->vds().data(); + T* vec1 = vds().data(); - for (std::size_t i = 0; i < vec_size_; ++i) + 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]); \ + + exprtk_loop( 0) exprtk_loop( 1) + exprtk_loop( 2) exprtk_loop( 3) + #ifndef exprtk_disable_superscalar_unroll + exprtk_loop( 4) exprtk_loop( 5) + exprtk_loop( 6) exprtk_loop( 7) + exprtk_loop( 8) exprtk_loop( 9) + exprtk_loop(10) exprtk_loop(11) + exprtk_loop(12) exprtk_loop(13) + exprtk_loop(14) exprtk_loop(15) + #endif + + vec0 += lud.batch_size; + vec1 += lud.batch_size; + } + + int i = 0; + + exprtk_disable_fallthrough_begin + switch (lud.remainder) { - T& vec0_i = *vec0[i]; - T& vec1_i = *vec1[i]; + #define case_stmt(N) \ + case N : { vec1[i] = Operation::process(vec0[i]); ++i; } \ - vec1_i = Operation::process(vec0_i); + #ifndef exprtk_disable_superscalar_unroll + case_stmt(15) case_stmt(14) + case_stmt(13) case_stmt(12) + case_stmt(11) case_stmt(10) + case_stmt( 9) case_stmt( 8) + case_stmt( 7) case_stmt( 6) + case_stmt( 5) case_stmt( 4) + #endif + case_stmt( 3) case_stmt( 2) + case_stmt( 1) } + exprtk_disable_fallthrough_end + + #undef exprtk_loop + #undef case_stmt - return *vec1[0]; + return (vds().data())[0]; } else return std::numeric_limits::quiet_NaN(); @@ -8896,16 +11630,25 @@ namespace exprtk std::size_t size() const { - return vec_size_; + return vds().size(); + } + + vds_t& vds() + { + return vds_; + } + + const vds_t& vds() const + { + return vds_; } private: vector_node_ptr vec0_node_ptr_; - std::size_t vec_size_; - T* data_; vector_holder_ptr temp_; vector_node_ptr temp_vec_node_; + vds_t vds_; }; template @@ -8918,11 +11661,14 @@ namespace exprtk scand_node(const operator_type& opr, expression_ptr branch0, expression_ptr branch1) - : binary_node(opr,branch0,branch1) + : binary_node(opr, branch0, branch1) {} 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()) && @@ -8942,11 +11688,14 @@ namespace exprtk scor_node(const operator_type& opr, expression_ptr branch0, expression_ptr branch1) - : binary_node(opr,branch0,branch1) + : binary_node(opr, branch0, branch1) {} 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()) || @@ -8966,16 +11715,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]) { @@ -9242,11 +11986,21 @@ 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_; + ifunction* function_; std::size_t parameter_count_; - branch_t branch_[N]; + branch_t branch_[N]; }; template @@ -9257,7 +12011,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)) {} @@ -9299,18 +12053,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])) - { - delete arg_list_[i]; - arg_list_[i] = 0; - } - } - } - inline bool operator <(const vararg_function_node& fn) const { return this < (&fn); @@ -9332,6 +12074,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 @@ -9352,32 +12110,38 @@ namespace exprtk { public: - typedef type_store type_store_t; - typedef expression_node* expression_ptr; - typedef variable_node variable_node_t; - typedef vector_elem_node vector_elem_node_t; - typedef vector_node vector_node_t; - typedef variable_node_t* variable_node_ptr_t; - typedef vector_elem_node_t* vector_elem_node_ptr_t; - typedef vector_node_t* vector_node_ptr_t; - typedef range_interface range_interface_t; - typedef range_data_type range_data_type_t; - typedef range_pack range_t; - typedef std::pair branch_t; - typedef std::pair void_t; - typedef std::vector tmp_vs_t; - typedef std::vector typestore_list_t; - typedef std::vector range_list_t; - - generic_function_node(GenericFunction* func, - const std::vector& arg_list) + typedef type_store type_store_t; + typedef expression_node* expression_ptr; + typedef variable_node variable_node_t; + typedef vector_node vector_node_t; + typedef variable_node_t* variable_node_ptr_t; + typedef vector_node_t* vector_node_ptr_t; + typedef range_interface range_interface_t; + typedef range_data_type range_data_type_t; + typedef range_pack range_t; + typedef std::pair branch_t; + typedef std::pair void_t; + typedef std::vector tmp_vs_t; + typedef std::vector typestore_list_t; + typedef std::vector range_list_t; + + explicit generic_function_node(const std::vector& arg_list, + GenericFunction* func = reinterpret_cast(0)) : function_(func), arg_list_(arg_list) {} - ~generic_function_node() + 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() @@ -9385,7 +12149,7 @@ namespace exprtk expr_as_vec1_store_.resize(arg_list_.size(),T(0) ); typestore_list_ .resize(arg_list_.size(),type_store_t() ); range_list_ .resize(arg_list_.size(),range_data_type_t()); - branch_ .resize(arg_list_.size(),branch_t((expression_ptr)0,false)); + branch_ .resize(arg_list_.size(),branch_t(reinterpret_cast(0),false)); for (std::size_t i = 0; i < arg_list_.size(); ++i) { @@ -9401,9 +12165,11 @@ namespace exprtk return false; ts.size = vi->size(); - ts.data = vi->vec()->ref()[0]; + 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])) { string_base_node* sbn = reinterpret_cast*>(0); @@ -9412,7 +12178,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; @@ -9420,28 +12186,26 @@ namespace exprtk range_list_[i].type_size = sizeof(char); range_list_[i].str_node = sbn; - if (is_generally_string_node(arg_list_[i])) - { - range_interface_t* ri = reinterpret_cast(0); + range_interface_t* ri = reinterpret_cast(0); - if (0 == (ri = dynamic_cast(arg_list_[i]))) - return false; + 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() && - is_const_string_range_node(arg_list_[i]) - ) - { - ts.size = rp.const_size(); - ts.data = static_cast(ts.data) + rp.n0_c.second; - range_list_[i].range = reinterpret_cast(0); - } - else - range_list_[i].range = &(ri->range_ref()); + if ( + rp.const_range() && + is_const_string_range_node(arg_list_[i]) + ) + { + ts.size = rp.const_size(); + ts.data = static_cast(ts.data) + rp.n0_c.second; + range_list_[i].range = reinterpret_cast(0); } + else + range_list_[i].range = &(ri->range_ref()); } + #endif else if (is_variable_node(arg_list_[i])) { variable_node_ptr_t var = variable_node_ptr_t(0); @@ -9453,17 +12217,6 @@ namespace exprtk ts.data = &var->ref(); ts.type = type_store_t::e_scalar; } - else if (is_vector_elem_node(arg_list_[i])) - { - vector_elem_node_ptr_t var = vector_elem_node_ptr_t(0); - - if (0 == (var = dynamic_cast(arg_list_[i]))) - return false; - - ts.size = 1; - ts.data = reinterpret_cast(&var->ref()); - ts.type = type_store_t::e_scalar; - } else { ts.size = 1; @@ -9517,20 +12270,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 - ts.data = static_cast(rdt.data) + (rp.cache.first * rdt.type_size); + #endif + ts.data = static_cast(rdt.data) + (rp.cache.first * rdt.type_size); } else return false; @@ -9546,11 +12300,12 @@ namespace exprtk private: std::vector arg_list_; - std::vector branch_; - mutable tmp_vs_t expr_as_vec1_store_; - mutable range_list_t range_list_; + std::vector branch_; + mutable tmp_vs_t expr_as_vec1_store_; + mutable range_list_t range_list_; }; + #ifndef exprtk_disable_string_capabilities template class string_function_node : public generic_function_node, public string_base_node, @@ -9558,12 +12313,12 @@ namespace exprtk { public: - typedef generic_function_node gen_function_t; + typedef generic_function_node gen_function_t; typedef range_pack range_t; string_function_node(StringFunction* func, const std::vector& arg_list) - : gen_function_t(func,arg_list) + : gen_function_t(arg_list,func) { range_.n0_c = std::make_pair(true,0); range_.n1_c = std::make_pair(true,0); @@ -9578,16 +12333,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; @@ -9596,7 +12352,7 @@ namespace exprtk } } - return result; + return std::numeric_limits::quiet_NaN(); } inline typename expression_node::node_type type() const @@ -9609,9 +12365,9 @@ namespace exprtk return ret_string_; } - const char* base() const + char_cptr base() const { - return ret_string_.data(); + return &ret_string_[0]; } std::size_t size() const @@ -9634,38 +12390,40 @@ namespace exprtk mutable range_t range_; mutable std::string ret_string_; }; + #endif template class multimode_genfunction_node : public generic_function_node { public: - typedef generic_function_node gen_function_t; + typedef generic_function_node gen_function_t; typedef range_pack range_t; multimode_genfunction_node(GenericFunction* func, const std::size_t& param_seq_index, const std::vector& arg_list) - : gen_function_t(func,arg_list), + : gen_function_t(arg_list,func), param_seq_index_(param_seq_index) {} 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 @@ -9678,12 +12436,13 @@ namespace exprtk std::size_t param_seq_index_; }; + #ifndef exprtk_disable_string_capabilities template class multimode_strfunction_node : public string_function_node { public: - typedef string_function_node str_function_t; + typedef string_function_node str_function_t; typedef range_pack range_t; multimode_strfunction_node(StringFunction* func, @@ -9695,17 +12454,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; @@ -9714,7 +12474,7 @@ namespace exprtk } } - return result; + return std::numeric_limits::quiet_NaN(); } inline typename expression_node::node_type type() const @@ -9724,30 +12484,159 @@ namespace exprtk private: - std::size_t param_seq_index_; + const std::size_t param_seq_index_; + }; + #endif + + class return_exception + {}; + + template + class null_igenfunc + { + public: + + virtual ~null_igenfunc() + {} + + typedef type_store generic_type; + typedef typename generic_type::parameter_list parameter_list_t; + + inline virtual T operator() (parameter_list_t) + { + return std::numeric_limits::quiet_NaN(); + } + }; + + #ifndef exprtk_disable_return_statement + template + class return_node : public generic_function_node > + { + public: + + typedef null_igenfunc igeneric_function_t; + typedef igeneric_function_t* igeneric_function_ptr; + typedef generic_function_node gen_function_t; + typedef results_context results_context_t; + + return_node(const std::vector& arg_list, + results_context_t& rc) + : gen_function_t (arg_list), + results_context_(&rc) + {} + + inline T value() const + { + if ( + (0 != results_context_) && + gen_function_t::populate_value_list() + ) + { + typedef typename type_store::parameter_list parameter_list_t; + + results_context_-> + assign(parameter_list_t(gen_function_t::typestore_list_)); + + throw return_exception(); + } + + return std::numeric_limits::quiet_NaN(); + } + + inline typename expression_node::node_type type() const + { + return expression_node::e_return; + } + + private: + + results_context_t* results_context_; + }; + + template + class return_envelope_node : public expression_node + { + public: + + 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) + { + construct_branch_pair(body_, body); + } + + inline T value() const + { + assert(body_.first); + + try + { + return_invoked_ = false; + results_context_->clear(); + + return body_.first->value(); + } + catch(const return_exception&) + { + return_invoked_ = true; + return std::numeric_limits::quiet_NaN(); + } + } + + inline typename expression_node::node_type type() const + { + return expression_node::e_retenv; + } + + inline bool* retinvk_ptr() + { + 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_; + branch_t body_; }; + #endif - #define exprtk_define_unary_op(OpName) \ - template \ - struct OpName##_op \ - { \ - typedef typename functor_t::Type Type; \ - \ - static inline T process(Type v) \ - { \ - return numeric:: OpName (v); \ - } \ - \ - static inline typename expression_node::node_type type() \ - { \ - return expression_node::e_##OpName; \ - } \ - \ - static inline details::operator_type operation() \ - { \ - return details::e_##OpName; \ - } \ - }; \ + #define exprtk_define_unary_op(OpName) \ + template \ + struct OpName##_op \ + { \ + typedef typename functor_t::Type Type; \ + typedef typename expression_node::node_type node_t; \ + \ + static inline T process(Type v) \ + { \ + return numeric:: OpName (v); \ + } \ + \ + static inline node_t type() \ + { \ + return expression_node::e_##OpName; \ + } \ + \ + static inline details::operator_type operation() \ + { \ + return details::e_##OpName; \ + } \ + }; \ exprtk_define_unary_op(abs ) exprtk_define_unary_op(acos ) @@ -9794,20 +12683,24 @@ namespace exprtk template struct opr_base { - typedef typename details::functor_t::Type Type; - 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::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; }; 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; } static inline typename expression_node::node_type type() { return expression_node::e_add; } static inline details::operator_type operation() { return details::e_add; } }; @@ -9815,9 +12708,12 @@ 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; } static inline typename expression_node::node_type type() { return expression_node::e_mul; } static inline details::operator_type operation() { return details::e_mul; } }; @@ -9825,9 +12721,12 @@ 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; } static inline typename expression_node::node_type type() { return expression_node::e_sub; } static inline details::operator_type operation() { return details::e_sub; } }; @@ -9835,9 +12734,12 @@ 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; } static inline typename expression_node::node_type type() { return expression_node::e_div; } static inline details::operator_type operation() { return details::e_div; } }; @@ -9845,8 +12747,11 @@ 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; } static inline details::operator_type operation() { return details::e_mod; } }; @@ -9854,8 +12759,11 @@ 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; } static inline details::operator_type operation() { return details::e_pow; } }; @@ -9864,6 +12772,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; } @@ -9874,6 +12783,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; } @@ -9884,6 +12794,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; } @@ -9894,6 +12805,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; } @@ -9910,10 +12822,22 @@ namespace exprtk static inline details::operator_type operation() { return details::e_eq; } }; + template + 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; } + static inline details::operator_type operation() { return details::e_equal; } + }; + template 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; } @@ -9924,6 +12848,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; } @@ -9933,6 +12858,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; } @@ -9942,6 +12868,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; } @@ -9951,6 +12878,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; } @@ -9960,6 +12888,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; } @@ -9969,6 +12898,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; } @@ -9978,6 +12908,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; } @@ -9988,6 +12919,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; } @@ -9998,6 +12930,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; } @@ -10008,6 +12941,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) { @@ -10024,11 +12958,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 { @@ -10036,7 +12982,7 @@ namespace exprtk template class Sequence> + template class Sequence> static inline T process(const Sequence& arg_list) { switch (arg_list.size()) @@ -10077,14 +13023,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 @@ -10092,7 +13038,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]) ; } }; @@ -10103,7 +13049,7 @@ namespace exprtk template class Sequence> + template class Sequence> static inline T process(const Sequence& arg_list) { switch (arg_list.size()) @@ -10144,14 +13090,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 @@ -10159,7 +13105,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]) ; } }; @@ -10170,7 +13116,7 @@ namespace exprtk template class Sequence> + template class Sequence> static inline T process(const Sequence& arg_list) { switch (arg_list.size()) @@ -10226,7 +13172,7 @@ namespace exprtk template class Sequence> + template class Sequence> static inline T process(const Sequence& arg_list) { switch (arg_list.size()) @@ -10276,16 +13222,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])); } }; @@ -10297,7 +13243,7 @@ namespace exprtk template class Sequence> + template class Sequence> static inline T process(const Sequence& arg_list) { switch (arg_list.size()) @@ -10315,6 +13261,7 @@ namespace exprtk for (std::size_t i = 1; i < arg_list.size(); ++i) { const T v = value(arg_list[i]); + if (v > result) result = v; } @@ -10346,16 +13293,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])); } }; @@ -10367,7 +13314,7 @@ namespace exprtk template class Sequence> + template class Sequence> static inline T process(const Sequence& arg_list) { switch (arg_list.size()) @@ -10381,7 +13328,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); } @@ -10394,15 +13341,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); } @@ -10410,9 +13357,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); } @@ -10420,10 +13367,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); } @@ -10431,11 +13378,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); } }; @@ -10447,7 +13394,7 @@ namespace exprtk template class Sequence> + template class Sequence> static inline T process(const Sequence& arg_list) { switch (arg_list.size()) @@ -10461,7 +13408,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); } @@ -10474,15 +13421,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); } @@ -10490,9 +13437,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); } @@ -10500,10 +13447,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); } @@ -10511,11 +13458,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); } }; @@ -10527,7 +13474,7 @@ namespace exprtk template class Sequence> + template class Sequence> static inline T process(const Sequence& arg_list) { switch (arg_list.size()) @@ -10637,16 +13584,97 @@ namespace exprtk static inline T process(const ivector_ptr v) { - vector_holder& vec = v->vec()->ref(); + const T* vec = v->vec()->vds().data(); + const std::size_t vec_size = v->vec()->vds().size(); - T result = T(0); + loop_unroll::details lud(vec_size); + + if (vec_size <= static_cast(lud.batch_size)) + { + T result = T(0); + int i = 0; + + exprtk_disable_fallthrough_begin + switch (vec_size) + { + #define case_stmt(N) \ + case N : result += vec[i++]; \ + + #ifndef exprtk_disable_superscalar_unroll + case_stmt(16) case_stmt(15) + case_stmt(14) case_stmt(13) + case_stmt(12) case_stmt(11) + case_stmt(10) case_stmt( 9) + case_stmt( 8) case_stmt( 7) + case_stmt( 6) case_stmt( 5) + #endif + case_stmt( 4) case_stmt( 3) + case_stmt( 2) case_stmt( 1) + } + exprtk_disable_fallthrough_end + + #undef case_stmt + + return result; + } + + T r[] = { + T(0), T(0), T(0), T(0), T(0), T(0), T(0), T(0), + T(0), T(0), T(0), T(0), T(0), T(0), T(0), T(0) + }; + + const T* upper_bound = vec + lud.upper_bound; + + while (vec < upper_bound) + { + #define exprtk_loop(N) \ + r[N] += vec[N]; \ - for (std::size_t i = 0; i < vec.size(); ++i) + exprtk_loop( 0) exprtk_loop( 1) + exprtk_loop( 2) exprtk_loop( 3) + #ifndef exprtk_disable_superscalar_unroll + exprtk_loop( 4) exprtk_loop( 5) + exprtk_loop( 6) exprtk_loop( 7) + exprtk_loop( 8) exprtk_loop( 9) + exprtk_loop(10) exprtk_loop(11) + exprtk_loop(12) exprtk_loop(13) + exprtk_loop(14) exprtk_loop(15) + #endif + + vec += lud.batch_size; + } + + int i = 0; + + exprtk_disable_fallthrough_begin + switch (lud.remainder) { - result += (*vec[i]); + #define case_stmt(N) \ + case N : r[0] += vec[i++]; \ + + #ifndef exprtk_disable_superscalar_unroll + case_stmt(15) case_stmt(14) + case_stmt(13) case_stmt(12) + case_stmt(11) case_stmt(10) + case_stmt( 9) case_stmt( 8) + case_stmt( 7) case_stmt( 6) + case_stmt( 5) case_stmt( 4) + #endif + case_stmt( 3) case_stmt( 2) + case_stmt( 1) } + exprtk_disable_fallthrough_end - return result; + #undef exprtk_loop + #undef case_stmt + + return (r[ 0] + r[ 1] + r[ 2] + r[ 3]) + #ifndef exprtk_disable_superscalar_unroll + + (r[ 4] + r[ 5] + r[ 6] + r[ 7]) + + (r[ 8] + r[ 9] + r[10] + r[11]) + + (r[12] + r[13] + r[14] + r[15]) + #endif + ; } }; @@ -10657,16 +13685,97 @@ namespace exprtk static inline T process(const ivector_ptr v) { - vector_holder& vec = v->vec()->ref(); + const T* vec = v->vec()->vds().data(); + const std::size_t vec_size = v->vec()->vds().size(); - T result = (*vec[0]); + loop_unroll::details lud(vec_size); - for (std::size_t i = 1; i < vec.size(); ++i) + if (vec_size <= static_cast(lud.batch_size)) { - result *= (*vec[i]); + T result = T(1); + int i = 0; + + exprtk_disable_fallthrough_begin + switch (vec_size) + { + #define case_stmt(N) \ + case N : result *= vec[i++]; \ + + #ifndef exprtk_disable_superscalar_unroll + case_stmt(16) case_stmt(15) + case_stmt(14) case_stmt(13) + case_stmt(12) case_stmt(11) + case_stmt(10) case_stmt( 9) + case_stmt( 8) case_stmt( 7) + case_stmt( 6) case_stmt( 5) + #endif + case_stmt( 4) case_stmt( 3) + case_stmt( 2) case_stmt( 1) + } + exprtk_disable_fallthrough_end + + #undef case_stmt + + return result; } - return result; + T r[] = { + T(1), T(1), T(1), T(1), T(1), T(1), T(1), T(1), + T(1), T(1), T(1), T(1), T(1), T(1), T(1), T(1) + }; + + const T* upper_bound = vec + lud.upper_bound; + + while (vec < upper_bound) + { + #define exprtk_loop(N) \ + r[N] *= vec[N]; \ + + exprtk_loop( 0) exprtk_loop( 1) + exprtk_loop( 2) exprtk_loop( 3) + #ifndef exprtk_disable_superscalar_unroll + exprtk_loop( 4) exprtk_loop( 5) + exprtk_loop( 6) exprtk_loop( 7) + exprtk_loop( 8) exprtk_loop( 9) + exprtk_loop(10) exprtk_loop(11) + exprtk_loop(12) exprtk_loop(13) + exprtk_loop(14) exprtk_loop(15) + #endif + + vec += lud.batch_size; + } + + int i = 0; + + exprtk_disable_fallthrough_begin + switch (lud.remainder) + { + #define case_stmt(N) \ + case N : r[0] *= vec[i++]; \ + + #ifndef exprtk_disable_superscalar_unroll + case_stmt(15) case_stmt(14) + case_stmt(13) case_stmt(12) + case_stmt(11) case_stmt(10) + case_stmt( 9) case_stmt( 8) + case_stmt( 7) case_stmt( 6) + case_stmt( 5) case_stmt( 4) + #endif + case_stmt( 3) case_stmt( 2) + case_stmt( 1) + } + exprtk_disable_fallthrough_end + + #undef exprtk_loop + #undef case_stmt + + return (r[ 0] * r[ 1] * r[ 2] * r[ 3]) + #ifndef exprtk_disable_superscalar_unroll + + (r[ 4] * r[ 5] * r[ 6] * r[ 7]) + + (r[ 8] * r[ 9] * r[10] * r[11]) + + (r[12] * r[13] * r[14] * r[15]) + #endif + ; } }; @@ -10677,16 +13786,9 @@ namespace exprtk static inline T process(const ivector_ptr v) { - vector_holder& vec = v->vec()->ref(); - - T result = T(0); + const std::size_t vec_size = v->vec()->vds().size(); - for (std::size_t i = 0; i < vec.size(); ++i) - { - result += (*vec[i]); - } - - return result / vec.size(); + return vec_add_op::process(v) / vec_size; } }; @@ -10697,16 +13799,17 @@ namespace exprtk static inline T process(const ivector_ptr v) { - vector_holder& vec = v->vec()->ref(); + const T* vec = v->vec()->vds().data(); + const std::size_t vec_size = v->vec()->vds().size(); - T result = (*vec[0]); + T result = vec[0]; - for (std::size_t i = 1; i < vec.size(); ++i) + 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; + if (v_i < result) + result = v_i; } return result; @@ -10720,15 +13823,17 @@ namespace exprtk static inline T process(const ivector_ptr v) { - vector_holder& vec = v->vec()->ref(); + const T* vec = v->vec()->vds().data(); + const std::size_t vec_size = v->vec()->vds().size(); - T result = (*vec[0]); + T result = vec[0]; - for (std::size_t i = 1; i < vec.size(); ++i) + for (std::size_t i = 1; i < vec_size; ++i) { - T v_i = (*vec[i]); - if (v_i > result) - result = v_i; + const T v_i = vec[i]; + + if (v_i > result) + result = v_i; } return result; @@ -10740,6 +13845,9 @@ namespace exprtk { public: + virtual ~vov_base_node() + {} + inline virtual operator_type operation() const { return details::e_default; @@ -10755,6 +13863,9 @@ namespace exprtk { public: + virtual ~cov_base_node() + {} + inline virtual operator_type operation() const { return details::e_default; @@ -10770,6 +13881,9 @@ namespace exprtk { public: + virtual ~voc_base_node() + {} + inline virtual operator_type operation() const { return details::e_default; @@ -10785,6 +13899,9 @@ namespace exprtk { public: + virtual ~vob_base_node() + {} + virtual const T& v() const = 0; }; @@ -10793,6 +13910,9 @@ namespace exprtk { public: + virtual ~bov_base_node() + {} + virtual const T& v() const = 0; }; @@ -10801,6 +13921,9 @@ namespace exprtk { public: + virtual ~cob_base_node() + {} + inline virtual operator_type operation() const { return details::e_default; @@ -10818,6 +13941,9 @@ namespace exprtk { public: + virtual ~boc_base_node() + {} + inline virtual operator_type operation() const { return details::e_default; @@ -10835,6 +13961,9 @@ namespace exprtk { public: + virtual ~uv_base_node() + {} + inline virtual operator_type operation() const { return details::e_default; @@ -10848,6 +13977,9 @@ namespace exprtk { public: + virtual ~sos_base_node() + {} + inline virtual operator_type operation() const { return details::e_default; @@ -10859,6 +13991,9 @@ namespace exprtk { public: + virtual ~sosos_base_node() + {} + inline virtual operator_type operation() const { return details::e_default; @@ -10870,6 +14005,9 @@ namespace exprtk { public: + virtual ~T0oT1oT2_base_node() + {} + virtual std::string type_id() const = 0; }; @@ -10878,6 +14016,9 @@ namespace exprtk { public: + virtual ~T0oT1oT2oT3_base_node() + {} + virtual std::string type_id() const = 0; }; @@ -10937,9 +14078,9 @@ namespace exprtk ufunc_t uf0, ufunc_t uf1, bfunc_t bf) : v0_(var0), v1_(var1), - u0_(uf0), - u1_(uf1), - f_ (bf) + u0_(uf0 ), + u1_(uf1 ), + f_ (bf ) {} inline T value() const @@ -11000,25 +14141,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_) - { - delete branch_; - branch_ = 0; - } + 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 @@ -11033,12 +14166,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: @@ -11046,8 +14189,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}; }; @@ -11234,15 +14376,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 @@ -11256,15 +14398,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 @@ -11278,22 +14420,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 @@ -11348,13 +14490,15 @@ namespace exprtk T0 p0, T1 p1, bfunc_t p2) { - return allocator.template allocate_type(p0,p1,p2); + return allocator + .template allocate_type + (p0, p1, p2); } private: T0oT1(T0oT1&) {} - T0oT1& operator=(T0oT1&) { return *this; } + T0oT1& operator=(T0oT1&) { return (*this); } T0 t0_; T1 t1_; @@ -11393,7 +14537,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 @@ -11434,13 +14578,15 @@ namespace exprtk template static inline expression_node* allocate(Allocator& allocator, T0 p0, T1 p1, T2 p2, bfunc_t p3, bfunc_t p4) { - return allocator.template allocate_type(p0,p1,p2,p3,p4); + return allocator + .template allocate_type + (p0, p1, p2, p3, p4); } private: T0oT1oT2(node_type&) {} - node_type& operator=(node_type&) { return *this; } + node_type& operator=(node_type&) { return (*this); } T0 t0_; T1 t1_; @@ -11476,7 +14622,7 @@ namespace exprtk inline T value() const { - return ProcessMode::process(t0_,t1_,t2_,t3_,f0_,f1_,f2_); + return ProcessMode::process(t0_, t1_, t2_, t3_, f0_, f1_, f2_); } inline T0 t0() const @@ -11521,7 +14667,7 @@ namespace exprtk static inline std::string id() { - return process_mode_t::template id(); + return process_mode_t::template id(); } template @@ -11529,13 +14675,15 @@ namespace exprtk T0 p0, T1 p1, T2 p2, T3 p3, bfunc_t p4, bfunc_t p5, bfunc_t p6) { - return allocator.template allocate_type(p0,p1,p2,p3,p4,p5,p6); + return allocator + .template allocate_type + (p0, p1, p2, p3, p4, p5, p6); } private: T0oT1oT2oT3(node_type&) {} - node_type& operator=(node_type&) { return *this; } + node_type& operator=(node_type&) { return (*this); } T0 t0_; T1 t1_; @@ -11576,7 +14724,7 @@ namespace exprtk inline T value() const { - return f_(t0_,t1_,t2_); + return f_(t0_, t1_, t2_); } inline T0 t0() const @@ -11612,13 +14760,15 @@ namespace exprtk template static inline expression_node* allocate(Allocator& allocator, T0 p0, T1 p1, T2 p2, tfunc_t p3) { - return allocator.template allocate_type(p0,p1,p2,p3); + return allocator + .template allocate_type + (p0, p1, p2, p3); } private: T0oT1oT2_sf3(node_type&) {} - node_type& operator=(node_type&) { return *this; } + node_type& operator=(node_type&) { return (*this); } T0 t0_; T1 t1_; @@ -11631,6 +14781,9 @@ namespace exprtk { public: + virtual ~sf3ext_type_node() + {} + virtual T0 t0() const = 0; virtual T1 t1() const = 0; @@ -11667,7 +14820,7 @@ namespace exprtk inline T value() const { - return SF3Operation::process(t0_,t1_,t2_); + return SF3Operation::process(t0_, t1_, t2_); } T0 t0() const @@ -11698,13 +14851,15 @@ namespace exprtk template static inline expression_node* allocate(Allocator& allocator, T0 p0, T1 p1, T2 p2) { - return allocator.template allocate_type(p0,p1,p2); + return allocator + .template allocate_type + (p0, p1, p2); } private: T0oT1oT2_sf3ext(node_type&) {} - node_type& operator=(node_type&) { return *this; } + node_type& operator=(node_type&) { return (*this); } T0 t0_; T1 t1_; @@ -11756,7 +14911,7 @@ namespace exprtk inline T value() const { - return f_(t0_,t1_,t2_,t3_); + return f_(t0_, t1_, t2_, t3_); } inline T0 t0() const @@ -11797,13 +14952,15 @@ namespace exprtk template static inline expression_node* allocate(Allocator& allocator, T0 p0, T1 p1, T2 p2, T3 p3, qfunc_t p4) { - return allocator.template allocate_type(p0,p1,p2,p3,p4); + return allocator + .template allocate_type + (p0, p1, p2, p3, p4); } private: T0oT1oT2oT3_sf4(node_type&) {} - node_type& operator=(node_type&) { return *this; } + node_type& operator=(node_type&) { return (*this); } T0 t0_; T1 t1_; @@ -11842,7 +14999,7 @@ namespace exprtk inline T value() const { - return SF4Operation::process(t0_,t1_,t2_,t3_); + return SF4Operation::process(t0_, t1_, t2_, t3_); } inline T0 t0() const @@ -11862,7 +15019,7 @@ namespace exprtk inline T3 t3() const { - return t2_; + return t3_; } std::string type_id() const @@ -11878,13 +15035,15 @@ namespace exprtk template static inline expression_node* allocate(Allocator& allocator, T0 p0, T1 p1, T2 p2, T3 p3) { - return allocator.template allocate_type(p0,p1,p2,p3); + return allocator + .template allocate_type + (p0, p1, p2, p3); } private: T0oT1oT2oT3_sf4ext(node_type&) {} - node_type& operator=(node_type&) { return *this; } + node_type& operator=(node_type&) { return (*this); } T0 t0_; T1 t1_; @@ -11913,27 +15072,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 @@ -12091,20 +15250,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 @@ -12119,7 +15274,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: @@ -12128,7 +15293,7 @@ namespace exprtk vob_node& operator=(const vob_node&); const T& v_; - branch_t branch_[1]; + branch_t branch_; }; template @@ -12141,20 +15306,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 @@ -12169,7 +15330,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: @@ -12178,7 +15349,7 @@ namespace exprtk bov_node& operator=(const bov_node&); const T& v_; - branch_t branch_[1]; + branch_t branch_; }; template @@ -12191,20 +15362,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 @@ -12224,13 +15391,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: @@ -12238,8 +15415,8 @@ namespace exprtk cob_node(const cob_node&); cob_node& operator=(const cob_node&); - const T c_; - branch_t branch_[1]; + const T c_; + branch_t branch_; }; template @@ -12252,20 +15429,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 @@ -12285,13 +15458,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: @@ -12299,8 +15482,8 @@ namespace exprtk boc_node(const boc_node&); boc_node& operator=(const boc_node&); - const T c_; - branch_t branch_[1]; + const T c_; + branch_t branch_; }; #ifndef exprtk_disable_string_capabilities @@ -12364,8 +15547,8 @@ namespace exprtk // string-range op string node explicit str_xrox_node(SType0 p0, SType1 p1, RangePack rp0) - : s0_(p0), - s1_(p1), + : s0_ (p0 ), + s1_ (p1 ), rp0_(rp0) {} @@ -12379,8 +15562,8 @@ namespace exprtk std::size_t r0 = 0; std::size_t r1 = 0; - if (rp0_(r0,r1,s0_.size())) - return Operation::process(s0_.substr(r0,(r1 - r0) + 1),s1_); + if (rp0_(r0, r1, s0_.size())) + return Operation::process(s0_.substr(r0, (r1 - r0) + 1), s1_); else return T(0); } @@ -12442,8 +15625,8 @@ namespace exprtk std::size_t r0 = 0; std::size_t r1 = 0; - if (rp1_(r0,r1,s1_.size())) - return Operation::process(s0_,s1_.substr(r0,(r1 - r0) + 1)); + if (rp1_(r0, r1, s1_.size())) + return Operation::process(s0_, s1_.substr(r0, (r1 - r0) + 1)); else return T(0); } @@ -12508,14 +15691,15 @@ namespace exprtk std::size_t r0_1 = 0; std::size_t r1_0 = 0; std::size_t r1_1 = 0; + if ( - rp0_(r0_0,r1_0,s0_.size()) && - rp1_(r0_1,r1_1,s1_.size()) + rp0_(r0_0, r1_0, s0_.size()) && + rp1_(r0_1, r1_1, s1_.size()) ) { return Operation::process( - s0_.substr(r0_0,(r1_0 - r0_0) + 1), - s1_.substr(r0_1,(r1_1 - r0_1) + 1) + s0_.substr(r0_0, (r1_0 - r0_0) + 1), + s1_.substr(r0_1, (r1_1 - r0_1) + 1) ); } else @@ -12570,7 +15754,7 @@ namespace exprtk str_sogens_node(const operator_type& opr, expression_ptr branch0, expression_ptr branch1) - : binary_node(opr,branch0,branch1), + : binary_node(opr, branch0, branch1), str0_base_ptr_ (0), str1_base_ptr_ (0), str0_range_ptr_(0), @@ -12583,12 +15767,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)) @@ -12598,12 +15782,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()); } } @@ -12625,12 +15809,12 @@ 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()) ) { return Operation::process( @@ -12752,6 +15936,49 @@ namespace exprtk const T& v_; }; + template + class bipow_node : public expression_node + { + public: + + typedef expression_node* expression_ptr; + typedef std::pair branch_t; + typedef PowOp operation_t; + + explicit bipow_node(expression_ptr branch) + { + construct_branch_pair(branch_, branch); + } + + inline T value() const + { + assert(branch_.first); + return PowOp::result(branch_.first->value()); + } + + inline typename expression_node::node_type type() const + { + 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_; + }; + template class ipowinv_node : public expression_node { @@ -12782,6 +16009,49 @@ namespace exprtk const T& v_; }; + template + class bipowninv_node : public expression_node + { + public: + + typedef expression_node* expression_ptr; + typedef std::pair branch_t; + typedef PowOp operation_t; + + explicit bipowninv_node(expression_ptr branch) + { + construct_branch_pair(branch_, branch); + } + + inline T value() const + { + assert(branch_.first); + return (T(1) / PowOp::result(branch_.first->value())); + } + + inline typename expression_node::node_type type() const + { + 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_; + }; + template inline bool is_vov_node(const expression_node* node) { @@ -12872,6 +16142,24 @@ namespace exprtk return node && (expression_node::e_strfunction == node->type()); } + template + inline bool is_string_condition_node(const expression_node* node) + { + return node && (expression_node::e_strcondition == node->type()); + } + + template + inline bool is_string_ccondition_node(const expression_node* node) + { + return node && (expression_node::e_strccondition == node->type()); + } + + template + inline bool is_string_vararg_node(const expression_node* node) + { + return node && (expression_node::e_stringvararg == node->type()); + } + template inline bool is_genricstring_range_node(const expression_node* node) { @@ -12892,7 +16180,10 @@ namespace exprtk case expression_node::e_strgenrange : case expression_node::e_strass : case expression_node::e_strconcat : - case expression_node::e_strfunction : return true; + case expression_node::e_strfunction : + case expression_node::e_strcondition : + case expression_node::e_strccondition : + case expression_node::e_stringvararg : return true; default : return false; } } @@ -12907,134 +16198,191 @@ 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 inline expression_node* allocate() const { - return new node_type(); + return (new node_type()); } 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 + typename T5, typename T6> inline expression_node* allocate_type(T1 t1, T2 t2, T3 t3, T4 t4, - T5 t5, T6 t6, - T7 t7) const + T5 t5, T6 t6) const { - return new node_type(t1,t2,t3,t4,t5,t6,t7); + expression_node* + result = (new node_type(t1, t2, t3, t4, t5, t6)); + result->node_depth(); + return result; } - template - void inline free(expression_node*& e) const - { - delete e; + template + inline expression_node* allocate_type(T1 t1, T2 t2, + T3 t3, T4 t4, + T5 t5, T6 t6, + T7 t7) const + { + expression_node* + 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; } }; @@ -13180,264 +16582,305 @@ namespace exprtk #define register_op(Symbol,Type,Args) \ m.insert(std::make_pair(std::string(Symbol),details::base_operation_t(Type,Args))); \ - register_op( "abs",e_abs , 1) - register_op( "acos",e_acos , 1) - register_op( "acosh",e_acosh , 1) - register_op( "asin",e_asin , 1) - register_op( "asinh",e_asinh , 1) - register_op( "atan",e_atan , 1) - register_op( "atanh",e_atanh , 1) - register_op( "ceil",e_ceil , 1) - register_op( "cos",e_cos , 1) - register_op( "cosh",e_cosh , 1) - register_op( "exp",e_exp , 1) - register_op( "expm1",e_expm1 , 1) - register_op( "floor",e_floor , 1) - register_op( "log",e_log , 1) - register_op( "log10",e_log10 , 1) - register_op( "log2",e_log2 , 1) - register_op( "log1p",e_log1p , 1) - register_op( "round",e_round , 1) - register_op( "sin",e_sin , 1) - register_op( "sinc",e_sinc , 1) - register_op( "sinh",e_sinh , 1) - register_op( "sec",e_sec , 1) - register_op( "csc",e_csc , 1) - register_op( "sqrt",e_sqrt , 1) - register_op( "tan",e_tan , 1) - register_op( "tanh",e_tanh , 1) - register_op( "cot",e_cot , 1) - register_op( "rad2deg",e_r2d , 1) - register_op( "deg2rad",e_d2r , 1) - register_op( "deg2grad",e_d2g , 1) - register_op( "grad2deg",e_g2d , 1) - register_op( "sgn",e_sgn , 1) - register_op( "not",e_notl , 1) - register_op( "erf",e_erf , 1) - register_op( "erfc",e_erfc , 1) - register_op( "ncdf",e_ncdf , 1) - register_op( "frac",e_frac , 1) - register_op( "trunc",e_trunc , 1) - register_op( "atan2",e_atan2 , 2) - register_op( "mod",e_mod , 2) - register_op( "logn",e_logn , 2) - register_op( "pow",e_pow , 2) - register_op( "root",e_root , 2) - register_op( "roundn",e_roundn , 2) - register_op( "equal",e_equal , 2) - register_op("not_equal",e_nequal , 2) - register_op( "hypot",e_hypot , 2) - register_op( "shr",e_shr , 2) - register_op( "shl",e_shl , 2) - register_op( "clamp",e_clamp , 3) - register_op( "iclamp",e_iclamp , 3) - register_op( "inrange",e_inrange , 3) + register_op( "abs", e_abs , 1) + register_op( "acos", e_acos , 1) + register_op( "acosh", e_acosh , 1) + register_op( "asin", e_asin , 1) + register_op( "asinh", e_asinh , 1) + register_op( "atan", e_atan , 1) + register_op( "atanh", e_atanh , 1) + register_op( "ceil", e_ceil , 1) + register_op( "cos", e_cos , 1) + register_op( "cosh", e_cosh , 1) + register_op( "exp", e_exp , 1) + register_op( "expm1", e_expm1 , 1) + register_op( "floor", e_floor , 1) + register_op( "log", e_log , 1) + register_op( "log10", e_log10 , 1) + register_op( "log2", e_log2 , 1) + register_op( "log1p", e_log1p , 1) + register_op( "round", e_round , 1) + register_op( "sin", e_sin , 1) + register_op( "sinc", e_sinc , 1) + register_op( "sinh", e_sinh , 1) + register_op( "sec", e_sec , 1) + register_op( "csc", e_csc , 1) + register_op( "sqrt", e_sqrt , 1) + register_op( "tan", e_tan , 1) + register_op( "tanh", e_tanh , 1) + register_op( "cot", e_cot , 1) + register_op( "rad2deg", e_r2d , 1) + register_op( "deg2rad", e_d2r , 1) + register_op( "deg2grad", e_d2g , 1) + register_op( "grad2deg", e_g2d , 1) + register_op( "sgn", e_sgn , 1) + register_op( "not", e_notl , 1) + register_op( "erf", e_erf , 1) + register_op( "erfc", e_erfc , 1) + register_op( "ncdf", e_ncdf , 1) + register_op( "frac", e_frac , 1) + register_op( "trunc", e_trunc , 1) + register_op( "atan2", e_atan2 , 2) + register_op( "mod", e_mod , 2) + register_op( "logn", e_logn , 2) + register_op( "pow", e_pow , 2) + register_op( "root", e_root , 2) + register_op( "roundn", e_roundn , 2) + register_op( "equal", e_equal , 2) + register_op("not_equal", e_nequal , 2) + register_op( "hypot", e_hypot , 2) + register_op( "shr", e_shr , 2) + register_op( "shl", e_shl , 2) + register_op( "clamp", e_clamp , 3) + register_op( "iclamp", e_iclamp , 3) + register_op( "inrange", e_inrange , 3) #undef register_op } } // namespace details - template - class ifunction + class function_traits { public: - explicit ifunction(const std::size_t& pc, const bool hse = true) - : param_count(pc), - has_side_effects(hse) - {} - - virtual ~ifunction() + function_traits() + : allow_zero_parameters_(false), + has_side_effects_(true), + min_num_args_(0), + max_num_args_(std::numeric_limits::max()) {} - inline virtual T operator()() + inline bool& allow_zero_parameters() { - return std::numeric_limits::quiet_NaN(); + return allow_zero_parameters_; } - inline virtual T operator()(const T&) + inline bool& has_side_effects() { - return std::numeric_limits::quiet_NaN(); + return has_side_effects_; } - inline virtual T operator()(const T&,const T&) + std::size_t& min_num_args() { - return std::numeric_limits::quiet_NaN(); + return min_num_args_; } - inline virtual T operator()(const T&, const T&, const T&) + std::size_t& max_num_args() { - return std::numeric_limits::quiet_NaN(); + return max_num_args_; } - inline virtual T operator()(const T&, const T&, const T&, const T&) - { - return std::numeric_limits::quiet_NaN(); - } + private: - inline virtual T operator()(const T&, const T&, const T&, const T&, const T&) - { - return std::numeric_limits::quiet_NaN(); - } + bool allow_zero_parameters_; + bool has_side_effects_; + std::size_t min_num_args_; + std::size_t max_num_args_; + }; - inline virtual T operator()(const T&, const T&, const T&, const T&, const T&, const T&) - { - return std::numeric_limits::quiet_NaN(); - } + template + void enable_zero_parameters(FunctionType& func) + { + func.allow_zero_parameters() = true; - inline virtual T operator()(const T&, const T&, const T&, const T&, const T&, const T&, const T&) + if (0 != func.min_num_args()) { - return std::numeric_limits::quiet_NaN(); + func.min_num_args() = 0; } + } - inline virtual T operator()(const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&) - { - return std::numeric_limits::quiet_NaN(); - } + template + void disable_zero_parameters(FunctionType& func) + { + func.allow_zero_parameters() = false; + } - inline virtual T operator()(const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&) - { - return std::numeric_limits::quiet_NaN(); - } + template + void enable_has_side_effects(FunctionType& func) + { + func.has_side_effects() = true; + } - inline virtual T operator()(const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&) - { - return std::numeric_limits::quiet_NaN(); - } + template + void disable_has_side_effects(FunctionType& func) + { + func.has_side_effects() = false; + } - inline virtual T operator()(const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, - const T&) - { - return std::numeric_limits::quiet_NaN(); - } + template + void set_min_num_args(FunctionType& func, const std::size_t& num_args) + { + func.min_num_args() = num_args; - inline virtual T operator()(const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, - const T&, const T&) - { - return std::numeric_limits::quiet_NaN(); - } + if ((0 != func.min_num_args()) && func.allow_zero_parameters()) + func.allow_zero_parameters() = false; + } - inline virtual T operator()(const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, - const T&, const T&, const T&) - { - return std::numeric_limits::quiet_NaN(); - } + template + void set_max_num_args(FunctionType& func, const std::size_t& num_args) + { + func.max_num_args() = num_args; + } - inline virtual T operator()(const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, - const T&, const T&, const T&, const T&) - { - return std::numeric_limits::quiet_NaN(); - } + template + class ifunction : public function_traits + { + public: - inline virtual T operator()(const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, - const T&, const T&, const T&, const T&, const T&) - { - return std::numeric_limits::quiet_NaN(); - } + explicit ifunction(const std::size_t& pc) + : param_count(pc) + {} - inline virtual T operator()(const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, - const T&, const T&, const T&, const T&, const T&, const T&) - { - return std::numeric_limits::quiet_NaN(); - } + virtual ~ifunction() + {} - inline virtual T operator()(const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, - const T&, const T&, const T&, const T&, const T&, const T&, const T&) - { - return std::numeric_limits::quiet_NaN(); - } + #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()(const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, - const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&) - { - return std::numeric_limits::quiet_NaN(); - } + inline virtual T operator() () + empty_method_body(0) - inline virtual T operator()(const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, - const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&) - { - return std::numeric_limits::quiet_NaN(); - } + inline virtual T operator() (const T&) + empty_method_body(1) - inline virtual T operator()(const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, - const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&) - { - return std::numeric_limits::quiet_NaN(); - } + 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(3) + + inline virtual T operator() (const T&, const T&, const T&, const T&) + empty_method_body(4) + + inline virtual T operator() (const T&, const T&, const T&, const T&, const T&) + empty_method_body(5) + + inline virtual T operator() (const T&, const T&, const T&, const T&, const T&, const T&) + 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(7) + + inline virtual T operator() (const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&) + 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(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(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(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(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(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(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(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(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(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(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(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(20) + + #undef empty_method_body std::size_t param_count; - bool has_side_effects; }; template - class ivararg_function + class ivararg_function : public function_traits { public: - ivararg_function(const bool hse = true) - : has_side_effects(hse) - {} - virtual ~ivararg_function() {} - inline virtual T operator()(const std::vector&) + inline virtual T operator() (const std::vector&) { - exprtk_debug(("ivararg_function::operator() - Operator has not been overriden.\n")); + exprtk_debug(("ivararg_function::operator() - Operator has not been overridden\n")); return std::numeric_limits::quiet_NaN(); } - - bool has_side_effects; }; template - class igeneric_function + class igeneric_function : public function_traits { public: + enum return_type + { + e_rtrn_scalar = 0, + e_rtrn_string = 1, + e_rtrn_overload = 2 + }; + typedef T type; typedef type_store generic_type; typedef typename generic_type::parameter_list parameter_list_t; - igeneric_function(const std::string& param_seq = "", - const bool hse = true) - : has_side_effects(hse), - parameter_sequence(param_seq) + igeneric_function(const std::string& param_seq = "", const return_type rtr_type = e_rtrn_scalar) + : parameter_sequence(param_seq), + rtrn_type(rtr_type) {} virtual ~igeneric_function() {} - // f(i_0,i_1,....,i_N) --> Number - inline virtual T operator()(parameter_list_t) - { - exprtk_debug(("igeneric_function::operator() - Operator has not been overriden. [1]\n")); - return std::numeric_limits::quiet_NaN(); - } + #define igeneric_function_empty_body(N) \ + { \ + exprtk_debug(("igeneric_function::operator() - Operator(" #N ") has not been overridden\n")); \ + return std::numeric_limits::quiet_NaN(); \ + } \ + + // f(i_0,i_1,....,i_N) --> Scalar + inline virtual T operator() (parameter_list_t) + igeneric_function_empty_body(1) // f(i_0,i_1,....,i_N) --> String - inline virtual T operator()(std::string&, parameter_list_t) - { - exprtk_debug(("igeneric_function::operator() - Operator has not been overriden. [2]\n")); - return std::numeric_limits::quiet_NaN(); - } + inline virtual T operator() (std::string&, parameter_list_t) + igeneric_function_empty_body(2) - // f(psi,i_0,i_1,....,i_N) --> Number - inline virtual T operator()(const std::size_t&, parameter_list_t) - { - exprtk_debug(("igeneric_function::operator() - Operator has not been overriden. [3]\n")); - return std::numeric_limits::quiet_NaN(); - } + // f(psi,i_0,i_1,....,i_N) --> Scalar + inline virtual T operator() (const std::size_t&, parameter_list_t) + igeneric_function_empty_body(3) // f(psi,i_0,i_1,....,i_N) --> String - inline virtual T operator()(const std::size_t&, std::string&, parameter_list_t) - { - exprtk_debug(("igeneric_function::operator() - Operator has not been overriden. [4]\n")); - return std::numeric_limits::quiet_NaN(); - } + inline virtual T operator() (const std::size_t&, std::string&, parameter_list_t) + igeneric_function_empty_body(4) - bool has_side_effects; std::string parameter_sequence; + return_type rtrn_type; }; template class parser; @@ -13446,12 +16889,200 @@ namespace exprtk template class symbol_table { - protected: + public: - template class parser; + typedef T (*ff00_functor)(); + typedef T (*ff01_functor)(T); + typedef T (*ff02_functor)(T, T); + typedef T (*ff03_functor)(T, T, T); + typedef T (*ff04_functor)(T, T, T, T); + typedef T (*ff05_functor)(T, T, T, T, T); + typedef T (*ff06_functor)(T, T, T, T, T, T); + typedef T (*ff07_functor)(T, T, T, T, T, T, T); + typedef T (*ff08_functor)(T, T, T, T, T, T, T, T); + typedef T (*ff09_functor)(T, T, T, T, T, T, T, T, T); + typedef T (*ff10_functor)(T, T, T, T, T, T, T, T, T, T); + typedef T (*ff11_functor)(T, T, T, T, T, T, T, T, T, T, T); + typedef T (*ff12_functor)(T, T, T, T, T, T, T, T, T, T, T, T); + typedef T (*ff13_functor)(T, T, T, T, T, T, T, T, T, T, T, T, T); + typedef T (*ff14_functor)(T, T, T, T, T, T, T, T, T, T, T, T, T, T); + typedef T (*ff15_functor)(T, T, T, T, T, T, T, T, T, T, T, T, T, T, T); protected: + struct freefunc00 : public exprtk::ifunction + { + using exprtk::ifunction::operator(); + + explicit freefunc00(ff00_functor ff) : exprtk::ifunction(0), f(ff) {} + inline T operator() () + { return f(); } + ff00_functor f; + }; + + struct freefunc01 : public exprtk::ifunction + { + using exprtk::ifunction::operator(); + + explicit freefunc01(ff01_functor ff) : exprtk::ifunction(1), f(ff) {} + inline T operator() (const T& v0) + { return f(v0); } + ff01_functor f; + }; + + struct freefunc02 : public exprtk::ifunction + { + using exprtk::ifunction::operator(); + + 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; + }; + + struct freefunc03 : public exprtk::ifunction + { + using exprtk::ifunction::operator(); + + 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; + }; + + struct freefunc04 : public exprtk::ifunction + { + using exprtk::ifunction::operator(); + + 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; + }; + + struct freefunc05 : public exprtk::ifunction + { + using exprtk::ifunction::operator(); + + 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; + }; + + struct freefunc06 : public exprtk::ifunction + { + using exprtk::ifunction::operator(); + + 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; + }; + + struct freefunc07 : public exprtk::ifunction + { + using exprtk::ifunction::operator(); + + 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); } + ff07_functor f; + }; + + struct freefunc08 : public exprtk::ifunction + { + using exprtk::ifunction::operator(); + + 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); } + ff08_functor f; + }; + + struct freefunc09 : public exprtk::ifunction + { + using exprtk::ifunction::operator(); + + 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); } + ff09_functor f; + }; + + struct freefunc10 : public exprtk::ifunction + { + using exprtk::ifunction::operator(); + + 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); } + ff10_functor f; + }; + + struct freefunc11 : public exprtk::ifunction + { + using exprtk::ifunction::operator(); + + 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); } + ff11_functor f; + }; + + struct freefunc12 : public exprtk::ifunction + { + using exprtk::ifunction::operator(); + + 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) + { return f(v00, v01, v02, v03, v04, v05, v06, v07, v08, v09, v10, v11); } + ff12_functor f; + }; + + struct freefunc13 : public exprtk::ifunction + { + using exprtk::ifunction::operator(); + + 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) + { return f(v00, v01, v02, v03, v04, v05, v06, v07, v08, v09, v10, v11, v12); } + ff13_functor f; + }; + + struct freefunc14 : public exprtk::ifunction + { + using exprtk::ifunction::operator(); + + 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) + { return f(v00, v01, v02, v03, v04, v05, v06, v07, v08, v09, v10, v11, v12, v13); } + ff14_functor f; + }; + + struct freefunc15 : public exprtk::ifunction + { + using exprtk::ifunction::operator(); + + 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) + { return f(v00, v01, v02, v03, v04, v05, v06, v07, v08, v09, v10, v11, v12, v13, v14); } + ff15_functor f; + }; + template struct type_store { @@ -13481,6 +17112,27 @@ namespace exprtk : size(0) {} + struct deleter + { + #define exprtk_define_process(Type) \ + static inline void process(std::pair& n) \ + { \ + delete n.second; \ + } \ + + exprtk_define_process(variable_node_t ) + exprtk_define_process(vector_t ) + #ifndef exprtk_disable_string_capabilities + exprtk_define_process(stringvar_node_t) + #endif + + #undef exprtk_define_process + + template + static inline void process(std::pair&) + {} + }; + inline bool symbol_exists(const std::string& symbol_name) const { if (symbol_name.empty()) @@ -13518,7 +17170,7 @@ namespace exprtk return false; else { - tm_const_itr_t itr = map.find(symbol_name); + const tm_const_itr_t itr = map.find(symbol_name); if (map.end() == itr) return false; @@ -13534,14 +17186,14 @@ namespace exprtk { for (std::size_t i = 0; i < details::reserved_symbols_size; ++i) { - if (details::imatch(symbol_name,details::reserved_symbols[i])) + if (details::imatch(symbol_name, details::reserved_symbols[i])) { return false; } } } - tm_itr_t itr = map.find(symbol_name); + const tm_itr_t itr = map.find(symbol_name); if (map.end() == itr) { @@ -13556,7 +17208,7 @@ namespace exprtk { static inline std::pair make(std::pair v, const bool is_const = false) { - return std::make_pair(is_const,new vector_t(v.first,v.second)); + return std::make_pair(is_const, new vector_t(v.first, v.second)); } }; @@ -13565,7 +17217,15 @@ namespace exprtk template static inline std::pair make(std::vector& v, const bool is_const = false) { - return std::make_pair(is_const,new vector_t(v)); + return std::make_pair(is_const, new vector_t(v)); + } + }; + + struct tie_vecview + { + static inline std::pair make(exprtk::vector_view& v, const bool is_const = false) + { + return std::make_pair(is_const, new vector_t(v)); } }; @@ -13574,31 +17234,41 @@ namespace exprtk template static inline std::pair make(std::deque& v, const bool is_const = false) { - return std::make_pair(is_const,new vector_t(v)); + return std::make_pair(is_const, new vector_t(v)); } }; template inline bool add(const std::string& symbol_name, T (&v)[v_size], const bool is_const = false) { - return add_impl >(symbol_name,std::make_pair(v,v_size),is_const); + return add_impl > + (symbol_name, std::make_pair(v,v_size), is_const); } inline bool add(const std::string& symbol_name, T* v, const std::size_t v_size, const bool is_const = false) { - return add_impl >(symbol_name,std::make_pair(v,v_size),is_const); + return add_impl > + (symbol_name, std::make_pair(v,v_size), is_const); } template inline bool add(const std::string& symbol_name, std::vector& v, const bool is_const = false) { - return add_impl&>(symbol_name,v,is_const); + return add_impl&> + (symbol_name, v, is_const); + } + + inline bool add(const std::string& symbol_name, exprtk::vector_view& v, const bool is_const = false) + { + return add_impl&> + (symbol_name, v, is_const); } template inline bool add(const std::string& symbol_name, std::deque& v, const bool is_const = false) { - return add_impl&>(symbol_name,v,is_const); + return add_impl&> + (symbol_name, v, is_const); } inline bool add(const std::string& symbol_name, RawType& t, const bool is_const = false) @@ -13607,13 +17277,13 @@ namespace exprtk { static inline std::pair make(T& t,const bool is_const = false) { - return std::make_pair(is_const,new variable_node_t(t)); + return std::make_pair(is_const, new variable_node_t(t)); } #ifndef exprtk_disable_string_capabilities static inline std::pair make(std::string& t,const bool is_const = false) { - return std::make_pair(is_const,new stringvar_node_t(t)); + return std::make_pair(is_const, new stringvar_node_t(t)); } #endif @@ -13633,18 +17303,7 @@ namespace exprtk } }; - if (symbol_name.size() > 1) - { - for (std::size_t i = 0; i < details::reserved_symbols_size; ++i) - { - if (details::imatch(symbol_name,details::reserved_symbols[i])) - { - return false; - } - } - } - - tm_itr_t itr = map.find(symbol_name); + const tm_itr_t itr = map.find(symbol_name); if (map.end() == itr) { @@ -13657,7 +17316,7 @@ namespace exprtk inline type_ptr get(const std::string& symbol_name) const { - tm_const_itr_t itr = map.find(symbol_name); + const tm_const_itr_t itr = map.find(symbol_name); if (map.end() == itr) return reinterpret_cast(0); @@ -13705,20 +17364,10 @@ namespace exprtk inline bool remove(const std::string& symbol_name, const bool delete_node = true) { - tm_itr_t itr = map.find(symbol_name); + const tm_itr_t itr = map.find(symbol_name); if (map.end() != itr) { - struct deleter - { - static inline void process(std::pair& n) { delete n.second; } - static inline void process(std::pair& n) { delete n.second; } - #ifndef exprtk_disable_string_capabilities - static inline void process(std::pair& n) { delete n.second; } - #endif - static inline void process(std::pair&) { } - }; - if (delete_node) { deleter::process((*itr).second); @@ -13745,7 +17394,8 @@ namespace exprtk static RawType null_type = init_type::set(RawType()); - tm_const_itr_t itr = map.find(symbol_name); + const tm_const_itr_t itr = map.find(symbol_name); + if (map.end() == itr) return null_type; else @@ -13754,22 +17404,12 @@ namespace exprtk inline void clear(const bool delete_node = true) { - struct deleter - { - static inline void process(std::pair& n) { delete n.second; } - static inline void process(std::pair& n) { delete n.second; } - static inline void process(std::pair&) { } - #ifndef exprtk_disable_string_capabilities - static inline void process(std::pair& n) { delete n.second; } - #endif - }; - if (!map.empty()) { if (delete_node) { tm_itr_t itr = map.begin(); - tm_itr_t end = map.end(); + tm_itr_t end = map.end (); while (end != itr) { @@ -13793,7 +17433,7 @@ namespace exprtk if (!map.empty()) { tm_const_itr_t itr = map.begin(); - tm_const_itr_t end = map.end(); + tm_const_itr_t end = map.end (); while (end != itr) { @@ -13815,7 +17455,7 @@ namespace exprtk if (!map.empty()) { tm_const_itr_t itr = map.begin(); - tm_const_itr_t end = map.end(); + tm_const_itr_t end = map.end (); while (end != itr) { @@ -13829,37 +17469,38 @@ namespace exprtk } }; - typedef details::expression_node* expression_ptr; - typedef typename details::variable_node variable_t; - typedef typename details::vector_holder vector_holder_t; - typedef variable_t* variable_ptr; + typedef details::expression_node* expression_ptr; + typedef typename details::variable_node variable_t; + typedef typename details::vector_holder vector_holder_t; + typedef variable_t* variable_ptr; #ifndef exprtk_disable_string_capabilities typedef typename details::stringvar_node stringvar_t; - typedef stringvar_t* stringvar_ptr; + typedef stringvar_t* stringvar_ptr; #endif - typedef ifunction function_t; - typedef ivararg_function vararg_function_t; - typedef igeneric_function generic_function_t; - typedef function_t* function_ptr; - typedef vararg_function_t* vararg_function_ptr; - typedef generic_function_t* generic_function_ptr; + typedef ifunction function_t; + typedef ivararg_function vararg_function_t; + typedef igeneric_function generic_function_t; + typedef function_t* function_ptr; + typedef vararg_function_t* vararg_function_ptr; + typedef generic_function_t* generic_function_ptr; static const std::size_t lut_size = 256; // Symbol Table Holder - struct st_holder + struct control_block { struct st_data { - type_store,T> variable_store; + type_store variable_store; + type_store function_store; + type_store vararg_function_store; + type_store generic_function_store; + type_store string_function_store; + type_store overload_function_store; + type_store vector_store; #ifndef exprtk_disable_string_capabilities - type_store,std::string> stringvar_store; + type_store stringvar_store; #endif - 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; st_data() { @@ -13874,32 +17515,76 @@ namespace exprtk } } + ~st_data() + { + for (std::size_t i = 0; i < free_function_list_.size(); ++i) + { + delete free_function_list_[i]; + } + } + inline bool is_reserved_symbol(const std::string& symbol) const { return (reserved_symbol_table_.end() != reserved_symbol_table_.find(symbol)); } - std::list local_symbol_list_; - std::list local_stringvar_list_; - std::set reserved_symbol_table_; + static inline st_data* create() + { + return (new st_data); + } + + static inline void destroy(st_data*& sd) + { + delete sd; + sd = reinterpret_cast(0); + } + + std::list local_symbol_list_; + std::list local_stringvar_list_; + std::set reserved_symbol_table_; + std::vector*> free_function_list_; }; - st_holder() + control_block() : ref_count(1), - data_(new st_data) + data_(st_data::create()) {} - st_holder(st_data* data) + explicit control_block(st_data* data) : ref_count(1), data_(data) {} - ~st_holder() + ~control_block() { if (data_ && (0 == ref_count)) { - delete data_; - data_ = 0; + st_data::destroy(data_); + } + } + + static inline control_block* create() + { + return (new control_block); + } + + template + static inline void destroy(control_block*& cntrl_blck, SymTab* sym_tab) + { + if (cntrl_blck) + { + if ( + (0 != cntrl_blck->ref_count) && + (0 == --cntrl_blck->ref_count) + ) + { + if (sym_tab) + sym_tab->clear(); + + delete cntrl_blck; + } + + cntrl_blck = 0; } } @@ -13910,50 +17595,38 @@ namespace exprtk public: symbol_table() - : holder_(new st_holder) + : control_block_(control_block::create()) { clear(); } ~symbol_table() { - if (holder_) - { - if (0 == --holder_->ref_count) - { - clear(); - delete holder_; - } - } + control_block::destroy(control_block_,this); } symbol_table(const symbol_table& st) { - holder_ = st.holder_; - holder_->ref_count++; + control_block_ = st.control_block_; + control_block_->ref_count++; } inline symbol_table& operator=(const symbol_table& st) { - if (holder_) + if (this != &st) { - if (0 == --holder_->ref_count) - { - delete holder_; - } + control_block::destroy(control_block_,reinterpret_cast*>(0)); - holder_ = 0; + control_block_ = st.control_block_; + control_block_->ref_count++; } - holder_ = st.holder_; - holder_->ref_count++; - - return *this; + return (*this); } - inline bool operator==(const symbol_table& st) + inline bool operator==(const symbol_table& st) const { - return (this == &st) || (holder_ == st.holder_); + return (this == &st) || (control_block_ == st.control_block_); } inline void clear_variables(const bool delete_node = true) @@ -13978,13 +17651,19 @@ namespace exprtk local_data().vector_store.clear(); } + inline void clear_local_constants() + { + local_data().local_symbol_list_.clear(); + } + inline void clear() { if (!valid()) return; - clear_variables(); - clear_functions(); - clear_strings (); - clear_vectors (); + clear_variables (); + clear_functions (); + clear_strings (); + clear_vectors (); + clear_local_constants(); } inline std::size_t variable_count() const @@ -14092,6 +17771,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 @@ -14193,7 +17882,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) @@ -14208,7 +17897,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 @@ -14221,7 +17910,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 @@ -14249,14 +17938,7 @@ namespace exprtk return local_data().vararg_function_store.add(vararg_function_name,vararg_function); } - enum func_type - { - e_ft_unknown = 0, - e_ft_basicfunc = 1, - e_ft_strfunc = 2 - }; - - inline bool add_function(const std::string& function_name, generic_function_t& function, const func_type ft = e_ft_basicfunc) + inline bool add_function(const std::string& function_name, generic_function_t& function) { if (!valid()) return false; @@ -14264,14 +17946,106 @@ namespace exprtk return false; else if (symbol_exists(function_name)) return false; - else if (std::string::npos != function.parameter_sequence.find_first_not_of("STV*?|")) + else + { + switch (function.rtrn_type) + { + case generic_function_t::e_rtrn_scalar : + return (std::string::npos == function.parameter_sequence.find_first_not_of("STVZ*?|")) ? + local_data().generic_function_store.add(function_name,function) : false; + + case generic_function_t::e_rtrn_string : + return (std::string::npos == function.parameter_sequence.find_first_not_of("STVZ*?|")) ? + local_data().string_function_store.add(function_name,function) : false; + + case generic_function_t::e_rtrn_overload : + return (std::string::npos == function.parameter_sequence.find_first_not_of("STVZ*?|:")) ? + local_data().overload_function_store.add(function_name,function) : false; + } + } + + return false; + } + + #define exprtk_define_freefunction(NN) \ + inline bool add_function(const std::string& function_name, ff##NN##_functor function) \ + { \ + if (!valid()) \ + { return false; } \ + if (!valid_symbol(function_name)) \ + { return false; } \ + if (symbol_exists(function_name)) \ + { return false; } \ + \ + exprtk::ifunction* ifunc = new freefunc##NN(function); \ + \ + local_data().free_function_list_.push_back(ifunc); \ + \ + return add_function(function_name,(*local_data().free_function_list_.back())); \ + } \ + + exprtk_define_freefunction(00) exprtk_define_freefunction(01) + exprtk_define_freefunction(02) exprtk_define_freefunction(03) + exprtk_define_freefunction(04) exprtk_define_freefunction(05) + exprtk_define_freefunction(06) exprtk_define_freefunction(07) + exprtk_define_freefunction(08) exprtk_define_freefunction(09) + exprtk_define_freefunction(10) exprtk_define_freefunction(11) + exprtk_define_freefunction(12) exprtk_define_freefunction(13) + exprtk_define_freefunction(14) exprtk_define_freefunction(15) + + #undef exprtk_define_freefunction + + inline bool add_reserved_function(const std::string& function_name, function_t& function) + { + if (!valid()) + return false; + else if (!valid_symbol(function_name,false)) + return false; + else if (symbol_exists(function_name,false)) + return false; + else + return local_data().function_store.add(function_name,function); + } + + inline bool add_reserved_function(const std::string& vararg_function_name, vararg_function_t& vararg_function) + { + if (!valid()) + return false; + else if (!valid_symbol(vararg_function_name,false)) + return false; + else if (symbol_exists(vararg_function_name,false)) return false; - else if (e_ft_basicfunc == ft) - return local_data().generic_function_store.add(function_name,function); - else if (e_ft_strfunc == ft) - return local_data().string_function_store.add(function_name, function); else + return local_data().vararg_function_store.add(vararg_function_name,vararg_function); + } + + inline bool add_reserved_function(const std::string& function_name, generic_function_t& function) + { + if (!valid()) + return false; + else if (!valid_symbol(function_name,false)) return false; + else if (symbol_exists(function_name,false)) + return false; + else + { + switch (function.rtrn_type) + { + case generic_function_t::e_rtrn_scalar : + return (std::string::npos == function.parameter_sequence.find_first_not_of("STVZ*?|")) ? + local_data().generic_function_store.add(function_name,function) : false; + + case generic_function_t::e_rtrn_string : + return (std::string::npos == function.parameter_sequence.find_first_not_of("STVZ*?|")) ? + local_data().string_function_store.add(function_name,function) : false; + + case generic_function_t::e_rtrn_overload : + return (std::string::npos == function.parameter_sequence.find_first_not_of("STVZ*?|:")) ? + local_data().overload_function_store.add(function_name,function) : false; + } + } + + return false; } template @@ -14295,8 +18069,10 @@ namespace exprtk return false; else if (symbol_exists(vector_name)) return false; + 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 @@ -14308,12 +18084,13 @@ namespace exprtk return false; else if (symbol_exists(vector_name)) return false; + else if (0 == v.size()) + return false; else return local_data().vector_store.add(vector_name,v); } - template - inline bool add_vector(const std::string& vector_name, std::deque& v) + inline bool add_vector(const std::string& vector_name, exprtk::vector_view& v) { if (!valid()) return false; @@ -14321,6 +18098,8 @@ namespace exprtk return false; else if (symbol_exists(vector_name)) return false; + else if (0 == v.size()) + return false; else return local_data().vector_store.add(vector_name,v); } @@ -14371,12 +18150,13 @@ namespace exprtk { return add_pi () && add_epsilon () && - add_infinity(); + add_infinity() ; } inline bool add_pi() { - static const T local_pi = T(details::numeric::constant::pi); + const typename details::numeric::details::number_type::type num_type; + static const T local_pi = details::numeric::details::const_pi_impl(num_type); return add_constant("pi",local_pi); } @@ -14392,6 +18172,12 @@ namespace exprtk return add_constant("inf",local_infinity); } + template + inline bool add_package(Package& package) + { + return package.register_package(*this); + } + template class Sequence> inline std::size_t get_variable_list(Sequence,Allocator>& vlist) const @@ -14444,11 +18230,12 @@ namespace exprtk return local_data().vector_store.get_list(vlist); } - inline bool symbol_exists(const std::string& symbol_name) const + inline bool symbol_exists(const std::string& symbol_name, const bool check_reserved_symb = true) const { /* - Will return true if symbol_name exists as either a reserved symbol, - variable, stringvar or function name in any of the type stores. + Function will return true if symbol_name exists as either a + reserved symbol, variable, stringvar, vector or function name + in any of the type stores. */ if (!valid()) return false; @@ -14458,9 +18245,11 @@ 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 (local_data().is_reserved_symbol(symbol_name)) + else if (check_reserved_symb && local_data().is_reserved_symbol(symbol_name)) return true; else return false; @@ -14548,7 +18337,7 @@ namespace exprtk inline bool valid() const { // Symbol table sanity check. - return holder_ && holder_->data_; + return control_block_ && control_block_->data_; } inline void load_from(const symbol_table& st) @@ -14608,7 +18397,22 @@ namespace exprtk for (std::size_t i = 0; i < name_list.size(); ++i) { exprtk::igeneric_function& ifunc = *st.get_string_function(name_list[i]); - add_function(name_list[i],ifunc,e_ft_strfunc); + add_function(name_list[i],ifunc); + } + } + } + + { + 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); } } } @@ -14616,41 +18420,73 @@ namespace exprtk private: - inline bool valid_symbol(const std::string& symbol) const + inline bool valid_symbol(const std::string& symbol, const bool check_reserved_symb = true) const { if (symbol.empty()) return false; - if (!details::is_letter(symbol[0])) + else if (!details::is_letter(symbol[0])) return false; else if (symbol.size() > 1) { for (std::size_t i = 1; i < symbol.size(); ++i) { if ( - (!details::is_letter(symbol[i])) && - (!details:: is_digit(symbol[i])) && + !details::is_letter_or_digit(symbol[i]) && ('_' != symbol[i]) ) { - return false; + if ((i < (symbol.size() - 1)) && ('.' == symbol[i])) + continue; + else + return false; + } + } + } + + return (check_reserved_symb) ? (!local_data().is_reserved_symbol(symbol)) : true; + } + + inline bool valid_function(const std::string& symbol) const + { + if (symbol.empty()) + return false; + else if (!details::is_letter(symbol[0])) + return false; + else if (symbol.size() > 1) + { + for (std::size_t i = 1; i < symbol.size(); ++i) + { + if ( + !details::is_letter_or_digit(symbol[i]) && + ('_' != symbol[i]) + ) + { + if ((i < (symbol.size() - 1)) && ('.' == symbol[i])) + continue; + else + return false; } } } - return (!local_data().is_reserved_symbol(symbol)); + return true; } - inline typename st_holder::st_data& local_data() + typedef typename control_block::st_data local_data_t; + + inline local_data_t& local_data() { - return *(holder_->data_); + return *(control_block_->data_); } - inline const typename st_holder::st_data& local_data() const + inline const local_data_t& local_data() const { - return *(holder_->data_); + return *(control_block_->data_); } - st_holder* holder_; + control_block* control_block_; + + friend class parser; }; template @@ -14663,8 +18499,9 @@ namespace exprtk typedef details::expression_node* expression_ptr; typedef details::vector_holder* vector_holder_ptr; + typedef std::vector > symtab_list_t; - struct expression_holder + struct control_block { enum data_type { @@ -14684,7 +18521,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) @@ -14696,22 +18533,29 @@ namespace exprtk }; typedef std::vector local_data_list_t; + typedef results_context results_context_t; - expression_holder() + control_block() : ref_count(0), - expr(0) + expr (0), + results (0), + retinv_null(false), + return_invoked(&retinv_null) {} - expression_holder(expression_ptr e) + explicit control_block(expression_ptr e) : ref_count(1), - expr(e) + expr (e), + results (0), + retinv_null(false), + return_invoked(&retinv_null) {} - ~expression_holder() + ~control_block() { if (expr && details::branch_deletable(expr)) { - delete expr; + destroy_node(expr); } if (!local_data_list.empty()) @@ -14726,24 +18570,53 @@ namespace exprtk case e_vecholder : delete reinterpret_cast(local_data_list[i].pointer); break; - case e_data : delete (T*)(local_data_list[i].pointer); + case e_data : delete reinterpret_cast(local_data_list[i].pointer); break; - case e_vecdata : delete [] (T*)(local_data_list[i].pointer); + case e_vecdata : delete [] reinterpret_cast(local_data_list[i].pointer); break; - case e_string : delete (std::string*)(local_data_list[i].pointer); + case e_string : delete reinterpret_cast(local_data_list[i].pointer); break; default : break; } } } + + if (results) + { + delete results; + } + } + + static inline control_block* create(expression_ptr e) + { + return new control_block(e); + } + + static inline void destroy(control_block*& cntrl_blck) + { + if (cntrl_blck) + { + if ( + (0 != cntrl_blck->ref_count) && + (0 == --cntrl_blck->ref_count) + ) + { + delete cntrl_blck; + } + + cntrl_blck = 0; + } } std::size_t ref_count; expression_ptr expr; local_data_list_t local_data_list; + results_context_t* results; + bool retinv_null; + bool* return_invoked; friend class function_compositor; }; @@ -14751,41 +18624,51 @@ namespace exprtk public: expression() - : expression_holder_(0) + : control_block_(0) { set_expression(new details::null_node()); } expression(const expression& e) - : expression_holder_(e.expression_holder_), - symbol_table_(e.symbol_table_) + : control_block_ (e.control_block_ ), + symbol_table_list_(e.symbol_table_list_) + { + control_block_->ref_count++; + } + + explicit expression(const symbol_table& symbol_table) + : control_block_(0) { - expression_holder_->ref_count++; + set_expression(new details::null_node()); + symbol_table_list_.push_back(symbol_table); } inline expression& operator=(const expression& e) { if (this != &e) { - if (expression_holder_) + if (control_block_) { - if (0 == --expression_holder_->ref_count) + if ( + (0 != control_block_->ref_count) && + (0 == --control_block_->ref_count) + ) { - delete expression_holder_; + delete control_block_; } - expression_holder_ = 0; + control_block_ = 0; } - expression_holder_ = e.expression_holder_; - expression_holder_->ref_count++; - symbol_table_ = e.symbol_table_; + control_block_ = e.control_block_; + control_block_->ref_count++; + symbol_table_list_ = e.symbol_table_list_; } return *this; } - inline bool operator==(const expression& e) + inline bool operator==(const expression& e) const { return (this == &e); } @@ -14793,43 +18676,32 @@ namespace exprtk inline bool operator!() const { return ( - (0 == expression_holder_ ) || - (0 == expression_holder_->expr) + (0 == control_block_ ) || + (0 == control_block_->expr) ); } inline expression& release() { - if (expression_holder_) - { - if (0 == --expression_holder_->ref_count) - { - delete expression_holder_; - } + control_block::destroy(control_block_); - expression_holder_ = 0; - } - - return *this; + return (*this); } ~expression() { - if (expression_holder_) - { - if (0 == --expression_holder_->ref_count) - { - delete expression_holder_; - } - } + control_block::destroy(control_block_); } inline T value() const { - return expression_holder_->expr->value(); + assert(control_block_ ); + assert(control_block_->expr); + + return control_block_->expr->value(); } - inline T operator()() const + inline T operator() () const { return value(); } @@ -14846,34 +18718,57 @@ namespace exprtk inline void register_symbol_table(symbol_table& st) { - symbol_table_ = st; + symbol_table_list_.push_back(st); } - inline const symbol_table& get_symbol_table() const + inline const symbol_table& get_symbol_table(const std::size_t& index = 0) const { - return symbol_table_; + return symbol_table_list_[index]; } - inline symbol_table& get_symbol_table() + inline symbol_table& get_symbol_table(const std::size_t& index = 0) { - return symbol_table_; + return symbol_table_list_[index]; + } + + typedef results_context results_context_t; + + inline const results_context_t& results() const + { + if (control_block_->results) + return (*control_block_->results); + else + { + static const results_context_t null_results; + return null_results; + } + } + + inline bool return_invoked() const + { + return (*control_block_->return_invoked); } private: + inline symtab_list_t get_symbol_table_list() const + { + return symbol_table_list_; + } + inline void set_expression(const expression_ptr expr) { if (expr) { - if (expression_holder_) + if (control_block_) { - if (0 == --expression_holder_->ref_count) + if (0 == --control_block_->ref_count) { - delete expression_holder_; + delete control_block_; } } - expression_holder_ = new expression_holder(expr); + control_block_ = control_block::create(expr); } } @@ -14881,13 +18776,13 @@ namespace exprtk { if (expr) { - if (expression_holder_) + if (control_block_) { - expression_holder_-> + control_block_-> local_data_list.push_back( - typename expression::expression_holder:: + typename expression::control_block:: data_pack(reinterpret_cast(expr), - expression_holder::e_expr)); + control_block::e_expr)); } } } @@ -14896,49 +18791,71 @@ namespace exprtk { if (vec_holder) { - if (expression_holder_) + if (control_block_) { - expression_holder_-> + control_block_-> local_data_list.push_back( - typename expression::expression_holder:: + typename expression::control_block:: data_pack(reinterpret_cast(vec_holder), - expression_holder::e_vecholder)); + control_block::e_vecholder)); } } } - inline void register_local_data(void* data, const std::size_t& size = 0, const bool vectype = false) + inline void register_local_data(void* data, const std::size_t& size = 0, const std::size_t data_mode = 0) { if (data) { - if (expression_holder_) + if (control_block_) { - expression_holder_-> + typename control_block::data_type dt = control_block::e_data; + + switch (data_mode) + { + case 0 : dt = control_block::e_data; break; + case 1 : dt = control_block::e_vecdata; break; + case 2 : dt = control_block::e_string; break; + } + + control_block_-> local_data_list.push_back( - typename expression::expression_holder:: - data_pack(reinterpret_cast(data), - vectype ? expression_holder::e_vecdata : - expression_holder::e_data, - size)); + typename expression::control_block:: + data_pack(reinterpret_cast(data), dt, size)); } } } - inline const typename expression_holder::local_data_list_t& local_data_list() + inline const typename control_block::local_data_list_t& local_data_list() { - if (expression_holder_) + if (control_block_) { - return expression_holder_->local_data_list; + return control_block_->local_data_list; } else { - static typename expression_holder::local_data_list_t null_local_data_list; + static typename control_block::local_data_list_t null_local_data_list; return null_local_data_list; } } - expression_holder* expression_holder_; - symbol_table symbol_table_; + inline void register_return_results(results_context_t* rc) + { + if (control_block_ && rc) + { + control_block_->results = rc; + } + } + + inline void set_retinvk(bool* retinvk_ptr) + { + if (control_block_) + { + control_block_->return_invoked = retinvk_ptr; + } + } + + control_block* control_block_; + symtab_list_t symbol_table_list_; friend class parser; friend class expression_helper; @@ -14952,30 +18869,41 @@ namespace exprtk static inline bool is_constant(const expression& expr) { - return details::is_constant_node(expr.expression_holder_->expr); + return details::is_constant_node(expr.control_block_->expr); } static inline bool is_variable(const expression& expr) { - return details::is_variable_node(expr.expression_holder_->expr); + return details::is_variable_node(expr.control_block_->expr); } static inline bool is_unary(const expression& expr) { - return details::is_unary_node(expr.expression_holder_->expr); + return details::is_unary_node(expr.control_block_->expr); } static inline bool is_binary(const expression& expr) { - return details::is_binary_node(expr.expression_holder_->expr); + return details::is_binary_node(expr.control_block_->expr); } static inline bool is_function(const expression& expr) { - return details::is_function(expr.expression_holder_->expr); + return details::is_function(expr.control_block_->expr); + } + + static inline bool is_null(const expression& expr) + { + return details::is_null_node(expr.control_block_->expr); } }; + template + inline bool is_valid(const expression& expr) + { + return !expression_helper::is_null(expr); + } + namespace parser_error { enum error_mode @@ -14986,7 +18914,8 @@ namespace exprtk e_numeric = 4, e_symtab = 5, e_lexer = 6, - e_helper = 7 + e_helper = 7, + e_parser = 8 }; struct type @@ -15000,28 +18929,36 @@ namespace exprtk lexer::token token; error_mode mode; std::string diagnostic; + std::string src_location; std::string error_line; std::size_t line_no; std::size_t column_no; }; - inline type make_error(error_mode mode, const std::string& diagnostic = "") + inline type make_error(const error_mode mode, + const std::string& diagnostic = "", + const std::string& src_location = "") { type t; - t.mode = mode; - t.token.type = lexer::token::e_error; - t.diagnostic = diagnostic; - exprtk_debug(((diagnostic + "\n").c_str())); + t.mode = mode; + t.token.type = lexer::token::e_error; + t.diagnostic = diagnostic; + t.src_location = src_location; + exprtk_debug(("%s\n",diagnostic .c_str())); return t; } - inline type make_error(error_mode mode, const lexer::token& tk, const std::string& diagnostic = "") + inline type make_error(const error_mode mode, + const lexer::token& tk, + const std::string& diagnostic = "", + const std::string& src_location = "") { type t; t.mode = mode; t.token = tk; t.diagnostic = diagnostic; - exprtk_debug(((diagnostic + "\n").c_str())); + t.src_location = src_location; + exprtk_debug(("%s\n",diagnostic .c_str())); return t; } @@ -15036,6 +18973,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"); } } @@ -15055,7 +18993,7 @@ namespace exprtk for (std::size_t i = error.token.position; i > 0; --i) { - const char c = expression[i]; + const details::char_t c = expression[i]; if (('\n' == c) || ('\r' == c)) { @@ -15091,8 +19029,17 @@ namespace exprtk } } + namespace details + { + template + inline void disable_type_checking(Parser& p) + { + p.state_.type_check_enabled = false; + } + } + template - class parser + class parser : public lexer::parser_helper { private: @@ -15129,8 +19076,6 @@ namespace exprtk typedef details::binary_node binary_node_t; typedef details::trinary_node trinary_node_t; typedef details::quaternary_node quaternary_node_t; - typedef details::quinary_node quinary_node_t; - typedef details::senary_node senary_node_t; typedef details::conditional_node conditional_node_t; typedef details::cons_conditional_node cons_conditional_node_t; typedef details::while_loop_node while_loop_node_t; @@ -15144,9 +19089,11 @@ namespace exprtk typedef details::switch_node switch_node_t; typedef details::variable_node variable_node_t; typedef details::vector_elem_node vector_elem_node_t; + typedef details::rebasevector_elem_node rebasevector_elem_node_t; + typedef details::rebasevector_celem_node rebasevector_celem_node_t; typedef details::vector_node vector_node_t; + typedef details::range_pack range_t; #ifndef exprtk_disable_string_capabilities - typedef details::range_pack range_t; typedef details::stringvar_node stringvar_node_t; typedef details::string_literal_node string_literal_node_t; typedef details::string_range_node string_range_node_t; @@ -15155,23 +19102,29 @@ namespace exprtk typedef details::string_concat_node string_concat_node_t; typedef details::assignment_string_node assignment_string_node_t; typedef details::assignment_string_range_node assignment_string_range_node_t; + typedef details::conditional_string_node conditional_string_node_t; + typedef details::cons_conditional_str_node cons_conditional_str_node_t; #endif typedef details::assignment_node assignment_node_t; - typedef details::assignment_vec_elem_node assignment_vec_elem_node_t; + typedef details::assignment_vec_elem_node assignment_vec_elem_node_t; + typedef details::assignment_rebasevec_elem_node assignment_rebasevec_elem_node_t; + typedef details::assignment_rebasevec_celem_node assignment_rebasevec_celem_node_t; typedef details::assignment_vec_node assignment_vec_node_t; typedef details::assignment_vecvec_node assignment_vecvec_node_t; typedef details::scand_node scand_node_t; typedef details::scor_node scor_node_t; typedef lexer::token token_t; typedef expression_node_t* expression_node_ptr; + typedef expression expression_t; typedef symbol_table symbol_table_t; + 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; @@ -15184,29 +19137,34 @@ namespace exprtk typedef std::map inv_binary_op_map_t; typedef std::multimap base_ops_map_t; + typedef std::set disabled_func_set_t; + + typedef details::T0oT1_define vov_t; + typedef details::T0oT1_define cov_t; + typedef details::T0oT1_define voc_t; + + typedef details::T0oT1oT2_define vovov_t; + typedef details::T0oT1oT2_define vovoc_t; + typedef details::T0oT1oT2_define vocov_t; + typedef details::T0oT1oT2_define covov_t; + typedef details::T0oT1oT2_define covoc_t; + typedef details::T0oT1oT2_define cocov_t; + typedef details::T0oT1oT2_define vococ_t; + + typedef details::T0oT1oT2oT3_define vovovov_t; + typedef details::T0oT1oT2oT3_define vovovoc_t; + typedef details::T0oT1oT2oT3_define vovocov_t; + typedef details::T0oT1oT2oT3_define vocovov_t; + typedef details::T0oT1oT2oT3_define covovov_t; + + typedef details::T0oT1oT2oT3_define covocov_t; + typedef details::T0oT1oT2oT3_define vocovoc_t; + typedef details::T0oT1oT2oT3_define covovoc_t; + typedef details::T0oT1oT2oT3_define vococov_t; - typedef details::T0oT1_define vov_t; - typedef details::T0oT1_define cov_t; - typedef details::T0oT1_define voc_t; - - typedef details::T0oT1oT2_define vovov_t; - typedef details::T0oT1oT2_define vovoc_t; - typedef details::T0oT1oT2_define vocov_t; - typedef details::T0oT1oT2_define covov_t; - typedef details::T0oT1oT2_define covoc_t; - typedef details::T0oT1oT2_define cocov_t; - typedef details::T0oT1oT2_define vococ_t; - - typedef details::T0oT1oT2oT3_define vovovov_t; - typedef details::T0oT1oT2oT3_define vovovoc_t; - typedef details::T0oT1oT2oT3_define vovocov_t; - typedef details::T0oT1oT2oT3_define vocovov_t; - typedef details::T0oT1oT2oT3_define covovov_t; - - typedef details::T0oT1oT2oT3_define covocov_t; - typedef details::T0oT1oT2oT3_define vocovoc_t; - typedef details::T0oT1oT2oT3_define covovoc_t; - typedef details::T0oT1oT2oT3_define vococov_t; + typedef results_context results_context_t; + + typedef parser_helper prsrhlpr_t; struct scope_element { @@ -15219,9 +19177,13 @@ namespace exprtk e_string }; - typedef variable_node_t* variable_node_ptr; typedef details::vector_holder vector_holder_t; - typedef vector_holder_t* vector_holder_ptr; + typedef variable_node_t* variable_node_ptr; + typedef vector_holder_t* vector_holder_ptr; + typedef expression_node_t* expression_node_ptr; + #ifndef exprtk_disable_string_capabilities + typedef stringvar_node_t* stringvar_node_ptr; + #endif scope_element() : name("???"), @@ -15235,6 +19197,9 @@ namespace exprtk data (0), var_node(0), vec_node(0) + #ifndef exprtk_disable_string_capabilities + ,str_node(0) + #endif {} bool operator < (const scope_element& se) const @@ -15255,6 +19220,24 @@ namespace exprtk return (name < se.name); } + void clear() + { + name = "???"; + size = std::numeric_limits::max(); + index = std::numeric_limits::max(); + depth = std::numeric_limits::max(); + type = e_none; + active = false; + ref_count = 0; + ip_index = 0; + data = 0; + var_node = 0; + vec_node = 0; + #ifndef exprtk_disable_string_capabilities + str_node = 0; + #endif + } + std::string name; std::size_t size; std::size_t index; @@ -15264,18 +19247,22 @@ namespace exprtk element_type type; bool active; void* data; - variable_node_ptr var_node; - vector_holder_ptr vec_node; + expression_node_ptr var_node; + vector_holder_ptr vec_node; + #ifndef exprtk_disable_string_capabilities + stringvar_node_ptr str_node; + #endif }; class scope_element_manager { public: - typedef variable_node_t* variable_node_ptr; - typedef parser parser_t; + typedef expression_node_t* expression_node_ptr; + 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) {} @@ -15301,14 +19288,16 @@ namespace exprtk inline scope_element& get_element(const std::string& var_name, const std::size_t index = std::numeric_limits::max()) { + const std::size_t current_depth = parser_.state_.scope_depth; + for (std::size_t i = 0; i < element_.size(); ++i) { scope_element& se = element_[i]; - if (se.depth > parser_.scope_depth_) - return null_element_; + if (se.depth > current_depth) + continue; else if ( - (se.name == var_name) && + details::imatch(se.name, var_name) && (se.index == index) ) return se; @@ -15317,15 +19306,41 @@ namespace exprtk return null_element_; } + inline scope_element& get_active_element(const std::string& var_name, + const std::size_t index = std::numeric_limits::max()) + { + const std::size_t current_depth = parser_.state_.scope_depth; + + for (std::size_t i = 0; i < element_.size(); ++i) + { + scope_element& se = element_[i]; + + if (se.depth > current_depth) + continue; + else if ( + details::imatch(se.name, var_name) && + (se.index == index) && + (se.active) + ) + return se; + } + + return null_element_; + } + inline bool add_element(const scope_element& se) { - for (std::size_t j = 0; j < element_.size(); ++j) + for (std::size_t i = 0; i < element_.size(); ++i) { + scope_element& cse = element_[i]; + if ( - (element_[j].name == se.name ) && - (element_[j].depth <= se.depth) && - (element_[j].index == se.index) && - (element_[j].size == se.size ) + details::imatch(cse.name, se.name) && + (cse.depth <= se.depth) && + (cse.index == se.index) && + (cse.size == se.size ) && + (cse.type == se.type ) && + (cse.active) ) return false; } @@ -15338,37 +19353,58 @@ namespace exprtk inline void deactivate(const std::size_t& scope_depth) { - for (std::size_t j = 0; j < element_.size(); ++j) + exprtk_debug(("deactivate() - Scope depth: %d\n", + static_cast(parser_.state_.scope_depth))); + + for (std::size_t i = 0; i < element_.size(); ++i) { - if (element_[j].depth >= scope_depth) + scope_element& se = element_[i]; + + if (se.active && (se.depth >= scope_depth)) { - element_[j].active = false; + exprtk_debug(("deactivate() - element[%02d] '%s'\n", + static_cast(i), + se.name.c_str())); + + se.active = false; } } } - void cleanup() + inline void free_element(scope_element& se) { - for (std::size_t i = 0; i < element_.size(); ++i) + exprtk_debug(("free_element() - se[%s]\n", se.name.c_str())); + + switch (se.type) { - if (element_[i].var_node) - { - delete element_[i].var_node; - } + case scope_element::e_variable : delete reinterpret_cast(se.data); + delete se.var_node; + break; - if (element_[i].vec_node) - { - delete element_[i].vec_node; - } + case scope_element::e_vector : delete[] reinterpret_cast(se.data); + delete se.vec_node; + break; - T* data = (T*)(element_[i].data); + case scope_element::e_vecelem : delete se.var_node; + break; - switch (element_[i].type) - { - case scope_element::e_variable : delete data; break; - case scope_element::e_vector : delete [] data; break; - default : break; - } + #ifndef exprtk_disable_string_capabilities + case scope_element::e_string : delete reinterpret_cast(se.data); + delete se.str_node; + break; + #endif + + default : return; + } + + se.clear(); + } + + inline void cleanup() + { + for (std::size_t i = 0; i < element_.size(); ++i) + { + free_element(element_[i]); } element_.clear(); @@ -15381,22 +19417,28 @@ namespace exprtk return ++input_param_cnt_; } - inline variable_node_ptr get_variable(const T& v) + inline expression_node_ptr get_variable(const T& v) { for (std::size_t i = 0; i < element_.size(); ++i) { scope_element& se = element_[i]; - if (se.active && se.var_node) + if ( + se.active && + se.var_node && + details::is_variable_node(se.var_node) + ) { - if (&se.var_node->ref() == (&v)) + variable_node_ptr vn = reinterpret_cast(se.var_node); + + if (&(vn->ref()) == (&v)) { return se.var_node; } } } - return variable_node_ptr(0); + return expression_node_ptr(0); } private: @@ -15415,23 +19457,27 @@ namespace exprtk typedef parser parser_t; - scope_handler(parser& p) + explicit scope_handler(parser& p) : parser_(p) { - parser_.scope_depth_++; + parser_.state_.scope_depth++; #ifdef exprtk_enable_debugging - std::string depth(2 * parser_.scope_depth_,'-'); - exprtk_debug(("%s> Scope Depth: %02d\n",depth.c_str(),static_cast(parser_.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))); #endif } ~scope_handler() { - parser_.scope_depth_--; - parser_.sem_.deactivate(parser_.scope_depth_); + parser_.sem_.deactivate(parser_.state_.scope_depth); + parser_.state_.scope_depth--; #ifdef exprtk_enable_debugging - std::string depth(2 * parser_.scope_depth_,'-'); - exprtk_debug(("<%s Scope Depth: %02d\n",depth.c_str(),static_cast(parser_.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))); #endif } @@ -15442,9107 +19488,14557 @@ namespace exprtk parser_t& parser_; }; - public: - - enum compilation_options + class stack_limit_handler { - e_unknown = 0, - e_replacer = 1, - e_joiner = 2, - e_numeric_check = 4, - e_bracket_check = 8, - e_sequence_check = 16, - e_commutative_check = 32, - e_strength_reduction = 64, - e_disable_vardef = 128, - e_collect_vars = 256, - e_collect_funcs = 512, - e_collect_assings = 1024 - }; + public: - struct unknown_symbol_resolver - { + typedef parser parser_t; - enum usr_symbol_type + explicit stack_limit_handler(parser& p) + : parser_(p), + limit_exceeded_(false) { - e_usr_variable_type = 0, - e_usr_constant_type = 1 - }; - - virtual ~unknown_symbol_resolver() - {} + 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)); + } + } - virtual bool process(const std::string& /*unknown_symbol*/, - usr_symbol_type& st, - T& default_value, - std::string& error_message) + ~stack_limit_handler() { - st = e_usr_variable_type; - default_value = T(0); - error_message = ""; + parser_.state_.stack_depth--; + } - return true; + bool operator!() + { + return limit_exceeded_; } - }; - enum collect_type - { - e_ct_none = 0, - e_ct_variables = 1, - e_ct_functions = 2, - e_ct_assignments = 4 - }; + private: - enum symbol_type - { - e_st_unknown = 0, - e_st_variable = 1, - e_st_vector = 2, - e_st_string = 3, - e_st_function = 4, - e_st_local_variable = 5, - e_st_local_vector = 6, - e_st_local_string = 7 + stack_limit_handler& operator=(const stack_limit_handler&); + + parser_t& parser_; + bool limit_exceeded_; }; - class dependent_entity_collector + struct symtab_store { - public: + symbol_table_list_t symtab_list_; - typedef std::pair symbol_t; - typedef std::vector symbol_list_t; + typedef typename symbol_table_t::local_data_t local_data_t; + typedef typename symbol_table_t::variable_ptr variable_ptr; + typedef typename symbol_table_t::function_ptr function_ptr; + #ifndef exprtk_disable_string_capabilities + typedef typename symbol_table_t::stringvar_ptr stringvar_ptr; + #endif + typedef typename symbol_table_t::vector_holder_ptr vector_holder_ptr; + typedef typename symbol_table_t::vararg_function_ptr vararg_function_ptr; + typedef typename symbol_table_t::generic_function_ptr generic_function_ptr; - dependent_entity_collector(const std::size_t options = e_ct_none) - : options_(options), - collect_variables_ ((options_ & e_ct_variables ) == e_ct_variables ), - collect_functions_ ((options_ & e_ct_functions ) == e_ct_functions ), - collect_assignments_((options_ & e_ct_assignments) == e_ct_assignments) - {} + inline bool empty() const + { + return symtab_list_.empty(); + } - template class Sequence> - inline std::size_t symbols(Sequence& symbols_list) + inline void clear() { - if (!collect_variables_ && !collect_functions_) - return 0; - else if (symbol_name_list_.empty()) - return 0; + symtab_list_.clear(); + } - for (std::size_t i = 0; i < symbol_name_list_.size(); ++i) + inline bool valid() const + { + if (!empty()) { - std::string& s = symbol_name_list_[i].first; - std::transform(s.begin(),s.end(),s.begin(),static_cast(std::tolower)); + for (std::size_t i = 0; i < symtab_list_.size(); ++i) + { + if (symtab_list_[i].valid()) + return true; + } } - std::sort(symbol_name_list_.begin(),symbol_name_list_.end()); - std::unique_copy(symbol_name_list_.begin(), - symbol_name_list_.end(), - std::back_inserter(symbols_list)); + return false; + } - return symbols_list.size(); + inline bool valid_symbol(const std::string& symbol) const + { + if (!symtab_list_.empty()) + return symtab_list_[0].valid_symbol(symbol); + else + return false; } - template class Sequence> - inline std::size_t assignment_symbols(Sequence& assignment_list) + inline bool valid_function_name(const std::string& symbol) const { - if (!collect_assignments_) - return 0; - else if (assignment_name_list_.empty()) - return 0; + if (!symtab_list_.empty()) + return symtab_list_[0].valid_function(symbol); + else + return false; + } - for (std::size_t i = 0; i < assignment_name_list_.size(); ++i) + inline variable_ptr get_variable(const std::string& variable_name) const + { + if (!valid_symbol(variable_name)) + return reinterpret_cast(0); + + variable_ptr result = reinterpret_cast(0); + + for (std::size_t i = 0; i < symtab_list_.size(); ++i) { - std::string& s = assignment_name_list_[i].first; - std::transform(s.begin(),s.end(),s.begin(),static_cast(std::tolower)); - } + if (!symtab_list_[i].valid()) + continue; + else + result = local_data(i) + .variable_store.get(variable_name); - std::sort(assignment_name_list_.begin(),assignment_name_list_.end()); - std::unique_copy(assignment_name_list_.begin(), - assignment_name_list_.end(), - std::back_inserter(assignment_list)); + if (result) break; + } - return assignment_list.size(); + return result; } - void clear() + inline variable_ptr get_variable(const T& var_ref) const { - symbol_name_list_ .clear(); - assignment_name_list_.clear(); - } + variable_ptr result = reinterpret_cast(0); - bool& collect_variables() - { - return collect_variables_; - } + for (std::size_t i = 0; i < symtab_list_.size(); ++i) + { + if (!symtab_list_[i].valid()) + continue; + else + result = local_data(i).variable_store + .get_from_varptr(reinterpret_cast(&var_ref)); - bool& collect_functions() - { - return collect_functions_; + if (result) break; + } + + return result; } - bool& collect_assignments() + #ifndef exprtk_disable_string_capabilities + inline stringvar_ptr get_stringvar(const std::string& string_name) const { - return collect_assignments_; - } + if (!valid_symbol(string_name)) + return reinterpret_cast(0); - private: + stringvar_ptr result = reinterpret_cast(0); - inline void add_symbol(const std::string& symbol, const symbol_type st) - { - switch (st) + for (std::size_t i = 0; i < symtab_list_.size(); ++i) { - case e_st_variable : - case e_st_vector : - case e_st_string : - case e_st_local_variable : - case e_st_local_vector : - case e_st_local_string : - case e_st_function : - if (collect_variables_ || collect_functions_) - symbol_name_list_.push_back(std::make_pair(symbol,st)); - break; + if (!symtab_list_[i].valid()) + continue; + else + result = local_data(i) + .stringvar_store.get(string_name); - default : return; + if (result) break; } + + return result; } + #endif - inline void add_assignment(const std::string& symbol, const symbol_type st) + inline function_ptr get_function(const std::string& function_name) const { - switch (st) + if (!valid_function_name(function_name)) + return reinterpret_cast(0); + + function_ptr result = reinterpret_cast(0); + + for (std::size_t i = 0; i < symtab_list_.size(); ++i) { - case e_st_variable : - case e_st_vector : - case e_st_string : - if (collect_assignments_) - assignment_name_list_.push_back(std::make_pair(symbol,st)); - break; + if (!symtab_list_[i].valid()) + continue; + else + result = local_data(i) + .function_store.get(function_name); - default : return; + if (result) break; } - } - std::size_t options_; - bool collect_variables_; - bool collect_functions_; - bool collect_assignments_; - symbol_list_t symbol_name_list_; - symbol_list_t assignment_name_list_; + return result; + } - friend class parser; - }; + inline vararg_function_ptr get_vararg_function(const std::string& vararg_function_name) const + { + if (!valid_function_name(vararg_function_name)) + return reinterpret_cast(0); - static const std::size_t compile_all_opts = e_replacer + - e_joiner + - e_numeric_check + - e_bracket_check + - e_sequence_check + - e_commutative_check + - e_strength_reduction; + vararg_function_ptr result = reinterpret_cast(0); - parser(const std::size_t compile_options = compile_all_opts) - : compile_options_(compile_options), - resolve_unknown_symbol_(false), - vardef_disabled_((compile_options & e_disable_vardef) == e_disable_vardef), - scope_depth_(0), - unknown_symbol_resolver_(reinterpret_cast(0)), - #ifdef _MSC_VER - #pragma warning(push) - #pragma warning (disable:4355) - #endif - sem_(*this), - #ifdef _MSC_VER - #pragma warning(pop) - #endif - operator_joiner_2_(2), - operator_joiner_3_(3) - { - init_precompilation(); + for (std::size_t i = 0; i < symtab_list_.size(); ++i) + { + if (!symtab_list_[i].valid()) + continue; + else + result = local_data(i) + .vararg_function_store.get(vararg_function_name); - load_operations_map(base_ops_map_); - load_unary_operations_map(unary_op_map_); - load_binary_operations_map(binary_op_map_); - load_inv_binary_operations_map(inv_binary_op_map_); - load_sf3_map(sf3_map_); - load_sf4_map(sf4_map_); + if (result) break; + } - expression_generator_.init_synthesize_map(); - expression_generator_.set_parser(*this); - expression_generator_.set_uom(unary_op_map_); - expression_generator_.set_bom(binary_op_map_); - expression_generator_.set_ibom(inv_binary_op_map_); - expression_generator_.set_sf3m(sf3_map_); - expression_generator_.set_sf4m(sf4_map_); - expression_generator_.set_strength_reduction_state(strength_reduction_enabled()); - } + return result; + } - ~parser() - {} + inline generic_function_ptr get_generic_function(const std::string& function_name) const + { + if (!valid_function_name(function_name)) + return reinterpret_cast(0); - inline void init_precompilation() - { - if (collect_variables_enabled()) - dec_.collect_variables() = true; + generic_function_ptr result = reinterpret_cast(0); - if (collect_functions_enabled()) - dec_.collect_functions() = true; + for (std::size_t i = 0; i < symtab_list_.size(); ++i) + { + if (!symtab_list_[i].valid()) + continue; + else + result = local_data(i) + .generic_function_store.get(function_name); - if (collect_assignments_enabled()) - dec_.collect_assignments() = true; + if (result) break; + } - if (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); - helper_assembly_.token_modifier_list.clear(); - helper_assembly_.register_modifier(&symbol_replacer_); + return result; } - if (commutative_check_enabled()) + inline generic_function_ptr get_string_function(const std::string& function_name) const { - for (std::size_t i = 0; i < details::reserved_words_size; ++i) + 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) { - commutative_inserter_.ignore_symbol(details::reserved_words[i]); + if (!symtab_list_[i].valid()) + continue; + else + result = + local_data(i).string_function_store.get(function_name); + + if (result) break; } - helper_assembly_.token_inserter_list.clear(); - helper_assembly_.register_inserter(&commutative_inserter_); + return result; } - if (joiner_enabled()) + inline generic_function_ptr get_overload_function(const std::string& function_name) const { - helper_assembly_.token_joiner_list.clear(); - helper_assembly_.register_joiner(&operator_joiner_2_); - helper_assembly_.register_joiner(&operator_joiner_3_); - } + if (!valid_function_name(function_name)) + return reinterpret_cast(0); - if ( - numeric_check_enabled () || - bracket_check_enabled () || - sequence_check_enabled() - ) - { - helper_assembly_.token_scanner_list.clear(); + generic_function_ptr result = reinterpret_cast(0); - if (numeric_check_enabled()) + for (std::size_t i = 0; i < symtab_list_.size(); ++i) { - helper_assembly_.register_scanner(&numeric_checker_); - } + if (!symtab_list_[i].valid()) + continue; + else + result = + local_data(i).overload_function_store.get(function_name); - if (bracket_check_enabled()) - { - helper_assembly_.register_scanner(&bracket_checker_); + if (result) break; } - if (sequence_check_enabled()) - { - helper_assembly_.register_scanner(&sequence_validator_); - } + return result; } - } - inline bool compile(const std::string& expression_string, expression& expr) - { - error_list_ .clear(); - brkcnt_list_ .clear(); - synthesis_error_.clear(); - sem_ .cleanup(); + inline vector_holder_ptr get_vector(const std::string& vector_name) const + { + if (!valid_symbol(vector_name)) + return reinterpret_cast(0); - expression_generator_.set_allocator(node_allocator_); + vector_holder_ptr result = reinterpret_cast(0); - scope_depth_ = 0; + for (std::size_t i = 0; i < symtab_list_.size(); ++i) + { + if (!symtab_list_[i].valid()) + continue; + else + result = + local_data(i).vector_store.get(vector_name); - if (expression_string.empty()) - { - set_error( - make_error(parser_error::e_syntax, - "ERR00 - Empty expression!")); + if (result) break; + } - return false; + return result; } - if (!lexer_.process(expression_string)) + inline bool is_constant_node(const std::string& symbol_name) const { - process_lexer_errors(); - return false; - } + if (!valid_symbol(symbol_name)) + return false; - if (lexer_.empty()) - { - set_error( - make_error(parser_error::e_syntax, - "ERR01 - Empty expression!")); + for (std::size_t i = 0; i < symtab_list_.size(); ++i) + { + if (!symtab_list_[i].valid()) + continue; + else if (local_data(i).variable_store.is_constant(symbol_name)) + return true; + } return false; } - if (!run_assemblies()) + #ifndef exprtk_disable_string_capabilities + inline bool is_constant_string(const std::string& symbol_name) const { - return false; - } + if (!valid_symbol(symbol_name)) + return false; - symbol_table_ = expr.get_symbol_table(); - dec_.clear(); - - lexer_.begin(); - next_token(); + for (std::size_t i = 0; i < symtab_list_.size(); ++i) + { + if (!symtab_list_[i].valid()) + continue; + else if (!local_data(i).stringvar_store.symbol_exists(symbol_name)) + continue; + else if ( local_data(i).stringvar_store.is_constant(symbol_name)) + return true; + } - expression_node_ptr e = parse_corpus(); + return false; + } + #endif - if ((0 != e) && (token_t::e_eof == current_token_.type)) + inline bool symbol_exists(const std::string& symbol) const { - expr.set_expression(e); - register_local_vars(expr); + for (std::size_t i = 0; i < symtab_list_.size(); ++i) + { + if (!symtab_list_[i].valid()) + continue; + else if (symtab_list_[i].symbol_exists(symbol)) + return true; + } - return !(!expr); + return false; } - else + + inline bool is_variable(const std::string& variable_name) const { - if (error_list_.empty()) + for (std::size_t i = 0; i < symtab_list_.size(); ++i) { - set_error( - make_error(parser_error::e_syntax, - current_token_, - "ERR02 - Invalid expression encountered")); + if (!symtab_list_[i].valid()) + continue; + else if ( + symtab_list_[i].local_data().variable_store + .symbol_exists(variable_name) + ) + return true; } - dec_.clear (); - sem_.cleanup(); + return false; + } - if (0 != e) + #ifndef exprtk_disable_string_capabilities + inline bool is_stringvar(const std::string& stringvar_name) const + { + for (std::size_t i = 0; i < symtab_list_.size(); ++i) { - delete e; + if (!symtab_list_[i].valid()) + continue; + else if ( + symtab_list_[i].local_data().stringvar_store + .symbol_exists(stringvar_name) + ) + return true; } return false; } - } - void process_lexer_errors() - { - for (std::size_t i = 0; i < lexer_.size(); ++i) + inline bool is_conststr_stringvar(const std::string& symbol_name) const { - if (lexer_[i].is_error()) + for (std::size_t i = 0; i < symtab_list_.size(); ++i) { - std::string diagnostic = "ERR03 - "; - - switch (lexer_[i].type) + if (!symtab_list_[i].valid()) + continue; + else if ( + symtab_list_[i].local_data().stringvar_store + .symbol_exists(symbol_name) + ) { - case lexer::token::e_error : diagnostic += "General token error"; - break; - - case lexer::token::e_err_symbol : diagnostic += "Symbol error"; - break; - - case lexer::token::e_err_number : diagnostic += "Invalid numeric token"; - break; - - case lexer::token::e_err_string : diagnostic += "Invalid string token"; - break; - - case lexer::token::e_err_sfunc : diagnostic += "Invalid special function token"; - break; + return ( + local_data(i).stringvar_store.symbol_exists(symbol_name) || + local_data(i).stringvar_store.is_constant (symbol_name) + ); - default : diagnostic += "Unknown compiler error"; } + } - set_error( - make_error(parser_error::e_lexer, - lexer_[i], - diagnostic + ": " + lexer_[i].value)); + return false; + } + #endif + + inline bool is_function(const std::string& function_name) const + { + for (std::size_t i = 0; i < symtab_list_.size(); ++i) + { + if (!symtab_list_[i].valid()) + continue; + else if ( + local_data(i).vararg_function_store + .symbol_exists(function_name) + ) + return true; } + + return false; } - } - inline bool replacer_enabled() const - { - return ((compile_options_ & e_replacer) == e_replacer); - } + inline bool is_vararg_function(const std::string& vararg_function_name) const + { + for (std::size_t i = 0; i < symtab_list_.size(); ++i) + { + if (!symtab_list_[i].valid()) + continue; + else if ( + local_data(i).vararg_function_store + .symbol_exists(vararg_function_name) + ) + return true; + } - inline bool commutative_check_enabled() const - { - return ((compile_options_ & e_commutative_check) == e_commutative_check); - } + return false; + } - inline bool joiner_enabled() const - { - return ((compile_options_ & e_joiner) == e_joiner); - } + inline bool is_vector(const std::string& vector_name) const + { + for (std::size_t i = 0; i < symtab_list_.size(); ++i) + { + if (!symtab_list_[i].valid()) + continue; + else if ( + local_data(i).vector_store + .symbol_exists(vector_name) + ) + return true; + } - inline bool numeric_check_enabled() const - { - return ((compile_options_ & e_numeric_check) == e_numeric_check); - } + return false; + } - inline bool bracket_check_enabled() const - { - return ((compile_options_ & e_bracket_check) == e_bracket_check); - } + inline std::string get_variable_name(const expression_node_ptr& ptr) const + { + return local_data().variable_store.entity_name(ptr); + } - inline bool sequence_check_enabled() const - { - return ((compile_options_ & e_sequence_check) == e_sequence_check); - } + inline std::string get_vector_name(const vector_holder_ptr& ptr) const + { + return local_data().vector_store.entity_name(ptr); + } - inline bool strength_reduction_enabled() const - { - return ((compile_options_ & e_strength_reduction) == e_strength_reduction); - } + #ifndef exprtk_disable_string_capabilities + inline std::string get_stringvar_name(const expression_node_ptr& ptr) const + { + return local_data().stringvar_store.entity_name(ptr); + } - inline bool collect_variables_enabled() const - { - return ((compile_options_ & e_collect_vars) == e_collect_vars); - } + inline std::string get_conststr_stringvar_name(const expression_node_ptr& ptr) const + { + return local_data().stringvar_store.entity_name(ptr); + } + #endif - inline bool collect_functions_enabled() const - { - return ((compile_options_ & e_collect_funcs) == e_collect_funcs); - } + inline local_data_t& local_data(const std::size_t& index = 0) + { + return symtab_list_[index].local_data(); + } - inline bool collect_assignments_enabled() const - { - return ((compile_options_ & e_collect_assings) == e_collect_assings); - } + inline const local_data_t& local_data(const std::size_t& index = 0) const + { + return symtab_list_[index].local_data(); + } - inline bool run_assemblies() - { - if (commutative_check_enabled()) + inline symbol_table_t& get_symbol_table(const std::size_t& index = 0) { - helper_assembly_.run_inserters(lexer_); + return symtab_list_[index]; } + }; - if (joiner_enabled()) + struct parser_state + { + parser_state() + : type_check_enabled(true) { - helper_assembly_.run_joiners(lexer_); + reset(); } - if (replacer_enabled()) + void reset() { - helper_assembly_.run_modifiers(lexer_); + 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; } - if ( - numeric_check_enabled () || - bracket_check_enabled () || - sequence_check_enabled() - ) + #ifndef exprtk_enable_debugging + void activate_side_effect(const std::string&) + #else + void activate_side_effect(const std::string& source) + #endif { - if (!helper_assembly_.run_scanners(lexer_)) + if (!side_effect_present) { - 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; + side_effect_present = true; - 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(), - "ERR04 - Mismatched brackets: '" + bracket_checker_ptr->error_token().value + "'")); - } - else if (0 != (numeric_checker_ptr = dynamic_cast(helper_assembly_.error_token_scanner))) - { - for (std::size_t i = 0; i < numeric_checker_ptr->error_count(); ++i) - { - lexer::token error_token = lexer_[numeric_checker_ptr->error_index(i)]; + exprtk_debug(("activate_side_effect() - caller: %s\n",source.c_str())); + } + } - set_error( - make_error(parser_error::e_token, - error_token, - "ERR05 - Invalid numeric token: '" + error_token.value + "'")); - } + bool parsing_return_stmt; + bool parsing_break_stmt; + bool return_stmt_present; + 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; + }; - if (numeric_checker_ptr->error_count()) - { - numeric_checker_ptr->clear_errors(); - } - } - else if (0 != (sequence_validator_ptr = dynamic_cast(helper_assembly_.error_token_scanner))) - { - for (std::size_t i = 0; i < sequence_validator_ptr->error_count(); ++i) - { - std::pair error_token = sequence_validator_ptr->error(i); + public: - set_error( - make_error(parser_error::e_token, - error_token.first, - "ERR06 - Invalid token sequence: '" + - error_token.first.value + "' and '" + - error_token.second.value + "'")); - } + struct unknown_symbol_resolver + { - if (sequence_validator_ptr->error_count()) - { - sequence_validator_ptr->clear_errors(); - } - } - } + enum usr_symbol_type + { + e_usr_unknown_type = 0, + e_usr_variable_type = 1, + e_usr_constant_type = 2 + }; + + enum usr_mode + { + e_usrmode_default = 0, + e_usrmode_extended = 1 + }; + + usr_mode mode; + + unknown_symbol_resolver(const usr_mode m = e_usrmode_default) + : mode(m) + {} + + virtual ~unknown_symbol_resolver() + {} + virtual bool process(const std::string& /*unknown_symbol*/, + usr_symbol_type& st, + T& default_value, + std::string& error_message) + { + if (e_usrmode_default != mode) return false; - } - } - return true; - } + st = e_usr_variable_type; + default_value = T(0); + error_message.clear(); - inline parser_error::type get_error(const std::size_t& index) - { - if (index < error_list_.size()) - return error_list_[index]; - else - throw std::invalid_argument("parser::get_error() - Invalid error index specificed"); - } + return true; + } - inline std::string error() const - { - if (!error_list_.empty()) + virtual bool process(const std::string& /* unknown_symbol */, + symbol_table_t& /* symbol_table */, + std::string& /* error_message */) { - return error_list_[0].diagnostic; + return false; } - else - return std::string("No Error"); - } + }; - inline std::size_t error_count() const + enum collect_type { - return error_list_.size(); - } + e_ct_none = 0, + e_ct_variables = 1, + e_ct_functions = 2, + e_ct_assignments = 4 + }; - inline dependent_entity_collector& dec() + enum symbol_type { - return dec_; - } + e_st_unknown = 0, + e_st_variable = 1, + e_st_vector = 2, + e_st_vecelem = 3, + e_st_string = 4, + e_st_function = 5, + e_st_local_variable = 6, + e_st_local_vector = 7, + e_st_local_string = 8 + }; - inline bool replace_symbol(const std::string& old_symbol, const std::string& new_symbol) + class dependent_entity_collector { - if (!replacer_enabled()) - return false; - else if (details::is_reserved_word(old_symbol)) - return false; - else - return symbol_replacer_.add_replace(old_symbol,new_symbol,lexer::token::e_symbol); - } + public: - inline bool remove_replace_symbol(const std::string& symbol) - { - if (!replacer_enabled()) - return false; - else if (details::is_reserved_word(symbol)) - return false; - else - return symbol_replacer_.remove(symbol); - } + typedef std::pair symbol_t; + typedef std::vector symbol_list_t; - inline void enable_unknown_symbol_resolver(unknown_symbol_resolver* usr = reinterpret_cast(0)) - { - resolve_unknown_symbol_ = true; + dependent_entity_collector(const std::size_t options = e_ct_none) + : options_(options), + collect_variables_ ((options_ & e_ct_variables ) == e_ct_variables ), + collect_functions_ ((options_ & e_ct_functions ) == e_ct_functions ), + collect_assignments_((options_ & e_ct_assignments) == e_ct_assignments), + return_present_ (false), + final_stmt_return_(false) + {} - if (usr) - unknown_symbol_resolver_ = usr; - else - unknown_symbol_resolver_ = &default_usr_; - } + template class Sequence> + inline std::size_t symbols(Sequence& symbols_list) + { + if (!collect_variables_ && !collect_functions_) + return 0; + else if (symbol_name_list_.empty()) + return 0; - inline void disable_unknown_symbol_resolver() - { - resolve_unknown_symbol_ = false; - unknown_symbol_resolver_ = &default_usr_; - } + for (std::size_t i = 0; i < symbol_name_list_.size(); ++i) + { + details::case_normalise(symbol_name_list_[i].first); + } - private: + std::sort(symbol_name_list_.begin(),symbol_name_list_.end()); - inline bool valid_base_operation(const std::string& symbol) - { - const std::size_t length = symbol.size(); - if ( - (length < 3) || // Shortest base op symbol length - (length > 9) // Longest base op symbol length - ) - return false; - else - return (base_ops_map_.end() != base_ops_map_.find(symbol)); - } + std::unique_copy(symbol_name_list_.begin(), + symbol_name_list_.end (), + std::back_inserter(symbols_list)); - inline bool valid_vararg_operation(const std::string& symbol) - { - static const std::string s_sum = "sum" ; - static const std::string s_mul = "mul" ; - static const std::string s_avg = "avg" ; - static const std::string s_min = "min" ; - static const std::string s_max = "max" ; - static const std::string s_mand = "mand"; - static const std::string s_mor = "mor" ; - static const std::string s_multi = "~" ; - static const std::string s_mswitch = "[*]" ; - return - ( - details::imatch(symbol,s_sum ) || - details::imatch(symbol,s_mul ) || - details::imatch(symbol,s_avg ) || - details::imatch(symbol,s_min ) || - details::imatch(symbol,s_max ) || - details::imatch(symbol,s_mand ) || - details::imatch(symbol,s_mor ) || - details::imatch(symbol,s_multi ) || - details::imatch(symbol,s_mswitch) - ); - } + return symbols_list.size(); + } - inline void store_token() - { - lexer_.store(); - store_current_token_ = current_token_; - } + template class Sequence> + inline std::size_t assignment_symbols(Sequence& assignment_list) + { + if (!collect_assignments_) + return 0; + else if (assignment_name_list_.empty()) + return 0; - inline void restore_token() - { - lexer_.restore(); - current_token_ = store_current_token_; - } + for (std::size_t i = 0; i < assignment_name_list_.size(); ++i) + { + details::case_normalise(assignment_name_list_[i].first); + } - #ifndef exprtk_enable_debugging - inline void next_token() - { - current_token_ = lexer_.next_token(); - } - #else - inline void next_token() - { - std::string ct_str = current_token_.value; - current_token_ = lexer_.next_token(); - std::string depth(2 * scope_depth_,' '); - exprtk_debug(("%s" - "prev[%s] --> curr[%s]\n", - depth.c_str(), - ct_str.c_str(), - current_token_.value.c_str())); - } - #endif + std::sort(assignment_name_list_.begin(),assignment_name_list_.end()); - inline const lexer::token& current_token() const - { - return current_token_; - } + std::unique_copy(assignment_name_list_.begin(), + assignment_name_list_.end (), + std::back_inserter(assignment_list)); - inline expression_node_ptr parse_corpus() - { - std::vector arg_list; - expression_node_ptr result = error_node(); + return assignment_list.size(); + } - scoped_vec_delete sdd(*this,arg_list); + void clear() + { + symbol_name_list_ .clear(); + assignment_name_list_.clear(); + retparam_list_ .clear(); + return_present_ = false; + final_stmt_return_ = false; + } - for (;;) + bool& collect_variables() { - expression_node_ptr arg = parse_expression(); + return collect_variables_; + } - if (0 == arg) + bool& collect_functions() + { + return collect_functions_; + } + + bool& collect_assignments() + { + return collect_assignments_; + } + + bool return_present() const + { + return return_present_; + } + + bool final_stmt_return() const + { + return final_stmt_return_; + } + + typedef std::vector retparam_list_t; + + retparam_list_t return_param_type_list() const + { + return retparam_list_; + } + + private: + + inline void add_symbol(const std::string& symbol, const symbol_type st) + { + switch (st) { - if (error_list_.empty()) - { - set_error( - make_error(parser_error::e_syntax, - current_token_, - "ERR07 - Invalid expression encountered")); - } + case e_st_variable : + case e_st_vector : + case e_st_string : + case e_st_local_variable : + case e_st_local_vector : + case e_st_local_string : if (collect_variables_) + symbol_name_list_ + .push_back(std::make_pair(symbol, st)); + break; - return error_node(); + case e_st_function : if (collect_functions_) + symbol_name_list_ + .push_back(std::make_pair(symbol, st)); + break; + + default : return; } - else - arg_list.push_back(arg); + } - if (lexer_.finished()) - break; - else if (token_is(token_t::e_eof,false)) + inline void add_assignment(const std::string& symbol, const symbol_type st) + { + switch (st) { - if (lexer_.finished()) - break; - else - next_token(); + case e_st_variable : + case e_st_vector : + case e_st_string : if (collect_assignments_) + assignment_name_list_ + .push_back(std::make_pair(symbol, st)); + break; + + default : return; } } - result = simplify(arg_list); - - sdd.delete_ptr = (0 == result); - return result; - } + std::size_t options_; + bool collect_variables_; + bool collect_functions_; + bool collect_assignments_; + bool return_present_; + bool final_stmt_return_; + symbol_list_t symbol_name_list_; + symbol_list_t assignment_name_list_; + retparam_list_t retparam_list_; - static const precedence_level default_precedence = e_level00; + friend class parser; + }; - struct state_t + class settings_store { - inline void set(const precedence_level& l, - const precedence_level& r, - const details::operator_type& o) + private: + + typedef std::set disabled_entity_set_t; + typedef disabled_entity_set_t::iterator des_itr_t; + + public: + + enum settings_compilation_options + { + e_unknown = 0, + e_replacer = 1, + e_joiner = 2, + e_numeric_check = 4, + e_bracket_check = 8, + e_sequence_check = 16, + e_commutative_check = 32, + e_strength_reduction = 64, + e_disable_vardef = 128, + e_collect_vars = 256, + e_collect_funcs = 512, + e_collect_assings = 1024, + e_disable_usr_on_rsrvd = 2048, + e_disable_zero_return = 4096 + }; + + enum settings_base_funcs + { + e_bf_unknown = 0, + e_bf_abs , e_bf_acos , e_bf_acosh , e_bf_asin , + e_bf_asinh , e_bf_atan , e_bf_atan2 , e_bf_atanh , + e_bf_avg , e_bf_ceil , e_bf_clamp , e_bf_cos , + e_bf_cosh , e_bf_cot , e_bf_csc , e_bf_equal , + e_bf_erf , e_bf_erfc , e_bf_exp , e_bf_expm1 , + e_bf_floor , e_bf_frac , e_bf_hypot , e_bf_iclamp , + e_bf_like , e_bf_log , e_bf_log10 , e_bf_log1p , + e_bf_log2 , e_bf_logn , e_bf_mand , e_bf_max , + e_bf_min , e_bf_mod , e_bf_mor , e_bf_mul , + e_bf_ncdf , e_bf_pow , e_bf_root , e_bf_round , + e_bf_roundn , e_bf_sec , e_bf_sgn , e_bf_sin , + e_bf_sinc , e_bf_sinh , e_bf_sqrt , e_bf_sum , + e_bf_swap , e_bf_tan , e_bf_tanh , e_bf_trunc , + e_bf_not_equal , e_bf_inrange , e_bf_deg2grad , e_bf_deg2rad, + e_bf_rad2deg , e_bf_grad2deg + }; + + enum settings_control_structs { - left = l; - right = r; - operation = o; + e_ctrl_unknown = 0, + e_ctrl_ifelse, + e_ctrl_switch, + e_ctrl_for_loop, + e_ctrl_while_loop, + e_ctrl_repeat_loop, + e_ctrl_return + }; + + enum settings_logic_opr + { + e_logic_unknown = 0, + e_logic_and, e_logic_nand, e_logic_nor, + e_logic_not, e_logic_or, e_logic_xnor, + e_logic_xor, e_logic_scand, e_logic_scor + }; + + enum settings_arithmetic_opr + { + e_arith_unknown = 0, + e_arith_add, e_arith_sub, e_arith_mul, + e_arith_div, e_arith_mod, e_arith_pow + }; + + enum settings_assignment_opr + { + e_assign_unknown = 0, + e_assign_assign, e_assign_addass, e_assign_subass, + e_assign_mulass, e_assign_divass, e_assign_modass + }; + + enum settings_inequality_opr + { + e_ineq_unknown = 0, + e_ineq_lt, e_ineq_lte, e_ineq_eq, + e_ineq_equal, e_ineq_ne, e_ineq_nequal, + e_ineq_gte, e_ineq_gt + }; + + static const std::size_t compile_all_opts = e_replacer + + e_joiner + + e_numeric_check + + e_bracket_check + + e_sequence_check + + e_commutative_check + + 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); } - inline void reset() + settings_store& enable_all_base_functions() { - left = e_level00; - right = e_level00; + disabled_func_set_.clear(); + return (*this); } - precedence_level left; - precedence_level right; - details::operator_type operation; - }; + settings_store& enable_all_control_structures() + { + disabled_ctrl_set_.clear(); + return (*this); + } - inline expression_node_ptr parse_expression(precedence_level precedence = e_level00) - { - expression_node_ptr expression = parse_branch(precedence); + settings_store& enable_all_logic_ops() + { + disabled_logic_set_.clear(); + return (*this); + } - if (0 == expression) + settings_store& enable_all_arithmetic_ops() { - return error_node(); + disabled_arithmetic_set_.clear(); + return (*this); } - bool break_loop = false; + settings_store& enable_all_assignment_ops() + { + disabled_assignment_set_.clear(); + return (*this); + } - state_t current_state; + settings_store& enable_all_inequality_ops() + { + disabled_inequality_set_.clear(); + return (*this); + } - for ( ; ; ) + settings_store& enable_local_vardef() { - current_state.reset(); + disable_vardef_ = false; + return (*this); + } - 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; - default : if (token_t::e_symbol == current_token_.type) - { - static const std::string s_and = "and"; - static const std::string s_nand = "nand"; - static const std::string s_or = "or"; - static const std::string s_nor = "nor"; - static const std::string s_xor = "xor"; - static const std::string s_xnor = "xnor"; - static const std::string s_in = "in"; - static const std::string s_like = "like"; - static const std::string s_ilike = "ilike"; - static const std::string s_and1 = "&"; - static const std::string s_or1 = "|"; + settings_store& disable_all_base_functions() + { + std::copy(details::base_function_list, + details::base_function_list + details::base_function_list_size, + std::insert_iterator + (disabled_func_set_, disabled_func_set_.begin())); + return (*this); + } - if (details::imatch(current_token_.value,s_and)) - { - current_state.set(e_level01,e_level02,details::e_and); - break; - } - else if (details::imatch(current_token_.value,s_and1)) - { - #ifndef exprtk_disable_sc_andor - current_state.set(e_level01,e_level02,details::e_scand); - #else - current_state.set(e_level01,e_level02,details::e_and); - #endif - break; - } - else if (details::imatch(current_token_.value,s_nand)) - { - current_state.set(e_level01,e_level02,details::e_nand); - break; - } - else if (details::imatch(current_token_.value,s_or)) - { - current_state.set(e_level03,e_level04,details::e_or); - break; - } - else if (details::imatch(current_token_.value,s_or1)) - { - #ifndef exprtk_disable_sc_andor - current_state.set(e_level03,e_level04,details::e_scor); - #else - current_state.set(e_level03,e_level04,details::e_or); - #endif - break; - } - else if (details::imatch(current_token_.value,s_nor)) - { - current_state.set(e_level03,e_level04,details::e_nor); - break; - } - else if (details::imatch(current_token_.value,s_xor)) - { - current_state.set(e_level03,e_level04,details::e_xor); - break; - } - else if (details::imatch(current_token_.value,s_xnor)) - { - current_state.set(e_level03,e_level04,details::e_xnor); - break; - } - else if (details::imatch(current_token_.value,s_in)) - { - current_state.set(e_level03,e_level04,details::e_in); - break; - } - else if (details::imatch(current_token_.value,s_like)) - { - current_state.set(e_level03,e_level04,details::e_like); - break; - } - else if (details::imatch(current_token_.value,s_ilike)) - { - current_state.set(e_level03,e_level04,details::e_ilike); - break; - } - } - - break_loop = true; - } - - if (break_loop) - { - parse_pending_string_rangesize(expression); - break; - } - else if (current_state.left < precedence) - break; + settings_store& disable_all_control_structures() + { + std::copy(details::cntrl_struct_list, + details::cntrl_struct_list + details::cntrl_struct_list_size, + std::insert_iterator + (disabled_ctrl_set_, disabled_ctrl_set_.begin())); + return (*this); + } - lexer::token prev_token = current_token_; + settings_store& disable_all_logic_ops() + { + std::copy(details::logic_ops_list, + details::logic_ops_list + details::logic_ops_list_size, + std::insert_iterator + (disabled_logic_set_, disabled_logic_set_.begin())); + return (*this); + } - next_token(); + settings_store& disable_all_arithmetic_ops() + { + std::copy(details::arithmetic_ops_list, + details::arithmetic_ops_list + details::arithmetic_ops_list_size, + std::insert_iterator + (disabled_arithmetic_set_, disabled_arithmetic_set_.begin())); + return (*this); + } - expression_node_ptr right_branch = error_node(); - expression_node_ptr new_expression = error_node(); + settings_store& disable_all_assignment_ops() + { + std::copy(details::assignment_ops_list, + details::assignment_ops_list + details::assignment_ops_list_size, + std::insert_iterator + (disabled_assignment_set_, disabled_assignment_set_.begin())); + return (*this); + } - if ((right_branch = parse_expression(current_state.right))) - { - new_expression = expression_generator_ - ( - current_state.operation, - expression, - right_branch - ); - } + settings_store& disable_all_inequality_ops() + { + std::copy(details::inequality_ops_list, + details::inequality_ops_list + details::inequality_ops_list_size, + std::insert_iterator + (disabled_inequality_set_, disabled_inequality_set_.begin())); + return (*this); + } - if (0 == new_expression) - { - if (error_list_.empty()) - { - set_error( - make_error(parser_error::e_syntax, - prev_token, - !synthesis_error_.empty() ? - synthesis_error_ : - "ERR08 - General parsing error at token: '" + prev_token.value + "'")); - } + settings_store& disable_local_vardef() + { + disable_vardef_ = true; + return (*this); + } - free_node(node_allocator_,expression); + bool replacer_enabled () const { return enable_replacer_; } + bool commutative_check_enabled () const { return enable_commutative_check_; } + bool joiner_enabled () const { return enable_joiner_; } + bool numeric_check_enabled () const { return enable_numeric_check_; } + bool bracket_check_enabled () const { return enable_bracket_check_; } + bool sequence_check_enabled () const { return enable_sequence_check_; } + bool strength_reduction_enabled () const { return enable_strength_reduction_; } + bool collect_variables_enabled () const { return enable_collect_vars_; } + bool collect_functions_enabled () const { return enable_collect_funcs_; } + bool collect_assignments_enabled() const { return enable_collect_assings_; } + bool vardef_disabled () const { return disable_vardef_; } + bool rsrvd_sym_usr_disabled () const { return disable_rsrvd_sym_usr_; } + bool zero_return_disabled () const { return disable_zero_return_; } - return error_node(); - } + bool function_enabled(const std::string& function_name) const + { + if (disabled_func_set_.empty()) + return true; else - { - expression = new_expression; - - if (token_is(token_t::e_ternary,false) && (precedence == e_level00)) - { - expression = parse_ternary_conditional_statement(expression); - } - - parse_pending_string_rangesize(expression); - } + return (disabled_func_set_.end() == disabled_func_set_.find(function_name)); } - return expression; - } - - bool simplify_unary_negation_branch(expression_node_ptr& node) - { + bool control_struct_enabled(const std::string& control_struct) const { - typedef details::unary_branch_node > ubn_t; - ubn_t* n = dynamic_cast(node); + if (disabled_ctrl_set_.empty()) + return true; + else + return (disabled_ctrl_set_.end() == disabled_ctrl_set_.find(control_struct)); + } - if (n) - { - expression_node_ptr un_r = n->branch(0); - n->release(); - free_node(node_allocator_,node); - node = un_r; + bool logic_enabled(const std::string& logic_operation) const + { + if (disabled_logic_set_.empty()) + return true; + else + return (disabled_logic_set_.end() == disabled_logic_set_.find(logic_operation)); + } + bool arithmetic_enabled(const details::operator_type& arithmetic_operation) const + { + if (disabled_logic_set_.empty()) return true; - } + else + return disabled_arithmetic_set_.end() == disabled_arithmetic_set_ + .find(arith_opr_to_string(arithmetic_operation)); } + bool assignment_enabled(const details::operator_type& assignment) const { - typedef details::unary_variable_node > ubn_t; + if (disabled_assignment_set_.empty()) + return true; + else + return disabled_assignment_set_.end() == disabled_assignment_set_ + .find(assign_opr_to_string(assignment)); + } - ubn_t* n = dynamic_cast(node); + bool inequality_enabled(const details::operator_type& inequality) const + { + if (disabled_inequality_set_.empty()) + return true; + else + return disabled_inequality_set_.end() == disabled_inequality_set_ + .find(inequality_opr_to_string(inequality)); + } - if (n) - { - const T& v = n->v(); - expression_node_ptr return_node = error_node(); + bool function_disabled(const std::string& function_name) const + { + if (disabled_func_set_.empty()) + return false; + else + return (disabled_func_set_.end() != disabled_func_set_.find(function_name)); + } - if ( - (return_node = symbol_table_.get_variable(v)) || - (return_node = sem_ .get_variable(v)) - ) - { - free_node(node_allocator_,node); - node = return_node; + bool control_struct_disabled(const std::string& control_struct) const + { + if (disabled_ctrl_set_.empty()) + return false; + else + return (disabled_ctrl_set_.end() != disabled_ctrl_set_.find(control_struct)); + } - return true; - } - else - { - set_error( - make_error(parser_error::e_syntax, - current_token_, - "ERR09 - Failed to find variable node in symbol table")); - free_node(node_allocator_,node); + bool logic_disabled(const std::string& logic_operation) const + { + if (disabled_logic_set_.empty()) + return false; + else + return (disabled_logic_set_.end() != disabled_logic_set_.find(logic_operation)); + } - return false; - } - } + bool assignment_disabled(const details::operator_type assignment_operation) const + { + if (disabled_assignment_set_.empty()) + return false; + else + return disabled_assignment_set_.end() != disabled_assignment_set_ + .find(assign_opr_to_string(assignment_operation)); } - return false; - } + 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)); + } - static inline expression_node_ptr error_node() - { - return reinterpret_cast(0); - } + bool arithmetic_disabled(const details::operator_type arithmetic_operation) const + { + if (disabled_arithmetic_set_.empty()) + return false; + else + return disabled_arithmetic_set_.end() != disabled_arithmetic_set_ + .find(arith_opr_to_string(arithmetic_operation)); + } - template - struct scoped_delete - { - typedef Type* ptr_t; + bool inequality_disabled(const details::operator_type& inequality) const + { + if (disabled_inequality_set_.empty()) + return false; + else + return disabled_inequality_set_.end() != disabled_inequality_set_ + .find(inequality_opr_to_string(inequality)); + } - scoped_delete(parser& pr, ptr_t& p) - : delete_ptr(true), - parser_(pr), - p_(&p) - {} + settings_store& disable_base_function(settings_base_funcs bf) + { + if ( + (e_bf_unknown != bf) && + (static_cast(bf) < (details::base_function_list_size + 1)) + ) + { + disabled_func_set_.insert(details::base_function_list[bf - 1]); + } - scoped_delete(parser& pr, ptr_t (&p)[N]) - : delete_ptr(true), - parser_(pr), - p_(&p[0]) - {} + return (*this); + } - ~scoped_delete() + settings_store& disable_control_structure(settings_control_structs ctrl_struct) { - if (delete_ptr) + if ( + (e_ctrl_unknown != ctrl_struct) && + (static_cast(ctrl_struct) < (details::cntrl_struct_list_size + 1)) + ) { - for (std::size_t i = 0; i < N; ++i) - { - free_node(parser_.node_allocator_,p_[i]); - } + disabled_ctrl_set_.insert(details::cntrl_struct_list[ctrl_struct - 1]); } - } - bool delete_ptr; - parser& parser_; - ptr_t* p_; + return (*this); + } - private: + settings_store& disable_logic_operation(settings_logic_opr logic) + { + if ( + (e_logic_unknown != logic) && + (static_cast(logic) < (details::logic_ops_list_size + 1)) + ) + { + disabled_logic_set_.insert(details::logic_ops_list[logic - 1]); + } - scoped_delete& operator=(const scoped_delete&); - }; + return (*this); + } - template - struct scoped_deq_delete - { - typedef Type* ptr_t; + settings_store& disable_arithmetic_operation(settings_arithmetic_opr arithmetic) + { + if ( + (e_arith_unknown != arithmetic) && + (static_cast(arithmetic) < (details::arithmetic_ops_list_size + 1)) + ) + { + disabled_arithmetic_set_.insert(details::arithmetic_ops_list[arithmetic - 1]); + } - scoped_deq_delete(parser& pr, std::deque& deq) - : delete_ptr(true), - parser_(pr), - deq_(deq) - {} + return (*this); + } - ~scoped_deq_delete() + settings_store& disable_assignment_operation(settings_assignment_opr assignment) { - if (delete_ptr && !deq_.empty()) + if ( + (e_assign_unknown != assignment) && + (static_cast(assignment) < (details::assignment_ops_list_size + 1)) + ) { - for (std::size_t i = 0; i < deq_.size(); ++i) - { - free_node(parser_.node_allocator_,deq_[i]); - } - - deq_.clear(); + disabled_assignment_set_.insert(details::assignment_ops_list[assignment - 1]); } + + return (*this); } - bool delete_ptr; - parser& parser_; - std::deque& deq_; + settings_store& disable_inequality_operation(settings_inequality_opr inequality) + { + if ( + (e_ineq_unknown != inequality) && + (static_cast(inequality) < (details::inequality_ops_list_size + 1)) + ) + { + disabled_inequality_set_.insert(details::inequality_ops_list[inequality - 1]); + } - private: + return (*this); + } - scoped_deq_delete& operator=(const scoped_deq_delete&); - }; + settings_store& enable_base_function(settings_base_funcs bf) + { + if ( + (e_bf_unknown != bf) && + (static_cast(bf) < (details::base_function_list_size + 1)) + ) + { + const des_itr_t itr = disabled_func_set_.find(details::base_function_list[bf - 1]); - template - struct scoped_vec_delete - { - typedef Type* ptr_t; + if (disabled_func_set_.end() != itr) + { + disabled_func_set_.erase(itr); + } + } - scoped_vec_delete(parser& pr, std::vector& vec) - : delete_ptr(true), - parser_(pr), - vec_(vec) - {} + return (*this); + } - ~scoped_vec_delete() + settings_store& enable_control_structure(settings_control_structs ctrl_struct) { - if (delete_ptr && !vec_.empty()) + if ( + (e_ctrl_unknown != ctrl_struct) && + (static_cast(ctrl_struct) < (details::cntrl_struct_list_size + 1)) + ) { - for (std::size_t i = 0; i < vec_.size(); ++i) + const des_itr_t itr = disabled_ctrl_set_.find(details::cntrl_struct_list[ctrl_struct - 1]); + + if (disabled_ctrl_set_.end() != itr) { - free_node(parser_.node_allocator_,vec_[i]); + disabled_ctrl_set_.erase(itr); } - - vec_.clear(); } - } - bool delete_ptr; - parser& parser_; - std::vector& vec_; + return (*this); + } - private: + settings_store& enable_logic_operation(settings_logic_opr logic) + { + if ( + (e_logic_unknown != logic) && + (static_cast(logic) < (details::logic_ops_list_size + 1)) + ) + { + const des_itr_t itr = disabled_logic_set_.find(details::logic_ops_list[logic - 1]); - scoped_vec_delete& operator=(const scoped_vec_delete&); - }; + if (disabled_logic_set_.end() != itr) + { + disabled_logic_set_.erase(itr); + } + } - inline expression_node_ptr parse_function_invocation(ifunction* function, const std::string& function_name) - { - expression_node_ptr func_node = reinterpret_cast(0); + return (*this); + } - switch (function->param_count) + settings_store& enable_arithmetic_operation(settings_arithmetic_opr arithmetic) { - case 0 : func_node = parse_function_call_0 (function,function_name); break; - case 1 : func_node = parse_function_call< 1>(function,function_name); break; - case 2 : func_node = parse_function_call< 2>(function,function_name); break; - case 3 : func_node = parse_function_call< 3>(function,function_name); break; - case 4 : func_node = parse_function_call< 4>(function,function_name); break; - case 5 : func_node = parse_function_call< 5>(function,function_name); break; - case 6 : func_node = parse_function_call< 6>(function,function_name); break; - case 7 : func_node = parse_function_call< 7>(function,function_name); break; - case 8 : func_node = parse_function_call< 8>(function,function_name); break; - case 9 : func_node = parse_function_call< 9>(function,function_name); break; - case 10 : func_node = parse_function_call<10>(function,function_name); break; - case 11 : func_node = parse_function_call<11>(function,function_name); break; - case 12 : func_node = parse_function_call<12>(function,function_name); break; - case 13 : func_node = parse_function_call<13>(function,function_name); break; - case 14 : func_node = parse_function_call<14>(function,function_name); break; - case 15 : func_node = parse_function_call<15>(function,function_name); break; - case 16 : func_node = parse_function_call<16>(function,function_name); break; - case 17 : func_node = parse_function_call<17>(function,function_name); break; - case 18 : func_node = parse_function_call<18>(function,function_name); break; - case 19 : func_node = parse_function_call<19>(function,function_name); break; - case 20 : func_node = parse_function_call<20>(function,function_name); break; - default : { - set_error( - make_error(parser_error::e_syntax, - current_token_, - "ERR10 - Invalid number of parameters for function: '" + function_name + "'")); + if ( + (e_arith_unknown != arithmetic) && + (static_cast(arithmetic) < (details::arithmetic_ops_list_size + 1)) + ) + { + const des_itr_t itr = disabled_arithmetic_set_.find(details::arithmetic_ops_list[arithmetic - 1]); - return error_node(); - } + if (disabled_arithmetic_set_.end() != itr) + { + disabled_arithmetic_set_.erase(itr); + } + } + + return (*this); } - if (func_node) - return func_node; - else + settings_store& enable_assignment_operation(settings_assignment_opr assignment) { - set_error( - make_error(parser_error::e_syntax, - current_token_, - "ERR11 - Failed to generate call to function: '" + function_name + "'")); + if ( + (e_assign_unknown != assignment) && + (static_cast(assignment) < (details::assignment_ops_list_size + 1)) + ) + { + const des_itr_t itr = disabled_assignment_set_.find(details::assignment_ops_list[assignment - 1]); - return error_node(); + if (disabled_assignment_set_.end() != itr) + { + disabled_assignment_set_.erase(itr); + } + } + + return (*this); } - } - template - inline expression_node_ptr parse_function_call(ifunction* function, const std::string& function_name) - { - if (0 == NumberofParameters) + settings_store& enable_inequality_operation(settings_inequality_opr inequality) { - set_error( - make_error(parser_error::e_syntax, - current_token_, - "ERR12 - Expecting ifunction '" + function_name + "' to have non-zero parameter count")); + if ( + (e_ineq_unknown != inequality) && + (static_cast(inequality) < (details::inequality_ops_list_size + 1)) + ) + { + const des_itr_t itr = disabled_inequality_set_.find(details::inequality_ops_list[inequality - 1]); - return error_node(); + if (disabled_inequality_set_.end() != itr) + { + disabled_inequality_set_.erase(itr); + } + } + + return (*this); } - expression_node_ptr branch[NumberofParameters]; - expression_node_ptr result = error_node(); + void set_max_stack_depth(const std::size_t mx_stack_depth) + { + max_stack_depth_ = mx_stack_depth; + } - std::fill_n(branch,NumberofParameters,reinterpret_cast(0)); - scoped_delete sd(*this,branch); + void set_max_node_depth(const std::size_t max_node_depth) + { + max_node_depth_ = max_node_depth; + } - next_token(); + private: - if (!token_is(token_t::e_lbracket)) + void load_compile_options(const std::size_t compile_options) { - set_error( - make_error(parser_error::e_syntax, - current_token_, - "ERR13 - Expecting argument list for function: '" + function_name + "'")); - - return error_node(); + enable_replacer_ = (compile_options & e_replacer ) == e_replacer; + enable_joiner_ = (compile_options & e_joiner ) == e_joiner; + enable_numeric_check_ = (compile_options & e_numeric_check ) == e_numeric_check; + enable_bracket_check_ = (compile_options & e_bracket_check ) == e_bracket_check; + enable_sequence_check_ = (compile_options & e_sequence_check ) == e_sequence_check; + enable_commutative_check_ = (compile_options & e_commutative_check ) == e_commutative_check; + enable_strength_reduction_ = (compile_options & e_strength_reduction ) == e_strength_reduction; + enable_collect_vars_ = (compile_options & e_collect_vars ) == e_collect_vars; + enable_collect_funcs_ = (compile_options & e_collect_funcs ) == e_collect_funcs; + enable_collect_assings_ = (compile_options & e_collect_assings ) == e_collect_assings; + disable_vardef_ = (compile_options & e_disable_vardef ) == e_disable_vardef; + disable_rsrvd_sym_usr_ = (compile_options & e_disable_usr_on_rsrvd) == e_disable_usr_on_rsrvd; + disable_zero_return_ = (compile_options & e_disable_zero_return ) == e_disable_zero_return; } - for (int i = 0; i < static_cast(NumberofParameters); ++i) + std::string assign_opr_to_string(details::operator_type opr) const { - branch[i] = parse_expression(); - - if (0 == branch[i]) + switch (opr) { - set_error( - make_error(parser_error::e_syntax, - current_token_, - "ERR14 - Failed to parse argument " + details::to_str(i) + " for function: '" + function_name + "'")); - - return error_node(); + case details::e_assign : return ":="; + case details::e_addass : return "+="; + case details::e_subass : return "-="; + case details::e_mulass : return "*="; + case details::e_divass : return "/="; + case details::e_modass : return "%="; + default : return ""; } - else if (i < static_cast(NumberofParameters - 1)) - { - if (!token_is(token_t::e_comma)) - { - set_error( - make_error(parser_error::e_syntax, - current_token_, - "ERR15 - Invalid number of arguments for function: '" + function_name + "'")); + } - return error_node(); - } + std::string arith_opr_to_string(details::operator_type opr) const + { + switch (opr) + { + case details::e_add : return "+"; + case details::e_sub : return "-"; + case details::e_mul : return "*"; + case details::e_div : return "/"; + case details::e_mod : return "%"; + default : return ""; } } - if (!token_is(token_t::e_rbracket)) + std::string inequality_opr_to_string(details::operator_type opr) const { - set_error( - make_error(parser_error::e_syntax, - current_token_, - "ERR16 - Invalid number of arguments for function: '" + function_name + "'")); - - return error_node(); + switch (opr) + { + case details::e_lt : return "<"; + case details::e_lte : return "<="; + case details::e_eq : return "=="; + case details::e_equal : return "="; + case details::e_ne : return "!="; + case details::e_nequal: return "<>"; + case details::e_gte : return ">="; + case details::e_gt : return ">"; + default : return ""; + } } - else - result = expression_generator_.function(function,branch); - sd.delete_ptr = false; + 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_; + bool enable_bracket_check_; + bool enable_sequence_check_; + bool enable_commutative_check_; + bool enable_strength_reduction_; + bool enable_collect_vars_; + bool enable_collect_funcs_; + bool enable_collect_assings_; + bool disable_vardef_; + bool disable_rsrvd_sym_usr_; + bool disable_zero_return_; + + disabled_entity_set_t disabled_func_set_ ; + disabled_entity_set_t disabled_ctrl_set_ ; + disabled_entity_set_t disabled_logic_set_; + disabled_entity_set_t disabled_arithmetic_set_; + 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_; - return result; - } + friend class parser; + }; - inline expression_node_ptr parse_function_call_0(ifunction* function, const std::string& function_name) + typedef settings_store settings_t; + + parser(const settings_t& settings = settings_t()) + : settings_(settings), + resolve_unknown_symbol_(false), + results_context_(0), + unknown_symbol_resolver_(reinterpret_cast(0)), + #ifdef _MSC_VER + #pragma warning(push) + #pragma warning (disable:4355) + #endif + sem_(*this), + #ifdef _MSC_VER + #pragma warning(pop) + #endif + operator_joiner_2_(2), + operator_joiner_3_(3), + loop_runtime_check_(0) { - expression_node_ptr result = expression_generator_.function(function); - next_token(); - if ( - token_is(token_t::e_lbracket) && - !token_is(token_t::e_rbracket) - ) - { - set_error( - make_error(parser_error::e_syntax, - current_token_, - "ERR17 - Expecting '()' to proceed call to function: '" + function_name + "'")); + init_precompilation(); - free_node(node_allocator_,result); + load_operations_map (base_ops_map_ ); + load_unary_operations_map (unary_op_map_ ); + load_binary_operations_map (binary_op_map_ ); + load_inv_binary_operations_map(inv_binary_op_map_); + load_sf3_map (sf3_map_ ); + load_sf4_map (sf4_map_ ); - return error_node(); - } - else - return result; + expression_generator_.init_synthesize_map(); + expression_generator_.set_parser(*this); + expression_generator_.set_uom(unary_op_map_); + expression_generator_.set_bom(binary_op_map_); + expression_generator_.set_ibom(inv_binary_op_map_); + expression_generator_.set_sf3m(sf3_map_); + expression_generator_.set_sf4m(sf4_map_); + expression_generator_.set_strength_reduction_state(settings_.strength_reduction_enabled()); } - template - inline int parse_base_function_call(expression_node_ptr (¶m_list)[MaxNumberofParameters]) + ~parser() + {} + + inline void init_precompilation() { - std::fill_n(param_list,MaxNumberofParameters,reinterpret_cast(0)); + if (settings_.collect_variables_enabled()) + dec_.collect_variables() = true; - scoped_delete sd(*this,param_list); + if (settings_.collect_functions_enabled()) + dec_.collect_functions() = true; - next_token(); + if (settings_.collect_assignments_enabled()) + dec_.collect_assignments() = true; - if (!token_is(token_t::e_lbracket)) + if (settings_.replacer_enabled()) { - set_error( - make_error(parser_error::e_syntax, - current_token_, - "ERR18 - Expected a '(' at start of function call, instead got: '" + current_token_.value + "'")); - - return 0; + symbol_replacer_.clear(); + 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_); } - int param_index = 0; - - for (; param_index < static_cast(MaxNumberofParameters); ++param_index) + if (settings_.commutative_check_enabled()) { - param_list[param_index] = parse_expression(); - - if (0 == param_list[param_index]) + for (std::size_t i = 0; i < details::reserved_words_size; ++i) { - return 0; + commutative_inserter_.ignore_symbol(details::reserved_words[i]); } - else if (token_is(token_t::e_rbracket)) - break; - else if (token_is(token_t::e_comma)) - continue; - else - { - set_error( - make_error(parser_error::e_syntax, - current_token_, - "ERR19 - Expected a ',' between function input parameters, instead got: '" + current_token_.value + "'")); - return 0; - } + helper_assembly_.token_inserter_list.clear(); + helper_assembly_.register_inserter(&commutative_inserter_); } - sd.delete_ptr = false; + if (settings_.joiner_enabled()) + { + helper_assembly_.token_joiner_list.clear(); + helper_assembly_.register_joiner(&operator_joiner_2_); + helper_assembly_.register_joiner(&operator_joiner_3_); + } - return (param_index + 1); - } - - inline expression_node_ptr parse_base_operation() - { - typedef std::pair map_range_t; - - const std::string operation_name = current_token_.value; - map_range_t itr_range = base_ops_map_.equal_range(operation_name); - - if (0 == std::distance(itr_range.first,itr_range.second)) + if ( + settings_.numeric_check_enabled () || + settings_.bracket_check_enabled () || + settings_.sequence_check_enabled() + ) { - set_error( - make_error(parser_error::e_syntax, - current_token_, - "ERR20 - No entry found for base operation: " + operation_name)); - - return error_node(); - } - - const std::size_t MaxNumberofParameters = 6; - expression_node_ptr param_list[MaxNumberofParameters] = {0}; - - std::size_t parameter_count = parse_base_function_call(param_list); + helper_assembly_.token_scanner_list.clear(); - if (0 == parameter_count) - { - return error_node(); - } - else if (parameter_count <= 6) - { - for (base_ops_map_t::iterator itr = itr_range.first; itr != itr_range.second; ++itr) + if (settings_.numeric_check_enabled()) { - details::base_operation_t& operation = itr->second; - - if (operation.num_params == parameter_count) - { - switch (parameter_count) - { - #define base_opr_case(N) \ - case N : { \ - expression_node_ptr pl##N[N] = {0}; \ - std::copy(param_list,param_list + N,pl##N); \ - lodge_symbol(operation_name,e_st_function); \ - return expression_generator_(operation.type,pl##N);\ - } \ + helper_assembly_.register_scanner(&numeric_checker_); + } - base_opr_case(1) - base_opr_case(2) - base_opr_case(3) - base_opr_case(4) - base_opr_case(5) - base_opr_case(6) - #undef base_opr_case - } - } + if (settings_.bracket_check_enabled()) + { + helper_assembly_.register_scanner(&bracket_checker_); } - } - for (std::size_t i = 0; i < MaxNumberofParameters; ++i) - { - free_node(node_allocator_,param_list[i]); + if (settings_.sequence_check_enabled()) + { + helper_assembly_.register_scanner(&sequence_validator_ ); + helper_assembly_.register_scanner(&sequence_validator_3tkns_); + } } - - set_error( - make_error(parser_error::e_syntax, - current_token_, - "ERR21 - Invalid number of parameters for call to function: '" + operation_name + "'")); - - return error_node(); } - inline expression_node_ptr parse_conditional_statement_01(expression_node_ptr condition) + inline bool compile(const std::string& expression_string, expression& expr) { - // Parse: [if][(][condition][,][consequent][,][alternative][)] + state_ .reset(); + error_list_ .clear(); + brkcnt_list_ .clear(); + synthesis_error_.clear(); + sem_ .cleanup(); - expression_node_ptr consequent = error_node(); - expression_node_ptr alternative = error_node(); + return_cleanup(); - bool result = true; + expression_generator_.set_allocator(node_allocator_); - if (!token_is(token_t::e_comma)) - { - set_error( - make_error(parser_error::e_syntax, - current_token_, - "ERR22 - Expected ',' between if-statement condition and consequent")); - result = false; - } - else if (0 == (consequent = parse_expression())) + if (expression_string.empty()) { set_error( make_error(parser_error::e_syntax, - current_token_, - "ERR23 - Failed to parse consequent for if-statement")); - result = false; + "ERR001 - Empty expression!", + exprtk_error_location)); + + return false; } - else if (!token_is(token_t::e_comma)) + + if (!init(expression_string)) { - set_error( - make_error(parser_error::e_syntax, - current_token_, - "ERR24 - Expected ',' between if-statement consequent and alternative")); - result = false; + process_lexer_errors(); + return false; } - else if (0 == (alternative = parse_expression())) + + if (lexer().empty()) { set_error( make_error(parser_error::e_syntax, - current_token_, - "ERR25 - Failed to parse alternative for if-statement")); - result = false; + "ERR002 - Empty expression!", + exprtk_error_location)); + + return false; } - else if (!token_is(token_t::e_rbracket)) + + if (!run_assemblies()) { - set_error( - make_error(parser_error::e_syntax, - current_token_, - "ERR26 - Expected ')' at the end of if-statement")); - result = false; + return false; } - if (!result) - { - free_node(node_allocator_, condition); - free_node(node_allocator_, consequent); - free_node(node_allocator_,alternative); + symtab_store_.symtab_list_ = expr.get_symbol_table_list(); + dec_.clear(); - return error_node(); - } - else - return expression_generator_.conditional(condition,consequent,alternative); - } + lexer().begin(); - inline expression_node_ptr parse_conditional_statement_02(expression_node_ptr condition) - { - expression_node_ptr consequent = error_node(); - expression_node_ptr alternative = error_node(); + next_token(); - bool result = true; + expression_node_ptr e = parse_corpus(); - if (token_is(token_t::e_lcrlbracket,false)) + if ((0 != e) && (token_t::e_eof == current_token().type)) { - if (0 == (consequent = parse_multi_sequence("if-statement-01"))) + bool* retinvk_ptr = 0; + + if (state_.return_stmt_present) { - set_error( - make_error(parser_error::e_syntax, - current_token_, - "ERR27 - Failed to parse body of consequent for if-statement")); - result = false; + dec_.return_present_ = true; + + e = expression_generator_ + .return_envelope(e, results_context_, retinvk_ptr); } + + expr.set_expression(e); + expr.set_retinvk(retinvk_ptr); + + register_local_vars(expr); + register_return_results(expr); + + return !(!expr); } else { - if ( - commutative_check_enabled() && - token_is(token_t::e_mul,false) - ) - { - next_token(); - } - - if (0 != (consequent = parse_expression())) - { - if (!token_is(token_t::e_eof)) - { - set_error( - make_error(parser_error::e_syntax, - current_token_, - "ERR28 - Expected ';' at the end of the consequent for if-statement")); - result = false; - } - } - else + if (error_list_.empty()) { set_error( make_error(parser_error::e_syntax, - current_token_, - "ERR29 - Failed to parse body of consequent for if-statement")); - result = false; + current_token(), + "ERR003 - Invalid expression encountered", + exprtk_error_location)); } - } - if (result) - { - if (details::imatch(current_token_.value,"else")) + if ((0 != e) && branch_deletable(e)) { - next_token(); - - if (token_is(token_t::e_lcrlbracket,false)) - { - if (0 == (alternative = parse_multi_sequence("else-statement-01"))) - { - set_error( - make_error(parser_error::e_syntax, - current_token_, - "ERR30 - Failed to parse body of the 'else' for if-statement")); - result = false; - } - } - else if (details::imatch(current_token_.value,"if")) - { - if (0 == (alternative = parse_conditional_statement())) - { - set_error( - make_error(parser_error::e_syntax, - current_token_, - "ERR31 - Failed to parse body of if-else statement")); - result = false; - } - } - else if (0 != (alternative = parse_expression())) - { - if (!token_is(token_t::e_eof)) - { - set_error( - make_error(parser_error::e_syntax, - current_token_, - "ERR32 - Expected ';' at the end of the 'else-if' for the if-statement")); - result = false; - } - } - else - { - set_error( - make_error(parser_error::e_syntax, - current_token_, - "ERR33 - Failed to parse body of the 'else' for if-statement")); - result = false; - } + destroy_node(e); } - } - if (!result) - { - free_node(node_allocator_, condition); - free_node(node_allocator_, consequent); - free_node(node_allocator_,alternative); + dec_.clear (); + sem_.cleanup (); + return_cleanup(); - return error_node(); + return false; } - else - return expression_generator_.conditional(condition,consequent,alternative); } - inline expression_node_ptr parse_conditional_statement() + inline expression_t compile(const std::string& expression_string, symbol_table_t& symtab) { - expression_node_ptr condition = error_node(); + expression_t expression; - next_token(); + expression.register_symbol_table(symtab); - if (!token_is(token_t::e_lbracket)) - { - set_error( - make_error(parser_error::e_syntax, - current_token_, - "ERR34 - Expected '(' at start of if-statement, instead got: '" + current_token_.value + "'")); + compile(expression_string,expression); - return error_node(); - } - else if (0 == (condition = parse_expression())) - { - set_error( - make_error(parser_error::e_syntax, - current_token_, - "ERR35 - Failed to parse condition for if-statement")); + return expression; + } - return error_node(); - } - else if (token_is(token_t::e_comma,false)) - { - // if (x,y,z) - return parse_conditional_statement_01(condition); - } - else if (token_is(token_t::e_rbracket)) + void process_lexer_errors() + { + for (std::size_t i = 0; i < lexer().size(); ++i) { - // 00. if (x) y; - // 01. if (x) y; else z; - // 02. if (x) y; else {z0; ... zn;} - // 03. if (x) y; else if (z) w; - // 04. if (x) y; else if (z) w; else u; - // 05. if (x) y; else if (z) w; else {u0; ... un;} - // 06. if (x) y; else if (z) {w0; ... wn;} - // 07. if (x) {y0; ... yn;} - // 08. if (x) {y0; ... yn;} else z; - // 09. if (x) {y0; ... yn;} else {z0; ... zn;}; - // 10. if (x) {y0; ... yn;} else if (z) w; - // 11. if (x) {y0; ... yn;} else if (z) w; else u; - // 12. if (x) {y0; ... nex;} else if (z) w; else {u0 ... un;} - // 13. if (x) {y0; ... yn;} else if (z) {w0; ... wn;} - return parse_conditional_statement_02(condition); - } + if (lexer()[i].is_error()) + { + std::string diagnostic = "ERR004 - "; - set_error( - make_error(parser_error::e_syntax, - current_token_, - "ERR36 - Invalid if-statement")); + switch (lexer()[i].type) + { + case lexer::token::e_error : diagnostic += "General token error"; + break; - free_node(node_allocator_,condition); + case lexer::token::e_err_symbol : diagnostic += "Symbol error"; + break; - return error_node(); - } + case lexer::token::e_err_number : diagnostic += "Invalid numeric token"; + break; - inline expression_node_ptr parse_ternary_conditional_statement(expression_node_ptr condition) - { - // Parse: [condition][?][consequent][:][alternative] - expression_node_ptr consequent = error_node(); - expression_node_ptr alternative = error_node(); + case lexer::token::e_err_string : diagnostic += "Invalid string token"; + break; - bool result = true; + case lexer::token::e_err_sfunc : diagnostic += "Invalid special function token"; + break; - if (0 == condition) - { - set_error( - make_error(parser_error::e_syntax, - current_token_, - "ERR37 - Encountered invalid condition branch for ternary if-statement")); + default : diagnostic += "Unknown compiler error"; + } - return error_node(); + set_error( + make_error(parser_error::e_lexer, + lexer()[i], + diagnostic + ": " + lexer()[i].value, + exprtk_error_location)); + } } - else if (!token_is(token_t::e_ternary)) - { - set_error( - make_error(parser_error::e_syntax, - current_token_, - "ERR38 - Expected '?' after condition of ternary if-statement")); + } - result = false; - } - else if (0 == (consequent = parse_expression())) + inline bool run_assemblies() + { + if (settings_.commutative_check_enabled()) { - set_error( - make_error(parser_error::e_syntax, - current_token_, - "ERR39 - Failed to parse consequent for if-statement")); - - result = false; + helper_assembly_.run_inserters(lexer()); } - else if (!token_is(token_t::e_colon)) - { - set_error( - make_error(parser_error::e_syntax, - current_token_, - "ERR40 - Expected ':' between ternary if-statement consequent and alternative")); - result = false; - } - else if (0 == (alternative = parse_expression())) + if (settings_.joiner_enabled()) { - set_error( - make_error(parser_error::e_syntax, - current_token_, - "ERR41 - Failed to parse alternative for if-statement")); - - result = false; + helper_assembly_.run_joiners(lexer()); } - if (!result) + if (settings_.replacer_enabled()) { - free_node(node_allocator_, condition); - free_node(node_allocator_, consequent); - free_node(node_allocator_,alternative); - - return error_node(); + helper_assembly_.run_modifiers(lexer()); } - else - return expression_generator_.conditional(condition,consequent,alternative); - } - inline expression_node_ptr parse_while_loop() - { - // Parse: [while][(][test expr][)][{][expression][}] - expression_node_ptr condition = error_node(); - expression_node_ptr branch = error_node(); - expression_node_ptr result_node = error_node(); + if ( + settings_.numeric_check_enabled () || + settings_.bracket_check_enabled () || + settings_.sequence_check_enabled() + ) + { + if (!helper_assembly_.run_scanners(lexer())) + { + 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::sequence_validator_3tokens* sequence_validator3_ptr = 0; - bool result = true; + 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(), + "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))) + { + for (std::size_t i = 0; i < numeric_checker_ptr->error_count(); ++i) + { + lexer::token error_token = lexer()[numeric_checker_ptr->error_index(i)]; - next_token(); + set_error( + make_error(parser_error::e_token, + error_token, + "ERR006 - Invalid numeric token: '" + error_token.value + "'", + exprtk_error_location)); + } - if (!token_is(token_t::e_lbracket)) - { - set_error( - make_error(parser_error::e_syntax, - current_token_, - "ERR42 - Expected '(' at start of while-loop condition statement")); + if (numeric_checker_ptr->error_count()) + { + numeric_checker_ptr->clear_errors(); + } + } + else if (0 != (sequence_validator_ptr = dynamic_cast(helper_assembly_.error_token_scanner))) + { + for (std::size_t i = 0; i < sequence_validator_ptr->error_count(); ++i) + { + std::pair error_token = sequence_validator_ptr->error(i); - return error_node(); - } - else if (0 == (condition = parse_expression())) - { - set_error( - make_error(parser_error::e_syntax, - current_token_, - "ERR43 - Failed to parse condition for while-loop")); + set_error( + make_error(parser_error::e_token, + error_token.first, + "ERR007 - Invalid token sequence: '" + + error_token.first.value + "' and '" + + error_token.second.value + "'", + exprtk_error_location)); + } - return error_node(); - } - else if (!token_is(token_t::e_rbracket)) - { - set_error( - make_error(parser_error::e_syntax, - current_token_, - "ERR44 - Expected ')' at end of while-loop condition statement")); - result = false; - } + if (sequence_validator_ptr->error_count()) + { + 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); - brkcnt_list_.push_front(false); + 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 (result) - { - if (0 == (branch = parse_multi_sequence("while-loop"))) - { - set_error( - make_error(parser_error::e_syntax, - current_token_, - "ERR45 - Failed to parse body of while-loop")); - result = false; - } - else if (0 == (result_node = expression_generator_.while_loop(condition, - branch, - brkcnt_list_.front()))) - { - set_error( - make_error(parser_error::e_syntax, - current_token_, - "ERR46 - Failed to synthesize while-loop")); - result = false; + if (sequence_validator3_ptr->error_count()) + { + sequence_validator3_ptr->clear_errors(); + } + } + } + + return false; } } - if (!result) - { - free_node(node_allocator_, branch); - free_node(node_allocator_, condition); - free_node(node_allocator_,result_node); + return true; + } - brkcnt_list_.pop_front(); + inline settings_store& settings() + { + return settings_; + } - return error_node(); - } + inline parser_error::type get_error(const std::size_t& index) const + { + if (index < error_list_.size()) + return error_list_[index]; else - return result_node; + throw std::invalid_argument("parser::get_error() - Invalid error index specificed"); } - inline expression_node_ptr parse_repeat_until_loop() + inline std::string error() const { - // Parse: [repeat][{][expression][}][until][(][test expr][)] - expression_node_ptr condition = error_node(); - expression_node_ptr branch = error_node(); - next_token(); - - std::vector arg_list; - scoped_vec_delete sdd(*this,arg_list); - - brkcnt_list_.push_front(false); - - if (details::imatch(current_token_.value,"until")) + if (!error_list_.empty()) { - next_token(); - branch = node_allocator_.allocate >(); + return error_list_[0].diagnostic; } else - { - token_t::token_type seperator = token_t::e_eof; - - scope_handler sh(*this); + return std::string("No Error"); + } - for (;;) - { - expression_node_ptr arg = parse_expression(); + inline std::size_t error_count() const + { + return error_list_.size(); + } - if (0 == arg) - return error_node(); - else - arg_list.push_back(arg); + inline dependent_entity_collector& dec() + { + return dec_; + } - if (details::imatch(current_token_.value,"until")) - { - next_token(); - break; - } + inline bool replace_symbol(const std::string& old_symbol, const std::string& new_symbol) + { + if (!settings_.replacer_enabled()) + return false; + else if (details::is_reserved_word(old_symbol)) + return false; + else + return symbol_replacer_.add_replace(old_symbol,new_symbol,lexer::token::e_symbol); + } - bool is_next_until = peek_token_is(token_t::e_symbol) && - peek_token_is("until"); + inline bool remove_replace_symbol(const std::string& symbol) + { + if (!settings_.replacer_enabled()) + return false; + else if (details::is_reserved_word(symbol)) + return false; + else + return symbol_replacer_.remove(symbol); + } - if (!token_is(seperator) && is_next_until) - { - set_error( - make_error(parser_error::e_syntax, - current_token_, - "ERR47 - Expected '" + token_t::to_str(seperator) + "' for body of repeat until loop")); + inline void enable_unknown_symbol_resolver(unknown_symbol_resolver* usr = reinterpret_cast(0)) + { + resolve_unknown_symbol_ = true; - return error_node(); - } + if (usr) + unknown_symbol_resolver_ = usr; + else + unknown_symbol_resolver_ = &default_usr_; + } - if (details::imatch(current_token_.value,"until")) - { - next_token(); - break; - } - } + inline void enable_unknown_symbol_resolver(unknown_symbol_resolver& usr) + { + enable_unknown_symbol_resolver(&usr); + } - branch = simplify(arg_list); + inline void disable_unknown_symbol_resolver() + { + resolve_unknown_symbol_ = false; + unknown_symbol_resolver_ = &default_usr_; + } - if ((sdd.delete_ptr = (0 == branch))) - { - brkcnt_list_.pop_front(); + inline void register_loop_runtime_check(loop_runtime_check& lrtchk) + { + loop_runtime_check_ = &lrtchk; + } - set_error( - make_error(parser_error::e_syntax, - current_token_, - "ERR48 - Failed to parse body of repeat until loop")); + inline void clear_loop_runtime_check() + { + loop_runtime_check_ = loop_runtime_check_ptr(0); + } - return error_node(); - } - } + private: - if (!token_is(token_t::e_lbracket)) - { - brkcnt_list_.pop_front(); + inline bool valid_base_operation(const std::string& symbol) const + { + const std::size_t length = symbol.size(); - set_error( - make_error(parser_error::e_syntax, - current_token_, - "ERR49 - Expected '(' before condition statement of repeat until loop")); + if ( + (length < 3) || // Shortest base op symbol length + (length > 9) // Longest base op symbol length + ) + return false; + else + return settings_.function_enabled(symbol) && + (base_ops_map_.end() != base_ops_map_.find(symbol)); + } - free_node(node_allocator_,branch); + inline bool valid_vararg_operation(const std::string& symbol) const + { + static const std::string s_sum = "sum" ; + static const std::string s_mul = "mul" ; + static const std::string s_avg = "avg" ; + static const std::string s_min = "min" ; + static const std::string s_max = "max" ; + static const std::string s_mand = "mand"; + static const std::string s_mor = "mor" ; + static const std::string s_multi = "~" ; + static const std::string s_mswitch = "[*]" ; - return error_node(); - } - else if (0 == (condition = parse_expression())) - { - brkcnt_list_.pop_front(); - - set_error( - make_error(parser_error::e_syntax, - current_token_, - "ERR50 - Failed to parse condition for repeat until loop")); - - free_node(node_allocator_,branch); - - return error_node(); - } - else if (!token_is(token_t::e_rbracket)) - { - set_error( - make_error(parser_error::e_syntax, - current_token_, - "ERR51 - Expected ')' after condition of repeat until loop")); - - free_node(node_allocator_, branch); - free_node(node_allocator_, condition); - - brkcnt_list_.pop_front(); - - return error_node(); - } - - expression_node_ptr result; + return + ( + details::imatch(symbol,s_sum ) || + details::imatch(symbol,s_mul ) || + details::imatch(symbol,s_avg ) || + details::imatch(symbol,s_min ) || + details::imatch(symbol,s_max ) || + details::imatch(symbol,s_mand ) || + details::imatch(symbol,s_mor ) || + details::imatch(symbol,s_multi ) || + details::imatch(symbol,s_mswitch) + ) && + settings_.function_enabled(symbol); + } - result = expression_generator_ - .repeat_until_loop(condition,branch,brkcnt_list_.front()); + bool is_invalid_logic_operation(const details::operator_type operation) const + { + return settings_.logic_disabled(operation); + } - if (0 == result) - { - set_error( - make_error(parser_error::e_syntax, - current_token_, - "ERR52 - Failed to synthesize repeat until loop")); + bool is_invalid_arithmetic_operation(const details::operator_type operation) const + { + return settings_.arithmetic_disabled(operation); + } - free_node(node_allocator_, condition); - brkcnt_list_.pop_front(); + bool is_invalid_assignment_operation(const details::operator_type operation) const + { + return settings_.assignment_disabled(operation); + } - return error_node(); - } - else - { - brkcnt_list_.pop_front(); - return result; - } + bool is_invalid_inequality_operation(const details::operator_type operation) const + { + return settings_.inequality_disabled(operation); } - inline expression_node_ptr parse_for_loop() + #ifdef exprtk_enable_debugging + inline void next_token() { - expression_node_ptr initialiser = error_node(); - expression_node_ptr condition = error_node(); - expression_node_ptr incrementor = error_node(); - expression_node_ptr loop_body = error_node(); + const std::string ct_str = current_token().value; + const std::size_t ct_pos = current_token().position; + parser_helper::next_token(); + const std::string depth(2 * state_.scope_depth,' '); + exprtk_debug(("%s" + "prev[%s | %04d] --> curr[%s | %04d] stack_level: %3d\n", + depth.c_str(), + ct_str.c_str(), + static_cast(ct_pos), + current_token().value.c_str(), + static_cast(current_token().position), + static_cast(state_.stack_depth))); + } + #endif - scope_element* se = 0; - bool result = true; - std::string loop_counter_symbol; + inline expression_node_ptr parse_corpus() + { + std::vector arg_list; + std::vector side_effect_list; - next_token(); + scoped_vec_delete sdd((*this),arg_list); - scope_handler sh(*this); + lexer::token begin_token; + lexer::token end_token; - if (!token_is(token_t::e_lbracket)) + for ( ; ; ) { - set_error( - make_error(parser_error::e_syntax, - current_token_, - "ERR53 - Expected '(' at start of for-loop")); - - return error_node(); - } + state_.side_effect_present = false; - if (!token_is(token_t::e_eof)) - { - if ( - !token_is(token_t::e_symbol,false) && - details::imatch(current_token_.value,"var") - ) - { - next_token(); + begin_token = current_token(); - if (!token_is(token_t::e_symbol,false)) - { - set_error( - make_error(parser_error::e_syntax, - current_token_, - "ERR54 - Expected a variable at the start of initialiser section of for-loop")); + expression_node_ptr arg = parse_expression(); - return error_node(); - } - else if (!peek_token_is(token_t::e_assign)) + if (0 == arg) + { + if (error_list_.empty()) { set_error( make_error(parser_error::e_syntax, - current_token_, - "ERR55 - Expected variable assignment of initialiser section of for-loop")); - - return error_node(); + current_token(), + "ERR009 - Invalid expression encountered", + exprtk_error_location)); } - loop_counter_symbol = current_token_.value; - - se = &sem_.get_element(loop_counter_symbol); + return error_node(); + } + else + { + arg_list.push_back(arg); - if ((se->name == loop_counter_symbol) && se->active) - { - set_error( - make_error(parser_error::e_syntax, - current_token_, - "ERR56 - For-loop variable '" + loop_counter_symbol+ "' is being shadowed by a previous declaration")); + side_effect_list.push_back(state_.side_effect_present); - return error_node(); - } - else if (!symbol_table_.is_variable(loop_counter_symbol)) - { - if ( - !se->active && - (se->name == loop_counter_symbol) && - (se->type == scope_element::e_variable) - ) - { - se->active = true; - se->ref_count++; - } - else - { - scope_element nse; - nse.name = loop_counter_symbol; - nse.type = scope_element::e_variable; - nse.depth = scope_depth_; - nse.data = new T(T(0)); - nse.var_node = new variable_node_t(*(T*)(nse.data)); + end_token = current_token(); - if (!sem_.add_element(nse)) - { - set_error( - make_error(parser_error::e_syntax, - current_token_, - "ERR57 - Failed to add new local variable '" + loop_counter_symbol + "' to SEM")); + const std::string sub_expr = construct_subexpr(begin_token, end_token); - result = false; + exprtk_debug(("parse_corpus(%02d) Subexpr: %s\n", + static_cast(arg_list.size() - 1), + sub_expr.c_str())); - } - else - exprtk_debug(("parse_for_loop() - INFO - Added new local variable: %s\n",nse.name.c_str())); - } - } - } + exprtk_debug(("parse_corpus(%02d) - Side effect present: %s\n", + static_cast(arg_list.size() - 1), + state_.side_effect_present ? "true" : "false")); - if (0 == (initialiser = parse_expression())) - { - set_error( - make_error(parser_error::e_syntax, - current_token_, - "ERR58 - Failed to parse initialiser of for-loop")); - result = false; + exprtk_debug(("-------------------------------------------------\n")); } - if (!token_is(token_t::e_eof)) + if (lexer().finished()) + break; + else if (token_is(token_t::e_eof,prsrhlpr_t::e_hold)) { - set_error( - make_error(parser_error::e_syntax, - current_token_, - "ERR59 - Expected ';' after initialiser of for-loop")); - result = false; + if (lexer().finished()) + break; + else + next_token(); } } - if (!token_is(token_t::e_eof)) + if ( + !arg_list.empty() && + is_return_node(arg_list.back()) + ) { - if (0 == (condition = parse_expression())) - { - set_error( - make_error(parser_error::e_syntax, - current_token_, - "ERR60 - Failed to parse condition of for-loop")); - result = false; - } - else if (!token_is(token_t::e_eof)) - { - set_error( - make_error(parser_error::e_syntax, - current_token_, - "ERR61 - Expected ';' after condition section of for-loop")); - result = false; - } + dec_.final_stmt_return_ = true; } - if (!token_is(token_t::e_rbracket)) - { - if (0 == (incrementor = parse_expression())) - { - set_error( - make_error(parser_error::e_syntax, - current_token_, - "ERR62 - Failed to parse incrementor of for-loop")); - result = false; - } - else if (!token_is(token_t::e_rbracket)) - { - set_error( - make_error(parser_error::e_syntax, - current_token_, - "ERR63 - Expected ')' after incrementor section of for-loop")); - result = false; - } - } + const expression_node_ptr result = simplify(arg_list,side_effect_list); - if (result) - { - brkcnt_list_.push_front(false); - if (0 == (loop_body = parse_multi_sequence("for-loop"))) - { - set_error( - make_error(parser_error::e_syntax, - current_token_, - "ERR64 - Failed to parse body of for-loop")); - result = false; - } - } + sdd.delete_ptr = (0 == result); - if (!result) - { - if (se) - { - se->ref_count--; - } + return result; + } - sem_.cleanup(); + std::string construct_subexpr(lexer::token& begin_token, lexer::token& end_token) + { + std::string result = lexer().substr(begin_token.position,end_token.position); - free_node(node_allocator_,initialiser); - free_node(node_allocator_, condition); - free_node(node_allocator_,incrementor); - free_node(node_allocator_, loop_body); + for (std::size_t i = 0; i < result.size(); ++i) + { + if (details::is_whitespace(result[i])) result[i] = ' '; + } - if (!brkcnt_list_.empty()) - { - brkcnt_list_.pop_front(); - } + return result; + } - return error_node(); - } - else + static const precedence_level default_precedence = e_level00; + + struct state_t + { + inline void set(const precedence_level& l, + const precedence_level& r, + const details::operator_type& o) { - expression_node_ptr result_node = - expression_generator_.for_loop(initialiser, - condition, - incrementor, - loop_body, - brkcnt_list_.front()); - brkcnt_list_.pop_front(); + left = l; + right = r; + operation = o; + } - return result_node; + inline void reset() + { + left = e_level00; + right = e_level00; + operation = details::e_default; } - } - inline expression_node_ptr parse_switch_statement() + precedence_level left; + precedence_level right; + details::operator_type operation; + }; + + inline expression_node_ptr parse_expression(precedence_level precedence = e_level00) { - std::vector arg_list; - expression_node_ptr result = error_node(); + stack_limit_handler slh(*this); - if (!details::imatch(current_token_.value,"switch")) + if (!slh) { - set_error( - make_error(parser_error::e_syntax, - current_token_, - "ERR65 - Expected keyword 'switch'")); - return error_node(); } - scoped_vec_delete svd(*this,arg_list); - - next_token(); + expression_node_ptr expression = parse_branch(precedence); - if (!token_is(token_t::e_lcrlbracket)) + if (0 == expression) { - set_error( - make_error(parser_error::e_syntax, - current_token_, - "ERR66 - Expected '{' for call to switch statement")); - return error_node(); } + bool break_loop = false; + + state_t current_state; + for ( ; ; ) { - if (!details::imatch("case",current_token_.value)) - { - set_error( - make_error(parser_error::e_syntax, - current_token_, - "ERR67 - Expected either a 'case' or 'default' statement")); + current_state.reset(); - return error_node(); + 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; + default : if (token_t::e_symbol == current_token().type) + { + static const std::string s_and = "and"; + static const std::string s_nand = "nand"; + static const std::string s_or = "or"; + static const std::string s_nor = "nor"; + static const std::string s_xor = "xor"; + static const std::string s_xnor = "xnor"; + static const std::string s_in = "in"; + static const std::string s_like = "like"; + static const std::string s_ilike = "ilike"; + static const std::string s_and1 = "&"; + static const std::string s_or1 = "|"; + static const std::string s_not = "not"; + + if (details::imatch(current_token().value,s_and)) + { + current_state.set(e_level03, e_level04, details::e_and); + break; + } + else if (details::imatch(current_token().value,s_and1)) + { + #ifndef exprtk_disable_sc_andor + current_state.set(e_level03, e_level04, details::e_scand); + #else + current_state.set(e_level03, e_level04, details::e_and); + #endif + break; + } + else if (details::imatch(current_token().value,s_nand)) + { + current_state.set(e_level03, e_level04, details::e_nand); + break; + } + else if (details::imatch(current_token().value,s_or)) + { + current_state.set(e_level01, e_level02, details::e_or); + break; + } + else if (details::imatch(current_token().value,s_or1)) + { + #ifndef exprtk_disable_sc_andor + current_state.set(e_level01, e_level02, details::e_scor); + #else + current_state.set(e_level01, e_level02, details::e_or); + #endif + break; + } + else if (details::imatch(current_token().value,s_nor)) + { + current_state.set(e_level01, e_level02, details::e_nor); + break; + } + else if (details::imatch(current_token().value,s_xor)) + { + current_state.set(e_level01, e_level02, details::e_xor); + break; + } + else if (details::imatch(current_token().value,s_xnor)) + { + current_state.set(e_level01, e_level02, details::e_xnor); + break; + } + else if (details::imatch(current_token().value,s_in)) + { + current_state.set(e_level04, e_level04, details::e_in); + break; + } + else if (details::imatch(current_token().value,s_like)) + { + current_state.set(e_level04, e_level04, details::e_like); + break; + } + else if (details::imatch(current_token().value,s_ilike)) + { + current_state.set(e_level04, e_level04, details::e_ilike); + break; + } + else if (details::imatch(current_token().value,s_not)) + { + break; + } + } + + break_loop = true; + } + + if (break_loop) + { + parse_pending_string_rangesize(expression); + break; } + else if (current_state.left < precedence) + break; + + const lexer::token prev_token = current_token(); next_token(); - expression_node_ptr condition = parse_expression(); + expression_node_ptr right_branch = error_node(); + expression_node_ptr new_expression = error_node(); - if (0 == condition) - return error_node(); - else if (!token_is(token_t::e_colon)) + if (is_invalid_logic_operation(current_state.operation)) { + free_node(node_allocator_,expression); + set_error( make_error(parser_error::e_syntax, - current_token_, - "ERR68 - Expected ':' for case of switch statement")); + 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); - expression_node_ptr consequent = parse_expression(); + set_error( + make_error(parser_error::e_syntax, + prev_token, + "ERR011 - Invalid or disabled arithmetic operation '" + details::to_str(current_state.operation) + "'", + exprtk_error_location)); - if (0 == consequent) return error_node(); - else if (!token_is(token_t::e_eof)) + } + else if (is_invalid_inequality_operation(current_state.operation)) { + free_node(node_allocator_,expression); + set_error( make_error(parser_error::e_syntax, - current_token_, - "ERR69 - Expected ';' at end of case for switch statement")); + prev_token, + "ERR012 - Invalid inequality operation '" + details::to_str(current_state.operation) + "'", + exprtk_error_location)); return error_node(); } - - // Can we optimize away the case statement? - if (is_constant_node(condition) && is_false(condition)) + else if (is_invalid_assignment_operation(current_state.operation)) { - free_node(node_allocator_, condition); - free_node(node_allocator_,consequent); + free_node(node_allocator_,expression); - condition = 0; - consequent = 0; - } - else - { - arg_list.push_back(condition); - arg_list.push_back(consequent); + set_error( + make_error(parser_error::e_syntax, + prev_token, + "ERR013 - Invalid or disabled assignment operation '" + details::to_str(current_state.operation) + "'", + exprtk_error_location)); + + return error_node(); } - if (details::imatch("default",current_token_.value)) + if (0 != (right_branch = parse_expression(current_state.right))) { - next_token(); - if (!token_is(token_t::e_colon)) + if ( + details::is_return_node( expression) || + details::is_return_node(right_branch) + ) { + free_node(node_allocator_, expression); + free_node(node_allocator_, right_branch); + set_error( make_error(parser_error::e_syntax, - current_token_, - "ERR70 - Expected ':' for default of switch statement")); + prev_token, + "ERR014 - Return statements cannot be part of sub-expressions", + exprtk_error_location)); return error_node(); } - expression_node_ptr default_statement = parse_expression(); + new_expression = expression_generator_ + ( + current_state.operation, + expression, + right_branch + ); + } - if (0 == default_statement) - return error_node(); - else if (!token_is(token_t::e_eof)) + if (0 == new_expression) + { + if (error_list_.empty()) { set_error( make_error(parser_error::e_syntax, - current_token_, - "ERR71 - Expected ';' at end of default for switch statement")); + prev_token, + !synthesis_error_.empty() ? + synthesis_error_ : + "ERR015 - General parsing error at token: '" + prev_token.value + "'", + exprtk_error_location)); + } - return error_node(); + free_node(node_allocator_, expression); + free_node(node_allocator_, right_branch); + + return error_node(); + } + else + { + if ( + token_is(token_t::e_ternary,prsrhlpr_t::e_hold) && + (precedence == e_level00) + ) + { + expression = parse_ternary_conditional_statement(new_expression); } + else + expression = new_expression; - arg_list.push_back(default_statement); - break; + parse_pending_string_rangesize(expression); } } - if (!token_is(token_t::e_rcrlbracket)) + if ((0 != expression) && (expression->node_depth() > settings_.max_node_depth_)) { set_error( make_error(parser_error::e_syntax, - current_token_, - "ERR72 - Expected '}' at end of switch statement")); + 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(); } - result = expression_generator_.switch_statement(arg_list); - - svd.delete_ptr = (0 == result); - - return result; + return expression; } - inline expression_node_ptr parse_multi_switch_statement() + bool simplify_unary_negation_branch(expression_node_ptr& node) { - 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_, - "ERR73 - Expected token '[*]'")); - - return error_node(); - } + typedef details::unary_branch_node > ubn_t; + ubn_t* n = dynamic_cast(node); - scoped_vec_delete svd(*this,arg_list); + if (n) + { + expression_node_ptr un_r = n->branch(0); + n->release(); + free_node(node_allocator_,node); + node = un_r; - next_token(); + return true; + } + } - if (!token_is(token_t::e_lcrlbracket)) { - set_error( - make_error(parser_error::e_syntax, - current_token_, - "ERR74 - Expected '{' for call to [*] statement")); + typedef details::unary_variable_node > uvn_t; - return error_node(); - } + uvn_t* n = dynamic_cast(node); - for ( ; ; ) - { - if (!details::imatch("case",current_token_.value)) + if (n) { - set_error( - make_error(parser_error::e_syntax, - current_token_, - "ERR75 - Expected a 'case' statement for multi-switch")); + const T& v = n->v(); + expression_node_ptr return_node = error_node(); - return error_node(); + if ( + (0 != (return_node = symtab_store_.get_variable(v))) || + (0 != (return_node = sem_ .get_variable(v))) + ) + { + free_node(node_allocator_,node); + node = return_node; + + return true; + } + else + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR017 - Failed to find variable node in symbol table", + exprtk_error_location)); + + free_node(node_allocator_,node); + + return false; + } } + } - next_token(); + return false; + } - expression_node_ptr condition = parse_expression(); + static inline expression_node_ptr error_node() + { + return reinterpret_cast(0); + } - if (0 == condition) - return error_node(); + struct scoped_expression_delete + { + scoped_expression_delete(parser& pr, expression_node_ptr& expression) + : delete_ptr(true), + parser_(pr), + expression_(expression) + {} - if (!token_is(token_t::e_colon)) + ~scoped_expression_delete() + { + if (delete_ptr) { - set_error( - make_error(parser_error::e_syntax, - current_token_, - "ERR76 - Expected ':' for case of [*] statement")); - - return error_node(); + free_node(parser_.node_allocator_, expression_); } + } - expression_node_ptr consequent = parse_expression(); + bool delete_ptr; + parser& parser_; + expression_node_ptr& expression_; - if (0 == consequent) - return error_node(); + private: - if (!token_is(token_t::e_eof)) - { - set_error( - make_error(parser_error::e_syntax, - current_token_, - "ERR77 - Expected ';' at end of case for [*] statement")); + scoped_expression_delete& operator=(const scoped_expression_delete&); + }; - return error_node(); - } + template + struct scoped_delete + { + typedef Type* ptr_t; - // Can we optimize away the case statement? - if (is_constant_node(condition) && is_false(condition)) - { - free_node(node_allocator_, condition); - free_node(node_allocator_,consequent); + scoped_delete(parser& pr, ptr_t& p) + : delete_ptr(true), + parser_(pr), + p_(&p) + {} - condition = 0; - consequent = 0; - } - else - { - arg_list.push_back(condition); - arg_list.push_back(consequent); - } + scoped_delete(parser& pr, ptr_t (&p)[N]) + : delete_ptr(true), + parser_(pr), + p_(&p[0]) + {} - if (token_is(token_t::e_rcrlbracket,false)) + ~scoped_delete() + { + if (delete_ptr) { - break; + for (std::size_t i = 0; i < N; ++i) + { + free_node(parser_.node_allocator_, p_[i]); + } } } - if (!token_is(token_t::e_rcrlbracket)) + bool delete_ptr; + parser& parser_; + ptr_t* p_; + + private: + + scoped_delete& operator=(const scoped_delete&); + }; + + template + struct scoped_deq_delete + { + typedef Type* ptr_t; + + scoped_deq_delete(parser& pr, std::deque& deq) + : delete_ptr(true), + parser_(pr), + deq_(deq) + {} + + ~scoped_deq_delete() { - set_error( - make_error(parser_error::e_syntax, - current_token_, - "ERR78 - Expected '}' at end of [*] statement")); + if (delete_ptr && !deq_.empty()) + { + for (std::size_t i = 0; i < deq_.size(); ++i) + { + free_node(parser_.node_allocator_,deq_[i]); + } - return error_node(); + deq_.clear(); + } } - result = expression_generator_.multi_switch_statement(arg_list); + bool delete_ptr; + parser& parser_; + std::deque& deq_; - svd.delete_ptr = (0 == result); + private: - return result; - } + scoped_deq_delete& operator=(const scoped_deq_delete&); + }; - inline expression_node_ptr parse_vararg_function() + template + struct scoped_vec_delete { - std::vector arg_list; - expression_node_ptr result = error_node(); + typedef Type* ptr_t; - details::operator_type opt_type = details::e_default; - const std::string symbol = current_token_.value; + scoped_vec_delete(parser& pr, std::vector& vec) + : delete_ptr(true), + parser_(pr), + vec_(vec) + {} - if (details::imatch(symbol,"~")) + ~scoped_vec_delete() { - next_token(); - return parse_multi_sequence(); + if (delete_ptr && !vec_.empty()) + { + for (std::size_t i = 0; i < vec_.size(); ++i) + { + free_node(parser_.node_allocator_,vec_[i]); + } + + vec_.clear(); + } } - else if (details::imatch(symbol,"[*]")) + + bool delete_ptr; + parser& parser_; + std::vector& vec_; + + private: + + scoped_vec_delete& operator=(const scoped_vec_delete&); + }; + + struct scoped_bool_negator + { + explicit scoped_bool_negator(bool& bb) + : b(bb) + { b = !b; } + + ~scoped_bool_negator() + { b = !b; } + + bool& b; + }; + + struct scoped_bool_or_restorer + { + explicit scoped_bool_or_restorer(bool& bb) + : b(bb), + original_value_(bb) + {} + + ~scoped_bool_or_restorer() { - return parse_multi_switch_statement(); + b = b || original_value_; + } + + bool& b; + 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); + + switch (function->param_count) + { + case 0 : func_node = parse_function_call_0 (function,function_name); break; + case 1 : func_node = parse_function_call< 1>(function,function_name); break; + case 2 : func_node = parse_function_call< 2>(function,function_name); break; + case 3 : func_node = parse_function_call< 3>(function,function_name); break; + case 4 : func_node = parse_function_call< 4>(function,function_name); break; + case 5 : func_node = parse_function_call< 5>(function,function_name); break; + case 6 : func_node = parse_function_call< 6>(function,function_name); break; + case 7 : func_node = parse_function_call< 7>(function,function_name); break; + case 8 : func_node = parse_function_call< 8>(function,function_name); break; + case 9 : func_node = parse_function_call< 9>(function,function_name); break; + case 10 : func_node = parse_function_call<10>(function,function_name); break; + case 11 : func_node = parse_function_call<11>(function,function_name); break; + case 12 : func_node = parse_function_call<12>(function,function_name); break; + case 13 : func_node = parse_function_call<13>(function,function_name); break; + case 14 : func_node = parse_function_call<14>(function,function_name); break; + case 15 : func_node = parse_function_call<15>(function,function_name); break; + case 16 : func_node = parse_function_call<16>(function,function_name); break; + case 17 : func_node = parse_function_call<17>(function,function_name); break; + case 18 : func_node = parse_function_call<18>(function,function_name); break; + case 19 : func_node = parse_function_call<19>(function,function_name); break; + case 20 : func_node = parse_function_call<20>(function,function_name); break; + default : { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR018 - Invalid number of parameters for function: '" + function_name + "'", + exprtk_error_location)); + + return error_node(); + } } - 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; + + if (func_node) + return func_node; else { set_error( make_error(parser_error::e_syntax, - current_token_, - "ERR79 - Unsupported vararg function: " + symbol)); + current_token(), + "ERR019 - Failed to generate call to function: '" + function_name + "'", + exprtk_error_location)); + + return error_node(); + } + } + + template + inline expression_node_ptr parse_function_call(ifunction* function, const std::string& function_name) + { + #ifdef _MSC_VER + #pragma warning(push) + #pragma warning(disable: 4127) + #endif + if (0 == NumberofParameters) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR020 - Expecting ifunction '" + function_name + "' to have non-zero parameter count", + exprtk_error_location)); return error_node(); } + #ifdef _MSC_VER + #pragma warning(pop) + #endif + + expression_node_ptr branch[NumberofParameters]; + expression_node_ptr result = error_node(); + + std::fill_n(branch, NumberofParameters, reinterpret_cast(0)); - scoped_vec_delete sdd(*this,arg_list); + scoped_delete sd((*this),branch); next_token(); + if (!token_is(token_t::e_lbracket)) { set_error( make_error(parser_error::e_syntax, - current_token_, - "ERR80 - Expected '(' for call to vararg function: " + symbol)); + current_token(), + "ERR021 - Expecting argument list for function: '" + function_name + "'", + exprtk_error_location)); return error_node(); } - for ( ; ; ) + for (int i = 0; i < static_cast(NumberofParameters); ++i) { - expression_node_ptr arg = parse_expression(); - - if (0 == arg) - return error_node(); - else - arg_list.push_back(arg); + branch[i] = parse_expression(); - if (token_is(token_t::e_rbracket)) - break; - else if (!token_is(token_t::e_comma)) + if (0 == branch[i]) { set_error( make_error(parser_error::e_syntax, - current_token_, - "ERR81 - Expected ',' for call to vararg function: " + symbol)); + current_token(), + "ERR022 - Failed to parse argument " + details::to_str(i) + " for function: '" + function_name + "'", + exprtk_error_location)); return error_node(); } + else if (i < static_cast(NumberofParameters - 1)) + { + if (!token_is(token_t::e_comma)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR023 - Invalid number of arguments for function: '" + function_name + "'", + exprtk_error_location)); + + return error_node(); + } + } } - result = expression_generator_.vararg_function(opt_type,arg_list); + if (!token_is(token_t::e_rbracket)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR024 - Invalid number of arguments for function: '" + function_name + "'", + exprtk_error_location)); + + return error_node(); + } + else + result = expression_generator_.function(function,branch); + + sd.delete_ptr = (0 == result); - sdd.delete_ptr = (0 == result); return result; } - inline expression_node_ptr parse_string_range_statement(expression_node_ptr& expression) + inline expression_node_ptr parse_function_call_0(ifunction* function, const std::string& function_name) { - if (!token_is(token_t::e_lsqrbracket)) + expression_node_ptr result = expression_generator_.function(function); + + state_.side_effect_present = function->has_side_effects(); + + next_token(); + + if ( + token_is(token_t::e_lbracket) && + !token_is(token_t::e_rbracket) + ) { set_error( make_error(parser_error::e_syntax, - current_token_, - "ERR82 - Expected '[' as start of string range definition")); + current_token(), + "ERR025 - Expecting '()' to proceed call to function: '" + function_name + "'", + exprtk_error_location)); - free_node(node_allocator_,expression); + free_node(node_allocator_,result); return error_node(); } - else if (token_is(token_t::e_rsqrbracket)) - { - return node_allocator_.allocate >(expression); - } + else + return result; + } - range_t rp; + template + inline std::size_t parse_base_function_call(expression_node_ptr (¶m_list)[MaxNumberofParameters], const std::string& function_name = "") + { + std::fill_n(param_list, MaxNumberofParameters, reinterpret_cast(0)); - if (!parse_range(rp,true)) + scoped_delete sd((*this),param_list); + + next_token(); + + if (!token_is(token_t::e_lbracket)) { - free_node(node_allocator_,expression); + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR026 - Expected a '(' at start of function call to '" + function_name + + "', instead got: '" + current_token().value + "'", + exprtk_error_location)); - return error_node(); + return 0; } - expression_node_ptr result = expression_generator_(expression,rp); - - if (0 == result) + if (token_is(token_t::e_rbracket, e_hold)) { set_error( make_error(parser_error::e_syntax, - current_token_, - "ERR83 - Failed to generate string range node")); + current_token(), + "ERR027 - Expected at least one input parameter for function call '" + function_name + "'", + exprtk_error_location)); - free_node(node_allocator_,expression); + return 0; } - rp.clear(); + std::size_t param_index = 0; - return result; - } + for (; param_index < MaxNumberofParameters; ++param_index) + { + param_list[param_index] = parse_expression(); - inline void parse_pending_string_rangesize(expression_node_ptr& expression) - { - const std::size_t max_rangesize_parses = 100; - std::size_t i = 0; + if (0 == param_list[param_index]) + return 0; + else if (token_is(token_t::e_rbracket)) + { + sd.delete_ptr = false; + break; + } + else if (token_is(token_t::e_comma)) + continue; + else + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR028 - Expected a ',' between function input parameters, instead got: '" + current_token().value + "'", + exprtk_error_location)); - while - ( - (0 != expression) && - (i++ < max_rangesize_parses) && - error_list_.empty() && - token_is(token_t::e_lsqrbracket,false) && - is_generally_string_node(expression) - ) - { - expression = parse_string_range_statement(expression); + return 0; + } } - } - template class Sequence> - inline expression_node_ptr simplify(Sequence& expression_list) - { - if (expression_list.empty()) - return error_node(); - else if (1 == expression_list.size()) - return expression_list[0]; - - Sequence tmp_expression_list; - - for (std::size_t i = 0; i < (expression_list.size() - 1); ++i) + if (sd.delete_ptr) { - if (is_variable_node(expression_list[i])) - continue; - else if ( - is_constant_node(expression_list[i]) || - is_null_node (expression_list[i]) - ) - { - free_node(node_allocator_,expression_list[i]); - continue; - } - else - tmp_expression_list.push_back(expression_list[i]); - } + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR029 - Invalid number of input parameters passed to function '" + function_name + "'", + exprtk_error_location)); - tmp_expression_list.push_back(expression_list.back()); - expression_list.swap(tmp_expression_list); + return 0; + } - if (1 == expression_list.size()) - return expression_list[0]; - else - return expression_generator_.vararg_function(details::e_multi,expression_list); + return (param_index + 1); } - inline expression_node_ptr parse_multi_sequence(const std::string& source = "") + inline expression_node_ptr parse_base_operation() { - token_t::token_type close_bracket = token_t::e_rcrlbracket; - token_t::token_type seperator = token_t::e_eof; - - if (!token_is(token_t::e_lcrlbracket)) - { - if (token_is(token_t::e_lbracket)) - { - close_bracket = token_t::e_rbracket; - seperator = token_t::e_comma; - } - else - { - set_error( - make_error(parser_error::e_syntax, - current_token_, - "ERR84 - Expected '" + token_t::to_str(close_bracket) + "' for call to multi-sequence" + - ((!source.empty()) ? std::string(" section of " + source): ""))); - - return error_node(); - } - } - else if (token_is(token_t::e_rcrlbracket)) - { - return node_allocator_.allocate >(); - } - - std::vector arg_list; - expression_node_ptr result = error_node(); + typedef std::pair map_range_t; - scoped_vec_delete sdd(*this,arg_list); + const std::string operation_name = current_token().value; + const token_t diagnostic_token = current_token(); - scope_handler sh(*this); + map_range_t itr_range = base_ops_map_.equal_range(operation_name); - for (;;) + if (0 == std::distance(itr_range.first,itr_range.second)) { - expression_node_ptr arg = parse_expression(); + set_error( + make_error(parser_error::e_syntax, + diagnostic_token, + "ERR030 - No entry found for base operation: " + operation_name, + exprtk_error_location)); - if (0 == arg) - return error_node(); - else - arg_list.push_back(arg); + return error_node(); + } - if (token_is(close_bracket)) - break; + static const std::size_t MaxNumberofParameters = 4; + expression_node_ptr param_list[MaxNumberofParameters] = {0}; - bool is_next_close = peek_token_is(close_bracket); + const std::size_t parameter_count = parse_base_function_call(param_list, operation_name); - if (!token_is(seperator) && is_next_close) + if ((parameter_count > 0) && (parameter_count <= MaxNumberofParameters)) + { + for (base_ops_map_t::iterator itr = itr_range.first; itr != itr_range.second; ++itr) { - set_error( - make_error(parser_error::e_syntax, - current_token_, - "ERR85 - Expected '" + details::to_str(seperator) + "' for call to multi-sequence section of " + source)); + const details::base_operation_t& operation = itr->second; - return error_node(); + if (operation.num_params == parameter_count) + { + switch (parameter_count) + { + #define base_opr_case(N) \ + case N : { \ + expression_node_ptr pl##N[N] = {0}; \ + std::copy(param_list, param_list + N, pl##N); \ + lodge_symbol(operation_name, e_st_function); \ + return expression_generator_(operation.type, pl##N); \ + } \ + + base_opr_case(1) + base_opr_case(2) + base_opr_case(3) + base_opr_case(4) + #undef base_opr_case + } + } } + } - if (token_is(close_bracket)) - break; + for (std::size_t i = 0; i < MaxNumberofParameters; ++i) + { + free_node(node_allocator_, param_list[i]); } - result = simplify(arg_list); + set_error( + make_error(parser_error::e_syntax, + diagnostic_token, + "ERR031 - Invalid number of input parameters for call to function: '" + operation_name + "'", + exprtk_error_location)); - sdd.delete_ptr = (0 == result); - return result; + return error_node(); } - inline bool parse_range(range_t& rp, const bool skip_lsqr = false) + inline expression_node_ptr parse_conditional_statement_01(expression_node_ptr condition) { - // Examples of valid ranges: - // 1. [1:5] -> 1..5 - // 2. [ :5] -> 0..5 - // 3. [1: ] -> 1..end - // 4. [x:y] -> x..y where x <= y - // 5. [x+1:y/2] -> x+1..y/2 where x+1 <= y/2 - // 6. [ :y] -> 0..y where 0 <= y - // 7. [x: ] -> x..end where x <= end + // Parse: [if][(][condition][,][consequent][,][alternative][)] - rp.clear(); + expression_node_ptr consequent = error_node(); + expression_node_ptr alternative = error_node(); - if (!skip_lsqr && !token_is(token_t::e_lsqrbracket)) + bool result = true; + + if (!token_is(token_t::e_comma)) { set_error( make_error(parser_error::e_syntax, - current_token_, - "ERR86 - Expected '[' for start of range")); - - return false; + current_token(), + "ERR032 - Expected ',' between if-statement condition and consequent", + exprtk_error_location)); + result = false; } - - if (token_is(token_t::e_colon)) + else if (0 == (consequent = parse_expression())) { - rp.n0_c.first = true; - rp.n0_c.second = 0; - rp.cache.first = 0; + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR033 - Failed to parse consequent for if-statement", + exprtk_error_location)); + result = false; } - else + else if (!token_is(token_t::e_comma)) { - expression_node_ptr r0 = parse_expression(); - - if (0 == r0) - { - set_error( - make_error(parser_error::e_syntax, - current_token_, - "ERR87 - Failed parse begin section of range")); + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR034 - Expected ',' between if-statement consequent and alternative", + exprtk_error_location)); + result = false; + } + else if (0 == (alternative = parse_expression())) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR035 - Failed to parse alternative for if-statement", + exprtk_error_location)); + result = false; + } + else if (!token_is(token_t::e_rbracket)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR036 - Expected ')' at the end of if-statement", + exprtk_error_location)); + result = false; + } - return false; + #ifndef exprtk_disable_string_capabilities + if (result) + { + const bool consq_is_str = is_generally_string_node( consequent); + const bool alter_is_str = is_generally_string_node(alternative); - } - else if (is_constant_node(r0)) + if (consq_is_str || alter_is_str) { - T r0_value = r0->value(); - - if (r0_value >= T(0)) - { - rp.n0_c.first = true; - rp.n0_c.second = static_cast(details::numeric::to_int64(r0_value)); - rp.cache.first = rp.n0_c.second; - } - - free_node(node_allocator_,r0); - - if (r0_value < T(0)) + if (consq_is_str && alter_is_str) { - set_error( - make_error(parser_error::e_syntax, - current_token_, - "ERR88 - Range lower bound less than zero! Constraint: r0 >= 0")); - - return false; + return expression_generator_ + .conditional_string(condition, consequent, alternative); } - } - else - { - rp.n0_e.first = true; - rp.n0_e.second = r0; - } - if (!token_is(token_t::e_colon)) - { set_error( make_error(parser_error::e_syntax, - current_token_, - "ERR89 - Expected ':' for break in range")); + current_token(), + "ERR037 - Return types of ternary if-statement differ", + exprtk_error_location)); - rp.free(); - return false; + result = false; } } + #endif - if (token_is(token_t::e_rsqrbracket)) + if (!result) { - rp.n1_c.first = true; - rp.n1_c.second = std::numeric_limits::max(); + free_node(node_allocator_, condition ); + free_node(node_allocator_, consequent ); + free_node(node_allocator_, alternative); + + return error_node(); } else - { - expression_node_ptr r1 = parse_expression(); + return expression_generator_ + .conditional(condition, consequent, alternative); + } - if (0 == r1) + inline expression_node_ptr parse_conditional_statement_02(expression_node_ptr condition) + { + expression_node_ptr consequent = error_node(); + expression_node_ptr alternative = error_node(); + + bool result = true; + + if (token_is(token_t::e_lcrlbracket,prsrhlpr_t::e_hold)) + { + if (0 == (consequent = parse_multi_sequence("if-statement-01"))) { set_error( make_error(parser_error::e_syntax, - current_token_, - "ERR90 - Failed parse end section of range")); - - rp.free(); - return false; + current_token(), + "ERR038 - Failed to parse body of consequent for if-statement", + exprtk_error_location)); + result = false; } - else if (is_constant_node(r1)) + } + else + { + if ( + settings_.commutative_check_enabled() && + token_is(token_t::e_mul,prsrhlpr_t::e_hold) + ) { - T r1_value = r1->value(); - - if (r1_value >= T(0)) - { - rp.n1_c.first = true; - rp.n1_c.second = static_cast(details::numeric::to_int64(r1_value)); - rp.cache.second = rp.n1_c.second; - } - - free_node(node_allocator_,r1); + next_token(); + } - if (r1_value < T(0)) + if (0 != (consequent = parse_expression())) + { + if (!token_is(token_t::e_eof)) { set_error( make_error(parser_error::e_syntax, - current_token_, - "ERR91 - Range upper bound less than zero! Constraint: r1 >= 0")); + current_token(), + "ERR039 - Expected ';' at the end of the consequent for if-statement", + exprtk_error_location)); - return false; + result = false; } } else - { - rp.n1_e.first = true; - rp.n1_e.second = r1; - } - - if (!token_is(token_t::e_rsqrbracket)) { set_error( make_error(parser_error::e_syntax, - current_token_, - "ERR92 - Expected ']' for start of range")); + current_token(), + "ERR040 - Failed to parse body of consequent for if-statement", + exprtk_error_location)); - rp.free(); - return false; + result = false; } } - if (rp.const_range()) + if (result) { - std::size_t r0 = 0; - std::size_t r1 = 0; - - bool rp_result = rp(r0,r1); - - if (!rp_result || (r0 > r1)) + if (details::imatch(current_token().value,"else")) { - set_error( - make_error(parser_error::e_syntax, - current_token_, - "ERR93 - Invalid range, Constraint: r0 <= r1")); + next_token(); - return false; - } - } - - return true; - } - - inline void lodge_symbol(const std::string& symbol, - const symbol_type st) - { - dec_.add_symbol(symbol,st); - } - - inline expression_node_ptr parse_string() - { - const std::string symbol = current_token_.value; - - if (!symbol_table_.is_conststr_stringvar(symbol)) - { - set_error( - make_error(parser_error::e_syntax, - current_token_, - "ERR94 - Unknown string symbol")); - - return error_node(); - } + if (token_is(token_t::e_lcrlbracket,prsrhlpr_t::e_hold)) + { + if (0 == (alternative = parse_multi_sequence("else-statement-01"))) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR041 - Failed to parse body of the 'else' for if-statement", + exprtk_error_location)); - expression_node_ptr result = symbol_table_.get_stringvar(symbol); + result = false; + } + } + else if (details::imatch(current_token().value,"if")) + { + if (0 == (alternative = parse_conditional_statement())) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR042 - Failed to parse body of if-else statement", + exprtk_error_location)); - typedef details::stringvar_node* strvar_node_t; - strvar_node_t const_str_node = static_cast(0); + result = false; + } + } + else if (0 != (alternative = parse_expression())) + { + if (!token_is(token_t::e_eof)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR043 - Expected ';' at the end of the 'else-if' for the if-statement", + exprtk_error_location)); - const bool is_const_string = symbol_table_.is_constant_string(symbol); + result = false; + } + } + else + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR044 - Failed to parse body of the 'else' for if-statement", + exprtk_error_location)); - if (is_const_string) - { - const_str_node = static_cast(result); - result = expression_generator_(const_str_node->str()); + result = false; + } + } } - lodge_symbol(symbol,e_st_string); - - if (peek_token_is(token_t::e_lsqrbracket)) + #ifndef exprtk_disable_string_capabilities + if (result) { - next_token(); + const bool consq_is_str = is_generally_string_node( consequent); + const bool alter_is_str = is_generally_string_node(alternative); - if (peek_token_is(token_t::e_rsqrbracket)) + if (consq_is_str || alter_is_str) { - next_token(); - next_token(); - - if (const_str_node) + if (consq_is_str && alter_is_str) { - free_node(node_allocator_,result); - - return expression_generator_(T(const_str_node->size())); + return expression_generator_ + .conditional_string(condition, consequent, alternative); } - else - return node_allocator_.allocate > - (static_cast*>(result)->ref()); - } - - range_t rp; - if (!parse_range(rp)) - { - free_node(node_allocator_,result); + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR045 - Return types of ternary if-statement differ", + exprtk_error_location)); - return error_node(); - } - else if (const_str_node) - { - free_node(node_allocator_,result); - result = expression_generator_(const_str_node->ref(),rp); + result = false; } - else - result = expression_generator_(static_cast*>(result)->ref(),rp); + } + #endif - if (result) - rp.clear(); + if (!result) + { + free_node(node_allocator_, condition); + free_node(node_allocator_, consequent); + free_node(node_allocator_, alternative); + + return error_node(); } else - next_token(); - - return result; + return expression_generator_ + .conditional(condition, consequent, alternative); } - inline expression_node_ptr parse_const_string() + inline expression_node_ptr parse_conditional_statement() { - const std::string const_str = current_token_.value; - expression_node_ptr result = expression_generator_(const_str); - - if (peek_token_is(token_t::e_lsqrbracket)) - { - next_token(); - - if (peek_token_is(token_t::e_rsqrbracket)) - { - next_token(); - next_token(); + expression_node_ptr condition = error_node(); - free_node(node_allocator_,result); + next_token(); - return expression_generator_(T(const_str.size())); - } + if (!token_is(token_t::e_lbracket)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR046 - Expected '(' at start of if-statement, instead got: '" + current_token().value + "'", + exprtk_error_location)); - range_t rp; + return error_node(); + } + else if (0 == (condition = parse_expression())) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR047 - Failed to parse condition for if-statement", + exprtk_error_location)); - if (!parse_range(rp)) - { - free_node(node_allocator_,result); + return error_node(); + } + else if (token_is(token_t::e_comma,prsrhlpr_t::e_hold)) + { + // if (x,y,z) + return parse_conditional_statement_01(condition); + } + else if (token_is(token_t::e_rbracket)) + { + // 00. if (x) y; + // 01. if (x) y; else z; + // 02. if (x) y; else {z0; ... zn;} + // 03. if (x) y; else if (z) w; + // 04. if (x) y; else if (z) w; else u; + // 05. if (x) y; else if (z) w; else {u0; ... un;} + // 06. if (x) y; else if (z) {w0; ... wn;} + // 07. if (x) {y0; ... yn;} + // 08. if (x) {y0; ... yn;} else z; + // 09. if (x) {y0; ... yn;} else {z0; ... zn;}; + // 10. if (x) {y0; ... yn;} else if (z) w; + // 11. if (x) {y0; ... yn;} else if (z) w; else u; + // 12. if (x) {y0; ... nex;} else if (z) w; else {u0 ... un;} + // 13. if (x) {y0; ... yn;} else if (z) {w0; ... wn;} + return parse_conditional_statement_02(condition); + } - return error_node(); - } + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR048 - Invalid if-statement", + exprtk_error_location)); - free_node(node_allocator_,result); + free_node(node_allocator_,condition); - if (rp.n1_c.first && (rp.n1_c.second == std::numeric_limits::max())) - { - rp.n1_c.second = const_str.size() - 1; - rp.cache.second = rp.n1_c.second; - } + return error_node(); + } - if ( - (rp.n0_c.first && (rp.n0_c.second >= const_str.size())) || - (rp.n1_c.first && (rp.n1_c.second >= const_str.size())) - ) - { - set_error( - make_error(parser_error::e_syntax, - current_token_, - "ERR95 - Overflow in range for string: '" + const_str + "'[" + - (rp.n0_c.first ? details::to_str(rp.n0_c.second) : "?") + ":" + - (rp.n1_c.first ? details::to_str(rp.n1_c.second) : "?") + "]")); + inline expression_node_ptr parse_ternary_conditional_statement(expression_node_ptr condition) + { + // Parse: [condition][?][consequent][:][alternative] + expression_node_ptr consequent = error_node(); + expression_node_ptr alternative = error_node(); - return error_node(); - } + bool result = true; - result = expression_generator_(const_str,rp); + if (0 == condition) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR049 - Encountered invalid condition branch for ternary if-statement", + exprtk_error_location)); - if (result) - rp.clear(); + return error_node(); } - else - next_token(); + else if (!token_is(token_t::e_ternary)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR050 - Expected '?' after condition of ternary if-statement", + exprtk_error_location)); - return result; - } + result = false; + } + else if (0 == (consequent = parse_expression())) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR051 - Failed to parse consequent for ternary if-statement", + exprtk_error_location)); - inline expression_node_ptr parse_vector() - { - const std::string symbol = current_token_.value; + result = false; + } + else if (!token_is(token_t::e_colon)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR052 - Expected ':' between ternary if-statement consequent and alternative", + exprtk_error_location)); - vector_holder_ptr vec = vector_holder_ptr(0); + result = false; + } + else if (0 == (alternative = parse_expression())) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR053 - Failed to parse alternative for ternary if-statement", + exprtk_error_location)); - const scope_element& se = sem_.get_element(symbol); + result = false; + } - if ( - (se.name != symbol) || - (se.depth > scope_depth_) || - (scope_element::e_vector != se.type) - ) + #ifndef exprtk_disable_string_capabilities + if (result) { - if (0 == (vec = symbol_table_.get_vector(symbol))) + const bool consq_is_str = is_generally_string_node( consequent); + const bool alter_is_str = is_generally_string_node(alternative); + + if (consq_is_str || alter_is_str) { + if (consq_is_str && alter_is_str) + { + return expression_generator_ + .conditional_string(condition, consequent, alternative); + } + set_error( make_error(parser_error::e_syntax, - current_token_, - "ERR96 - Symbol '" + symbol+ " not a vector")); + current_token(), + "ERR054 - Return types of ternary if-statement differ", + exprtk_error_location)); - return error_node(); + result = false; } } - else - vec = se.vec_node; - - expression_node_ptr index_expr = error_node(); - - next_token(); + #endif - if (!token_is(token_t::e_lsqrbracket)) - { - return node_allocator_.allocate(vec); - } - else if (token_is(token_t::e_rsqrbracket)) - { - return expression_generator_(T(vec->size())); - } - else if (0 == (index_expr = parse_expression())) + if (!result) { - set_error( - make_error(parser_error::e_syntax, - current_token_, - "ERR97 - Failed to parse index for vector: '" + symbol + "'")); + free_node(node_allocator_, condition); + free_node(node_allocator_, consequent); + free_node(node_allocator_, alternative); return error_node(); } - else if (!token_is(token_t::e_rsqrbracket)) + else + return expression_generator_ + .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_, - "ERR98 - Expected ']' for index of vector: '" + symbol + "'")); - - free_node(node_allocator_,index_expr); + current_token(), + "ERR055 - Invalid or disabled logic operation 'not'", + exprtk_error_location)); return error_node(); } - return expression_generator_.vector_element(symbol,vec,index_expr); + return parse_base_operation(); } - inline expression_node_ptr parse_vararg_function_call(ivararg_function* vararg_function, const std::string& vararg_function_name) + inline expression_node_ptr parse_while_loop() { - std::vector arg_list; - expression_node_ptr result = error_node(); + // Parse: [while][(][test expr][)][{][expression][}] + expression_node_ptr condition = error_node(); + expression_node_ptr branch = error_node(); + expression_node_ptr result_node = error_node(); - scoped_vec_delete sdd(*this,arg_list); + bool result = true; next_token(); - if (token_is(token_t::e_lbracket)) + if (!token_is(token_t::e_lbracket)) { - if (!token_is(token_t::e_rbracket)) - { - for ( ; ; ) - { - expression_node_ptr arg = parse_expression(); - - if (0 == arg) - return error_node(); - else - arg_list.push_back(arg); - - if (token_is(token_t::e_rbracket)) - break; - else if (!token_is(token_t::e_comma)) - { - set_error( - make_error(parser_error::e_syntax, - current_token_, - "ERR99 - Expected ',' for call to vararg function: " + vararg_function_name)); + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR056 - Expected '(' at start of while-loop condition statement", + exprtk_error_location)); - return error_node(); - } - } - } + return error_node(); } - - result = expression_generator_.vararg_function_call(vararg_function,arg_list); - - sdd.delete_ptr = (0 == result); - - return result; - } - - class type_checker - { - public: - - typedef parser parser_t; - typedef std::vector param_seq_list_t; - - type_checker(parser_t& p, - const std::string& func_name, - const std::string& param_seq) - : invalid_state_(true), - parser_(p), - function_name_(func_name) + else if (0 == (condition = parse_expression())) { - split(param_seq); - } + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR057 - Failed to parse condition for while-loop", + exprtk_error_location)); - bool verify(const std::string& param_seq, std::size_t& pseq_index) + return error_node(); + } + else if (!token_is(token_t::e_rbracket)) { - if (param_seq_list_.empty()) - return true; - - std::vector > error_list; + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR058 - Expected ')' at end of while-loop condition statement", + exprtk_error_location)); - for (std::size_t i = 0; i < param_seq_list_.size(); ++i) - { - std::size_t diff_index = 0; - char diff_value = 0; + result = false; + } - bool result = details::sequence_match(param_seq_list_[i], - param_seq, - diff_index,diff_value); + brkcnt_list_.push_front(false); - if (result) - { - pseq_index = i; - return true; - } - else - error_list.push_back(std::make_pair(diff_index,diff_value)); - } + if (result) + { + scoped_inc_dec sid(state_.parsing_loop_stmt_count); - if (1 == error_list.size()) + if (0 == (branch = parse_multi_sequence("while-loop"))) { - parser_. - set_error( - make_error(parser_error::e_syntax, - parser_.current_token(), - "ERR100 - Failed parameter type check for function '" + function_name_ + "', " - "Expected '" + param_seq_list_[0] + "' call set: '" + param_seq +"'")); + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR059 - Failed to parse body of while-loop")); + result = false; } - else + else if (0 == (result_node = expression_generator_.while_loop(condition, + branch, + brkcnt_list_.front()))) { - // find first with largest diff_index; - std::size_t max_diff_index = 0; - - for (std::size_t i = 1; i < error_list.size(); ++i) - { - if (error_list[i].first > error_list[max_diff_index].first) - { - max_diff_index = i; - } - } + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR060 - Failed to synthesize while-loop", + exprtk_error_location)); - parser_. - set_error( - make_error(parser_error::e_syntax, - parser_.current_token(), - "ERR101 - Failed parameter type check for function '" + function_name_ + "', " - "Best match: '" + param_seq_list_[max_diff_index] + "' call set: '" + param_seq +"'")); + result = false; } - - return false; } - std::size_t paramseq_count() const + if (!result) { - return param_seq_list_.size(); - } + free_node(node_allocator_, branch); + free_node(node_allocator_, condition); + free_node(node_allocator_, result_node); - std::string paramseq(const std::size_t& index) const - { - return param_seq_list_[index]; - } + brkcnt_list_.pop_front(); - bool invalid() const - { - return !invalid_state_; + return error_node(); } + else + return result_node; + } - private: + inline expression_node_ptr parse_repeat_until_loop() + { + // Parse: [repeat][{][expression][}][until][(][test expr][)] + expression_node_ptr condition = error_node(); + expression_node_ptr branch = error_node(); + next_token(); + + std::vector arg_list; + std::vector side_effect_list; + + scoped_vec_delete sdd((*this),arg_list); + + brkcnt_list_.push_front(false); - void split(const std::string& s) + if (details::imatch(current_token().value,"until")) { - if (s.empty()) - return; + next_token(); + branch = node_allocator_.allocate >(); + } + else + { + const token_t::token_type seperator = token_t::e_eof; + + scope_handler sh(*this); - std::size_t start = 0; - std::size_t end = 0; + scoped_bool_or_restorer sbr(state_.side_effect_present); - param_seq_list_t param_seq_list; + scoped_inc_dec sid(state_.parsing_loop_stmt_count); - struct token_validator + for ( ; ; ) { - static inline bool process(const std::string& str, - std::size_t s, std::size_t e, - param_seq_list_t& psl) - { - if ( - (e - s) && - (std::string::npos == str.find("?*")) && - (std::string::npos == str.find("**")) - ) - { - const std::string curr_str = str.substr(s,e - s); + state_.side_effect_present = false; - if (std::string::npos == curr_str.find_first_not_of("STV*?|")) - { - psl.push_back(curr_str); - return true; - } - } + expression_node_ptr arg = parse_expression(); - return false; + if (0 == arg) + return error_node(); + else + { + arg_list.push_back(arg); + side_effect_list.push_back(state_.side_effect_present); } - }; - while (std::string::npos != (end = s.find('|',start))) - { - if (!token_validator::process(s,start,end,param_seq_list)) + if (details::imatch(current_token().value,"until")) { - invalid_state_ = false; + next_token(); + break; + } - const std::string err_param_seq = s.substr(start,end - start); + const bool is_next_until = peek_token_is(token_t::e_symbol) && + peek_token_is("until"); - parser_. - set_error( - make_error(parser_error::e_syntax, - parser_.current_token(), - "ERR102 - Invalid parameter sequence of '" + err_param_seq + - "' for function: " + function_name_)); + if (!token_is(seperator) && is_next_until) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR061 - Expected '" + token_t::to_str(seperator) + "' in body of repeat until loop", + exprtk_error_location)); - return; + return error_node(); } - 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 + if (details::imatch(current_token().value,"until")) { - const std::string err_param_seq = s.substr(start,s.size() - start); - - parser_. - set_error( - make_error(parser_error::e_syntax, - parser_.current_token(), - "ERR103 - Invalid parameter sequence of '" + err_param_seq + - "' for function: " + function_name_)); - return; + next_token(); + break; } } - } - - type_checker(const type_checker&); - type_checker& operator=(const type_checker&); - - bool invalid_state_; - parser_t& parser_; - std::string function_name_; - param_seq_list_t param_seq_list_; - }; - inline expression_node_ptr parse_generic_function_call(igeneric_function* function, const std::string& function_name) - { - std::vector arg_list; + branch = simplify(arg_list,side_effect_list); - scoped_vec_delete sdd(*this,arg_list); + sdd.delete_ptr = (0 == branch); - next_token(); + if (sdd.delete_ptr) + { + brkcnt_list_.pop_front(); - std::string param_type_list; + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR062 - Failed to parse body of repeat until loop", + exprtk_error_location)); - type_checker tc(*this,function_name,function->parameter_sequence); + return error_node(); + } + } - if (tc.invalid()) + if (!token_is(token_t::e_lbracket)) { + brkcnt_list_.pop_front(); + set_error( make_error(parser_error::e_syntax, - current_token_, - "ERR104 - Type checker instantiation failure for generic function: " + function_name)); + current_token(), + "ERR063 - Expected '(' before condition statement of repeat until loop", + exprtk_error_location)); + + free_node(node_allocator_,branch); return error_node(); } - - if (token_is(token_t::e_lbracket)) + else if (0 == (condition = parse_expression())) { - if (!token_is(token_t::e_rbracket)) - { - for ( ; ; ) - { - expression_node_ptr arg = parse_expression(); - - if (0 == arg) - return error_node(); - - if (is_ivector_node(arg)) - param_type_list += 'V'; - else if (is_generally_string_node(arg)) - param_type_list += 'S'; - else // Everything else is assumed to be scalar returning expression - param_type_list += 'T'; + brkcnt_list_.pop_front(); - arg_list.push_back(arg); + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR064 - Failed to parse condition for repeat until loop", + exprtk_error_location)); - if (token_is(token_t::e_rbracket)) - break; - else if (!token_is(token_t::e_comma)) - { - set_error( - make_error(parser_error::e_syntax, - current_token_, - "ERR105 - Expected ',' for call to generic function: " + function_name)); + free_node(node_allocator_,branch); - return error_node(); - } - } - } + return error_node(); } - - std::size_t param_seq_index = 0; - - if (!tc.verify(param_type_list, param_seq_index)) + else if (!token_is(token_t::e_rbracket)) { set_error( make_error(parser_error::e_syntax, - current_token_, - "ERR106 - Expected ',' for call to generic function: " + function_name)); + current_token(), + "ERR065 - Expected ')' after condition of repeat until loop", + exprtk_error_location)); + + free_node(node_allocator_, branch); + free_node(node_allocator_, condition); + + brkcnt_list_.pop_front(); return error_node(); } - expression_node_ptr result = error_node(); + expression_node_ptr result; - 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); + result = expression_generator_ + .repeat_until_loop(condition, branch, brkcnt_list_.front()); - sdd.delete_ptr = (0 == result); + if (0 == result) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR066 - Failed to synthesize repeat until loop", + exprtk_error_location)); - return result; + free_node(node_allocator_,condition); + + brkcnt_list_.pop_front(); + + return error_node(); + } + else + { + brkcnt_list_.pop_front(); + return result; + } } - inline expression_node_ptr parse_string_function_call(igeneric_function* function, const std::string& function_name) + inline expression_node_ptr parse_for_loop() { - std::vector arg_list; + expression_node_ptr initialiser = error_node(); + expression_node_ptr condition = error_node(); + expression_node_ptr incrementor = error_node(); + expression_node_ptr loop_body = error_node(); - scoped_vec_delete sdd(*this,arg_list); + scope_element* se = 0; + bool result = true; next_token(); - std::string param_type_list; - - type_checker tc(*this,function_name,function->parameter_sequence); + scope_handler sh(*this); - if ( - (!function->parameter_sequence.empty()) && - (0 == tc.paramseq_count()) - ) + if (!token_is(token_t::e_lbracket)) { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR067 - Expected '(' at start of for-loop", + exprtk_error_location)); + return error_node(); } - if (token_is(token_t::e_lbracket)) + if (!token_is(token_t::e_eof)) { - if (!token_is(token_t::e_rbracket)) + if ( + !token_is(token_t::e_symbol,prsrhlpr_t::e_hold) && + details::imatch(current_token().value,"var") + ) { - for ( ; ; ) + next_token(); + + if (!token_is(token_t::e_symbol,prsrhlpr_t::e_hold)) { - expression_node_ptr arg = parse_expression(); + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR068 - Expected a variable at the start of initialiser section of for-loop", + exprtk_error_location)); - if (0 == arg) - return error_node(); + return error_node(); + } + else if (!peek_token_is(token_t::e_assign)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR069 - Expected variable assignment of initialiser section of for-loop", + exprtk_error_location)); - if (is_ivector_node(arg)) - param_type_list += 'V'; - else if (is_generally_string_node(arg)) - param_type_list += 'S'; - else // Everything else is a scalar returning expression - param_type_list += 'T'; + return error_node(); + } - arg_list.push_back(arg); + const std::string loop_counter_symbol = current_token().value; - if (token_is(token_t::e_rbracket)) - break; - else if (!token_is(token_t::e_comma)) + se = &sem_.get_element(loop_counter_symbol); + + if ((se->name == loop_counter_symbol) && se->active) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR070 - For-loop variable '" + loop_counter_symbol+ "' is being shadowed by a previous declaration", + exprtk_error_location)); + + return error_node(); + } + else if (!symtab_store_.is_variable(loop_counter_symbol)) + { + if ( + !se->active && + (se->name == loop_counter_symbol) && + (se->type == scope_element::e_variable) + ) { - set_error( - make_error(parser_error::e_syntax, - current_token_, - "ERR107 - Expected ',' for call to string function: " + function_name)); + se->active = true; + se->ref_count++; + } + else + { + scope_element nse; + nse.name = loop_counter_symbol; + nse.active = true; + nse.ref_count = 1; + nse.type = scope_element::e_variable; + nse.depth = state_.scope_depth; + nse.data = new T(T(0)); + nse.var_node = node_allocator_.allocate(*reinterpret_cast(nse.data)); - return error_node(); + if (!sem_.add_element(nse)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR071 - Failed to add new local variable '" + loop_counter_symbol + "' to SEM", + exprtk_error_location)); + + sem_.free_element(nse); + + result = false; + } + else + { + exprtk_debug(("parse_for_loop() - INFO - Added new local variable: %s\n",nse.name.c_str())); + + state_.activate_side_effect("parse_for_loop()"); + } } } } - } - std::size_t param_seq_index = 0; + if (0 == (initialiser = parse_expression())) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR072 - Failed to parse initialiser of for-loop", + exprtk_error_location)); - if (!tc.verify(param_type_list, param_seq_index)) - { - set_error( - make_error(parser_error::e_syntax, - current_token_, - "ERR108 - Expected ',' for call to string function: " + function_name)); + result = false; + } + else if (!token_is(token_t::e_eof)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR073 - Expected ';' after initialiser of for-loop", + exprtk_error_location)); - return error_node(); + result = false; + } } - expression_node_ptr result = error_node(); + if (!token_is(token_t::e_eof)) + { + if (0 == (condition = parse_expression())) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR074 - Failed to parse condition of for-loop", + exprtk_error_location)); - 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); + result = false; + } + else if (!token_is(token_t::e_eof)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR075 - Expected ';' after condition section of for-loop", + exprtk_error_location)); - sdd.delete_ptr = (0 == result); + result = false; + } + } - return result; - } + if (!token_is(token_t::e_rbracket)) + { + if (0 == (incrementor = parse_expression())) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR076 - Failed to parse incrementor of for-loop", + exprtk_error_location)); - template - struct parse_special_function_impl - { - static inline expression_node_ptr process(parser& p,const details::operator_type opt_type) + result = false; + } + else if (!token_is(token_t::e_rbracket)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR077 - Expected ')' after incrementor section of for-loop", + exprtk_error_location)); + + result = false; + } + } + + if (result) { - expression_node_ptr branch[NumberOfParameters]; - expression_node_ptr result = error_node(); - std::fill_n(branch,NumberOfParameters,reinterpret_cast(0)); - scoped_delete sd(p,branch); + brkcnt_list_.push_front(false); - p.next_token(); + scoped_inc_dec sid(state_.parsing_loop_stmt_count); - if (!p.token_is(token_t::e_lbracket)) + if (0 == (loop_body = parse_multi_sequence("for-loop"))) { - p.set_error( - make_error(parser_error::e_syntax, - p.current_token(), - "ERR109 - Expected '(' for special function")); + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR078 - Failed to parse body of for-loop", + exprtk_error_location)); - return error_node(); + result = false; } + } - for (std::size_t i = 0; i < NumberOfParameters; ++i) + if (!result) + { + if (se) { - branch[i] = p.parse_expression(); + se->ref_count--; + } - if (0 == branch[i]) - { - return p.error_node(); - } - else if (i < (NumberOfParameters - 1)) - { - if (!p.token_is(token_t::e_comma)) - { - p.set_error( - make_error(parser_error::e_syntax, - p.current_token(), - "ERR110 - Expected ',' before next parameter of special function")); + free_node(node_allocator_, initialiser); + free_node(node_allocator_, condition); + free_node(node_allocator_, incrementor); + free_node(node_allocator_, loop_body); - return p.error_node(); - } - } + if (!brkcnt_list_.empty()) + { + brkcnt_list_.pop_front(); } - if (!p.token_is(token_t::e_rbracket)) - return p.error_node(); - else - result = p.expression_generator_.special_function(opt_type,branch); - - sd.delete_ptr = (0 == result); + return error_node(); + } + else + { + expression_node_ptr result_node = + expression_generator_.for_loop(initialiser, + condition, + incrementor, + loop_body, + brkcnt_list_.front()); + brkcnt_list_.pop_front(); - return result; + return result_node; } - }; + } - inline expression_node_ptr parse_special_function() + inline expression_node_ptr parse_switch_statement() { - // 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]) - ) + std::vector arg_list; + expression_node_ptr result = error_node(); + + if (!details::imatch(current_token().value,"switch")) { set_error( - make_error(parser_error::e_token, - current_token_, - "ERR111 - Invalid special function[1]: " + current_token_.value)); + make_error(parser_error::e_syntax, + current_token(), + "ERR079 - Expected keyword 'switch'", + exprtk_error_location)); return error_node(); } - const unsigned int id = (current_token_.value[2] - '0') * 10 + (current_token_.value[3] - '0'); + scoped_vec_delete svd((*this),arg_list); - if (id >= details::e_sffinal) + next_token(); + + if (!token_is(token_t::e_lcrlbracket)) { set_error( - make_error(parser_error::e_token, - current_token_, - "ERR112 - Invalid special function[2]: " + current_token_.value)); + make_error(parser_error::e_syntax, + current_token(), + "ERR080 - Expected '{' for call to switch statement", + exprtk_error_location)); return error_node(); } - const std::size_t sf_3_to_4 = details::e_sf48; - const details::operator_type opt_type = details::operator_type(id + 1000); - const std::size_t NumberOfParameters = (id < (sf_3_to_4 - 1000)) ? 3 : 4; + expression_node_ptr default_statement = error_node(); - switch (NumberOfParameters) + scoped_expression_delete defstmt_delete((*this), default_statement); + + for ( ; ; ) { - case 3 : return parse_special_function_impl::process(*this,opt_type); - case 4 : return parse_special_function_impl::process(*this,opt_type); - default : return error_node(); - } - } + if (details::imatch("case",current_token().value)) + { + next_token(); - inline expression_node_ptr parse_null_statement() - { - next_token(); - return node_allocator_.allocate >(); - } + expression_node_ptr condition = parse_expression(); - #ifndef exprtk_disable_break_continue - inline expression_node_ptr parse_break_statement() - { - if (!brkcnt_list_.empty()) - { - 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)); - brkcnt_list_.front() = true; + free_node(node_allocator_, condition); - expression_node_ptr return_expr = error_node(); + return error_node(); + } - if (token_is(token_t::e_lsqrbracket)) - { - if (0 == (return_expr = parse_expression())) + expression_node_ptr consequent = parse_expression(); + + if (0 == consequent) { - set_error( - make_error(parser_error::e_syntax, - current_token_, - "ERR113 - Failed to parse return expression for 'break' statement")); + free_node(node_allocator_, condition); return error_node(); } - else if (!token_is(token_t::e_rsqrbracket)) + else if (!token_is(token_t::e_eof)) { set_error( make_error(parser_error::e_syntax, - current_token_, - "ERR114 - Expected ']' at the completion of break's return expression")); + current_token(), + "ERR082 - Expected ';' at end of case for switch statement", + exprtk_error_location)); - free_node(node_allocator_,return_expr); + 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); + } + } + else if (details::imatch("default",current_token().value)) + { + 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 node_allocator_.allocate >(return_expr); - } - else - { - set_error( - make_error(parser_error::e_syntax, - current_token_, - "ERR115 - Invalid use of 'break', allowed only in the scope of a loop")); - } + return error_node(); + } - return error_node(); - } + next_token(); - inline expression_node_ptr parse_continue_statement() - { - if (!brkcnt_list_.empty()) - { - next_token(); - brkcnt_list_.front() = true; - return node_allocator_.allocate >(); - } - else - { - set_error( - make_error(parser_error::e_syntax, - current_token_, - "ERR116 - Invalid use of 'continue', allowed only in the scope of a loop")); + if (!token_is(token_t::e_colon)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR084 - Expected ':' for default of switch statement", + exprtk_error_location)); - return error_node(); - } - } - #endif + return error_node(); + } - inline expression_node_ptr parse_define_vector_statement(const std::string& vec_name) - { - expression_node_ptr size_expr = error_node(); + if (token_is(token_t::e_lcrlbracket,prsrhlpr_t::e_hold)) + default_statement = parse_multi_sequence("switch-default"); + else + default_statement = parse_expression(); - if (!token_is(token_t::e_lsqrbracket)) - { - set_error( - make_error(parser_error::e_syntax, - current_token_, - "ERR117 - Expected '[' as part of vector size definition")); + if (0 == default_statement) + return error_node(); + else if (!token_is(token_t::e_eof)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR085 - Expected ';' at end of default for switch statement", + exprtk_error_location)); - return error_node(); - } - else if (0 == (size_expr = parse_expression())) - { - set_error( - make_error(parser_error::e_syntax, - current_token_, - "ERR118 - Failed to determine size of vector '" + vec_name + "'")); + return error_node(); + } + } + 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(); + return error_node(); + } } - else if (!is_constant_node(size_expr)) - { - free_node(node_allocator_,size_expr); - set_error( - make_error(parser_error::e_syntax, - current_token_, - "ERR119 - Expected a literal number as size of vector '" + vec_name + "'")); + const bool default_statement_present = (0 != default_statement); - return error_node(); + if (default_statement_present) + { + arg_list.push_back(default_statement); } - T vector_size = size_expr->value(); + result = expression_generator_.switch_statement(arg_list, (0 != default_statement)); - free_node(node_allocator_,size_expr); + svd.delete_ptr = (0 == result); + defstmt_delete.delete_ptr = (0 == result); - if ( - (vector_size <= T(0)) || - std::not_equal_to() - (T(0),vector_size - details::numeric::trunc(vector_size)) - ) + return result; + } + + inline expression_node_ptr parse_multi_switch_statement() + { + std::vector arg_list; + + if (!details::imatch(current_token().value,"[*]")) { set_error( make_error(parser_error::e_syntax, - current_token_, - "ERR120 - Invalid vector size. Must be an integer greater than zero, size: " + - details::to_str(details::numeric::to_int32(vector_size)))); + current_token(), + "ERR087 - Expected token '[*]'", + exprtk_error_location)); return error_node(); } - std::vector vec_initilizer_list; - - scoped_vec_delete svd(*this,vec_initilizer_list); + scoped_vec_delete svd((*this),arg_list); - bool single_value_initialiser = false; + next_token(); - if (!token_is(token_t::e_rsqrbracket)) + if (!token_is(token_t::e_lcrlbracket)) { set_error( make_error(parser_error::e_syntax, - current_token_, - "ERR121 - Expected ']' as part of vector size definition")); + current_token(), + "ERR088 - Expected '{' for call to [*] statement", + exprtk_error_location)); return error_node(); } - else if (!token_is(token_t::e_eof)) + + for ( ; ; ) { - if (!token_is(token_t::e_assign)) + if (!details::imatch("case",current_token().value)) { set_error( make_error(parser_error::e_syntax, - current_token_, - "ERR122 - Expected ':=' as part of vector definition")); + current_token(), + "ERR089 - Expected a 'case' statement for multi-switch", + exprtk_error_location)); return error_node(); } - else if (token_is(token_t::e_lsqrbracket)) - { - expression_node_ptr initialiser = parse_expression(); - - if (0 == initialiser) - { - set_error( - make_error(parser_error::e_syntax, - current_token_, - "ERR123 - Failed to parse single vector initialiser")); - - return error_node(); - } - vec_initilizer_list.push_back(initialiser); + next_token(); - if (!token_is(token_t::e_rsqrbracket)) - { - set_error( - make_error(parser_error::e_syntax, - current_token_, - "ERR124 - Expected ']' to close single value vector initialiser")); + expression_node_ptr condition = parse_expression(); - return error_node(); - } + if (0 == condition) + return error_node(); - single_value_initialiser = true; - } - else if (!token_is(token_t::e_lcrlbracket)) + if (!token_is(token_t::e_colon)) { set_error( make_error(parser_error::e_syntax, - current_token_, - "ERR125 - Expected '{' as part of vector initialiser list")); + current_token(), + "ERR090 - Expected ':' for case of [*] statement", + exprtk_error_location)); return error_node(); } - else if (!token_is(token_t::e_rcrlbracket)) - { - for (;;) - { - expression_node_ptr initialiser = parse_expression(); - - if (0 == initialiser) - { - set_error( - make_error(parser_error::e_syntax, - current_token_, - "ERR126 - Expected '{' as part of vector initialiser list")); - - return error_node(); - } - else - vec_initilizer_list.push_back(initialiser); - - if (token_is(token_t::e_rcrlbracket)) - break; - - 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_, - "ERR127 - Expected ',' between vector initialisers")); - - return error_node(); - } - - if (token_is(token_t::e_rcrlbracket)) - break; - } - } - if ( - !token_is(token_t::e_rbracket ,false) && - !token_is(token_t::e_rcrlbracket,false) && - !token_is(token_t::e_rsqrbracket,false) - ) - { - if (!token_is(token_t::e_eof)) - { - set_error( - make_error(parser_error::e_syntax, - current_token_, - "ERR128 - Expected ';' at end of vector definition")); + expression_node_ptr consequent = parse_expression(); - return error_node(); - } - } + if (0 == consequent) + return error_node(); - if (vec_initilizer_list.size() > vector_size) + if (!token_is(token_t::e_eof)) { set_error( make_error(parser_error::e_syntax, - current_token_, - "ERR129 - Initialiser list larger than the number of elements in the vector: '" + vec_name + "'")); + current_token(), + "ERR091 - Expected ';' at end of case for [*] statement", + exprtk_error_location)); return error_node(); } - } - - typename symbol_table_t::vector_holder_ptr vec_holder = typename symbol_table_t::vector_holder_ptr(0); - std::size_t vec_size = static_cast(details::numeric::to_int32(vector_size)); - - scope_element& se = sem_.get_element(vec_name); - - if (se.name == vec_name) - { - if (se.active) + // Can we optimise away the case statement? + if (is_constant_node(condition) && is_false(condition)) { - set_error( - make_error(parser_error::e_syntax, - current_token_, - "ERR130 - Illegal redefinition of local vector: '" + vec_name + "'")); - - return error_node(); + free_node(node_allocator_, condition); + free_node(node_allocator_, consequent); } - else if ( - (se.size == vec_size) && - (scope_element::e_vector == se.type) - ) + else { - vec_holder = se.vec_node; - se.active = true; - se.ref_count++; + arg_list.push_back( condition); + arg_list.push_back(consequent); } - } - - if (0 == vec_holder) - { - scope_element nse; - nse.name = vec_name; - nse.type = scope_element::e_vector; - nse.depth = scope_depth_; - nse.size = vec_size; - nse.data = new T[vec_size]; - nse.vec_node = new typename scope_element::vector_holder_t((T*)(nse.data),nse.size); - if (!sem_.add_element(nse)) + if (token_is(token_t::e_rcrlbracket,prsrhlpr_t::e_hold)) { - set_error( - make_error(parser_error::e_syntax, - current_token_, - "ERR131 - Failed to add new local vector '" + vec_name + "' to SEM")); - - return error_node(); + break; } + } - vec_holder = nse.vec_node; + if (!token_is(token_t::e_rcrlbracket)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR092 - Expected '}' at end of [*] statement", + exprtk_error_location)); - exprtk_debug(("parse_define_vector_statement() - INFO - Added new local vector: %s[%d]\n", - nse.name.c_str(), - static_cast(nse.size))); + return error_node(); } - lodge_symbol(vec_name,e_st_local_vector); - - expression_node_ptr result = - node_allocator_ - .allocate >( - (*vec_holder)[0], - vec_size, - vec_initilizer_list, - single_value_initialiser); + const expression_node_ptr result = expression_generator_.multi_switch_statement(arg_list); svd.delete_ptr = (0 == result); return result; } - inline bool local_variable_is_shadowed(const std::string& symbol) + inline expression_node_ptr parse_vararg_function() { - const scope_element& se = sem_.get_element(symbol); - return (se.name == symbol) && se.active; - } + std::vector arg_list; - inline expression_node_ptr parse_define_var_statement() - { - if (vardef_disabled_) - { - set_error( - make_error(parser_error::e_syntax, - current_token_, - "ERR132 - Illegal variable definition")); + details::operator_type opt_type = details::e_default; + const std::string symbol = current_token().value; - return error_node(); + if (details::imatch(symbol,"~")) + { + next_token(); + return parse_multi_sequence(); } - else if (!details::imatch(current_token_.value,"var")) + else if (details::imatch(symbol,"[*]")) { - return error_node(); + 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 - next_token(); - - const std::string var_name = current_token_.value; - - expression_node_ptr initialisation_expression = error_node(); - - if (!token_is(token_t::e_symbol)) { set_error( make_error(parser_error::e_syntax, - current_token_, - "ERR133 - Expected a symbol for variable definition")); + current_token(), + "ERR093 - Unsupported vararg function: " + symbol, + exprtk_error_location)); return error_node(); } - else if (details::is_reserved_symbol(var_name)) + + scoped_vec_delete sdd((*this),arg_list); + + lodge_symbol(symbol, e_st_function); + + next_token(); + + if (!token_is(token_t::e_lbracket)) { set_error( make_error(parser_error::e_syntax, - current_token_, - "ERR134 - Illegal redefinition of reserved keyword: '" + var_name + "'")); + current_token(), + "ERR094 - Expected '(' for call to vararg function: " + symbol, + exprtk_error_location)); return error_node(); } - else if (symbol_table_.symbol_exists(var_name)) + + for ( ; ; ) { - set_error( - make_error(parser_error::e_syntax, - current_token_, - "ERR135 - Illegal redefinition of variable '" + var_name + "'")); + expression_node_ptr arg = parse_expression(); - return error_node(); + if (0 == arg) + return error_node(); + else + arg_list.push_back(arg); + + if (token_is(token_t::e_rbracket)) + break; + else if (!token_is(token_t::e_comma)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR095 - Expected ',' for call to vararg function: " + symbol, + exprtk_error_location)); + + return error_node(); + } } - else if (local_variable_is_shadowed(var_name)) + + const expression_node_ptr result = expression_generator_.vararg_function(opt_type,arg_list); + + sdd.delete_ptr = (0 == result); + return result; + } + + #ifndef exprtk_disable_string_capabilities + inline expression_node_ptr parse_string_range_statement(expression_node_ptr& expression) + { + if (!token_is(token_t::e_lsqrbracket)) { set_error( make_error(parser_error::e_syntax, - current_token_, - "ERR136 - Illegal redefinition of local variable: '" + var_name + "'")); + current_token(), + "ERR096 - Expected '[' as start of string range definition", + exprtk_error_location)); + + free_node(node_allocator_,expression); return error_node(); } - else if (token_is(token_t::e_lsqrbracket,false)) + else if (token_is(token_t::e_rsqrbracket)) { - return parse_define_vector_statement(var_name); + return node_allocator_.allocate >(expression); } - else if (token_is(token_t::e_lcrlbracket,false)) + + range_t rp; + + if (!parse_range(rp,true)) { - return parse_uninitialised_var_statement(var_name); + free_node(node_allocator_,expression); + + return error_node(); } - else if (token_is(token_t::e_assign)) + + expression_node_ptr result = expression_generator_(expression,rp); + + if (0 == result) { - if (0 == (initialisation_expression = parse_expression())) - { - set_error( - make_error(parser_error::e_syntax, - current_token_, - "ERR137 - Failed to parse initialisation expression")); + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR097 - Failed to generate string range node", + exprtk_error_location)); - return error_node(); - } + free_node(node_allocator_,expression); + rp.free(); } - if ( - !token_is(token_t::e_rbracket ,false) && - !token_is(token_t::e_rcrlbracket,false) && - !token_is(token_t::e_rsqrbracket,false) - ) - { - if (!token_is(token_t::e_eof,false)) - { - set_error( - make_error(parser_error::e_syntax, - current_token_, - "ERR138 - Expected ';' after variable definition")); + rp.clear(); - free_node(node_allocator_,initialisation_expression); + return result; + } + #else + inline expression_node_ptr parse_string_range_statement(expression_node_ptr&) + { + return error_node(); + } + #endif - return error_node(); - } + inline void parse_pending_string_rangesize(expression_node_ptr& expression) + { + // Allow no more than 100 range calls, eg: s[][][]...[][] + const std::size_t max_rangesize_parses = 100; + + std::size_t i = 0; + + while + ( + (0 != expression) && + (i++ < max_rangesize_parses) && + error_list_.empty() && + is_generally_string_node(expression) && + token_is(token_t::e_lsqrbracket,prsrhlpr_t::e_hold) + ) + { + expression = parse_string_range_statement(expression); } + } + + template class Sequence> + inline expression_node_ptr simplify(Sequence& expression_list, + Sequence& side_effect_list, + const bool specialise_on_final_type = false) + { + if (expression_list.empty()) + return error_node(); + else if (1 == expression_list.size()) + return expression_list[0]; - variable_node_t* var_node = reinterpret_cast(0); + Sequence tmp_expression_list; - scope_element& se = sem_.get_element(var_name); + bool return_node_present = false; - if (se.name == var_name) + for (std::size_t i = 0; i < (expression_list.size() - 1); ++i) { - if (se.active) + if (is_variable_node(expression_list[i])) + continue; + else if ( + is_return_node (expression_list[i]) || + is_break_node (expression_list[i]) || + is_continue_node(expression_list[i]) + ) { - set_error( - make_error(parser_error::e_syntax, - current_token_, - "ERR139 - Illegal redefinition of local variable: '" + var_name + "'")); + tmp_expression_list.push_back(expression_list[i]); - free_node(node_allocator_,initialisation_expression); + // Remove all subexpressions after first short-circuit + // node has been encountered. - return error_node(); + for (std::size_t j = i + 1; j < expression_list.size(); ++j) + { + free_node(node_allocator_,expression_list[j]); + } + + return_node_present = true; + + break; } - else if (scope_element::e_variable == se.type) + else if ( + is_constant_node(expression_list[i]) || + is_null_node (expression_list[i]) || + !side_effect_list[i] + ) { - var_node = se.var_node; - se.active = true; - se.ref_count++; + free_node(node_allocator_,expression_list[i]); + continue; } + else + tmp_expression_list.push_back(expression_list[i]); } - if (0 == var_node) + if (!return_node_present) { - scope_element nse; - nse.name = var_name; - nse.active = true; - nse.ref_count = 1; - nse.type = scope_element::e_variable; - nse.depth = scope_depth_; - nse.data = new T(T(0)); - nse.var_node = new variable_node_t(*(T*)(nse.data)); - - if (!sem_.add_element(nse)) - { - set_error( - make_error(parser_error::e_syntax, - current_token_, - "ERR140 - Failed to add new local variable '" + var_name + "' to SEM")); - - free_node(node_allocator_,initialisation_expression); - - return error_node(); - } - - var_node = nse.var_node; - - exprtk_debug(("parse_define_var_statement() - INFO - Added new local variable: %s\n",nse.name.c_str())); + tmp_expression_list.push_back(expression_list.back()); } - lodge_symbol(var_name,e_st_local_variable); + expression_list.swap(tmp_expression_list); - expression_node_ptr branch[2] = {0}; + if (tmp_expression_list.size() > expression_list.size()) + { + exprtk_debug(("simplify() - Reduced subexpressions from %d to %d\n", + static_cast(tmp_expression_list.size()), + static_cast(expression_list .size()))); + } - branch[0] = var_node; - branch[1] = initialisation_expression ? initialisation_expression : expression_generator_(T(0)); + if ( + return_node_present || + side_effect_list.back() || + (expression_list.size() > 1) + ) + state_.activate_side_effect("simplify()"); - return expression_generator_(details::e_assign,branch); + if (1 == expression_list.size()) + return expression_list[0]; + else if (specialise_on_final_type && is_generally_string_node(expression_list.back())) + return expression_generator_.vararg_function(details::e_smulti,expression_list); + else + return expression_generator_.vararg_function(details::e_multi,expression_list); } - inline expression_node_ptr parse_uninitialised_var_statement(const std::string& var_name) + inline expression_node_ptr parse_multi_sequence(const std::string& source = "") { - if ( - !token_is(token_t::e_lcrlbracket) || - !token_is(token_t::e_rcrlbracket) - ) + token_t::token_type close_bracket = token_t::e_rcrlbracket; + token_t::token_type seperator = token_t::e_eof; + + if (!token_is(token_t::e_lcrlbracket)) { - set_error( - make_error(parser_error::e_syntax, - current_token_, - "ERR141 - Expected a '{}' for uninitialised var definition")); + if (token_is(token_t::e_lbracket)) + { + close_bracket = token_t::e_rbracket; + seperator = token_t::e_comma; + } + else + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR098 - Expected '" + token_t::to_str(close_bracket) + "' for call to multi-sequence" + + ((!source.empty()) ? std::string(" section of " + source): ""), + exprtk_error_location)); - return error_node(); + return error_node(); + } } - else if (!token_is(token_t::e_eof,false)) + else if (token_is(token_t::e_rcrlbracket)) { - set_error( - make_error(parser_error::e_syntax, - current_token_, - "ERR142 - Expected ';' after uninitialised variable definition")); - - return error_node(); + return node_allocator_.allocate >(); } - variable_node_t* var_node = reinterpret_cast(0); + std::vector arg_list; + std::vector side_effect_list; - scope_element& se = sem_.get_element(var_name); + expression_node_ptr result = error_node(); - if (se.name == var_name) + scoped_vec_delete sdd((*this),arg_list); + + scope_handler sh(*this); + + scoped_bool_or_restorer sbr(state_.side_effect_present); + + for ( ; ; ) { - if (se.active) - { - set_error( - make_error(parser_error::e_syntax, - current_token_, - "ERR143 - Illegal redefinition of local variable: '" + var_name + "'")); + state_.side_effect_present = false; + + expression_node_ptr arg = parse_expression(); + if (0 == arg) return error_node(); - } - else if (scope_element::e_variable == se.type) + else { - var_node = se.var_node; - se.active = true; - se.ref_count++; + arg_list.push_back(arg); + side_effect_list.push_back(state_.side_effect_present); } - } - if (0 == var_node) - { - scope_element nse; - nse.name = var_name; - nse.active = true; - nse.ref_count = 1; - nse.type = scope_element::e_variable; - nse.depth = scope_depth_; - nse.ip_index = sem_.next_ip_index(); - nse.data = new T(T(0)); - nse.var_node = new variable_node_t(*(T*)(nse.data)); + if (token_is(close_bracket)) + break; - if (!sem_.add_element(nse)) + 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_, - "ERR144 - Failed to add new local variable '" + var_name + "' to SEM")); + current_token(), + "ERR099 - Expected '" + details::to_str(seperator) + "' for call to multi-sequence section of " + source, + exprtk_error_location)); return error_node(); } - exprtk_debug(("parse_uninitialised_var_statement() - INFO - Added new local variable: %s\n",nse.name.c_str())); + if (token_is(close_bracket)) + break; } - lodge_symbol(var_name,e_st_local_variable); + result = simplify(arg_list,side_effect_list,source.empty()); - return expression_generator_(T(0)); + sdd.delete_ptr = (0 == result); + return result; } - inline expression_node_ptr parse_swap_statement() + inline bool parse_range(range_t& rp, const bool skip_lsqr = false) { - if (!details::imatch(current_token_.value,"swap")) - { - return error_node(); - } - else - next_token(); + // Examples of valid ranges: + // 1. [1:5] -> 1..5 + // 2. [ :5] -> 0..5 + // 3. [1: ] -> 1..end + // 4. [x:y] -> x..y where x <= y + // 5. [x+1:y/2] -> x+1..y/2 where x+1 <= y/2 + // 6. [ :y] -> 0..y where 0 <= y + // 7. [x: ] -> x..end where x <= end - if (!token_is(token_t::e_lbracket)) + rp.clear(); + + if (!skip_lsqr && !token_is(token_t::e_lsqrbracket)) { set_error( make_error(parser_error::e_syntax, - current_token_, - "ERR145 - Expected '(' at start of swap statement")); + current_token(), + "ERR100 - Expected '[' for start of range", + exprtk_error_location)); - return error_node(); + return false; } - expression_node_ptr variable0 = error_node(); - expression_node_ptr variable1 = error_node(); - - bool variable0_generated = false; - bool variable1_generated = false; - - const std::string var0_name = current_token_.value; - - if (!token_is(token_t::e_symbol,false)) + if (token_is(token_t::e_colon)) { - set_error( - make_error(parser_error::e_syntax, - current_token_, - "ERR146 - Expected a symbol for variable or vector element definition")); - - return error_node(); + rp.n0_c.first = true; + rp.n0_c.second = 0; + rp.cache.first = 0; } - else if (peek_token_is(token_t::e_lsqrbracket)) + else { - if (0 == (variable0 = parse_vector())) + expression_node_ptr r0 = parse_expression(); + + if (0 == r0) { set_error( make_error(parser_error::e_syntax, - current_token_, - "ERR147 - First parameter to swap is an invalid vector element: '" + var0_name + "'")); + current_token(), + "ERR101 - Failed parse begin section of range", + exprtk_error_location)); - return error_node(); + return false; } - - variable0_generated = true; - } - else - { - if (symbol_table_.is_variable(var0_name)) + else if (is_constant_node(r0)) { - variable0 = symbol_table_.get_variable(var0_name); - } + const T r0_value = r0->value(); - scope_element& se = sem_.get_element(var0_name); + if (r0_value >= T(0)) + { + rp.n0_c.first = true; + rp.n0_c.second = static_cast(details::numeric::to_int64(r0_value)); + rp.cache.first = rp.n0_c.second; + } - if ( - (se.active) && - (se.name == var0_name) && - (scope_element::e_variable == se.type) - ) + free_node(node_allocator_,r0); + + if (r0_value < T(0)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR102 - Range lower bound less than zero! Constraint: r0 >= 0", + exprtk_error_location)); + + return false; + } + } + else { - variable0 = se.var_node; + rp.n0_e.first = true; + rp.n0_e.second = r0; } - lodge_symbol(var0_name,e_st_variable); - - if (0 == variable0) + if (!token_is(token_t::e_colon)) { set_error( make_error(parser_error::e_syntax, - current_token_, - "ERR148 - First parameter to swap is an invalid variable: '" + var0_name + "'")); - - return error_node(); - } - else - next_token(); - } + current_token(), + "ERR103 - Expected ':' for break in range", + exprtk_error_location)); - if (!token_is(token_t::e_comma)) - { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR149 - Expected ',' between parameters to swap")); + rp.free(); - if (variable0_generated) - { - free_node(node_allocator_,variable0); + return false; } - - return error_node(); } - const std::string var1_name = current_token_.value; - - if (!token_is(token_t::e_symbol,false)) + if (token_is(token_t::e_rsqrbracket)) { - set_error( - make_error(parser_error::e_syntax, - current_token_, - "ERR150 - Expected a symbol for variable or vector element definition")); - - if (variable0_generated) - { - free_node(node_allocator_,variable0); - } - - return error_node(); + rp.n1_c.first = true; + rp.n1_c.second = std::numeric_limits::max(); } - else if (peek_token_is(token_t::e_lsqrbracket)) + else { - if (0 == (variable1 = parse_vector())) + expression_node_ptr r1 = parse_expression(); + + if (0 == r1) { set_error( make_error(parser_error::e_syntax, - current_token_, - "ERR151 - Second parameter to swap is an invalid vector element: '" + var1_name + "'")); + current_token(), + "ERR104 - Failed parse end section of range", + exprtk_error_location)); - if (variable0_generated) - { - free_node(node_allocator_,variable0); - } + rp.free(); - return error_node(); + return false; } - - variable1_generated = true; - } - else - { - if (symbol_table_.is_variable(var1_name)) + else if (is_constant_node(r1)) { - variable1 = symbol_table_.get_variable(var1_name); - } + const T r1_value = r1->value(); - scope_element& se = sem_.get_element(var1_name); + if (r1_value >= T(0)) + { + rp.n1_c.first = true; + rp.n1_c.second = static_cast(details::numeric::to_int64(r1_value)); + rp.cache.second = rp.n1_c.second; + } - if ( - (se.active) && - (se.name == var1_name) && - (scope_element::e_variable == se.type) - ) - { - variable1 = se.var_node; - } + free_node(node_allocator_,r1); - lodge_symbol(var1_name,e_st_variable); + if (r1_value < T(0)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR105 - Range upper bound less than zero! Constraint: r1 >= 0", + exprtk_error_location)); - if (0 == variable1) - { - set_error( - make_error(parser_error::e_syntax, - current_token_, - "ERR152 - Second parameter to swap is an invalid variable: '" + var1_name + "'")); + rp.free(); - if (variable0_generated) - { - free_node(node_allocator_,variable0); + return false; } - - return error_node(); } else - next_token(); - } - - if (!token_is(token_t::e_rbracket)) - { - set_error( - make_error(parser_error::e_syntax, - current_token_, - "ERR153 - Expected ')' at end of swap statement")); - - if (variable0_generated) { - free_node(node_allocator_,variable0); + rp.n1_e.first = true; + rp.n1_e.second = r1; } - if (variable1_generated) + if (!token_is(token_t::e_rsqrbracket)) { - free_node(node_allocator_,variable1); - } + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR106 - Expected ']' for start of range", + exprtk_error_location)); - return error_node(); - } + rp.free(); - typedef details::variable_node* variable_node_ptr; - variable_node_ptr v0 = variable_node_ptr(0); - variable_node_ptr v1 = variable_node_ptr(0); + return false; + } + } - if ( - (0 != (v0 = dynamic_cast(variable0))) && - (0 != (v1 = dynamic_cast(variable1))) - ) + if (rp.const_range()) { - expression_node_ptr result = node_allocator_.allocate >(v0,v1); + std::size_t r0 = 0; + std::size_t r1 = 0; - if (variable0_generated) - { - free_node(node_allocator_,variable0); - } + bool rp_result = false; - if (variable1_generated) + try { - free_node(node_allocator_,variable1); + rp_result = rp(r0, r1); } + catch (std::runtime_error&) + {} - return result; - } - else - return node_allocator_.allocate >(variable0,variable1); - } - - inline bool post_variable_process(const std::string& symbol) - { - if ( - peek_token_is(token_t::e_lbracket ) || - peek_token_is(token_t::e_lcrlbracket) || - peek_token_is(token_t::e_lsqrbracket) - ) - { - if (!commutative_check_enabled()) + if (!rp_result || (r0 > r1)) { set_error( make_error(parser_error::e_syntax, - current_token_, - "ERR154 - Invalid sequence of variable '"+ symbol + "' and bracket")); + current_token(), + "ERR107 - Invalid range, Constraint: r0 <= r1", + exprtk_error_location)); return false; } - - lexer_.insert_front(token_t::e_mul); } return true; } - inline bool post_bracket_process(const typename token_t::token_type& token, expression_node_ptr& branch) + inline void lodge_symbol(const std::string& symbol, + const symbol_type st) { - bool implied_mul = false; + dec_.add_symbol(symbol,st); + } - if (is_generally_string_node(branch)) - return true; + #ifndef exprtk_disable_string_capabilities + inline expression_node_ptr parse_string() + { + const std::string symbol = current_token().value; - switch (token) - { - case token_t::e_lcrlbracket : implied_mul = token_is(token_t::e_lbracket ,false) || - token_is(token_t::e_lcrlbracket,false) || - token_is(token_t::e_lsqrbracket,false) ; - break; + typedef details::stringvar_node* strvar_node_t; - case token_t::e_lbracket : implied_mul = token_is(token_t::e_lbracket ,false) || - token_is(token_t::e_lcrlbracket,false) || - token_is(token_t::e_lsqrbracket,false) ; - break; + expression_node_ptr result = error_node(); + strvar_node_t const_str_node = static_cast(0); - case token_t::e_lsqrbracket : implied_mul = token_is(token_t::e_lbracket ,false) || - token_is(token_t::e_lcrlbracket,false) || - token_is(token_t::e_lsqrbracket,false) ; - break; + scope_element& se = sem_.get_active_element(symbol); - default : return true; + if (scope_element::e_string == se.type) + { + se.active = true; + result = se.str_node; + lodge_symbol(symbol, e_st_local_string); } - - if (implied_mul) + else { - if (!commutative_check_enabled()) + if (!symtab_store_.is_conststr_stringvar(symbol)) { set_error( make_error(parser_error::e_syntax, - current_token_, - "ERR155 - Invalid sequence of brackets")); + current_token(), + "ERR108 - Unknown string symbol", + exprtk_error_location)); - return false; - } - else if (token_t::e_eof != current_token_.type) - { - lexer_.insert_front(current_token_.type); - lexer_.insert_front(token_t::e_mul); - next_token(); + return error_node(); } - } - - return true; - } - inline expression_node_ptr parse_symtab_symbol() - { - const std::string symbol = current_token_.value; - - // Are we dealing with a variable or a special constant? - expression_node_ptr variable = symbol_table_.get_variable(symbol); + result = symtab_store_.get_stringvar(symbol); - if (variable) - { - if (symbol_table_.is_constant_node(symbol)) + if (symtab_store_.is_constant_string(symbol)) { - variable = expression_generator_(variable->value()); + const_str_node = static_cast(result); + result = expression_generator_(const_str_node->str()); } - if (!post_variable_process(symbol)) - return error_node(); + lodge_symbol(symbol, e_st_string); + } - lodge_symbol(symbol,e_st_variable); + if (peek_token_is(token_t::e_lsqrbracket)) + { next_token(); - return variable; - } - - // Are we dealing with a locally defined variable or vector? - if (!sem_.empty()) - { - scope_element& se = sem_.get_element(symbol); - - if (se.name == symbol) + if (peek_token_is(token_t::e_rsqrbracket)) { - if (scope_element::e_variable == se.type) - { - se.active = true; - lodge_symbol(symbol,e_st_local_variable); - - if (!post_variable_process(symbol)) - return error_node(); - - next_token(); + next_token(); + next_token(); - return se.var_node; - } - else if (scope_element::e_vector == se.type) + if (const_str_node) { - return parse_vector(); + free_node(node_allocator_,result); + + return expression_generator_(T(const_str_node->size())); } + else + return node_allocator_.allocate > + (static_cast*>(result)->ref()); } - } - #ifndef exprtk_disable_string_capabilities - // Are we dealing with a string variable? - if (symbol_table_.is_stringvar(symbol)) - { - return parse_string(); - } - #endif + range_t rp; - { - // Are we dealing with a function? - ifunction* function = symbol_table_.get_function(symbol); + if (!parse_range(rp)) + { + free_node(node_allocator_,result); - if (function) + return error_node(); + } + else if (const_str_node) { - lodge_symbol(symbol,e_st_function); + free_node(node_allocator_,result); + result = expression_generator_(const_str_node->ref(),rp); + } + else + result = expression_generator_(static_cast*> + (result)->ref(), rp); - expression_node_ptr func_node = - parse_function_invocation(function,symbol); + if (result) + rp.clear(); + } + else + next_token(); - if (func_node) - return func_node; - else - { - set_error( - make_error(parser_error::e_syntax, - current_token_, - "ERR156 - Failed to generate node for function: '" + symbol + "'")); + return result; + } + #else + inline expression_node_ptr parse_string() + { + return error_node(); + } + #endif - return error_node(); - } - } - } + #ifndef exprtk_disable_string_capabilities + inline expression_node_ptr parse_const_string() + { + const std::string const_str = current_token().value; + expression_node_ptr result = expression_generator_(const_str); + if (peek_token_is(token_t::e_lsqrbracket)) { - // Are we dealing with a vararg function? - ivararg_function* vararg_function = symbol_table_.get_vararg_function(symbol); + next_token(); - if (vararg_function) + if (peek_token_is(token_t::e_rsqrbracket)) { - lodge_symbol(symbol,e_st_function); + next_token(); + next_token(); - expression_node_ptr vararg_func_node = - parse_vararg_function_call(vararg_function,symbol); + free_node(node_allocator_,result); - if (vararg_func_node) - return vararg_func_node; - else - { - set_error( - make_error(parser_error::e_syntax, - current_token_, - "ERR157 - Failed to generate node for vararg function: '" + symbol + "'")); + return expression_generator_(T(const_str.size())); + } - return error_node(); - } + range_t rp; + + if (!parse_range(rp)) + { + free_node(node_allocator_,result); + rp.free(); + + return error_node(); } - } - { - // Are we dealing with a vararg generic function? - igeneric_function* generic_function = symbol_table_.get_generic_function(symbol); + free_node(node_allocator_,result); - if (generic_function) + if (rp.n1_c.first && (rp.n1_c.second == std::numeric_limits::max())) { - lodge_symbol(symbol,e_st_function); + rp.n1_c.second = const_str.size() - 1; + rp.cache.second = rp.n1_c.second; + } - expression_node_ptr genericfunc_node = - parse_generic_function_call(generic_function,symbol); + if ( + (rp.n0_c.first && (rp.n0_c.second >= const_str.size())) || + (rp.n1_c.first && (rp.n1_c.second >= const_str.size())) + ) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "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)); - if (genericfunc_node) - return genericfunc_node; - else - { - set_error( - make_error(parser_error::e_syntax, - current_token_, - "ERR158 - Failed to generate node for generic function: '" + symbol + "'")); + rp.free(); - return error_node(); - } + return error_node(); } + + result = expression_generator_(const_str,rp); + + if (result) + rp.clear(); } + else + next_token(); - { - // Are we dealing with a vararg string returing function? - igeneric_function* string_function = symbol_table_.get_string_function(symbol); + return result; + } + #else + inline expression_node_ptr parse_const_string() + { + return error_node(); + } + #endif - if (string_function) - { - lodge_symbol(symbol,e_st_function); + inline expression_node_ptr parse_vector() + { + const std::string symbol = current_token().value; - expression_node_ptr stringfunc_node = - parse_string_function_call(string_function,symbol); + vector_holder_ptr vec = vector_holder_ptr(0); - if (stringfunc_node) - return stringfunc_node; - else - { - set_error( - make_error(parser_error::e_syntax, - current_token_, - "ERR159 - Failed to generate node for string function: '" + symbol + "'")); + const scope_element& se = sem_.get_active_element(symbol); - return error_node(); - } + if ( + !details::imatch(se.name, symbol) || + (se.depth > state_.scope_depth) || + (scope_element::e_vector != se.type) + ) + { + if (0 == (vec = symtab_store_.get_vector(symbol))) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR110 - Symbol '" + symbol+ " not a vector", + exprtk_error_location)); + + return error_node(); } } + else + vec = se.vec_node; + + expression_node_ptr index_expr = error_node(); + + next_token(); - // Are we dealing with a vector element? - if (symbol_table_.is_vector(symbol)) + if (!token_is(token_t::e_lsqrbracket)) { - lodge_symbol(symbol,e_st_vector); - return parse_vector(); + return node_allocator_.allocate(vec); + } + else if (token_is(token_t::e_rsqrbracket)) + { + return expression_generator_(T(vec->size())); } + else if (0 == (index_expr = parse_expression())) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR111 - Failed to parse index for vector: '" + symbol + "'", + exprtk_error_location)); - if (details::is_reserved_symbol(symbol)) + return error_node(); + } + else if (!token_is(token_t::e_rsqrbracket)) { - set_error( - make_error(parser_error::e_syntax, - current_token_, - "ERR160 - Invalid use of reserved symbol '" + symbol + "'")); + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR112 - Expected ']' for index of vector: '" + symbol + "'", + exprtk_error_location)); - return error_node(); + free_node(node_allocator_,index_expr); + + return error_node(); } - // Should we handle unknown symbols? - if (resolve_unknown_symbol_ && unknown_symbol_resolver_) + // Perform compile-time range check + if (details::is_constant_node(index_expr)) { - T default_value = T(0); - std::string error_message; - typename unknown_symbol_resolver::usr_symbol_type usr_symbol_type; + const std::size_t index = static_cast(details::numeric::to_int32(index_expr->value())); + const std::size_t vec_size = vec->size(); - if (unknown_symbol_resolver_->process(symbol,usr_symbol_type,default_value,error_message)) + if (index >= vec_size) { - bool create_result = false; + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR113 - Index of " + details::to_str(index) + " out of range for " + "vector '" + symbol + "' of size " + details::to_str(vec_size), + exprtk_error_location)); - switch (usr_symbol_type) - { - case unknown_symbol_resolver::e_usr_variable_type : create_result = symbol_table_.create_variable(symbol,default_value); - break; + free_node(node_allocator_,index_expr); - case unknown_symbol_resolver::e_usr_constant_type : create_result = symbol_table_.add_constant(symbol,default_value); - break; + return error_node(); + } + } - default : create_result = false; - } + return expression_generator_.vector_element(symbol, vec, index_expr); + } - if (create_result) - { - expression_node_ptr var = symbol_table_.get_variable(symbol); + inline expression_node_ptr parse_vararg_function_call(ivararg_function* vararg_function, const std::string& vararg_function_name) + { + std::vector arg_list; - if (var) - { - if (symbol_table_.is_constant_node(symbol)) - { - var = expression_generator_(var->value()); - } + expression_node_ptr result = error_node(); - lodge_symbol(symbol,e_st_variable); + scoped_vec_delete sdd((*this),arg_list); - if (!post_variable_process(symbol)) - return error_node(); + next_token(); - next_token(); + if (token_is(token_t::e_lbracket)) + { + if (token_is(token_t::e_rbracket)) + { + if (!vararg_function->allow_zero_parameters()) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR114 - Zero parameter call to vararg function: " + + vararg_function_name + " not allowed", + exprtk_error_location)); - return var; - } + return error_node(); } + } + else + { + for ( ; ; ) + { + expression_node_ptr arg = parse_expression(); - set_error( - make_error(parser_error::e_symtab, - current_token_, - "ERR161 - Failed to create variable: '" + symbol + "'")); + if (0 == arg) + return error_node(); + else + arg_list.push_back(arg); - return error_node(); + if (token_is(token_t::e_rbracket)) + break; + else if (!token_is(token_t::e_comma)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR115 - Expected ',' for call to vararg function: " + + vararg_function_name, + exprtk_error_location)); + + return error_node(); + } + } } } + else if (!vararg_function->allow_zero_parameters()) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR116 - Zero parameter call to vararg function: " + + vararg_function_name + " not allowed", + exprtk_error_location)); - set_error( - make_error(parser_error::e_syntax, - current_token_, - "ERR162 - Undefined symbol: '" + symbol + "'")); - - return error_node(); - } - - inline expression_node_ptr parse_symbol() - { - static const std::string symbol_if = "if" ; - static const std::string symbol_while = "while" ; - static const std::string symbol_repeat = "repeat" ; - static const std::string symbol_for = "for" ; - static const std::string symbol_switch = "switch" ; - static const std::string symbol_null = "null" ; - static const std::string symbol_break = "break" ; - static const std::string symbol_continue = "continue"; - static const std::string symbol_var = "var" ; - static const std::string symbol_swap = "swap" ; - - if (valid_vararg_operation(current_token_.value)) - { - return parse_vararg_function(); - } - else if (valid_base_operation(current_token_.value)) - { - return parse_base_operation(); - } - else if (details::imatch(current_token_.value,symbol_if)) - { - return parse_conditional_statement(); - } - else if (details::imatch(current_token_.value,symbol_while)) - { - return parse_while_loop(); - } - else if (details::imatch(current_token_.value,symbol_repeat)) - { - return parse_repeat_until_loop(); - } - else if (details::imatch(current_token_.value,symbol_for)) - { - return parse_for_loop(); - } - else if (details::imatch(current_token_.value,symbol_switch)) - { - return parse_switch_statement(); - } - else if (details::is_valid_sf_symbol(current_token_.value)) - { - return parse_special_function(); - } - else if (details::imatch(current_token_.value,symbol_null)) - { - return parse_null_statement(); - } - #ifndef exprtk_disable_break_continue - else if (details::imatch(current_token_.value,symbol_break)) - { - return parse_break_statement(); - } - else if (details::imatch(current_token_.value,symbol_continue)) - { - return parse_continue_statement(); - } - #endif - else if (details::imatch(current_token_.value,symbol_var)) - { - return parse_define_var_statement(); - } - else if (details::imatch(current_token_.value,symbol_swap)) - { - return parse_swap_statement(); + return error_node(); } - else if (symbol_table_.valid() || !sem_.empty()) + + if (arg_list.size() < vararg_function->min_num_args()) { - return parse_symtab_symbol(); + set_error( + make_error(parser_error::e_syntax, + current_token(), + "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)); + + return error_node(); } - else + else if (arg_list.size() > vararg_function->max_num_args()) { set_error( - make_error(parser_error::e_symtab, - current_token_, - "ERR163 - Variable or function detected, yet symbol-table is invalid, Symbol: " + current_token_.value)); + make_error(parser_error::e_syntax, + current_token(), + "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)); return error_node(); } + + result = expression_generator_.vararg_function_call(vararg_function,arg_list); + + sdd.delete_ptr = (0 == result); + + return result; } - inline expression_node_ptr parse_branch(precedence_level precedence = e_level00) + class type_checker { - expression_node_ptr branch = error_node(); + public: - if (token_t::e_number == current_token_.type) + enum return_type_t { - T numeric_value = T(0); + 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 function_definition_list_t; + + type_checker(parser_t& p, + const std::string& func_name, + const std::string& func_prototypes, + const return_type_t default_return_type) + : invalid_state_(true), + parser_(p), + function_name_(func_name), + default_return_type_(default_return_type) + { + parse_function_prototypes(func_prototypes); + } + + bool verify(const std::string& param_seq, std::size_t& pseq_index) + { + if (function_definition_list_.empty()) + return true; + + std::vector > error_list; - if (details::string_to_real(current_token_.value,numeric_value)) + for (std::size_t i = 0; i < function_definition_list_.size(); ++i) { - expression_node_ptr literal_exp = expression_generator_(numeric_value); - next_token(); - branch = literal_exp; + details::char_t diff_value = 0; + std::size_t diff_index = 0; + + const bool result = details::sequence_match(function_definition_list_[i].param_seq, + param_seq, + diff_index, diff_value); + + if (result) + { + pseq_index = i; + return true; + } + else + error_list.push_back(std::make_pair(diff_index, diff_value)); + } + + if (1 == error_list.size()) + { + parser_. + set_error( + make_error(parser_error::e_syntax, + parser_.current_token(), + "ERR119 - Failed parameter type check for function '" + function_name_ + "', " + "Expected '" + function_definition_list_[0].param_seq + + "' call set: '" + param_seq + "'", + exprtk_error_location)); } else { - set_error( - make_error(parser_error::e_numeric, - current_token_, - "ERR164 - Failed to convert '" + current_token_.value + "' to a number")); + // find first with largest diff_index; + std::size_t max_diff_index = 0; - return error_node(); + for (std::size_t i = 1; i < error_list.size(); ++i) + { + if (error_list[i].first > error_list[max_diff_index].first) + { + max_diff_index = i; + } + } + + parser_. + set_error( + make_error(parser_error::e_syntax, + parser_.current_token(), + "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)); } + + return false; } - else if (token_t::e_symbol == current_token_.type) + + std::size_t paramseq_count() const { - branch = parse_symbol(); + return function_definition_list_.size(); } - #ifndef exprtk_disable_string_capabilities - else if (token_t::e_string == current_token_.type) + + std::string paramseq(const std::size_t& index) const { - branch = parse_const_string(); + return function_definition_list_[index].param_seq; } - #endif - else if (token_t::e_lbracket == current_token_.type) + + return_type_t return_type(const std::size_t& index) const { - next_token(); + return function_definition_list_[index].return_type; + } - if (0 == (branch = parse_expression())) - return error_node(); - else if (!token_is(token_t::e_rbracket)) - { - set_error( - make_error(parser_error::e_syntax, - current_token_, - "ERR165 - Expected ')' instead of: '" + current_token_.value + "'")); + bool invalid() const + { + return !invalid_state_; + } - free_node(node_allocator_,branch); + bool allow_zero_parameters() const + { - return error_node(); - } - else if (!post_bracket_process(token_t::e_lbracket,branch)) + for (std::size_t i = 0; i < function_definition_list_.size(); ++i) { - free_node(node_allocator_,branch); - - return error_node(); + if (std::string::npos != function_definition_list_[i].param_seq.find("Z")) + { + return true; + } } + + return false; } - else if (token_t::e_lsqrbracket == current_token_.type) + + private: + + std::vector split_param_seq(const std::string& param_seq, const details::char_t delimiter = '|') const { - next_token(); + std::string::const_iterator current_begin = param_seq.begin(); + std::string::const_iterator iter = param_seq.begin(); - if (0 == (branch = parse_expression())) - return error_node(); - else if (!token_is(token_t::e_rsqrbracket)) - { - set_error( - make_error(parser_error::e_syntax, - current_token_, - "ERR166 - Expected ']' instead of: '" + current_token_.value + "'")); + std::vector result; - free_node(node_allocator_,branch); + while (iter != param_seq.end()) + { + if (*iter == delimiter) + { + result.push_back(std::string(current_begin, iter)); + current_begin = ++iter; + } + else + ++iter; + } - return error_node(); - } - else if (!post_bracket_process(token_t::e_lsqrbracket,branch)) - { - free_node(node_allocator_,branch); + if (current_begin != iter) + { + result.push_back(std::string(current_begin, iter)); + } - return error_node(); - } + return result; } - else if (token_t::e_lcrlbracket == current_token_.type) + + inline bool is_valid_token(std::string param_seq, + function_prototype_t& funcproto) const { - next_token(); + // Determine return type + funcproto.return_type = default_return_type_; - if (0 == (branch = parse_expression())) - return error_node(); - else if (!token_is(token_t::e_rcrlbracket)) + if (param_seq.size() > 2) { - set_error( - make_error(parser_error::e_syntax, - current_token_, - "ERR167 - Expected '}' instead of: '" + current_token_.value + "'")); + if (':' == param_seq[1]) + { + // Note: Only overloaded igeneric functions can have return + // type definitions. + if (type_checker::e_overload != default_return_type_) + return false; - free_node(node_allocator_,branch); + switch (param_seq[0]) + { + case 'T' : funcproto.return_type = type_checker::e_numeric; + break; - return error_node(); - } - else if (!post_bracket_process(token_t::e_lcrlbracket,branch)) - { - free_node(node_allocator_,branch); + case 'S' : funcproto.return_type = type_checker::e_string; + break; - return error_node(); + default : return false; + } + + param_seq.erase(0,2); + } } - } - else if (token_t::e_sub == current_token_.type) - { - next_token(); - branch = parse_expression(e_level11); if ( - branch && - !( - details::is_neg_unary_node (branch) && - simplify_unary_negation_branch(branch) - ) + (std::string::npos != param_seq.find("?*")) || + (std::string::npos != param_seq.find("**")) ) { - branch = expression_generator_(details::e_neg,branch); + return false; + } + else if ( + (std::string::npos == param_seq.find_first_not_of("STV*?|")) || + ("Z" == param_seq) + ) + { + funcproto.param_seq = param_seq; + return true; } - } - else if (token_t::e_add == current_token_.type) - { - next_token(); - branch = parse_expression(e_level13); - } - else if (token_t::e_eof == current_token_.type) - { - set_error( - make_error(parser_error::e_syntax, - current_token_, - "ERR168 - Premature end of expression[1]")); - - return error_node(); - } - else - { - set_error( - make_error(parser_error::e_syntax, - current_token_, - "ERR169 - Premature end of expression[2]")); - return error_node(); + return false; } - if ( - branch && - (e_level00 == precedence) && - token_is(token_t::e_ternary,false) - ) + void parse_function_prototypes(const std::string& func_prototypes) { - branch = parse_ternary_conditional_statement(branch); - } + if (func_prototypes.empty()) + return; - parse_pending_string_rangesize(branch); + std::vector param_seq_list = split_param_seq(func_prototypes); - return branch; - } + typedef std::map param_seq_map_t; + param_seq_map_t param_seq_map; - inline bool token_is(const typename token_t::token_type& ttype, const bool advance_token = true) - { - if (current_token_.type != ttype) - { - return false; - } + for (std::size_t i = 0; i < param_seq_list.size(); ++i) + { + function_prototype_t func_proto; - if (advance_token) - { - next_token(); - } - - return true; - } + if (!is_valid_token(param_seq_list[i], func_proto)) + { + invalid_state_ = false; - inline bool peek_token_is(const typename token_t::token_type& ttype) - { - return (lexer_.peek_next_token().type == ttype); - } + parser_. + set_error( + make_error(parser_error::e_syntax, + parser_.current_token(), + "ERR121 - Invalid parameter sequence of '" + param_seq_list[i] + + "' for function: " + function_name_, + exprtk_error_location)); + return; + } - inline bool peek_token_is(const std::string& s) - { - return (details::imatch(lexer_.peek_next_token().value,s)); - } + param_seq_map_t::const_iterator seq_itr = param_seq_map.find(param_seq_list[i]); - template - class expression_generator - { - public: + if (param_seq_map.end() != seq_itr) + { + invalid_state_ = false; - typedef details::expression_node* expression_node_ptr; - typedef expression_node_ptr (*synthesize_functor_t)(expression_generator&, const details::operator_type& operation, expression_node_ptr (&branch)[2]); - typedef std::map synthesize_map_t; - typedef typename exprtk::parser parser_t; - typedef const Type& vtype; - typedef const Type ctype; + parser_. + set_error( + make_error(parser_error::e_syntax, + parser_.current_token(), + "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; + } - inline void init_synthesize_map() - { - #ifndef exprtk_disable_enhanced_features - synthesize_map_["(v)o(v)"] = synthesize_vov_expression::process; - synthesize_map_["(c)o(v)"] = synthesize_cov_expression::process; - synthesize_map_["(v)o(c)"] = synthesize_voc_expression::process; + function_definition_list_.push_back(func_proto); + } + } - #define register_synthezier(S) \ - synthesize_map_[S ::node_type::id()] = S ::process; \ + type_checker(const type_checker&); + type_checker& operator=(const type_checker&); - register_synthezier(synthesize_vovov_expression0) - register_synthezier(synthesize_vovov_expression1) - register_synthezier(synthesize_vovoc_expression0) - register_synthezier(synthesize_vovoc_expression1) - register_synthezier(synthesize_vocov_expression0) - register_synthezier(synthesize_vocov_expression1) - register_synthezier(synthesize_covov_expression0) - register_synthezier(synthesize_covov_expression1) - register_synthezier(synthesize_covoc_expression0) - register_synthezier(synthesize_covoc_expression1) - register_synthezier(synthesize_cocov_expression1) - register_synthezier(synthesize_vococ_expression0) + bool invalid_state_; + parser_t& parser_; + std::string function_name_; + const return_type_t default_return_type_; + function_definition_list_t function_definition_list_; + }; - register_synthezier(synthesize_vovovov_expression0) - register_synthezier(synthesize_vovovoc_expression0) - register_synthezier(synthesize_vovocov_expression0) - register_synthezier(synthesize_vocovov_expression0) - register_synthezier(synthesize_covovov_expression0) - register_synthezier(synthesize_covocov_expression0) - register_synthezier(synthesize_vocovoc_expression0) - register_synthezier(synthesize_covovoc_expression0) - register_synthezier(synthesize_vococov_expression0) + inline expression_node_ptr parse_generic_function_call(igeneric_function* function, const std::string& function_name) + { + std::vector arg_list; - register_synthezier(synthesize_vovovov_expression1) - register_synthezier(synthesize_vovovoc_expression1) - register_synthezier(synthesize_vovocov_expression1) - register_synthezier(synthesize_vocovov_expression1) - register_synthezier(synthesize_covovov_expression1) - register_synthezier(synthesize_covocov_expression1) - register_synthezier(synthesize_vocovoc_expression1) - register_synthezier(synthesize_covovoc_expression1) - register_synthezier(synthesize_vococov_expression1) + scoped_vec_delete sdd((*this),arg_list); - register_synthezier(synthesize_vovovov_expression2) - register_synthezier(synthesize_vovovoc_expression2) - register_synthezier(synthesize_vovocov_expression2) - register_synthezier(synthesize_vocovov_expression2) - register_synthezier(synthesize_covovov_expression2) - register_synthezier(synthesize_covocov_expression2) - register_synthezier(synthesize_vocovoc_expression2) - register_synthezier(synthesize_covovoc_expression2) + next_token(); - register_synthezier(synthesize_vovovov_expression3) - register_synthezier(synthesize_vovovoc_expression3) - register_synthezier(synthesize_vovocov_expression3) - register_synthezier(synthesize_vocovov_expression3) - register_synthezier(synthesize_covovov_expression3) - register_synthezier(synthesize_covocov_expression3) - register_synthezier(synthesize_vocovoc_expression3) - register_synthezier(synthesize_covovoc_expression3) - register_synthezier(synthesize_vococov_expression3) + std::string param_type_list; - register_synthezier(synthesize_vovovov_expression4) - register_synthezier(synthesize_vovovoc_expression4) - register_synthezier(synthesize_vovocov_expression4) - register_synthezier(synthesize_vocovov_expression4) - register_synthezier(synthesize_covovov_expression4) - register_synthezier(synthesize_covocov_expression4) - register_synthezier(synthesize_vocovoc_expression4) - register_synthezier(synthesize_covovoc_expression4) - #endif - } + type_checker tc((*this), function_name, function->parameter_sequence, type_checker::e_string); - inline void set_parser(parser_t& p) + if (tc.invalid()) { - parser_ = &p; - } + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR123 - Type checker instantiation failure for generic function: " + function_name, + exprtk_error_location)); - inline void set_uom(unary_op_map_t& unary_op_map) - { - unary_op_map_ = &unary_op_map; + return error_node(); } - inline void set_bom(binary_op_map_t& binary_op_map) + if (token_is(token_t::e_lbracket)) { - binary_op_map_ = &binary_op_map; - } + 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(), + "ERR124 - Zero parameter call to generic function: " + + function_name + " not allowed", + exprtk_error_location)); - inline void set_ibom(inv_binary_op_map_t& inv_binary_op_map) - { - inv_binary_op_map_ = &inv_binary_op_map; - } + return error_node(); + } + } + else + { + for ( ; ; ) + { + expression_node_ptr arg = parse_expression(); - inline void set_sf3m(sf3_map_t& sf3_map) - { - sf3_map_ = &sf3_map; - } + if (0 == arg) + return error_node(); - inline void set_sf4m(sf4_map_t& sf4_map) - { - sf4_map_ = &sf4_map; - } + if (is_ivector_node(arg)) + param_type_list += 'V'; + else if (is_generally_string_node(arg)) + param_type_list += 'S'; + else // Everything else is assumed to be a scalar returning expression + param_type_list += 'T'; - inline void set_allocator(details::node_allocator& na) - { - node_allocator_ = &na; - } + arg_list.push_back(arg); - inline void set_strength_reduction_state(const bool enabled) - { - strength_reduction_enabled_ = enabled; - } + if (token_is(token_t::e_rbracket)) + break; + else if (!token_is(token_t::e_comma)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR125 - Expected ',' for call to generic function: " + function_name, + exprtk_error_location)); - inline bool strength_reduction_enabled() const - { - return strength_reduction_enabled_; + return error_node(); + } + } + } } - - inline bool valid_operator(const details::operator_type& operation, binary_functor_t& bop) + else if ( + !function->parameter_sequence.empty() && + function->allow_zero_parameters () && + !tc .allow_zero_parameters () + ) { - typename binary_op_map_t::iterator bop_itr = binary_op_map_->find(operation); - - if ((*binary_op_map_).end() == bop_itr) - return false; - - bop = bop_itr->second; + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR126 - Zero parameter call to generic function: " + + function_name + " not allowed", + exprtk_error_location)); - return true; + return error_node(); } - inline bool valid_operator(const details::operator_type& operation, unary_functor_t& uop) - { - typename unary_op_map_t::iterator uop_itr = unary_op_map_->find(operation); - - if ((*unary_op_map_).end() == uop_itr) - return false; + std::size_t param_seq_index = 0; - uop = uop_itr->second; + if ( + state_.type_check_enabled && + !tc.verify(param_type_list, param_seq_index) + ) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR127 - Invalid input parameter sequence for call to generic function: " + function_name, + exprtk_error_location)); - return true; + return error_node(); } - inline details::operator_type get_operator(const binary_functor_t& bop) - { - return (*inv_binary_op_map_).find(bop)->second; - } + expression_node_ptr result = error_node(); - inline expression_node_ptr operator()(const Type& v) const - { - return node_allocator_->allocate(v); - } + 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); - inline expression_node_ptr operator()(const std::string& s) const - { - return node_allocator_->allocate(s); - } + sdd.delete_ptr = (0 == result); - inline expression_node_ptr operator()(std::string& s, range_t& rp) const - { - return node_allocator_->allocate_rr(s,rp); - } + return result; + } - inline expression_node_ptr operator()(const std::string& s, range_t& rp) const + 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) + { + if (token_is(token_t::e_lbracket)) { - return node_allocator_->allocate_tt(s,rp); - } + 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)); - inline expression_node_ptr operator()(expression_node_ptr branch, range_t& rp) const - { - if (is_generally_string_node(branch)) - return node_allocator_->allocate_tt(branch,rp); + return false; + } + } else - return error_node(); - } + { + for ( ; ; ) + { + expression_node_ptr arg = parse_expression(); - inline bool unary_optimizable(const details::operator_type& operation) const - { - return (details::e_abs == operation) || (details::e_acos == operation) || - (details::e_acosh == operation) || (details::e_asin == operation) || - (details::e_asinh == operation) || (details::e_atan == operation) || - (details::e_atanh == operation) || (details::e_ceil == operation) || - (details::e_cos == operation) || (details::e_cosh == operation) || - (details::e_exp == operation) || (details::e_expm1 == operation) || - (details::e_floor == operation) || (details::e_log == operation) || - (details::e_log10 == operation) || (details::e_log2 == operation) || - (details::e_log1p == operation) || (details::e_neg == operation) || - (details::e_pos == operation) || (details::e_round == operation) || - (details::e_sin == operation) || (details::e_sinc == operation) || - (details::e_sinh == operation) || (details::e_sqrt == operation) || - (details::e_tan == operation) || (details::e_tanh == operation) || - (details::e_cot == operation) || (details::e_sec == operation) || - (details::e_csc == operation) || (details::e_r2d == operation) || - (details::e_d2r == operation) || (details::e_d2g == operation) || - (details::e_g2d == operation) || (details::e_notl == operation) || - (details::e_sgn == operation) || (details::e_erf == operation) || - (details::e_erfc == operation) || (details::e_ncdf == operation) || - (details::e_frac == operation) || (details::e_trunc == operation); - } - - inline bool sf3_optimizable(const std::string& sf3id, trinary_functor_t& tfunc) - { - typename sf3_map_t::iterator itr = sf3_map_->find(sf3id); + if (0 == arg) + return false; - if (sf3_map_->end() == itr) - return false; - else - tfunc = itr->second.first; + if (is_ivector_node(arg)) + param_type_list += 'V'; + else if (is_generally_string_node(arg)) + param_type_list += 'S'; + else // Everything else is a scalar returning expression + param_type_list += 'T'; - return true; - } + arg_list.push_back(arg); - inline bool sf4_optimizable(const std::string& sf4id, quaternary_functor_t& qfunc) - { - typename sf4_map_t::iterator itr = sf4_map_->find(sf4id); + if (token_is(token_t::e_rbracket)) + break; + else if (!token_is(token_t::e_comma)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR129 - Expected ',' for call to string function: " + function_name, + exprtk_error_location)); - if (sf4_map_->end() == itr) - return false; - else - qfunc = itr->second.first; + return false; + } + } + } return true; } + else + return false; + } - inline bool sf3_optimizable(const std::string& sf3id, details::operator_type& operation) - { - typename sf3_map_t::iterator itr = sf3_map_->find(sf3id); + #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(); - if (sf3_map_->end() == itr) - return false; - else - operation = itr->second.second; + std::string param_type_list; - return true; - } + type_checker tc((*this), function_name, function->parameter_sequence, type_checker::e_string); - inline bool sf4_optimizable(const std::string& sf4id, details::operator_type& operation) + if ( + (!function->parameter_sequence.empty()) && + (0 == tc.paramseq_count()) + ) { - typename sf4_map_t::iterator itr = sf4_map_->find(sf4id); - - if (sf4_map_->end() == itr) - return false; - else - operation = itr->second.second; - - return true; + return error_node(); } - inline expression_node_ptr operator()(const details::operator_type& operation, expression_node_ptr (&branch)[1]) - { - if (0 == branch[0]) - return error_node(); - else if (details::is_null_node(branch[0])) - return branch[0]; - else if (details::is_break_node(branch[0])) - return error_node(); - else if (details::is_continue_node(branch[0])) - return error_node(); - else if (details::is_constant_node(branch[0])) - return synthesize_expression(operation,branch); - else if (unary_optimizable(operation) && details::is_variable_node(branch[0])) - return synthesize_uv_expression(operation,branch); - else if (unary_optimizable(operation) && details::is_ivector_node(branch[0])) - return synthesize_uvec_expression(operation,branch); - else - return synthesize_unary_expression(operation,branch); - } + std::vector arg_list; + scoped_vec_delete sdd((*this),arg_list); - inline bool is_assignment_operation(const details::operator_type& operation) const + if (!parse_igeneric_function_params(param_type_list, arg_list, function_name, function, tc)) { - return (details::e_addass == operation) || - (details::e_subass == operation) || - (details::e_mulass == operation) || - (details::e_divass == operation) || - (details::e_modass == operation) ; + return error_node(); } - #ifndef exprtk_disable_string_capabilities - inline bool valid_string_operation(const details::operator_type& operation) const - { - return (details::e_add == 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_in == operation) || - (details::e_like == operation) || - (details::e_ilike == operation) || - (details::e_assign == operation) || - (details::e_addass == operation) || - (details::e_swap == operation) ; - } - #else - inline bool valid_string_operation(const details::operator_type&) const - { - return false; - } - #endif + std::size_t param_seq_index = 0; - inline std::string to_str(const details::operator_type& operation) const + if (!tc.verify(param_type_list, param_seq_index)) { - switch (operation) - { - case details::e_add : return "+"; - case details::e_sub : return "-"; - case details::e_mul : return "*"; - case details::e_div : return "/"; - case details::e_mod : return "%"; - case details::e_pow : return "^"; - case details::e_lt : return "<"; - case details::e_lte : return "<="; - case details::e_gt : return ">"; - case details::e_gte : return ">="; - case details::e_eq : return "=="; - case details::e_ne : return "!="; - case details::e_and : return "and"; - case details::e_nand : return "nand"; - case details::e_or : return "or"; - case details::e_nor : return "nor"; - case details::e_xor : return "xor"; - case details::e_xnor : return "xnor"; - default : return "UNKNOWN"; - } - } + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR130 - Invalid input parameter sequence for call to string function: " + function_name, + exprtk_error_location)); - inline bool operation_optimizable(const details::operator_type& operation) const - { - return (details::e_add == operation) || - (details::e_sub == operation) || - (details::e_mul == operation) || - (details::e_div == operation) || - (details::e_mod == operation) || - (details::e_pow == 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_and == operation) || - (details::e_nand == operation) || - (details::e_or == operation) || - (details::e_nor == operation) || - (details::e_xor == operation) || - (details::e_xnor == operation) ; + return error_node(); } - inline std::string branch_to_id(expression_node_ptr branch) - { - static const std::string null_str ("(null)" ); - static const std::string const_str ("(c)" ); - static const std::string var_str ("(v)" ); - static const std::string vov_str ("(vov)" ); - static const std::string cov_str ("(cov)" ); - static const std::string voc_str ("(voc)" ); - static const std::string str_str ("(s)" ); - static const std::string strrng_str ("(rngs)" ); - static const std::string cs_str ("(cs)" ); - static const std::string cstrrng_str("(crngs)"); + expression_node_ptr result = error_node(); - if (details::is_null_node(branch)) - return null_str; - else if (details::is_constant_node(branch)) - return const_str; - else if (details::is_variable_node(branch)) - return var_str; - else if (details::is_vov_node(branch)) - return vov_str; - else if (details::is_cov_node(branch)) - return cov_str; - else if (details::is_voc_node(branch)) - return voc_str; - else if (details::is_string_node(branch)) - return str_str; - else if (details::is_const_string_node(branch)) - return cs_str; - else if (details::is_string_range_node(branch)) - return strrng_str; - else if (details::is_const_string_range_node(branch)) - return cstrrng_str; - else if (details::is_t0ot1ot2_node(branch)) - return "(" + dynamic_cast*>(branch)->type_id() + ")"; - else if (details::is_t0ot1ot2ot3_node(branch)) - return "(" + dynamic_cast*>(branch)->type_id() + ")"; - else - return "ERROR"; - } + 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); - inline std::string branch_to_id(expression_node_ptr (&branch)[2]) - { - return branch_to_id(branch[0]) + std::string("o") + branch_to_id(branch[1]); - } + sdd.delete_ptr = (0 == result); + + 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; - inline bool cov_optimizable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const + type_checker tc((*this), function_name, function->parameter_sequence, type_checker::e_overload); + + if ( + (!function->parameter_sequence.empty()) && + (0 == tc.paramseq_count()) + ) { - if (!operation_optimizable(operation)) - return false; - else - return (details::is_constant_node(branch[0]) && details::is_variable_node(branch[1])); + return error_node(); } - inline bool voc_optimizable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const + 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)) { - if (!operation_optimizable(operation)) - return false; - else - return (details::is_variable_node(branch[0]) && details::is_constant_node(branch[1])); + return error_node(); } - inline bool vov_optimizable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const + std::size_t param_seq_index = 0; + + if (!tc.verify(param_type_list, param_seq_index)) { - if (!operation_optimizable(operation)) - return false; - else - return (details::is_variable_node(branch[0]) && details::is_variable_node(branch[1])); + 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(); } - inline bool cob_optimizable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const + expression_node_ptr result = error_node(); + + if (type_checker::e_numeric == tc.return_type(param_seq_index)) { - if (!operation_optimizable(operation)) - return false; + if (tc.paramseq_count() <= 1) + result = expression_generator_ + .generic_function_call(function, arg_list); else - return (details::is_constant_node(branch[0]) && !details::is_constant_node(branch[1])); + result = expression_generator_ + .generic_function_call(function, arg_list, param_seq_index); } - - inline bool boc_optimizable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const + else if (type_checker::e_string == tc.return_type(param_seq_index)) { - if (!operation_optimizable(operation)) - return false; + if (tc.paramseq_count() <= 1) + result = expression_generator_ + .string_function_call(function, arg_list); else - return (!details::is_constant_node(branch[0]) && details::is_constant_node(branch[1])); + result = expression_generator_ + .string_function_call(function, arg_list, param_seq_index); } - - inline bool cocob_optimizable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const + else { - if ( - (details::e_add == operation) || - (details::e_sub == operation) || - (details::e_mul == operation) || - (details::e_div == operation) - ) - { - return (details::is_constant_node(branch[0]) && details::is_cob_node(branch[1])) || - (details::is_constant_node(branch[1]) && details::is_cob_node(branch[0])); - } - else - return false; + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR132 - Invalid return type for call to overloaded function: " + function_name, + exprtk_error_location)); } - inline bool coboc_optimizable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const - { - if ( - (details::e_add == operation) || - (details::e_sub == operation) || - (details::e_mul == operation) || - (details::e_div == operation) - ) + 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, const std::string& sf_name) + { + expression_node_ptr branch[NumberOfParameters]; + expression_node_ptr result = error_node(); + + std::fill_n(branch, NumberOfParameters, reinterpret_cast(0)); + + scoped_delete sd(p,branch); + + p.next_token(); + + if (!p.token_is(token_t::e_lbracket)) { - return (details::is_constant_node(branch[0]) && details::is_boc_node(branch[1])) || - (details::is_constant_node(branch[1]) && details::is_boc_node(branch[0])); + p.set_error( + make_error(parser_error::e_syntax, + p.current_token(), + "ERR133 - Expected '(' for special function '" + sf_name + "'", + exprtk_error_location)); + + return error_node(); } - else - return false; - } - inline bool uvouv_optimizable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const - { - if (!operation_optimizable(operation)) - return false; + for (std::size_t i = 0; i < NumberOfParameters; ++i) + { + branch[i] = p.parse_expression(); + + if (0 == branch[i]) + { + return p.error_node(); + } + else if (i < (NumberOfParameters - 1)) + { + if (!p.token_is(token_t::e_comma)) + { + p.set_error( + make_error(parser_error::e_syntax, + p.current_token(), + "ERR134 - Expected ',' before next parameter of special function '" + sf_name + "'", + exprtk_error_location)); + + return p.error_node(); + } + } + } + + 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 - return (details::is_uv_node(branch[0]) && details::is_uv_node(branch[1])); + result = p.expression_generator_.special_function(opt_type,branch); + + sd.delete_ptr = (0 == result); + + return result; } + }; + + inline expression_node_ptr parse_special_function() + { + const std::string sf_name = current_token().value; - inline bool vob_optimizable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const + // Expect: $fDD(expr0,expr1,expr2) or $fDD(expr0,expr1,expr2,expr3) + if ( + !details::is_digit(sf_name[2]) || + !details::is_digit(sf_name[3]) + ) { - if (!operation_optimizable(operation)) - return false; - else - return (details::is_variable_node(branch[0]) && !details::is_variable_node(branch[1])); + set_error( + make_error(parser_error::e_token, + current_token(), + "ERR136 - Invalid special function[1]: " + sf_name, + exprtk_error_location)); + + return error_node(); } - inline bool bov_optimizable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const + const int id = (sf_name[2] - '0') * 10 + + (sf_name[3] - '0'); + + if (id >= details::e_sffinal) { - if (!operation_optimizable(operation)) - return false; - else - return (!details::is_variable_node(branch[0]) && details::is_variable_node(branch[1])); + set_error( + make_error(parser_error::e_token, + current_token(), + "ERR137 - Invalid special function[2]: " + sf_name, + exprtk_error_location)); + + return error_node(); } - inline bool binext_optimizable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const + const int sf_3_to_4 = details::e_sf48; + const details::operator_type opt_type = details::operator_type(id + 1000); + const std::size_t NumberOfParameters = (id < (sf_3_to_4 - 1000)) ? 3U : 4U; + + switch (NumberOfParameters) { - if (!operation_optimizable(operation)) - return false; - else - return (!details::is_constant_node(branch[0]) || !details::is_constant_node(branch[1])); + 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(); } + } + + inline expression_node_ptr parse_null_statement() + { + next_token(); + return node_allocator_.allocate >(); + } - inline bool is_invalid_assignment_op(const details::operator_type& operation, expression_node_ptr (&branch)[2]) + #ifndef exprtk_disable_break_continue + inline expression_node_ptr parse_break_statement() + { + if (state_.parsing_break_stmt) { - if (is_assignment_operation(operation)) - { - const bool b1_is_genstring = details::is_generally_string_node(branch[1]); + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR138 - Invoking 'break' within a break call is not allowed", + exprtk_error_location)); - if (details::is_string_node(branch[0])) - return !b1_is_genstring; - else - return ( - !details::is_variable_node (branch[0]) && - !details::is_vector_elem_node(branch[0]) && - !details::is_vector_node (branch[0]) - ) - || b1_is_genstring; - } - else - return false; + return error_node(); } - - inline bool is_invalid_break_continue_op(expression_node_ptr (&branch)[2]) + else if (0 == state_.parsing_loop_stmt_count) { - return ( - details::is_break_node (branch[0]) || - details::is_break_node (branch[1]) || - details::is_continue_node(branch[0]) || - details::is_continue_node(branch[1]) - ); + 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(); } - inline bool is_invalid_string_op(const details::operator_type& operation, expression_node_ptr (&branch)[2]) + scoped_bool_negator sbn(state_.parsing_break_stmt); + + if (!brkcnt_list_.empty()) { - const bool b0_string = is_generally_string_node(branch[0]); - const bool b1_string = is_generally_string_node(branch[1]); + next_token(); - bool result = false; + brkcnt_list_.front() = true; - if (b0_string ^ b1_string) - result = true; - else if (!valid_string_operation(operation) && b0_string && b1_string) - result = true; + expression_node_ptr return_expr = error_node(); - if (result) + if (token_is(token_t::e_lsqrbracket)) { - parser_->set_synthesis_error("Invalid string operation"); - } - - return result; - } - - inline bool is_invalid_string_op(const details::operator_type& operation, expression_node_ptr (&branch)[3]) - { - const bool b0_string = is_generally_string_node(branch[0]); - const bool b1_string = is_generally_string_node(branch[1]); - const bool b2_string = is_generally_string_node(branch[2]); + if (0 == (return_expr = parse_expression())) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR140 - Failed to parse return expression for 'break' statement", + exprtk_error_location)); - bool result = false; + return error_node(); + } + else if (!token_is(token_t::e_rsqrbracket)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR141 - Expected ']' at the completion of break's return expression", + exprtk_error_location)); - if ((b0_string ^ b1_string) || (b1_string ^ b2_string)) - result = true; - else if ((details::e_inrange != operation) && b0_string && b1_string && b2_string) - result = true; + free_node(node_allocator_,return_expr); - if (result) - { - parser_->set_synthesis_error("Invalid string operation"); + return error_node(); + } } - return result; + state_.activate_side_effect("parse_break_statement()"); + + return node_allocator_.allocate >(return_expr); + } + else + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR142 - Invalid use of 'break', allowed only in the scope of a loop", + exprtk_error_location)); } - inline bool is_string_operation(const details::operator_type& operation, expression_node_ptr (&branch)[2]) + return error_node(); + } + + inline expression_node_ptr parse_continue_statement() + { + if (0 == state_.parsing_loop_stmt_count) { - const bool b0_string = is_generally_string_node(branch[0]); - const bool b1_string = is_generally_string_node(branch[1]); + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR143 - Invalid use of 'continue', allowed only in the scope of a loop", + exprtk_error_location)); - return (b0_string && b1_string && valid_string_operation(operation)); + return error_node(); } - - inline bool is_string_operation(const details::operator_type& operation, expression_node_ptr (&branch)[3]) + else { - const bool b0_string = is_generally_string_node(branch[0]); - const bool b1_string = is_generally_string_node(branch[1]); - const bool b2_string = is_generally_string_node(branch[2]); + next_token(); - return (b0_string && b1_string && b2_string && (details::e_inrange == operation)); + brkcnt_list_.front() = true; + state_.activate_side_effect("parse_continue_statement()"); + + return node_allocator_.allocate >(); } + } + #endif - #ifndef exprtk_disable_sc_andor - inline bool is_shortcircuit_expression(const details::operator_type& operation) + inline expression_node_ptr parse_define_vector_statement(const std::string& vec_name) + { + expression_node_ptr size_expr = error_node(); + + if (!token_is(token_t::e_lsqrbracket)) { - return ( - (details::e_scand == operation) || - (details::e_scor == operation) - ); + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR144 - Expected '[' as part of vector size definition", + exprtk_error_location)); + + return error_node(); } - #else - inline bool is_shortcircuit_expression(const details::operator_type&) + else if (0 == (size_expr = parse_expression())) { - return false; - } - #endif + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR145 - Failed to determine size of vector '" + vec_name + "'", + exprtk_error_location)); - inline bool is_null_present(expression_node_ptr (&branch)[2]) + return error_node(); + } + else if (!is_constant_node(size_expr)) { - return ( - details::is_null_node(branch[0]) || - details::is_null_node(branch[1]) - ); + free_node(node_allocator_,size_expr); + + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR146 - Expected a literal number as size of vector '" + vec_name + "'", + exprtk_error_location)); + + return error_node(); } - inline bool is_vector_eqineq_operation(const details::operator_type& operation, expression_node_ptr (&branch)[2]) + 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)) || + (vector_size > max_vector_size) + ) { - 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) - ); + set_error( + make_error(parser_error::e_syntax, + current_token(), + "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)); + + return error_node(); } - inline bool is_vector_arithmetic_operation(const details::operator_type& operation, expression_node_ptr (&branch)[2]) - { - if (!is_ivector_node(branch[0]) && !is_ivector_node(branch[1])) - return false; - else - return ( - (details::e_add == operation) || - (details::e_sub == operation) || - (details::e_mul == operation) || - (details::e_div == operation) || - (details::e_pow == operation) - ); - } - - inline expression_node_ptr operator()(const details::operator_type& operation, expression_node_ptr (&branch)[2]) - { - if ((0 == branch[0]) || (0 == branch[1])) - return error_node(); - else if (is_invalid_string_op(operation,branch)) - return error_node(); - else if (is_invalid_assignment_op(operation,branch)) - return error_node(); - else if (is_invalid_break_continue_op(branch)) - return error_node(); - else if (details::e_assign == operation) - return synthesize_assignment_expression(operation,branch); - else if (details::e_swap == operation) - return synthesize_swap_expression(branch); - else if (is_assignment_operation(operation)) - return synthesize_assignment_operation_expression(operation,branch); - else if (is_vector_eqineq_operation(operation,branch)) - return synthesize_veceqineq_operation_expression(operation,branch); - else if (is_vector_arithmetic_operation(operation,branch)) - return synthesize_vecarithmetic_operation_expression(operation,branch); - else if (is_shortcircuit_expression(operation)) - return synthesize_shortcircuit_expression(operation,branch); - else if (is_string_operation(operation,branch)) - return synthesize_string_expression(operation,branch); - else if (is_null_present(branch)) - return synthesize_null_expression(operation,branch); - - expression_node_ptr result = error_node(); - - #ifndef exprtk_disable_enhanced_features - if (synthesize_expression(operation,branch,result)) - return result; - else - #endif + std::vector vec_initilizer_list; - { - /* - Possible reductions: - 1. c o cob -> cob - 2. cob o c -> cob - 3. c o boc -> boc - 4. boc o c -> boc - */ - result = error_node(); + scoped_vec_delete svd((*this),vec_initilizer_list); - if (cocob_optimizable(operation,branch)) - result = synthesize_cocob_expression::process(*this,operation,branch); - else if (coboc_optimizable(operation,branch) && (0 == result)) - result = synthesize_coboc_expression::process(*this,operation,branch); + bool single_value_initialiser = false; + bool vec_to_vec_initialiser = false; + bool null_initialisation = false; - if (result) - return result; - } + if (!token_is(token_t::e_rsqrbracket)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR148 - Expected ']' as part of vector size definition", + exprtk_error_location)); - if (uvouv_optimizable(operation,branch)) - return synthesize_uvouv_expression(operation,branch); - else if (vob_optimizable(operation,branch)) - return synthesize_vob_expression::process(*this,operation,branch); - else if (bov_optimizable(operation,branch)) - return synthesize_bov_expression::process(*this,operation,branch); - else if (cob_optimizable(operation,branch)) - return synthesize_cob_expression::process(*this,operation,branch); - else if (boc_optimizable(operation,branch)) - return synthesize_boc_expression::process(*this,operation,branch); - #ifndef exprtk_disable_enhanced_features - else if (cov_optimizable(operation,branch)) - return synthesize_cov_expression::process(*this,operation,branch); - #endif - else if (binext_optimizable(operation,branch)) - return synthesize_binary_ext_expression::process(*this,operation,branch); - else - return synthesize_expression(operation,branch); + return error_node(); } - - inline expression_node_ptr operator()(const details::operator_type& operation, expression_node_ptr (&branch)[3]) + else if (!token_is(token_t::e_eof)) { - if ( - (0 == branch[0]) || - (0 == branch[1]) || - (0 == branch[2]) - ) + if (!token_is(token_t::e_assign)) { - details::free_all_nodes(*node_allocator_,branch); + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR149 - Expected ':=' as part of vector definition", + exprtk_error_location)); return error_node(); } - else if (is_invalid_string_op(operation,branch)) - return error_node(); - else if (is_string_operation(operation,branch)) - return synthesize_string_expression(operation,branch); - else - return synthesize_expression(operation,branch); - } - - inline expression_node_ptr operator()(const details::operator_type& operation, expression_node_ptr (&branch)[4]) - { - return synthesize_expression(operation,branch); - } + else if (token_is(token_t::e_lsqrbracket)) + { + expression_node_ptr initialiser = parse_expression(); - inline expression_node_ptr operator()(const details::operator_type& operation, expression_node_ptr (&branch)[5]) - { - return synthesize_expression(operation,branch); - } + if (0 == initialiser) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR150 - Failed to parse single vector initialiser", + exprtk_error_location)); - inline expression_node_ptr operator()(const details::operator_type& operation, expression_node_ptr (&branch)[6]) - { - return synthesize_expression(operation,branch); - } + return error_node(); + } - inline expression_node_ptr operator()(const details::operator_type& operation, expression_node_ptr b0) - { - expression_node_ptr branch[1] = { b0 }; - return (*this)(operation,branch); - } + vec_initilizer_list.push_back(initialiser); - 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 branch[2] = { b0, b1 }; - return expression_generator::operator()(operation,branch); - } - } + if (!token_is(token_t::e_rsqrbracket)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR151 - Expected ']' to close single value vector initialiser", + exprtk_error_location)); - inline expression_node_ptr conditional(expression_node_ptr condition, - expression_node_ptr consequent, - expression_node_ptr alternative) const - { - if ((0 == condition) || (0 == consequent)) - { - free_node(*node_allocator_,condition ); - free_node(*node_allocator_,consequent ); - free_node(*node_allocator_,alternative); + return error_node(); + } - return error_node(); + single_value_initialiser = true; } - // Can the condition be immediately evaluated? if so optimize. - else if (details::is_constant_node(condition)) + else if (!token_is(token_t::e_lcrlbracket)) { - // True branch - if (details::is_true(condition)) + expression_node_ptr initialiser = error_node(); + + // Is this a vector to vector assignment and initialisation? + if (token_t::e_symbol == current_token().type) { - free_node(*node_allocator_,condition ); - free_node(*node_allocator_,alternative); + // Is it a locally defined vector? + const scope_element& se = sem_.get_active_element(current_token().value); - return consequent; + if (scope_element::e_vector == se.type) + { + if (0 != (initialiser = parse_expression())) + vec_initilizer_list.push_back(initialiser); + else + return error_node(); + } + // 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); + + if (0 != (initialiser = parse_expression())) + vec_initilizer_list.push_back(initialiser); + else + return error_node(); + } + // Are we dealing with a null initialisation vector definition? + else if (token_is(token_t::e_symbol,"null")) + null_initialisation = true; } - // False branch - else + + if (!null_initialisation) { - free_node(*node_allocator_,condition); - free_node(*node_allocator_,consequent); + if (0 == initialiser) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR152 - Expected '{' as part of vector initialiser list", + exprtk_error_location)); - if (alternative) - return alternative; + return error_node(); + } else - return node_allocator_->allocate >(); + vec_to_vec_initialiser = true; } } - else if ((0 != consequent) && (0 != alternative)) + else if (!token_is(token_t::e_rcrlbracket)) { - return node_allocator_->allocate(condition,consequent,alternative); - } - else - return node_allocator_->allocate(condition,consequent); - } + for ( ; ; ) + { + expression_node_ptr initialiser = parse_expression(); - inline expression_node_ptr while_loop(expression_node_ptr& condition, - expression_node_ptr& branch, - const bool brkcont = false) const - { - if (!brkcont && details::is_constant_node(condition)) - { - expression_node_ptr result = error_node(); - if (details::is_true(condition)) - // Infinite loops are not allowed. - result = error_node(); - else - result = node_allocator_->allocate >(); + if (0 == initialiser) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR153 - Expected '{' as part of vector initialiser list", + exprtk_error_location)); - free_node(*node_allocator_, condition); - free_node(*node_allocator_, branch ); + return error_node(); + } + else + vec_initilizer_list.push_back(initialiser); - return result; - } - else if (details::is_null_node(condition)) - { - free_node(*node_allocator_,condition); + if (token_is(token_t::e_rcrlbracket)) + break; - return branch; + 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(), + "ERR154 - Expected ',' between vector initialisers", + exprtk_error_location)); + + return error_node(); + } + + if (token_is(token_t::e_rcrlbracket)) + break; + } } - else if (!brkcont) - return node_allocator_->allocate(condition,branch); - #ifndef exprtk_disable_break_continue - else - return node_allocator_->allocate(condition,branch); - #else - return error_node(); - #endif - } - inline expression_node_ptr repeat_until_loop(expression_node_ptr& condition, - expression_node_ptr& branch, - const bool brkcont = false) const - { - if (!brkcont && details::is_constant_node(condition)) + 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) + ) { - if (details::is_true(condition) && details::is_constant_node(branch)) + if (!token_is(token_t::e_eof)) { - free_node(*node_allocator_,condition); + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR155 - Expected ';' at end of vector definition", + exprtk_error_location)); - return branch; + return error_node(); } - - free_node(*node_allocator_, condition); - free_node(*node_allocator_, branch ); - - return error_node(); } - else if (details::is_null_node(condition)) + + if (vec_initilizer_list.size() > vector_size) { - free_node(*node_allocator_,condition); + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR156 - Initialiser list larger than the number of elements in the vector: '" + vec_name + "'", + exprtk_error_location)); - return branch; - } - else if (!brkcont) - return node_allocator_->allocate(condition,branch); - #ifndef exprtk_disable_break_continue - else - return node_allocator_->allocate(condition,branch); - #else return error_node(); - #endif + } } - inline expression_node_ptr for_loop(expression_node_ptr& initialiser, - expression_node_ptr& condition, - expression_node_ptr& incrementor, - expression_node_ptr& loop_body, - bool brkcont = false) const - { - if (!brkcont && details::is_constant_node(condition)) - { - expression_node_ptr result = error_node(); + typename symbol_table_t::vector_holder_ptr vec_holder = typename symbol_table_t::vector_holder_ptr(0); - if (details::is_true(condition)) - // Infinite loops are not allowed. - result = error_node(); - else - result = node_allocator_->allocate >(); + const std::size_t vec_size = static_cast(details::numeric::to_int32(vector_size)); - free_node(*node_allocator_,initialiser); - free_node(*node_allocator_,condition ); - free_node(*node_allocator_,incrementor); - free_node(*node_allocator_,loop_body ); + scope_element& se = sem_.get_element(vec_name); - return result; - } - else if (details::is_null_node(condition)) + if (se.name == vec_name) + { + if (se.active) { - free_node(*node_allocator_,initialiser); - free_node(*node_allocator_,condition ); - free_node(*node_allocator_,incrementor); + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR157 - Illegal redefinition of local vector: '" + vec_name + "'", + exprtk_error_location)); - return loop_body; + return error_node(); + } + else if ( + (se.size == vec_size) && + (scope_element::e_vector == se.type) + ) + { + vec_holder = se.vec_node; + se.active = true; + se.depth = state_.scope_depth; + se.ref_count++; } - else if (!brkcont) - return node_allocator_->allocate(initialiser, - condition, - incrementor, - loop_body); - #ifndef exprtk_disable_break_continue - else - return node_allocator_->allocate(initialiser, - condition, - incrementor, - loop_body); - #else - return error_node(); - #endif } - template class Sequence> - inline expression_node_ptr const_optimize_switch(Sequence& arg_list) + if (0 == vec_holder) { - expression_node_ptr result = error_node(); + scope_element nse; + nse.name = vec_name; + nse.active = true; + nse.ref_count = 1; + nse.type = scope_element::e_vector; + nse.depth = state_.scope_depth; + nse.size = vec_size; + nse.data = new T[vec_size]; + nse.vec_node = new typename scope_element::vector_holder_t(reinterpret_cast(nse.data),nse.size); - for (std::size_t i = 0; i < (arg_list.size() / 2); ++i) + if (!sem_.add_element(nse)) { - expression_node_ptr condition = arg_list[(2 * i) ]; - expression_node_ptr consequent = arg_list[(2 * i) + 1]; + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR158 - Failed to add new local vector '" + vec_name + "' to SEM", + exprtk_error_location)); - if ((0 == result) && details::is_true(condition)) - { - result = consequent; - break; - } - } + sem_.free_element(nse); - if (0 == result) - { - result = arg_list.back(); + return error_node(); } - for (std::size_t i = 0; i < arg_list.size(); ++i) - { - expression_node_ptr current_expr = arg_list[i]; - - if (current_expr && (current_expr != result)) - { - free_node(*node_allocator_,current_expr); - } - } + vec_holder = nse.vec_node; - return result; + exprtk_debug(("parse_define_vector_statement() - INFO - Added new local vector: %s[%d]\n", + nse.name.c_str(), + static_cast(nse.size))); } - template class Sequence> - inline expression_node_ptr const_optimize_mswitch(Sequence& arg_list) - { - expression_node_ptr result = error_node(); + state_.activate_side_effect("parse_define_vector_statement()"); - for (std::size_t i = 0; i < (arg_list.size() / 2); ++i) - { - expression_node_ptr condition = arg_list[(2 * i) ]; - expression_node_ptr consequent = arg_list[(2 * i) + 1]; + lodge_symbol(vec_name, e_st_local_vector); - if (details::is_true(condition)) - { - result = consequent; - } - } + expression_node_ptr result = error_node(); - if (0 == result) - { - T zero = T(0); - result = node_allocator_->allocate(zero); - } + 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); - for (std::size_t i = 0; i < arg_list.size(); ++i) - { - expression_node_ptr& current_expr = arg_list[i]; + result = expression_generator_( + details::e_assign, + vec_node, + vec_initilizer_list[0]); + } + else + result = node_allocator_ + .allocate >( + (*vec_holder)[0], + vec_size, + vec_initilizer_list, + single_value_initialiser); - if (current_expr && (current_expr != result)) - { - free_node(*node_allocator_,current_expr); - } - } + svd.delete_ptr = (0 == result); - return result; - } + return result; + } - template class Sequence> - inline expression_node_ptr switch_statement(Sequence& arg_list) + #ifndef exprtk_disable_string_capabilities + inline expression_node_ptr parse_define_string_statement(const std::string& str_name, expression_node_ptr initialisation_expression) + { + stringvar_node_t* str_node = reinterpret_cast(0); + + scope_element& se = sem_.get_element(str_name); + + if (se.name == str_name) { - if (!all_nodes_valid(arg_list)) + if (se.active) { - details::free_all_nodes(*node_allocator_,arg_list); + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR159 - Illegal redefinition of local variable: '" + str_name + "'", + exprtk_error_location)); + + free_node(node_allocator_,initialisation_expression); return error_node(); } - else if (is_constant_foldable(arg_list)) - return const_optimize_switch(arg_list); - else - return node_allocator_->allocate >(arg_list); + else if (scope_element::e_string == se.type) + { + str_node = se.str_node; + se.active = true; + se.depth = state_.scope_depth; + se.ref_count++; + } } - template class Sequence> - inline expression_node_ptr multi_switch_statement(Sequence& arg_list) + if (0 == str_node) { - if (!all_nodes_valid(arg_list)) + scope_element nse; + nse.name = str_name; + nse.active = true; + nse.ref_count = 1; + nse.type = scope_element::e_string; + nse.depth = state_.scope_depth; + nse.data = new std::string; + nse.str_node = new stringvar_node_t(*reinterpret_cast(nse.data)); + + if (!sem_.add_element(nse)) { - details::free_all_nodes(*node_allocator_,arg_list); + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR160 - Failed to add new local string variable '" + str_name + "' to SEM", + exprtk_error_location)); + + free_node(node_allocator_,initialisation_expression); + + sem_.free_element(nse); return error_node(); } - else if (is_constant_foldable(arg_list)) - return const_optimize_mswitch(arg_list); - else - return node_allocator_->allocate >(arg_list); + + str_node = nse.str_node; + + exprtk_debug(("parse_define_string_statement() - INFO - Added new local string variable: %s\n",nse.name.c_str())); } - #define unary_opr_switch_statements \ - case_stmt(details:: e_abs,details:: abs_op) \ - case_stmt(details:: e_acos,details:: acos_op) \ - case_stmt(details::e_acosh,details::acosh_op) \ - case_stmt(details:: e_asin,details:: asin_op) \ - case_stmt(details::e_asinh,details::asinh_op) \ - case_stmt(details:: e_atan,details:: atan_op) \ - case_stmt(details::e_atanh,details::atanh_op) \ - case_stmt(details:: e_ceil,details:: ceil_op) \ - case_stmt(details:: e_cos,details:: cos_op) \ - case_stmt(details:: e_cosh,details:: cosh_op) \ - case_stmt(details:: e_exp,details:: exp_op) \ - case_stmt(details::e_expm1,details::expm1_op) \ - case_stmt(details::e_floor,details::floor_op) \ - case_stmt(details:: e_log,details:: log_op) \ - case_stmt(details::e_log10,details::log10_op) \ - case_stmt(details:: e_log2,details:: log2_op) \ - case_stmt(details::e_log1p,details::log1p_op) \ - case_stmt(details:: e_neg,details:: neg_op) \ - case_stmt(details:: e_pos,details:: pos_op) \ - case_stmt(details::e_round,details::round_op) \ - case_stmt(details:: e_sin,details:: sin_op) \ - case_stmt(details:: e_sinc,details:: sinc_op) \ - case_stmt(details:: e_sinh,details:: sinh_op) \ - case_stmt(details:: e_sqrt,details:: sqrt_op) \ - case_stmt(details:: e_tan,details:: tan_op) \ - case_stmt(details:: e_tanh,details:: tanh_op) \ - case_stmt(details:: e_cot,details:: cot_op) \ - case_stmt(details:: e_sec,details:: sec_op) \ - case_stmt(details:: e_csc,details:: csc_op) \ - case_stmt(details:: e_r2d,details:: r2d_op) \ - case_stmt(details:: e_d2r,details:: d2r_op) \ - case_stmt(details:: e_d2g,details:: d2g_op) \ - case_stmt(details:: e_g2d,details:: g2d_op) \ - case_stmt(details:: e_notl,details:: notl_op) \ - case_stmt(details:: e_sgn,details:: sgn_op) \ - case_stmt(details:: e_erf,details:: erf_op) \ - case_stmt(details:: e_erfc,details:: erfc_op) \ - case_stmt(details:: e_ncdf,details:: ncdf_op) \ - case_stmt(details:: e_frac,details:: frac_op) \ - case_stmt(details::e_trunc,details::trunc_op) \ + lodge_symbol(str_name, e_st_local_string); - inline expression_node_ptr synthesize_uv_expression(const details::operator_type& operation, - expression_node_ptr (&branch)[1]) - { - T& v = static_cast*>(branch[0])->ref(); + state_.activate_side_effect("parse_define_string_statement()"); - switch (operation) - { - #define case_stmt(op0,op1) \ - case op0 : return node_allocator_-> \ - allocate > >(v); \ + expression_node_ptr branch[2] = {0}; - unary_opr_switch_statements - #undef case_stmt - default : return error_node(); - } - } + branch[0] = str_node; + branch[1] = initialisation_expression; - inline expression_node_ptr synthesize_uvec_expression(const details::operator_type& operation, - expression_node_ptr (&branch)[1]) - { - switch (operation) - { - #define case_stmt(op0,op1) \ - case op0 : return node_allocator_-> \ - allocate > > \ - (operation,branch[0]); \ + return expression_generator_(details::e_assign,branch); + } + #else + inline expression_node_ptr parse_define_string_statement(const std::string&, expression_node_ptr) + { + return error_node(); + } + #endif - unary_opr_switch_statements - #undef case_stmt - default : return error_node(); - } - } + inline bool local_variable_is_shadowed(const std::string& symbol) + { + const scope_element& se = sem_.get_element(symbol); + return (se.name == symbol) && se.active; + } - inline expression_node_ptr synthesize_unary_expression(const details::operator_type& operation, - expression_node_ptr (&branch)[1]) + inline expression_node_ptr parse_define_var_statement() + { + if (settings_.vardef_disabled()) { - switch (operation) - { - #define case_stmt(op0,op1) \ - case op0 : return node_allocator_-> \ - allocate > >(branch[0]); \ + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR161 - Illegal variable definition", + exprtk_error_location)); - unary_opr_switch_statements - #undef case_stmt - default : return error_node(); - } + return error_node(); } - - inline expression_node_ptr const_optimize_sf3(const details::operator_type& operation, - expression_node_ptr (&branch)[3]) + else if (!details::imatch(current_token().value,"var")) { - expression_node_ptr temp_node = error_node(); + return error_node(); + } + else + next_token(); - switch (operation) - { - #define case_stmt(op0,op1) \ - case op0 : temp_node = node_allocator_-> \ - allocate > > \ - (operation,branch); \ - break; \ - - case_stmt(details::e_sf00,details::sf00_op) case_stmt(details::e_sf01,details::sf01_op) - case_stmt(details::e_sf02,details::sf02_op) case_stmt(details::e_sf03,details::sf03_op) - case_stmt(details::e_sf04,details::sf04_op) case_stmt(details::e_sf05,details::sf05_op) - case_stmt(details::e_sf06,details::sf06_op) case_stmt(details::e_sf07,details::sf07_op) - case_stmt(details::e_sf08,details::sf08_op) case_stmt(details::e_sf09,details::sf09_op) - case_stmt(details::e_sf10,details::sf10_op) case_stmt(details::e_sf11,details::sf11_op) - case_stmt(details::e_sf12,details::sf12_op) case_stmt(details::e_sf13,details::sf13_op) - case_stmt(details::e_sf14,details::sf14_op) case_stmt(details::e_sf15,details::sf15_op) - case_stmt(details::e_sf16,details::sf16_op) case_stmt(details::e_sf17,details::sf17_op) - case_stmt(details::e_sf18,details::sf18_op) case_stmt(details::e_sf19,details::sf19_op) - case_stmt(details::e_sf20,details::sf20_op) case_stmt(details::e_sf21,details::sf21_op) - case_stmt(details::e_sf22,details::sf22_op) case_stmt(details::e_sf23,details::sf23_op) - case_stmt(details::e_sf24,details::sf24_op) case_stmt(details::e_sf25,details::sf25_op) - case_stmt(details::e_sf26,details::sf26_op) case_stmt(details::e_sf27,details::sf27_op) - case_stmt(details::e_sf28,details::sf28_op) case_stmt(details::e_sf29,details::sf29_op) - case_stmt(details::e_sf30,details::sf30_op) case_stmt(details::e_sf31,details::sf31_op) - case_stmt(details::e_sf32,details::sf32_op) case_stmt(details::e_sf33,details::sf33_op) - case_stmt(details::e_sf34,details::sf34_op) case_stmt(details::e_sf35,details::sf35_op) - case_stmt(details::e_sf36,details::sf36_op) case_stmt(details::e_sf37,details::sf37_op) - case_stmt(details::e_sf38,details::sf38_op) case_stmt(details::e_sf39,details::sf39_op) - case_stmt(details::e_sf40,details::sf40_op) case_stmt(details::e_sf41,details::sf41_op) - case_stmt(details::e_sf42,details::sf42_op) case_stmt(details::e_sf43,details::sf43_op) - case_stmt(details::e_sf44,details::sf44_op) case_stmt(details::e_sf45,details::sf45_op) - case_stmt(details::e_sf46,details::sf46_op) case_stmt(details::e_sf47,details::sf47_op) - #undef case_stmt - default : return error_node(); - } + const std::string var_name = current_token().value; - T v = temp_node->value(); - node_allocator_->free(temp_node); - details::free_node(*node_allocator_,temp_node); + expression_node_ptr initialisation_expression = error_node(); - return node_allocator_->allocate(v); + if (!token_is(token_t::e_symbol)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR162 - Expected a symbol for variable definition", + exprtk_error_location)); + + return error_node(); } + else if (details::is_reserved_symbol(var_name)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR163 - Illegal redefinition of reserved keyword: '" + var_name + "'", + exprtk_error_location)); - inline expression_node_ptr varnode_optimize_sf3(const details::operator_type& operation, expression_node_ptr (&branch)[3]) + return error_node(); + } + else if (symtab_store_.symbol_exists(var_name)) { - typedef details::variable_node* variable_ptr; + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR164 - Illegal redefinition of variable '" + var_name + "'", + exprtk_error_location)); - const Type& v0 = static_cast(branch[0])->ref(); - const Type& v1 = static_cast(branch[1])->ref(); - const Type& v2 = static_cast(branch[2])->ref(); + return error_node(); + } + else if (local_variable_is_shadowed(var_name)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR165 - Illegal redefinition of local variable: '" + var_name + "'", + exprtk_error_location)); - switch (operation) + return error_node(); + } + else if (token_is(token_t::e_lsqrbracket,prsrhlpr_t::e_hold)) + { + return parse_define_vector_statement(var_name); + } + else if (token_is(token_t::e_lcrlbracket,prsrhlpr_t::e_hold)) + { + return parse_uninitialised_var_statement(var_name); + } + else if (token_is(token_t::e_assign)) + { + if (0 == (initialisation_expression = parse_expression())) { - #define case_stmt(op0,op1) \ - case op0 : return node_allocator_-> \ - allocate_rrr > > \ - (v0,v1,v2); \ - - case_stmt(details::e_sf00,details::sf00_op) case_stmt(details::e_sf01,details::sf01_op) - case_stmt(details::e_sf02,details::sf02_op) case_stmt(details::e_sf03,details::sf03_op) - case_stmt(details::e_sf04,details::sf04_op) case_stmt(details::e_sf05,details::sf05_op) - case_stmt(details::e_sf06,details::sf06_op) case_stmt(details::e_sf07,details::sf07_op) - case_stmt(details::e_sf08,details::sf08_op) case_stmt(details::e_sf09,details::sf09_op) - case_stmt(details::e_sf10,details::sf10_op) case_stmt(details::e_sf11,details::sf11_op) - case_stmt(details::e_sf12,details::sf12_op) case_stmt(details::e_sf13,details::sf13_op) - case_stmt(details::e_sf14,details::sf14_op) case_stmt(details::e_sf15,details::sf15_op) - case_stmt(details::e_sf16,details::sf16_op) case_stmt(details::e_sf17,details::sf17_op) - case_stmt(details::e_sf18,details::sf18_op) case_stmt(details::e_sf19,details::sf19_op) - case_stmt(details::e_sf20,details::sf20_op) case_stmt(details::e_sf21,details::sf21_op) - case_stmt(details::e_sf22,details::sf22_op) case_stmt(details::e_sf23,details::sf23_op) - case_stmt(details::e_sf24,details::sf24_op) case_stmt(details::e_sf25,details::sf25_op) - case_stmt(details::e_sf26,details::sf26_op) case_stmt(details::e_sf27,details::sf27_op) - case_stmt(details::e_sf28,details::sf28_op) case_stmt(details::e_sf29,details::sf29_op) - case_stmt(details::e_sf30,details::sf30_op) case_stmt(details::e_sf31,details::sf31_op) - case_stmt(details::e_sf32,details::sf32_op) case_stmt(details::e_sf33,details::sf33_op) - case_stmt(details::e_sf34,details::sf34_op) case_stmt(details::e_sf35,details::sf35_op) - case_stmt(details::e_sf36,details::sf36_op) case_stmt(details::e_sf37,details::sf37_op) - case_stmt(details::e_sf38,details::sf38_op) case_stmt(details::e_sf39,details::sf39_op) - case_stmt(details::e_sf40,details::sf40_op) case_stmt(details::e_sf41,details::sf41_op) - case_stmt(details::e_sf42,details::sf42_op) case_stmt(details::e_sf43,details::sf43_op) - case_stmt(details::e_sf44,details::sf44_op) case_stmt(details::e_sf45,details::sf45_op) - case_stmt(details::e_sf46,details::sf46_op) case_stmt(details::e_sf47,details::sf47_op) - #undef case_stmt - default : return error_node(); + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR166 - Failed to parse initialisation expression", + exprtk_error_location)); + + return error_node(); } } - inline expression_node_ptr special_function(const details::operator_type& operation, expression_node_ptr (&branch)[3]) + 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) + ) { - if (!all_nodes_valid(branch)) - return error_node(); - else if (is_constant_foldable(branch)) - return const_optimize_sf3(operation,branch); - else if (all_nodes_variables(branch)) - return varnode_optimize_sf3(operation,branch); - else + if (!token_is(token_t::e_eof,prsrhlpr_t::e_hold)) { - switch (operation) - { - #define case_stmt(op0,op1) \ - case op0 : return node_allocator_-> \ - allocate > >(operation,branch); \ - - case_stmt(details::e_sf00,details::sf00_op) case_stmt(details::e_sf01,details::sf01_op) - case_stmt(details::e_sf02,details::sf02_op) case_stmt(details::e_sf03,details::sf03_op) - case_stmt(details::e_sf04,details::sf04_op) case_stmt(details::e_sf05,details::sf05_op) - case_stmt(details::e_sf06,details::sf06_op) case_stmt(details::e_sf07,details::sf07_op) - case_stmt(details::e_sf08,details::sf08_op) case_stmt(details::e_sf09,details::sf09_op) - case_stmt(details::e_sf10,details::sf10_op) case_stmt(details::e_sf11,details::sf11_op) - case_stmt(details::e_sf12,details::sf12_op) case_stmt(details::e_sf13,details::sf13_op) - case_stmt(details::e_sf14,details::sf14_op) case_stmt(details::e_sf15,details::sf15_op) - case_stmt(details::e_sf16,details::sf16_op) case_stmt(details::e_sf17,details::sf17_op) - case_stmt(details::e_sf18,details::sf18_op) case_stmt(details::e_sf19,details::sf19_op) - case_stmt(details::e_sf20,details::sf20_op) case_stmt(details::e_sf21,details::sf21_op) - case_stmt(details::e_sf22,details::sf22_op) case_stmt(details::e_sf23,details::sf23_op) - case_stmt(details::e_sf24,details::sf24_op) case_stmt(details::e_sf25,details::sf25_op) - case_stmt(details::e_sf26,details::sf26_op) case_stmt(details::e_sf27,details::sf27_op) - case_stmt(details::e_sf28,details::sf28_op) case_stmt(details::e_sf29,details::sf29_op) - case_stmt(details::e_sf30,details::sf30_op) case_stmt(details::e_sf31,details::sf31_op) - case_stmt(details::e_sf32,details::sf32_op) case_stmt(details::e_sf33,details::sf33_op) - case_stmt(details::e_sf34,details::sf34_op) case_stmt(details::e_sf35,details::sf35_op) - case_stmt(details::e_sf36,details::sf36_op) case_stmt(details::e_sf37,details::sf37_op) - case_stmt(details::e_sf38,details::sf38_op) case_stmt(details::e_sf39,details::sf39_op) - case_stmt(details::e_sf40,details::sf40_op) case_stmt(details::e_sf41,details::sf41_op) - case_stmt(details::e_sf42,details::sf42_op) case_stmt(details::e_sf43,details::sf43_op) - case_stmt(details::e_sf44,details::sf44_op) case_stmt(details::e_sf45,details::sf45_op) - case_stmt(details::e_sf46,details::sf46_op) case_stmt(details::e_sf47,details::sf47_op) - #undef case_stmt - default : return error_node(); - } + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR167 - Expected ';' after variable definition", + exprtk_error_location)); + + free_node(node_allocator_,initialisation_expression); + + return error_node(); } } - inline expression_node_ptr const_optimize_sf4(const details::operator_type& operation, expression_node_ptr (&branch)[4]) + if ( + (0 != initialisation_expression) && + details::is_generally_string_node(initialisation_expression) + ) { - expression_node_ptr temp_node = error_node(); + return parse_define_string_statement(var_name,initialisation_expression); + } - switch (operation) - { - #define case_stmt(op0,op1) \ - case op0 : temp_node = node_allocator_-> \ - allocate > >(operation,branch); \ - break; \ - - case_stmt(details::e_sf48,details::sf48_op) case_stmt(details::e_sf49,details::sf49_op) - case_stmt(details::e_sf50,details::sf50_op) case_stmt(details::e_sf51,details::sf51_op) - case_stmt(details::e_sf52,details::sf52_op) case_stmt(details::e_sf53,details::sf53_op) - case_stmt(details::e_sf54,details::sf54_op) case_stmt(details::e_sf55,details::sf55_op) - case_stmt(details::e_sf56,details::sf56_op) case_stmt(details::e_sf57,details::sf57_op) - case_stmt(details::e_sf58,details::sf58_op) case_stmt(details::e_sf59,details::sf59_op) - case_stmt(details::e_sf60,details::sf60_op) case_stmt(details::e_sf61,details::sf61_op) - case_stmt(details::e_sf62,details::sf62_op) case_stmt(details::e_sf63,details::sf63_op) - case_stmt(details::e_sf64,details::sf64_op) case_stmt(details::e_sf65,details::sf65_op) - case_stmt(details::e_sf66,details::sf66_op) case_stmt(details::e_sf67,details::sf67_op) - case_stmt(details::e_sf68,details::sf68_op) case_stmt(details::e_sf69,details::sf69_op) - case_stmt(details::e_sf70,details::sf70_op) case_stmt(details::e_sf71,details::sf71_op) - case_stmt(details::e_sf72,details::sf72_op) case_stmt(details::e_sf73,details::sf73_op) - case_stmt(details::e_sf74,details::sf74_op) case_stmt(details::e_sf75,details::sf75_op) - case_stmt(details::e_sf76,details::sf76_op) case_stmt(details::e_sf77,details::sf77_op) - case_stmt(details::e_sf78,details::sf78_op) case_stmt(details::e_sf79,details::sf79_op) - case_stmt(details::e_sf80,details::sf80_op) case_stmt(details::e_sf81,details::sf81_op) - case_stmt(details::e_sf82,details::sf82_op) case_stmt(details::e_sf83,details::sf83_op) - case_stmt(details::e_sf84,details::sf84_op) case_stmt(details::e_sf85,details::sf85_op) - case_stmt(details::e_sf86,details::sf86_op) case_stmt(details::e_sf87,details::sf87_op) - case_stmt(details::e_sf88,details::sf88_op) case_stmt(details::e_sf89,details::sf89_op) - case_stmt(details::e_sf90,details::sf90_op) case_stmt(details::e_sf91,details::sf91_op) - case_stmt(details::e_sf92,details::sf92_op) case_stmt(details::e_sf93,details::sf93_op) - case_stmt(details::e_sf94,details::sf94_op) case_stmt(details::e_sf95,details::sf95_op) - case_stmt(details::e_sf96,details::sf96_op) case_stmt(details::e_sf97,details::sf97_op) - case_stmt(details::e_sf98,details::sf98_op) case_stmt(details::e_sf99,details::sf99_op) - #undef case_stmt - default : return error_node(); - } - - T v = temp_node->value(); - details::free_node(*node_allocator_,temp_node); + expression_node_ptr var_node = reinterpret_cast(0); - return node_allocator_->allocate(v); - } + scope_element& se = sem_.get_element(var_name); - inline expression_node_ptr varnode_optimize_sf4(const details::operator_type& operation, expression_node_ptr (&branch)[4]) + if (se.name == var_name) { - typedef details::variable_node* variable_ptr; - - const Type& v0 = static_cast(branch[0])->ref(); - const Type& v1 = static_cast(branch[1])->ref(); - const Type& v2 = static_cast(branch[2])->ref(); - const Type& v3 = static_cast(branch[3])->ref(); - - switch (operation) + if (se.active) { - #define case_stmt(op0,op1) \ - case op0 : return node_allocator_-> \ - allocate_rrrr > >(v0,v1,v2,v3); \ - - case_stmt(details::e_sf48,details::sf48_op) case_stmt(details::e_sf49,details::sf49_op) - case_stmt(details::e_sf50,details::sf50_op) case_stmt(details::e_sf51,details::sf51_op) - case_stmt(details::e_sf52,details::sf52_op) case_stmt(details::e_sf53,details::sf53_op) - case_stmt(details::e_sf54,details::sf54_op) case_stmt(details::e_sf55,details::sf55_op) - case_stmt(details::e_sf56,details::sf56_op) case_stmt(details::e_sf57,details::sf57_op) - case_stmt(details::e_sf58,details::sf58_op) case_stmt(details::e_sf59,details::sf59_op) - case_stmt(details::e_sf60,details::sf60_op) case_stmt(details::e_sf61,details::sf61_op) - case_stmt(details::e_sf62,details::sf62_op) case_stmt(details::e_sf63,details::sf63_op) - case_stmt(details::e_sf64,details::sf64_op) case_stmt(details::e_sf65,details::sf65_op) - case_stmt(details::e_sf66,details::sf66_op) case_stmt(details::e_sf67,details::sf67_op) - case_stmt(details::e_sf68,details::sf68_op) case_stmt(details::e_sf69,details::sf69_op) - case_stmt(details::e_sf70,details::sf70_op) case_stmt(details::e_sf71,details::sf71_op) - case_stmt(details::e_sf72,details::sf72_op) case_stmt(details::e_sf73,details::sf73_op) - case_stmt(details::e_sf74,details::sf74_op) case_stmt(details::e_sf75,details::sf75_op) - case_stmt(details::e_sf76,details::sf76_op) case_stmt(details::e_sf77,details::sf77_op) - case_stmt(details::e_sf78,details::sf78_op) case_stmt(details::e_sf79,details::sf79_op) - case_stmt(details::e_sf80,details::sf80_op) case_stmt(details::e_sf81,details::sf81_op) - case_stmt(details::e_sf82,details::sf82_op) case_stmt(details::e_sf83,details::sf83_op) - case_stmt(details::e_sf84,details::sf84_op) case_stmt(details::e_sf85,details::sf85_op) - case_stmt(details::e_sf86,details::sf86_op) case_stmt(details::e_sf87,details::sf87_op) - case_stmt(details::e_sf88,details::sf88_op) case_stmt(details::e_sf89,details::sf89_op) - case_stmt(details::e_sf90,details::sf90_op) case_stmt(details::e_sf91,details::sf91_op) - case_stmt(details::e_sf92,details::sf92_op) case_stmt(details::e_sf93,details::sf93_op) - case_stmt(details::e_sf94,details::sf94_op) case_stmt(details::e_sf95,details::sf95_op) - case_stmt(details::e_sf96,details::sf96_op) case_stmt(details::e_sf97,details::sf97_op) - case_stmt(details::e_sf98,details::sf98_op) case_stmt(details::e_sf99,details::sf99_op) - #undef case_stmt - default : return error_node(); - } - } + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR168 - Illegal redefinition of local variable: '" + var_name + "'", + exprtk_error_location)); + + free_node(node_allocator_, initialisation_expression); - inline expression_node_ptr special_function(const details::operator_type& operation, expression_node_ptr (&branch)[4]) - { - if (!all_nodes_valid(branch)) return error_node(); - else if (is_constant_foldable(branch)) - return const_optimize_sf4(operation,branch); - else if (all_nodes_variables(branch)) - return varnode_optimize_sf4(operation,branch); - switch (operation) + } + else if (scope_element::e_variable == se.type) { - #define case_stmt(op0,op1) \ - case op0 : return node_allocator_-> \ - allocate > >(operation,branch); \ - - case_stmt(details::e_sf48,details::sf48_op) case_stmt(details::e_sf49,details::sf49_op) - case_stmt(details::e_sf50,details::sf50_op) case_stmt(details::e_sf51,details::sf51_op) - case_stmt(details::e_sf52,details::sf52_op) case_stmt(details::e_sf53,details::sf53_op) - case_stmt(details::e_sf54,details::sf54_op) case_stmt(details::e_sf55,details::sf55_op) - case_stmt(details::e_sf56,details::sf56_op) case_stmt(details::e_sf57,details::sf57_op) - case_stmt(details::e_sf58,details::sf58_op) case_stmt(details::e_sf59,details::sf59_op) - case_stmt(details::e_sf60,details::sf60_op) case_stmt(details::e_sf61,details::sf61_op) - case_stmt(details::e_sf62,details::sf62_op) case_stmt(details::e_sf63,details::sf63_op) - case_stmt(details::e_sf64,details::sf64_op) case_stmt(details::e_sf65,details::sf65_op) - case_stmt(details::e_sf66,details::sf66_op) case_stmt(details::e_sf67,details::sf67_op) - case_stmt(details::e_sf68,details::sf68_op) case_stmt(details::e_sf69,details::sf69_op) - case_stmt(details::e_sf70,details::sf70_op) case_stmt(details::e_sf71,details::sf71_op) - case_stmt(details::e_sf72,details::sf72_op) case_stmt(details::e_sf73,details::sf73_op) - case_stmt(details::e_sf74,details::sf74_op) case_stmt(details::e_sf75,details::sf75_op) - case_stmt(details::e_sf76,details::sf76_op) case_stmt(details::e_sf77,details::sf77_op) - case_stmt(details::e_sf78,details::sf78_op) case_stmt(details::e_sf79,details::sf79_op) - case_stmt(details::e_sf80,details::sf80_op) case_stmt(details::e_sf81,details::sf81_op) - case_stmt(details::e_sf82,details::sf82_op) case_stmt(details::e_sf83,details::sf83_op) - case_stmt(details::e_sf84,details::sf84_op) case_stmt(details::e_sf85,details::sf85_op) - case_stmt(details::e_sf86,details::sf86_op) case_stmt(details::e_sf87,details::sf87_op) - case_stmt(details::e_sf88,details::sf88_op) case_stmt(details::e_sf89,details::sf89_op) - case_stmt(details::e_sf90,details::sf90_op) case_stmt(details::e_sf91,details::sf91_op) - case_stmt(details::e_sf92,details::sf92_op) case_stmt(details::e_sf93,details::sf93_op) - case_stmt(details::e_sf94,details::sf94_op) case_stmt(details::e_sf95,details::sf95_op) - case_stmt(details::e_sf96,details::sf96_op) case_stmt(details::e_sf97,details::sf97_op) - case_stmt(details::e_sf98,details::sf98_op) case_stmt(details::e_sf99,details::sf99_op) - #undef case_stmt - default : return error_node(); + var_node = se.var_node; + se.active = true; + se.depth = state_.scope_depth; + se.ref_count++; } } - template class Sequence> - inline expression_node_ptr const_optimize_varargfunc(const details::operator_type& operation, Sequence& arg_list) + if (0 == var_node) { - expression_node_ptr temp_node = error_node(); + scope_element nse; + nse.name = var_name; + nse.active = true; + nse.ref_count = 1; + nse.type = scope_element::e_variable; + nse.depth = state_.scope_depth; + nse.data = new T(T(0)); + nse.var_node = node_allocator_.allocate(*reinterpret_cast(nse.data)); - switch (operation) + if (!sem_.add_element(nse)) { - #define case_stmt(op0,op1) \ - case op0 : temp_node = node_allocator_-> \ - allocate > > \ - (arg_list); \ - break; \ + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR169 - Failed to add new local variable '" + var_name + "' to SEM", + exprtk_error_location)); - case_stmt(details::e_sum, details::vararg_add_op ) - case_stmt(details::e_prod, details::vararg_mul_op ) - case_stmt(details::e_avg, details::vararg_avg_op ) - case_stmt(details::e_min, details::vararg_min_op ) - case_stmt(details::e_max, details::vararg_max_op ) - case_stmt(details::e_mand, details::vararg_mand_op ) - case_stmt(details::e_mor, details::vararg_mor_op ) - case_stmt(details::e_multi,details::vararg_multi_op) - #undef case_stmt - default : return error_node(); + free_node(node_allocator_, initialisation_expression); + + sem_.free_element(nse); + + return error_node(); } - T v = temp_node->value(); - details::free_node(*node_allocator_,temp_node); + var_node = nse.var_node; - return node_allocator_->allocate(v); + exprtk_debug(("parse_define_var_statement() - INFO - Added new local variable: %s\n",nse.name.c_str())); } - inline bool special_one_parameter_vararg(const details::operator_type& operation) - { - return ( - (details::e_sum == operation) || - (details::e_prod == operation) || - (details::e_avg == operation) || - (details::e_min == operation) || - (details::e_max == operation) - ); - } + state_.activate_side_effect("parse_define_var_statement()"); - template class Sequence> - inline expression_node_ptr varnode_optimize_varargfunc(const details::operator_type& operation, Sequence& arg_list) + lodge_symbol(var_name, e_st_local_variable); + + expression_node_ptr branch[2] = {0}; + + branch[0] = var_node; + branch[1] = initialisation_expression ? initialisation_expression : expression_generator_(T(0)); + + return expression_generator_(details::e_assign,branch); + } + + inline expression_node_ptr parse_uninitialised_var_statement(const std::string& var_name) + { + if ( + !token_is(token_t::e_lcrlbracket) || + !token_is(token_t::e_rcrlbracket) + ) { - switch (operation) - { - #define case_stmt(op0,op1) \ - case op0 : return node_allocator_-> \ - allocate > >(arg_list); \ + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR170 - Expected a '{}' for uninitialised var definition", + exprtk_error_location)); - case_stmt(details::e_sum, details::vararg_add_op ) - case_stmt(details::e_prod, details::vararg_mul_op ) - case_stmt(details::e_avg, details::vararg_avg_op ) - case_stmt(details::e_min, details::vararg_min_op ) - case_stmt(details::e_max, details::vararg_max_op ) - case_stmt(details::e_mand, details::vararg_mand_op ) - case_stmt(details::e_mor, details::vararg_mor_op ) - case_stmt(details::e_multi,details::vararg_multi_op) - #undef case_stmt - default : return error_node(); - } + return error_node(); } - - template class Sequence> - inline expression_node_ptr vectorize_func(const details::operator_type& operation, Sequence& arg_list) + else if (!token_is(token_t::e_eof,prsrhlpr_t::e_hold)) { - if (1 == arg_list.size()) - { - switch (operation) - { - #define case_stmt(op0,op1) \ - case op0 : return node_allocator_-> \ - allocate > >(arg_list[0]); \ + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR171 - Expected ';' after uninitialised variable definition", + exprtk_error_location)); - case_stmt(details::e_sum, details::vec_add_op) - case_stmt(details::e_prod, details::vec_mul_op) - case_stmt(details::e_avg, details::vec_avg_op) - case_stmt(details::e_min, details::vec_min_op) - case_stmt(details::e_max, details::vec_max_op) - #undef case_stmt - default : return error_node(); - } - } - else - return error_node(); + return error_node(); } - template class Sequence> - inline expression_node_ptr vararg_function(const details::operator_type& operation, Sequence& arg_list) + expression_node_ptr var_node = reinterpret_cast(0); + + scope_element& se = sem_.get_element(var_name); + + if (se.name == var_name) { - if (!all_nodes_valid(arg_list)) + if (se.active) { - details::free_all_nodes(*node_allocator_,arg_list); + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR172 - Illegal redefinition of local variable: '" + var_name + "'", + exprtk_error_location)); return error_node(); } - else if (is_constant_foldable(arg_list)) - return const_optimize_varargfunc(operation,arg_list); - else if ((arg_list.size() == 1) && details::is_ivector_node(arg_list[0])) - return vectorize_func(operation,arg_list); - else if ((arg_list.size() == 1) && special_one_parameter_vararg(operation)) - return arg_list[0]; - else if (all_nodes_variables(arg_list)) - return varnode_optimize_varargfunc(operation,arg_list); - - switch (operation) + else if (scope_element::e_variable == se.type) { - #define case_stmt(op0,op1) \ - case op0 : return node_allocator_-> \ - allocate > >(arg_list); \ - - case_stmt(details::e_sum, details::vararg_add_op ) - case_stmt(details::e_prod, details::vararg_mul_op ) - case_stmt(details::e_avg, details::vararg_avg_op ) - case_stmt(details::e_min, details::vararg_min_op ) - case_stmt(details::e_max, details::vararg_max_op ) - case_stmt(details::e_mand, details::vararg_mand_op ) - case_stmt(details::e_mor, details::vararg_mor_op ) - case_stmt(details::e_multi,details::vararg_multi_op) - #undef case_stmt - default : return error_node(); + var_node = se.var_node; + se.active = true; + se.ref_count++; } } - template - inline expression_node_ptr function(ifunction_t* f, expression_node_ptr (&b)[N]) + if (0 == var_node) { - typedef typename details::function_N_node function_N_node_t; - expression_node_ptr result = synthesize_expression(f,b); + scope_element nse; + nse.name = var_name; + nse.active = true; + nse.ref_count = 1; + nse.type = scope_element::e_variable; + nse.depth = state_.scope_depth; + nse.ip_index = sem_.next_ip_index(); + nse.data = new T(T(0)); + nse.var_node = node_allocator_.allocate(*reinterpret_cast(nse.data)); - if (0 == result) - return error_node(); - else + if (!sem_.add_element(nse)) { - // Can the function call be completely optimized? - if (details::is_constant_node(result)) - return result; - else if (!all_nodes_valid(b)) - return error_node(); - else if (N != f->param_count) - { - details::free_all_nodes(*node_allocator_,b); + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR173 - Failed to add new local variable '" + var_name + "' to SEM", + exprtk_error_location)); - return error_node(); - } + sem_.free_element(nse); - function_N_node_t* func_node_ptr = static_cast(result); + return error_node(); + } - if (func_node_ptr->init_branches(b)) - return result; - else - { - details::free_all_nodes(*node_allocator_,b); + exprtk_debug(("parse_uninitialised_var_statement() - INFO - Added new local variable: %s\n", + nse.name.c_str())); + } - return error_node(); - } - } + lodge_symbol(var_name, e_st_local_variable); + + state_.activate_side_effect("parse_uninitialised_var_statement()"); + + return expression_generator_(T(0)); + } + + inline expression_node_ptr parse_swap_statement() + { + if (!details::imatch(current_token().value,"swap")) + { + return error_node(); } + else + next_token(); - inline expression_node_ptr function(ifunction_t* f) + if (!token_is(token_t::e_lbracket)) { - typedef typename details::function_N_node function_N_node_t; - return node_allocator_->allocate(f); + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR174 - Expected '(' at start of swap statement", + exprtk_error_location)); + + return error_node(); } - inline expression_node_ptr vararg_function_call(ivararg_function_t* vaf, - std::vector& arg_list) + expression_node_ptr variable0 = error_node(); + expression_node_ptr variable1 = error_node(); + + bool variable0_generated = false; + bool variable1_generated = false; + + const std::string var0_name = current_token().value; + + if (!token_is(token_t::e_symbol,prsrhlpr_t::e_hold)) { - if (!all_nodes_valid(arg_list)) + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR175 - Expected a symbol for variable or vector element definition", + exprtk_error_location)); + + return error_node(); + } + else if (peek_token_is(token_t::e_lsqrbracket)) + { + if (0 == (variable0 = parse_vector())) { - details::free_all_nodes(*node_allocator_,arg_list); + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR176 - First parameter to swap is an invalid vector element: '" + var0_name + "'", + exprtk_error_location)); return error_node(); } - typedef details::vararg_function_node alloc_type; + variable0_generated = true; + } + else + { + if (symtab_store_.is_variable(var0_name)) + { + variable0 = symtab_store_.get_variable(var0_name); + } - expression_node_ptr result = node_allocator_->allocate(vaf,arg_list); + const scope_element& se = sem_.get_element(var0_name); if ( - !arg_list.empty() && - !vaf->has_side_effects && - is_constant_foldable(arg_list) + (se.active) && + (se.name == var0_name) && + (scope_element::e_variable == se.type) ) { - Type v = result->value(); - details::free_node(*node_allocator_,result); - result = node_allocator_->allocate(v); + variable0 = se.var_node; } - return result; - } + lodge_symbol(var0_name, e_st_variable); - inline expression_node_ptr generic_function_call(igeneric_function_t* gf, - std::vector& arg_list, - const std::size_t& param_seq_index = std::numeric_limits::max()) - { - if (!all_nodes_valid(arg_list)) + if (0 == variable0) { - details::free_all_nodes(*node_allocator_,arg_list); + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR177 - First parameter to swap is an invalid variable: '" + var0_name + "'", + exprtk_error_location)); + return error_node(); } + else + next_token(); + } - typedef details::generic_function_node alloc_type1; - typedef details::multimode_genfunction_node alloc_type2; - - const std::size_t no_psi = std::numeric_limits::max(); - - expression_node_ptr result = error_node(); - - if (no_psi == param_seq_index) - result = node_allocator_->allocate(gf,arg_list); - else - result = node_allocator_->allocate(gf,param_seq_index,arg_list); - - alloc_type1* genfunc_node_ptr = static_cast(result); + if (!token_is(token_t::e_comma)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR178 - Expected ',' between parameters to swap", + exprtk_error_location)); - if ( - !arg_list.empty() && - !gf->has_side_effects && - is_constant_foldable(arg_list) - ) - { - genfunc_node_ptr->init_branches(); - Type v = result->value(); - details::free_node(*node_allocator_,result); - return node_allocator_->allocate(v); - } - else if (genfunc_node_ptr->init_branches()) - return result; - else + if (variable0_generated) { - details::free_node(*node_allocator_,result); - details::free_all_nodes(*node_allocator_,arg_list); - return error_node(); + free_node(node_allocator_,variable0); } + + return error_node(); } - inline expression_node_ptr string_function_call(igeneric_function_t* gf, - std::vector& arg_list, - const std::size_t& param_seq_index = std::numeric_limits::max()) + const std::string var1_name = current_token().value; + + if (!token_is(token_t::e_symbol,prsrhlpr_t::e_hold)) { - if (!all_nodes_valid(arg_list)) + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR179 - Expected a symbol for variable or vector element definition", + exprtk_error_location)); + + if (variable0_generated) { - details::free_all_nodes(*node_allocator_,arg_list); - return error_node(); + free_node(node_allocator_,variable0); } - typedef details::string_function_node alloc_type1; - typedef details::multimode_strfunction_node alloc_type2; + return error_node(); + } + else if (peek_token_is(token_t::e_lsqrbracket)) + { + if (0 == (variable1 = parse_vector())) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR180 - Second parameter to swap is an invalid vector element: '" + var1_name + "'", + exprtk_error_location)); - const std::size_t no_psi = std::numeric_limits::max(); + if (variable0_generated) + { + free_node(node_allocator_,variable0); + } - expression_node_ptr result = error_node(); + return error_node(); + } - if (no_psi == param_seq_index) - result = node_allocator_->allocate(gf,arg_list); - else - result = node_allocator_->allocate(gf,param_seq_index,arg_list); + variable1_generated = true; + } + else + { + if (symtab_store_.is_variable(var1_name)) + { + variable1 = symtab_store_.get_variable(var1_name); + } - alloc_type1* strfunc_node_ptr = static_cast(result); + const scope_element& se = sem_.get_element(var1_name); if ( - !arg_list.empty() && - !gf->has_side_effects && - is_constant_foldable(arg_list) + (se.active) && + (se.name == var1_name) && + (scope_element::e_variable == se.type) ) { - strfunc_node_ptr->init_branches(); - Type v = result->value(); - details::free_node(*node_allocator_,result); - return node_allocator_->allocate(v); - } - else if (strfunc_node_ptr->init_branches()) - return result; - else - { - details::free_node(*node_allocator_,result); - details::free_all_nodes(*node_allocator_,arg_list); - return error_node(); + variable1 = se.var_node; } - } - inline expression_node_ptr vector_element(const std::string& symbol, - vector_holder_ptr vector_base, - expression_node_ptr index) - { - expression_node_ptr result = error_node(); + lodge_symbol(var1_name, e_st_variable); - if (details::is_constant_node(index)) + if (0 == variable1) { - std::size_t i = static_cast(details::numeric::to_int64(index->value())); - details::free_node(*node_allocator_,index); - Type* v = (*vector_base)[i]; - - scope_element& se = parser_->sem_.get_element(symbol,i); + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR181 - Second parameter to swap is an invalid variable: '" + var1_name + "'", + exprtk_error_location)); - if (se.index == i) + if (variable0_generated) { - result = se.var_node; + free_node(node_allocator_,variable0); } - else - { - scope_element nse; - nse.name = symbol; - nse.type = scope_element::e_vecelem; - nse.index = i; - nse.depth = parser_->scope_depth_; - nse.data = 0; - nse.var_node = new variable_node_t((*v)); - - if (!parser_->sem_.add_element(nse)) - { - parser_->set_synthesis_error("Failed to add new local vector element to SEM [1]"); - result = error_node(); - } - else - exprtk_debug(("vector_element() - INFO - Added new local vector element: %s\n",nse.name.c_str())); - result = nse.var_node; - } + return error_node(); } else - result = node_allocator_->allocate >(index,(*vector_base)[0]); - - return result; + next_token(); } - private: - - template - inline bool is_constant_foldable(NodePtr (&b)[N]) const + if (!token_is(token_t::e_rbracket)) { - for (std::size_t i = 0; i < N; ++i) + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR182 - Expected ')' at end of swap statement", + exprtk_error_location)); + + if (variable0_generated) { - if (0 == b[i]) - return false; - else if (!details::is_constant_node(b[i])) - return false; + free_node(node_allocator_,variable0); } - return true; - } - - template class Sequence> - inline bool is_constant_foldable(const Sequence& b) const - { - for (std::size_t i = 0; i < b.size(); ++i) + if (variable1_generated) { - if (0 == b[i]) - return false; - else if (!details::is_constant_node(b[i])) - return false; + free_node(node_allocator_,variable1); } - return true; + return error_node(); } - void lodge_assignment(symbol_type cst, expression_node_ptr node) + typedef details::variable_node* variable_node_ptr; + + variable_node_ptr v0 = variable_node_ptr(0); + variable_node_ptr v1 = variable_node_ptr(0); + + expression_node_ptr result = error_node(); + + if ( + (0 != (v0 = dynamic_cast(variable0))) && + (0 != (v1 = dynamic_cast(variable1))) + ) { - if (!parser_->dec_.collect_assignments()) - return; + result = node_allocator_.allocate >(v0, v1); - std::string symbol_name; + if (variable0_generated) + { + free_node(node_allocator_,variable0); + } - switch (cst) + if (variable1_generated) { - case e_st_variable : symbol_name = parser_->symbol_table_ - .get_variable_name(node); - break; + free_node(node_allocator_,variable1); + } + } + else + result = node_allocator_.allocate > + (variable0, variable1); - case e_st_string : symbol_name = parser_->symbol_table_ - .get_stringvar_name(node); - break; + state_.activate_side_effect("parse_swap_statement()"); - case e_st_vector : { - typedef details::vector_holder vector_holder_t; + return result; + } - vector_holder_t& vh = static_cast(node)->ref(); + #ifndef exprtk_disable_return_statement + inline expression_node_ptr parse_return_statement() + { + if (state_.parsing_return_stmt) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR183 - Return call within a return call is not allowed", + exprtk_error_location)); - symbol_name = parser_->symbol_table_.get_vector_name(&vh); - } - break; + return error_node(); + } - default : return; - } + scoped_bool_negator sbn(state_.parsing_return_stmt); - parser_->dec_.add_assignment(symbol_name,cst); + std::vector arg_list; + + scoped_vec_delete sdd((*this),arg_list); + + if (!details::imatch(current_token().value,"return")) + { + return error_node(); } + else + next_token(); - inline expression_node_ptr synthesize_assignment_expression(const details::operator_type& operation, expression_node_ptr (&branch)[2]) + if (!token_is(token_t::e_lsqrbracket)) { - if (details::is_variable_node(branch[0])) - { - lodge_assignment(e_st_variable,branch[0]); + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR184 - Expected '[' at start of return statement", + exprtk_error_location)); - return synthesize_expression(operation,branch); - } - else if (details::is_vector_elem_node(branch[0])) - return synthesize_expression(operation,branch); - else if (details::is_string_node(branch[0])) + return error_node(); + } + else if (!token_is(token_t::e_rsqrbracket)) + { + for ( ; ; ) { - lodge_assignment(e_st_string,branch[0]); + expression_node_ptr arg = parse_expression(); - return synthesize_expression(operation,branch); - } - else if (details::is_string_range_node(branch[0])) - { - lodge_assignment(e_st_string,branch[0]); + if (0 == arg) + return error_node(); - return synthesize_expression(operation,branch); - } - else if (details::is_vector_node(branch[0])) - { - lodge_assignment(e_st_vector,branch[0]); + arg_list.push_back(arg); - if (details::is_ivector_node(branch[1])) - return synthesize_expression(operation,branch); - else - return synthesize_expression(operation,branch); + if (token_is(token_t::e_rsqrbracket)) + break; + else if (!token_is(token_t::e_comma)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR185 - Expected ',' between values during call to return", + exprtk_error_location)); + + return error_node(); + } } - else + } + else if (settings_.zero_return_disabled()) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR186 - Zero parameter return statement not allowed", + exprtk_error_location)); + + return error_node(); + } + + const lexer::token prev_token = current_token(); + + if (token_is(token_t::e_rsqrbracket)) + { + if (!arg_list.empty()) { - parser_->set_synthesis_error("Invalid assignment operation.[1]"); + set_error( + make_error(parser_error::e_syntax, + prev_token, + "ERR187 - Invalid ']' found during return call", + exprtk_error_location)); return error_node(); } } - inline expression_node_ptr synthesize_assignment_operation_expression(const details::operator_type& operation, - expression_node_ptr (&branch)[2]) + std::string ret_param_type_list; + + for (std::size_t i = 0; i < arg_list.size(); ++i) { - if (details::is_variable_node(branch[0])) - { - lodge_assignment(e_st_variable,branch[0]); + if (0 == arg_list[i]) + return error_node(); + else if (is_ivector_node(arg_list[i])) + ret_param_type_list += 'V'; + else if (is_generally_string_node(arg_list[i])) + ret_param_type_list += 'S'; + else + ret_param_type_list += 'T'; + } - switch (operation) - { - #define case_stmt(op0,op1) \ - case op0 : return node_allocator_-> \ - template allocate_rrr > > \ - (operation,branch[0],branch[1]); \ + dec_.retparam_list_.push_back(ret_param_type_list); - case_stmt(details::e_addass,details::add_op) - case_stmt(details::e_subass,details::sub_op) - case_stmt(details::e_mulass,details::mul_op) - case_stmt(details::e_divass,details::div_op) - case_stmt(details::e_modass,details::mod_op) - #undef case_stmt - default : return error_node(); - } - } - else if (details::is_vector_elem_node(branch[0])) + expression_node_ptr result = expression_generator_.return_call(arg_list); + + sdd.delete_ptr = (0 == result); + + state_.return_stmt_present = true; + + state_.activate_side_effect("parse_return_statement()"); + + return result; + } + #else + inline expression_node_ptr parse_return_statement() + { + return error_node(); + } + #endif + + inline bool post_variable_process(const std::string& symbol) + { + if ( + peek_token_is(token_t::e_lbracket ) || + peek_token_is(token_t::e_lcrlbracket) || + peek_token_is(token_t::e_lsqrbracket) + ) + { + if (!settings_.commutative_check_enabled()) { - switch (operation) - { - #define case_stmt(op0,op1) \ - case op0 : return node_allocator_-> \ - template allocate_rrr > > \ - (operation,branch[0],branch[1]); \ + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR188 - Invalid sequence of variable '"+ symbol + "' and bracket", + exprtk_error_location)); - case_stmt(details::e_addass,details::add_op) - case_stmt(details::e_subass,details::sub_op) - case_stmt(details::e_mulass,details::mul_op) - case_stmt(details::e_divass,details::div_op) - case_stmt(details::e_modass,details::mod_op) - #undef case_stmt - default : return error_node(); - } + return false; } - else if (details::is_vector_node(branch[0])) - { - lodge_assignment(e_st_vector,branch[0]); - if (details::is_ivector_node(branch[1])) - { - switch (operation) - { - #define case_stmt(op0,op1) \ - case op0 : return node_allocator_-> \ - template allocate_rrr > > \ - (operation,branch[0],branch[1]); \ + lexer().insert_front(token_t::e_mul); + } - case_stmt(details::e_addass,details::add_op) - case_stmt(details::e_subass,details::sub_op) - case_stmt(details::e_mulass,details::mul_op) - case_stmt(details::e_divass,details::div_op) - case_stmt(details::e_modass,details::mod_op) - #undef case_stmt - default : return error_node(); - } - } - else - { - switch (operation) - { - #define case_stmt(op0,op1) \ - case op0 : return node_allocator_-> \ - template allocate_rrr > > \ - (operation,branch[0],branch[1]); \ + return true; + } - case_stmt(details::e_addass,details::add_op) - case_stmt(details::e_subass,details::sub_op) - case_stmt(details::e_mulass,details::mul_op) - case_stmt(details::e_divass,details::div_op) - case_stmt(details::e_modass,details::mod_op) - #undef case_stmt - default : return error_node(); - } - } + inline bool post_bracket_process(const typename token_t::token_type& token, expression_node_ptr& branch) + { + bool implied_mul = false; + + if (is_generally_string_node(branch)) + return true; + + const lexer::parser_helper::token_advance_mode hold = prsrhlpr_t::e_hold; + + switch (token) + { + case token_t::e_lcrlbracket : implied_mul = token_is(token_t::e_lbracket ,hold) || + token_is(token_t::e_lcrlbracket,hold) || + token_is(token_t::e_lsqrbracket,hold) ; + break; + + case token_t::e_lbracket : implied_mul = token_is(token_t::e_lbracket ,hold) || + token_is(token_t::e_lcrlbracket,hold) || + token_is(token_t::e_lsqrbracket,hold) ; + break; + + case token_t::e_lsqrbracket : implied_mul = token_is(token_t::e_lbracket ,hold) || + token_is(token_t::e_lcrlbracket,hold) || + token_is(token_t::e_lsqrbracket,hold) ; + break; + + default : return true; + } + + if (implied_mul) + { + if (!settings_.commutative_check_enabled()) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR189 - Invalid sequence of brackets", + exprtk_error_location)); + + return false; } - else if ( - (details::e_addass == operation) && - details::is_string_node(branch[0]) - ) + else if (token_t::e_eof != current_token().type) { - typedef details::assignment_string_node addass_t; + lexer().insert_front(current_token().type); + lexer().insert_front(token_t::e_mul); + next_token(); + } + } - lodge_assignment(e_st_string,branch[0]); + return true; + } - return synthesize_expression(operation,branch); - } - else + inline expression_node_ptr parse_symtab_symbol() + { + const std::string symbol = current_token().value; + + // Are we dealing with a variable or a special constant? + expression_node_ptr variable = symtab_store_.get_variable(symbol); + + if (variable) + { + if (symtab_store_.is_constant_node(symbol)) { - parser_->set_synthesis_error("Invalid assignment operation[2]"); + variable = expression_generator_(variable->value()); + } + if (!post_variable_process(symbol)) return error_node(); - } + + lodge_symbol(symbol, e_st_variable); + next_token(); + + return variable; } - inline expression_node_ptr synthesize_veceqineq_operation_expression(const details::operator_type& operation, - expression_node_ptr (&branch)[2]) + // Are we dealing with a locally defined variable, vector or string? + if (!sem_.empty()) { - const bool is_b0_ivec = details::is_ivector_node(branch[0]); - const bool is_b1_ivec = details::is_ivector_node(branch[1]); + scope_element& se = sem_.get_active_element(symbol); - if (is_b0_ivec && is_b1_ivec) + if (se.active && details::imatch(se.name, symbol)) { - switch (operation) + if (scope_element::e_variable == se.type) { - #define case_stmt(op0,op1) \ - case op0 : return node_allocator_-> \ - template allocate_rrr > > \ - (operation,branch[0],branch[1]); \ - - case_stmt(details:: e_lt,details:: lt_op) - case_stmt(details:: e_lte,details:: lte_op) - case_stmt(details:: e_gt,details:: gt_op) - case_stmt(details:: e_gte,details:: gte_op) - case_stmt(details:: e_eq,details:: eq_op) - case_stmt(details:: e_ne,details:: ne_op) - #undef case_stmt - default : return error_node(); + se.active = true; + lodge_symbol(symbol, e_st_local_variable); + + if (!post_variable_process(symbol)) + return error_node(); + + next_token(); + + return se.var_node; } - } - else if (is_b0_ivec && !is_b1_ivec) - { - switch (operation) + else if (scope_element::e_vector == se.type) { - #define case_stmt(op0,op1) \ - case op0 : return node_allocator_-> \ - template allocate_rrr > > \ - (operation,branch[0],branch[1]); \ - - case_stmt(details:: e_lt,details:: lt_op) - case_stmt(details:: e_lte,details:: lte_op) - case_stmt(details:: e_gt,details:: gt_op) - case_stmt(details:: e_gte,details:: gte_op) - case_stmt(details:: e_eq,details:: eq_op) - case_stmt(details:: e_ne,details:: ne_op) - #undef case_stmt - default : return error_node(); + return parse_vector(); } - } - else if (!is_b0_ivec && is_b1_ivec) - { - switch (operation) + #ifndef exprtk_disable_string_capabilities + else if (scope_element::e_string == se.type) { - #define case_stmt(op0,op1) \ - case op0 : return node_allocator_-> \ - template allocate_rrr > > \ - (operation,branch[0],branch[1]); \ - - case_stmt(details:: e_lt,details:: lt_op) - case_stmt(details:: e_lte,details:: lte_op) - case_stmt(details:: e_gt,details:: gt_op) - case_stmt(details:: e_gte,details:: gte_op) - case_stmt(details:: e_eq,details:: eq_op) - case_stmt(details:: e_ne,details:: ne_op) - #undef case_stmt - default : return error_node(); + return parse_string(); } + #endif } - else - return error_node(); } - inline expression_node_ptr synthesize_vecarithmetic_operation_expression(const details::operator_type& operation, - expression_node_ptr (&branch)[2]) + #ifndef exprtk_disable_string_capabilities + // Are we dealing with a string variable? + if (symtab_store_.is_stringvar(symbol)) { - const bool is_b0_ivec = details::is_ivector_node(branch[0]); - const bool is_b1_ivec = details::is_ivector_node(branch[1]); + return parse_string(); + } + #endif - #define vector_ops \ - case_stmt(details::e_add,details::add_op) \ - case_stmt(details::e_sub,details::sub_op) \ - case_stmt(details::e_mul,details::mul_op) \ - case_stmt(details::e_div,details::div_op) \ - case_stmt(details::e_mod,details::mod_op) \ + { + // Are we dealing with a function? + ifunction* function = symtab_store_.get_function(symbol); - if (is_b0_ivec && is_b1_ivec) + if (function) { - switch (operation) - { - #define case_stmt(op0,op1) \ - case op0 : return node_allocator_-> \ - template allocate_rrr > > \ - (operation,branch[0],branch[1]); \ + lodge_symbol(symbol, e_st_function); - vector_ops - case_stmt(details::e_pow,details:: pow_op) - #undef case_stmt - default : return error_node(); - } - } - else if (is_b0_ivec && !is_b1_ivec) - { - switch (operation) - { - #define case_stmt(op0,op1) \ - case op0 : return node_allocator_-> \ - template allocate_rrr > > \ - (operation,branch[0],branch[1]); \ + expression_node_ptr func_node = + parse_function_invocation(function,symbol); - vector_ops - case_stmt(details::e_pow,details:: pow_op) - #undef case_stmt - default : return error_node(); - } - } - else if (!is_b0_ivec && is_b1_ivec) - { - switch (operation) + if (func_node) + return func_node; + else { - #define case_stmt(op0,op1) \ - case op0 : return node_allocator_-> \ - template allocate_rrr > > \ - (operation,branch[0],branch[1]); \ + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR190 - Failed to generate node for function: '" + symbol + "'", + exprtk_error_location)); - vector_ops - #undef case_stmt - default : return error_node(); + return error_node(); } } - else - return error_node(); - - #undef vector_ops } - inline expression_node_ptr synthesize_swap_expression(expression_node_ptr (&branch)[2]) { - const bool v0_is_ivar = details::is_ivariable_node(branch[0]); - const bool v1_is_ivar = details::is_ivariable_node(branch[1]); - - const bool v0_is_ivec = details::is_ivector_node(branch[0]); - const bool v1_is_ivec = details::is_ivector_node(branch[1]); - - const bool v0_is_str = details::is_generally_string_node(branch[0]); - const bool v1_is_str = details::is_generally_string_node(branch[1]); + // Are we dealing with a vararg function? + ivararg_function* vararg_function = symtab_store_.get_vararg_function(symbol); - if (v0_is_ivar && v1_is_ivar) + if (vararg_function) { - typedef details::variable_node* variable_node_ptr; + lodge_symbol(symbol, e_st_function); - variable_node_ptr v0 = variable_node_ptr(0); - variable_node_ptr v1 = variable_node_ptr(0); + expression_node_ptr vararg_func_node = + parse_vararg_function_call(vararg_function, symbol); - if ( - (0 != (v0 = dynamic_cast(branch[0]))) && - (0 != (v1 = dynamic_cast(branch[1]))) - ) - { - return node_allocator_->allocate >(v0,v1); - } + if (vararg_func_node) + return vararg_func_node; else - return node_allocator_->allocate >(branch[0],branch[1]); - } - else if (v0_is_ivec && v1_is_ivec) - { - return node_allocator_->allocate >(branch[0],branch[1]); - } - else if (v0_is_str && v1_is_str) - { - return node_allocator_->allocate >(branch[0],branch[1]); - } - else - { - parser_->set_synthesis_error("Only variables, strings, vectors or vector elements can be swapped"); + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR191 - Failed to generate node for vararg function: '" + symbol + "'", + exprtk_error_location)); - return error_node(); + return error_node(); + } } } - #ifndef exprtk_disable_sc_andor - inline expression_node_ptr synthesize_shortcircuit_expression(const details::operator_type& operation, expression_node_ptr (&branch)[2]) { - expression_node_ptr result = error_node(); + // Are we dealing with a vararg generic function? + igeneric_function* generic_function = symtab_store_.get_generic_function(symbol); - if (details::is_constant_node(branch[0])) + if (generic_function) { - if ( - (details::e_scand == operation) && - std::equal_to()(T(0),branch[0]->value()) - ) - result = node_allocator_->allocate_c(T(0)); - else if ( - (details::e_scor == operation) && - std::not_equal_to()(T(0),branch[0]->value()) - ) - result = node_allocator_->allocate_c(T(1)); - } + lodge_symbol(symbol, e_st_function); - if (details::is_constant_node(branch[1]) && (0 == result)) - { - if ( - (details::e_scand == operation) && - std::equal_to()(T(0),branch[1]->value()) - ) - result = node_allocator_->allocate_c(T(0)); - else if ( - (details::e_scor == operation) && - std::not_equal_to()(T(0),branch[1]->value()) - ) - result = node_allocator_->allocate_c(T(1)); - } + expression_node_ptr genericfunc_node = + parse_generic_function_call(generic_function, symbol); - if (result) - { - free_node(*node_allocator_,branch[0]); - free_node(*node_allocator_,branch[1]); + if (genericfunc_node) + return genericfunc_node; + else + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR192 - Failed to generate node for generic function: '" + symbol + "'", + exprtk_error_location)); - return result; + return error_node(); + } } - else if (details::e_scand == operation) - return synthesize_expression(operation,branch); - else if (details::e_scor == operation) - return synthesize_expression(operation,branch); - else - return error_node(); - } - #else - inline expression_node_ptr synthesize_shortcircuit_expression(const details::operator_type&, expression_node_ptr (&)[2]) - { - return error_node(); } - #endif - - #define basic_opr_switch_statements \ - case_stmt(details::e_add,details::add_op) \ - case_stmt(details::e_sub,details::sub_op) \ - case_stmt(details::e_mul,details::mul_op) \ - case_stmt(details::e_div,details::div_op) \ - case_stmt(details::e_mod,details::mod_op) \ - case_stmt(details::e_pow,details::pow_op) \ - - #define extended_opr_switch_statements \ - case_stmt(details:: e_lt,details:: lt_op) \ - case_stmt(details:: e_lte,details:: lte_op) \ - case_stmt(details:: e_gt,details:: gt_op) \ - case_stmt(details:: e_gte,details:: gte_op) \ - case_stmt(details:: e_eq,details:: eq_op) \ - case_stmt(details:: e_ne,details:: ne_op) \ - case_stmt(details:: e_and,details:: and_op) \ - case_stmt(details::e_nand,details::nand_op) \ - case_stmt(details:: e_or,details:: or_op) \ - case_stmt(details:: e_nor,details:: nor_op) \ - case_stmt(details:: e_xor,details:: xor_op) \ - case_stmt(details::e_xnor,details::xnor_op) \ - #ifndef exprtk_disable_cardinal_pow_optimisation - template