/* ****************************************************************** * C++ Mathematical Expression Toolkit Library * * * * Author: Arash Partow (1999-2022) * * URL: https://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 MIT License. * * https://www.opensource.org/licenses/MIT * * * * Example expressions: * * (00) (y + x / y) * (x - y / x) * * (01) (x^2 / sin(2 * pi / y)) - x / 2 * * (02) sqrt(1 - (x^2)) * * (03) 1 - sin(2 * x) + cos(pi / y) * * (04) a * exp(2 * t) + c * * (05) if(((x + 2) == 3) and ((y + 5) <= 9),1 + w, 2 / z) * * (06) (avg(x,y) <= x + y ? x - y : x * y) + 2 * pi / x * * (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) * * (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)] * * * ****************************************************************** */ #ifndef INCLUDE_EXPRTK_HPP #define INCLUDE_EXPRTK_HPP #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace exprtk { #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 #if __cplusplus >= 201103L #define exprtk_override override #define exprtk_final final #define exprtk_delete = delete #else #define exprtk_override #define exprtk_final #define exprtk_delete #endif namespace details { typedef char char_t; typedef char_t* char_ptr; typedef char_t const* char_cptr; typedef unsigned char uchar_t; typedef uchar_t* uchar_ptr; typedef uchar_t const* uchar_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) || ('\b' == c) || ('\v' == c) || ('\f' == c) ; } inline bool is_operator_char(const char_t c) { return ('+' == c) || ('-' == c) || ('*' == c) || ('/' == c) || ('^' == c) || ('<' == c) || ('>' == c) || ('=' == c) || (',' == c) || ('!' == c) || ('(' == c) || (')' == c) || ('[' == c) || (']' == c) || ('{' == c) || ('}' == c) || ('%' == c) || (':' == c) || ('?' == c) || ('&' == c) || ('|' == c) || (';' == c) ; } inline bool is_letter(const char_t c) { return (('a' <= c) && (c <= 'z')) || (('A' <= c) && (c <= 'Z')) ; } inline bool is_digit(const char_t c) { return ('0' <= c) && (c <= '9'); } inline bool is_letter_or_digit(const char_t c) { return is_letter(c) || is_digit(c); } inline bool is_left_bracket(const char_t c) { return ('(' == c) || ('[' == c) || ('{' == c); } inline bool is_right_bracket(const char_t c) { return (')' == c) || (']' == c) || ('}' == c); } inline bool is_bracket(const char_t c) { return is_left_bracket(c) || is_right_bracket(c); } inline bool is_sign(const char_t c) { return ('+' == c) || ('-' == c); } inline bool is_invalid(const char_t c) { return !is_whitespace (c) && !is_operator_char(c) && !is_letter (c) && !is_digit (c) && ('.' != c) && ('_' != c) && ('$' != c) && ('~' != c) && ('\'' != c); } inline bool is_valid_string_char(const char_t c) { return std::isprint(static_cast(c)) || is_whitespace(c); } #ifndef exprtk_disable_caseinsensitivity inline void case_normalise(std::string& s) { 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); } inline bool imatch(const std::string& s1, const std::string& s2) { if (s1.size() == s2.size()) { for (std::size_t i = 0; i < s1.size(); ++i) { if (std::tolower(s1[i]) != std::tolower(s2[i])) { return false; } } return true; } 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 return (4 == symbol.size()) && ('$' == symbol[0]) && imatch('f',symbol[1]) && is_digit(symbol[2]) && 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; const int sign = (i < 0) ? -1 : 1; for ( ; i; i /= 10) { result += '0' + static_cast(sign * (i % 10)); } if (sign < 0) { 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 uchar_t digit) { return (('0' <= digit) && (digit <= '9')) || (('A' <= digit) && (digit <= 'F')) || (('a' <= digit) && (digit <= 'f')) ; } inline uchar_t hex_to_bin(uchar_t h) { if (('0' <= h) && (h <= '9')) return (h - '0'); else return static_cast(std::toupper(h) - 'A'); } template inline bool parse_hex(Iterator& itr, Iterator end, char_t& result) { if ( (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))) ) { return false; } result = hex_to_bin(static_cast(*(itr + 2))) << 4 | hex_to_bin(static_cast(*(itr + 3))) ; return true; } inline bool cleanup_escapes(std::string& s) { 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)) { if (end == ++itr1) { 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; } else (*itr2++) = (*itr1++); } if ((removal_count > s.size()) || (0 == removal_count)) return false; s.resize(s.size() - removal_count); return true; } class build_string { public: build_string(const std::size_t& initial_size = 64) { data_.reserve(initial_size); } inline build_string& operator << (const std::string& s) { data_ += s; return (*this); } inline build_string& operator << (char_cptr s) { data_ += std::string(s); return (*this); } inline operator std::string () const { return data_; } inline std::string as_string() const { return data_; } private: std::string data_; }; static const std::string reserved_words[] = { "break", "case", "continue", "default", "false", "for", "if", "else", "ilike", "in", "like", "and", "nand", "nor", "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); static const std::string reserved_symbols[] = { "abs", "acos", "acosh", "and", "asin", "asinh", "atan", "atanh", "atan2", "avg", "break", "case", "ceil", "clamp", "continue", "cos", "cosh", "cot", "csc", "default", "deg2grad", "deg2rad", "equal", "erf", "erfc", "exp", "expm1", "false", "floor", "for", "frac", "grad2deg", "hypot", "iclamp", "if", "else", "ilike", "in", "inrange", "like", "log", "log10", "log2", "logn", "log1p", "mand", "max", "min", "mod", "mor", "mul", "ncdf", "nand", "nor", "not", "not_equal", "null", "or", "pow", "rad2deg", "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])) { return true; } } return false; } inline bool is_reserved_symbol(const std::string& symbol) { for (std::size_t i = 0; i < reserved_symbols_size; ++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; } } return false; } struct cs_match { static inline bool cmp(const char_t c0, const char_t c1) { return (c0 == c1); } }; struct cis_match { static inline bool cmp(const char_t c0, const char_t c1) { return (std::tolower(c0) == std::tolower(c1)); } }; template inline bool match_impl(const Iterator pattern_begin, 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& exactly_one ) { const Iterator null_itr(0); Iterator p_itr = pattern_begin; Iterator d_itr = data_begin; Iterator np_itr = null_itr; Iterator nd_itr = null_itr; for ( ; ; ) { const bool pvalid = p_itr != pattern_end; const bool dvalid = d_itr != data_end; if (!pvalid && !dvalid) break; if (pvalid) { const typename std::iterator_traits::value_type c = *(p_itr); if (zero_or_more == c) { np_itr = p_itr; nd_itr = d_itr + 1; ++p_itr; continue; } else if (dvalid && ((exactly_one == c) || Compare::cmp(c,*(d_itr)))) { ++p_itr; ++d_itr; continue; } } if ((null_itr != nd_itr) && (nd_itr <= data_end)) { p_itr = np_itr; d_itr = nd_itr; continue; } return false; } return true; } 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(), '*', '?'); } 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(), '*', '?'); } inline bool sequence_match(const std::string& pattern, const std::string& str, std::size_t& diff_index, char_t& diff_value) { if (str.empty()) { return ("Z" == pattern); } else if ('*' == pattern[0]) return false; typedef std::string::const_iterator itr_t; itr_t p_itr = pattern.begin(); itr_t s_itr = str .begin(); const itr_t p_end = pattern.end(); const itr_t s_end = str .end(); while ((s_end != s_itr) && (p_end != p_itr)) { if ('*' == (*p_itr)) { const char_t target = static_cast(std::toupper(*(p_itr - 1))); if ('*' == target) { diff_index = static_cast(std::distance(str.begin(),s_itr)); diff_value = static_cast(std::toupper(*p_itr)); return false; } else ++p_itr; while (s_itr != s_end) { if (target != std::toupper(*s_itr)) break; else ++s_itr; } continue; } else if ( ('?' != *p_itr) && std::toupper(*p_itr) != std::toupper(*s_itr) ) { diff_index = static_cast(std::distance(str.begin(),s_itr)); diff_value = static_cast(std::toupper(*p_itr)); return false; } ++p_itr; ++s_itr; } return ( (s_end == s_itr) && ( (p_end == p_itr) || ('*' == *p_itr) ) ); } 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 }; static const std::size_t pow10_size = sizeof(pow10) / sizeof(double); namespace numeric { namespace constant { 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 { 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; number_type() {} }; #define exprtk_register_real_type_tag(T) \ template <> struct number_type \ { typedef real_type_tag type; number_type() {} }; \ #define exprtk_register_complex_type_tag(T) \ template <> struct number_type > \ { typedef complex_type_tag type; number_type() {} }; \ #define exprtk_register_int_type_tag(T) \ template <> struct number_type \ { typedef int_type_tag type; number_type() {} }; \ exprtk_register_real_type_tag(double ) exprtk_register_real_type_tag(long double) exprtk_register_real_type_tag(float ) exprtk_register_complex_type_tag(double ) exprtk_register_complex_type_tag(long double) exprtk_register_complex_type_tag(float ) exprtk_register_int_type_tag(short ) exprtk_register_int_type_tag(int ) exprtk_register_int_type_tag(_int64_t ) 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 {}; #define exprtk_define_epsilon_type(Type, Epsilon) \ template <> struct epsilon_type \ { \ static inline Type value() \ { \ const Type epsilon = static_cast(Epsilon); \ return epsilon; \ } \ }; \ exprtk_define_epsilon_type(float , 0.00000100000f) exprtk_define_epsilon_type(double , 0.000000000100) 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) { return std::not_equal_to()(v,v); } template inline int to_int32_impl(const T v, real_type_tag) { return static_cast(v); } template inline _int64_t to_int64_impl(const T v, real_type_tag) { return static_cast<_int64_t>(v); } template inline bool is_true_impl(const T v) { return std::not_equal_to()(T(0),v); } template inline bool is_false_impl(const T v) { return std::equal_to()(T(0),v); } template inline T abs_impl(const T v, real_type_tag) { return ((v < T(0)) ? -v : v); } template inline T min_impl(const T v0, const T v1, real_type_tag) { return std::min(v0,v1); } template inline T max_impl(const T v0, const T v1, real_type_tag) { return std::max(v0,v1); } template inline T equal_impl(const T v0, const T v1, real_type_tag) { 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); } inline float equal_impl(const float v0, const float v1, real_type_tag) { 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; } template inline T equal_impl(const T v0, const T v1, int_type_tag) { return (v0 == v1) ? 1 : 0; } template inline T expm1_impl(const T v, real_type_tag) { // return std::expm1(v); if (abs_impl(v,real_type_tag()) < T(0.00001)) return v + (T(0.5) * v * v); else return std::exp(v) - T(1); } template inline T expm1_impl(const T v, int_type_tag) { return T(std::exp(v)) - T(1); } 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,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,rtg()) > (std::max(1.0f,std::max(abs_impl(v0,rtg()),abs_impl(v1,rtg()))) * epsilon)) ? 1.0f : 0.0f; } template inline T nequal_impl(const T v0, const T v1, int_type_tag) { return (v0 != v1) ? 1 : 0; } template inline T modulus_impl(const T v0, const T v1, real_type_tag) { return std::fmod(v0,v1); } template inline T modulus_impl(const T v0, const T v1, int_type_tag) { return v0 % v1; } template inline T pow_impl(const T v0, const T v1, real_type_tag) { return std::pow(v0,v1); } template inline T pow_impl(const T v0, const T v1, int_type_tag) { return std::pow(static_cast(v0),static_cast(v1)); } template inline T logn_impl(const T v0, const T v1, real_type_tag) { return std::log(v0) / std::log(v1); } template inline T logn_impl(const T v0, const T v1, int_type_tag) { return static_cast(logn_impl(static_cast(v0),static_cast(v1),real_type_tag())); } template inline T log1p_impl(const T v, real_type_tag) { if (v > T(-1)) { if (abs_impl(v,real_type_tag()) > T(0.0001)) { return std::log(T(1) + v); } else return (T(-0.5) * v + T(1)) * v; } else return std::numeric_limits::quiet_NaN(); } template inline T log1p_impl(const T v, int_type_tag) { if (v > T(-1)) { return std::log(T(1) + v); } else return std::numeric_limits::quiet_NaN(); } template inline T root_impl(const T v0, const T v1, real_type_tag) { 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 inline T root_impl(const T v0, const T v1, int_type_tag) { return root_impl(static_cast(v0),static_cast(v1),real_type_tag()); } template inline T round_impl(const T v, real_type_tag) { return ((v < T(0)) ? std::ceil(v - T(0.5)) : std::floor(v + T(0.5))); } 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, 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 return T(std::floor((v0 * p10) + T(0.5)) / p10); } template inline T roundn_impl(const T v0, const T, int_type_tag) { return v0; } template inline T hypot_impl(const T v0, const T v1, real_type_tag) { return std::sqrt((v0 * v0) + (v1 * v1)); } template inline T hypot_impl(const T v0, const T v1, int_type_tag) { return static_cast(std::sqrt(static_cast((v0 * v0) + (v1 * v1)))); } template inline T atan2_impl(const T v0, const T v1, real_type_tag) { return std::atan2(v0,v1); } template inline T atan2_impl(const T, const T, int_type_tag) { return 0; } template inline T shr_impl(const T v0, const T v1, real_type_tag) { return v0 * (T(1) / std::pow(T(2),static_cast(static_cast(v1)))); } template inline T shr_impl(const T v0, const T v1, int_type_tag) { return v0 >> v1; } template inline T shl_impl(const T v0, const T v1, real_type_tag) { return v0 * std::pow(T(2),static_cast(static_cast(v1))); } template inline T shl_impl(const T v0, const T v1, int_type_tag) { return v0 << v1; } template inline T sgn_impl(const T v, real_type_tag) { if (v > T(0)) return T(+1); else if (v < T(0)) return T(-1); else return T( 0); } template inline T sgn_impl(const T v, int_type_tag) { if (v > T(0)) return T(+1); else if (v < T(0)) return T(-1); else return T( 0); } template inline T and_impl(const T v0, const T v1, real_type_tag) { return (is_true_impl(v0) && is_true_impl(v1)) ? T(1) : T(0); } template inline T and_impl(const T v0, const T v1, int_type_tag) { return v0 && v1; } template inline T nand_impl(const T v0, const T v1, real_type_tag) { return (is_false_impl(v0) || is_false_impl(v1)) ? T(1) : T(0); } template inline T nand_impl(const T v0, const T v1, int_type_tag) { return !(v0 && v1); } template inline T or_impl(const T v0, const T v1, real_type_tag) { return (is_true_impl(v0) || is_true_impl(v1)) ? T(1) : T(0); } template inline T or_impl(const T v0, const T v1, int_type_tag) { return (v0 || v1); } template inline T nor_impl(const T v0, const T v1, real_type_tag) { return (is_false_impl(v0) && is_false_impl(v1)) ? T(1) : T(0); } template inline T nor_impl(const T v0, const T v1, int_type_tag) { return !(v0 || v1); } template inline T xor_impl(const T v0, const T v1, real_type_tag) { return (is_false_impl(v0) != is_false_impl(v1)) ? T(1) : T(0); } template inline T xor_impl(const T v0, const T v1, int_type_tag) { return v0 ^ v1; } template inline T xnor_impl(const T v0, const T v1, real_type_tag) { 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); } template inline T xnor_impl(const T v0, const T v1, int_type_tag) { 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(const 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(const T v, real_type_tag) { #if defined(_MSC_VER) && (_MSC_VER < 1900) // Credits: Abramowitz & Stegun Equations 7.1.25-28 static const T c[] = { T( 1.26551223), T(1.00002368), T( 0.37409196), T(0.09678418), T(-0.18628806), T(0.27886807), 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())); const 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_impl(v); #endif } template inline T erf_impl(const T v, int_type_tag) { 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(const 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(const T v, real_type_tag) { #if defined(_MSC_VER) && (_MSC_VER < 1900) return T(1) - erf_impl(v,real_type_tag()); #else return erfc_impl(v); #endif } template inline T erfc_impl(const T v, int_type_tag) { return erfc_impl(static_cast(v),real_type_tag()); } template inline T ncdf_impl(const T v, real_type_tag) { const T cnd = T(0.5) * (T(1) + erf_impl(abs_impl(v,real_type_tag()) / T(numeric::constant::sqrt2),real_type_tag())); return (v < T(0)) ? (T(1) - cnd) : cnd; } template inline T ncdf_impl(const T v, int_type_tag) { return ncdf_impl(static_cast(v),real_type_tag()); } template inline T sinc_impl(const T v, real_type_tag) { if (std::abs(v) >= std::numeric_limits::epsilon()) return(std::sin(v) / v); else return T(1); } template inline T sinc_impl(const T v, int_type_tag) { return sinc_impl(static_cast(v),real_type_tag()); } template inline T acos_impl(const T v, real_type_tag) { return std::acos (v); } template inline T acosh_impl(const T v, real_type_tag) { return std::log(v + std::sqrt((v * v) - T(1))); } 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) - 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); } template inline T exp_impl(const T v, real_type_tag) { return std::exp (v); } template inline T floor_impl(const T v, real_type_tag) { return std::floor(v); } template inline T log_impl(const T v, real_type_tag) { return std::log (v); } template inline T log10_impl(const T v, real_type_tag) { return std::log10(v); } template inline T log2_impl(const T v, real_type_tag) { return std::log(v)/T(numeric::constant::log2); } template inline T neg_impl(const T v, real_type_tag) { return -v; } template inline T pos_impl(const T v, real_type_tag) { return +v; } template inline T sin_impl(const T v, real_type_tag) { return std::sin (v); } template inline T sinh_impl(const T v, real_type_tag) { return std::sinh (v); } template inline T sqrt_impl(const T v, real_type_tag) { return std::sqrt (v); } template inline T tan_impl(const T v, real_type_tag) { return std::tan (v); } template inline T tanh_impl(const T v, real_type_tag) { return std::tanh (v); } template inline T cot_impl(const T v, real_type_tag) { return T(1) / std::tan(v); } template inline T sec_impl(const T v, real_type_tag) { return T(1) / std::cos(v); } template inline T csc_impl(const T v, real_type_tag) { return T(1) / std::sin(v); } template inline T r2d_impl(const T v, real_type_tag) { return (v * T(numeric::constant::_180_pi)); } template inline T d2r_impl(const T v, real_type_tag) { return (v * T(numeric::constant::pi_180)); } template inline T d2g_impl(const T v, real_type_tag) { return (v * T(10.0/9.0)); } template inline T g2d_impl(const T v, real_type_tag) { return (v * T(9.0/10.0)); } template inline T notl_impl(const T v, real_type_tag) { return (std::not_equal_to()(T(0),v) ? T(0) : T(1)); } 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 const_qnan_impl(real_type_tag) { return std::numeric_limits::quiet_NaN(); } 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); } template inline T log10_impl(const T v, int_type_tag) { return std::log10(v); } template inline T log2_impl(const T v, int_type_tag) { return std::log(v)/T(numeric::constant::log2); } template inline T neg_impl(const T v, int_type_tag) { return -v; } template inline T pos_impl(const T v, int_type_tag) { return +v; } template inline T ceil_impl(const T v, int_type_tag) { return v; } template inline T floor_impl(const T v, int_type_tag) { return v; } template inline T round_impl(const T v, int_type_tag) { return v; } template inline T notl_impl(const T v, int_type_tag) { return !v; } template inline T sqrt_impl(const T v, int_type_tag) { return std::sqrt (v); } template inline T frac_impl(const T , int_type_tag) { return T(0); } template inline T trunc_impl(const T v, int_type_tag) { return v; } template inline T acos_impl(const T , int_type_tag) { return std::numeric_limits::quiet_NaN(); } template inline T acosh_impl(const T , int_type_tag) { return std::numeric_limits::quiet_NaN(); } template inline T asin_impl(const T , int_type_tag) { return std::numeric_limits::quiet_NaN(); } template inline T asinh_impl(const T , int_type_tag) { return std::numeric_limits::quiet_NaN(); } template inline T atan_impl(const T , int_type_tag) { return std::numeric_limits::quiet_NaN(); } template inline T atanh_impl(const T , int_type_tag) { return std::numeric_limits::quiet_NaN(); } template inline T cos_impl(const T , int_type_tag) { return std::numeric_limits::quiet_NaN(); } template inline T cosh_impl(const T , int_type_tag) { return std::numeric_limits::quiet_NaN(); } template inline T sin_impl(const T , int_type_tag) { return std::numeric_limits::quiet_NaN(); } template inline T sinh_impl(const T , int_type_tag) { return std::numeric_limits::quiet_NaN(); } template inline T tan_impl(const T , int_type_tag) { return std::numeric_limits::quiet_NaN(); } template inline T tanh_impl(const T , int_type_tag) { return std::numeric_limits::quiet_NaN(); } template inline T cot_impl(const T , int_type_tag) { return std::numeric_limits::quiet_NaN(); } template inline T sec_impl(const T , int_type_tag) { return std::numeric_limits::quiet_NaN(); } template inline T csc_impl(const T , int_type_tag) { return std::numeric_limits::quiet_NaN(); } template inline bool is_integer_impl(const T& v, real_type_tag) { return std::equal_to()(T(0),std::fmod(v,T(1))); } template inline bool is_integer_impl(const T&, int_type_tag) { return true; } } 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 inline int to_int32(const T v) { const typename details::number_type::type num_type; return to_int32_impl(v, num_type); } template inline _int64_t to_int64(const T v) { const typename details::number_type::type num_type; return to_int64_impl(v, num_type); } template inline bool is_nan(const T v) { 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) { 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) { 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) { 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) { 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) { 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) { 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) { 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) { 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) { 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) { 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) { 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) { 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) { 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) { 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) { 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) { 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) { 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) { 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) { const typename details::number_type::type num_type; return xnor_impl(v0, v1, num_type); } template inline bool is_integer(const T v) { const typename details::number_type::type num_type; return is_integer_impl(v, num_type); } template struct fast_exp { static inline T result(T v) { unsigned int k = N; T l = T(1); while (k) { if (1 == (k % 2)) { l *= v; --k; } v *= v; k /= 2; } return l; } }; template struct fast_exp { static inline T result(const T v) { T v_5 = fast_exp::result(v); return v_5 * v_5; } }; template struct fast_exp { static inline T result(const T v) { return fast_exp::result(v) * v; } }; template struct fast_exp { static inline T result(const T v) { T v_4 = fast_exp::result(v); return v_4 * v_4; } }; template struct fast_exp { static inline T result(const T v) { return fast_exp::result(v) * v; } }; template struct fast_exp { static inline T result(const T v) { T v_3 = fast_exp::result(v); return v_3 * v_3; } }; template struct fast_exp { static inline T result(const T v) { return fast_exp::result(v) * v; } }; template struct fast_exp { static inline T result(const T v) { T v_2 = v * v; return v_2 * v_2; } }; template struct fast_exp { static inline T result(const T v) { return v * v * v; } }; template struct fast_exp { static inline T result(const T v) { return v * v; } }; template struct fast_exp { static inline T result(const T v) { return v; } }; template struct fast_exp { static inline T result(const T ) { return T(1); } }; #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 ) exprtk_define_unary_function(acosh) exprtk_define_unary_function(asin ) exprtk_define_unary_function(asinh) exprtk_define_unary_function(atan ) exprtk_define_unary_function(atanh) exprtk_define_unary_function(ceil ) exprtk_define_unary_function(cos ) exprtk_define_unary_function(cosh ) exprtk_define_unary_function(exp ) exprtk_define_unary_function(expm1) exprtk_define_unary_function(floor) exprtk_define_unary_function(log ) exprtk_define_unary_function(log10) exprtk_define_unary_function(log2 ) exprtk_define_unary_function(log1p) exprtk_define_unary_function(neg ) exprtk_define_unary_function(pos ) exprtk_define_unary_function(round) exprtk_define_unary_function(sin ) exprtk_define_unary_function(sinc ) exprtk_define_unary_function(sinh ) exprtk_define_unary_function(sqrt ) exprtk_define_unary_function(tan ) exprtk_define_unary_function(tanh ) exprtk_define_unary_function(cot ) exprtk_define_unary_function(sec ) exprtk_define_unary_function(csc ) exprtk_define_unary_function(r2d ) exprtk_define_unary_function(d2r ) exprtk_define_unary_function(d2g ) exprtk_define_unary_function(g2d ) exprtk_define_unary_function(notl ) exprtk_define_unary_function(sgn ) exprtk_define_unary_function(erf ) exprtk_define_unary_function(erfc ) exprtk_define_unary_function(ncdf ) exprtk_define_unary_function(frac ) exprtk_define_unary_function(trunc) #undef exprtk_define_unary_function } template inline T compute_pow10(T d, const int exponent) { 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 }; static const int fract10_size = static_cast(sizeof(fract10) / sizeof(double)); const int e = std::abs(exponent); if (exponent >= std::numeric_limits::min_exponent10) { if (e < fract10_size) { if (exponent > 0) return T(d * fract10[e]); else return T(d / fract10[e]); } else return T(d * std::pow(10.0, 10.0 * exponent)); } else { d /= T(fract10[ -std::numeric_limits::min_exponent10]); return T(d / fract10[-exponent + std::numeric_limits::min_exponent10]); } } template inline bool string_to_type_converter_impl_ref(Iterator& itr, const Iterator end, T& result) { if (itr == end) return false; const bool negative = ('-' == (*itr)); if (negative || ('+' == (*itr))) { if (end == ++itr) return false; } 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 = 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; \ } \ #else #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 - zero))>= 10) { digit = 0; return_result = false; } #undef exprtk_process_digit } exprtk_disable_fallthrough_end } else return_result = false; if (length && return_result) { result = result * 10 + static_cast(digit); ++itr; } result = negative ? -result : result; return return_result; } template 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 ( (static_cast('a') != *(itr + 1)) || (static_cast('n') != *(itr + 2)) ) { return false; } } else if ( (static_cast('A') != *(itr + 1)) || (static_cast('N') != *(itr + 2)) ) { return false; } t = std::numeric_limits::quiet_NaN(); return true; } template static inline bool parse_inf(Iterator& itr, const Iterator end, T& t, const bool negative) { 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 = static_cast(std::distance(itr,end)); if ((3 != length) && (inf_length != length)) return false; char_cptr inf_itr = ('i' == (*itr)) ? inf_lc : inf_uc; while (end != itr) { if (*inf_itr == static_cast(*itr)) { ++itr; ++inf_itr; continue; } else return false; } if (negative) t = -std::numeric_limits::infinity(); else t = std::numeric_limits::infinity(); return true; } 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; Iterator itr = itr_external; T d = T(0); const bool negative = ('-' == (*itr)); if (negative || '+' == (*itr)) { if (end == ++itr) return false; } bool instate = false; static const char_t zero = static_cast('0'); #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) && (zero == (*itr))) ++itr; while (end != itr) { unsigned int digit; parse_digit_1(d) parse_digit_1(d) parse_digit_2(d) } if (curr != itr) instate = true; } int exponent = 0; if (end != itr) { if ('.' == (*itr)) { const Iterator curr = ++itr; T tmp_d = T(0); while (end != itr) { unsigned int digit; parse_digit_1(tmp_d) parse_digit_1(tmp_d) parse_digit_2(tmp_d) } if (curr != itr) { instate = true; 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 #undef parse_digit_2 } if (end != itr) { typename std::iterator_traits::value_type c = (*itr); if (('e' == c) || ('E' == c)) { int exp = 0; if (!details::string_to_type_converter_impl_ref(++itr, end, exp)) { if (end == itr) return false; else c = (*itr); } exponent += exp; } if (end != itr) { if (('f' == c) || ('F' == c) || ('l' == c) || ('L' == c)) ++itr; else if ('#' == c) { if (end == ++itr) return false; else if (('I' <= (*itr)) && ((*itr) <= 'n')) { if (('i' == (*itr)) || ('I' == (*itr))) { return parse_inf(itr, end, t, negative); } else if (('n' == (*itr)) || ('N' == (*itr))) { return parse_nan(itr, end, t); } else return false; } else return false; } else if (('I' <= (*itr)) && ((*itr) <= 'n')) { if (('i' == (*itr)) || ('I' == (*itr))) { return parse_inf(itr, end, t, negative); } else if (('n' == (*itr)) || ('N' == (*itr))) { return parse_nan(itr, end, t); } else return false; } else return false; } } } 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); t = static_cast((negative) ? -d : d); return true; } template inline bool string_to_real(const std::string& s, T& t) { 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 struct functor_t { /* Note: The following definitions for Type, may require tweaking based on the compiler and target architecture. The benchmark should provide enough information to make the right choice. */ //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); typedef T (*ufunc_t)(Type t0); }; } // 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 { enum token_type { e_none = 0, e_error = 1, e_err_symbol = 2, e_err_number = 3, e_err_string = 4, e_err_sfunc = 5, e_eof = 6, e_number = 7, e_symbol = 8, e_string = 9, e_assign = 10, e_addass = 11, e_subass = 12, e_mulass = 13, e_divass = 14, e_modass = 15, e_shr = 16, e_shl = 17, e_lte = 18, e_ne = 19, e_gte = 20, e_swap = 21, e_lt = '<', e_gt = '>', e_eq = '=', e_rbracket = ')', e_lbracket = '(', e_rsqrbracket = ']', e_lsqrbracket = '[', e_rcrlbracket = '}', e_lcrlbracket = '{', e_comma = ',', e_add = '+', e_sub = '-', e_div = '/', e_mul = '*', e_mod = '%', e_pow = '^', e_colon = ':', e_ternary = '?' }; token() : type(e_none) , value("") , position(std::numeric_limits::max()) {} void clear() { type = e_none; value = ""; position = std::numeric_limits::max(); } template 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 = static_cast(std::distance(base_begin,begin)); return (*this); } template inline token& set_symbol(const Iterator begin, const Iterator end, const Iterator base_begin = Iterator(0)) { type = e_symbol; value.assign(begin,end); if (base_begin) position = static_cast(std::distance(base_begin,begin)); return (*this); } template inline token& set_numeric(const Iterator begin, const Iterator end, const Iterator base_begin = Iterator(0)) { type = e_number; value.assign(begin,end); if (base_begin) position = static_cast(std::distance(base_begin,begin)); return (*this); } template inline token& set_string(const Iterator begin, const Iterator end, const Iterator base_begin = Iterator(0)) { type = e_string; value.assign(begin,end); if (base_begin) position = static_cast(std::distance(base_begin,begin)); return (*this); } inline token& set_string(const std::string& s, const std::size_t p) { type = e_string; value = s; position = p; return (*this); } template inline token& set_error(const token_type et, const Iterator begin, const Iterator end, const Iterator base_begin = Iterator(0)) { if ( (e_error == et) || (e_err_symbol == et) || (e_err_number == et) || (e_err_string == et) || (e_err_sfunc == et) ) { type = et; } else type = e_error; value.assign(begin,end); if (base_begin) position = static_cast(std::distance(base_begin,begin)); return (*this); } static inline std::string to_str(token_type t) { switch (t) { case e_none : return "NONE"; case e_error : return "ERROR"; case e_err_symbol : return "ERROR_SYMBOL"; case e_err_number : return "ERROR_NUMBER"; case e_err_string : return "ERROR_STRING"; case e_eof : return "EOF"; case e_number : return "NUMBER"; case e_symbol : return "SYMBOL"; case e_string : return "STRING"; 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_shr : return ">>"; case e_shl : return "<<"; case e_lte : return "<="; case e_ne : return "!="; case e_gte : return ">="; case e_lt : return "<"; case e_gt : return ">"; case e_eq : return "="; case e_rbracket : return ")"; case e_lbracket : return "("; case e_rsqrbracket : return "]"; case e_lsqrbracket : return "["; case e_rcrlbracket : return "}"; case e_lcrlbracket : return "{"; case e_comma : return ","; case e_add : return "+"; case e_sub : return "-"; case e_div : return "/"; case e_mul : return "*"; case e_mod : return "%"; case e_pow : return "^"; case e_colon : return ":"; case e_ternary : return "?"; case e_swap : return "<=>"; default : return "UNKNOWN"; } } inline bool is_error() const { return ( (e_error == type) || (e_err_symbol == type) || (e_err_number == type) || (e_err_string == type) || (e_err_sfunc == type) ); } token_type type; std::string value; std::size_t position; }; class generator { public: typedef token token_t; typedef std::vector token_list_t; typedef token_list_t::iterator token_list_itr_t; typedef details::char_t char_t; generator() : base_itr_(0) , s_itr_ (0) , s_end_ (0) { clear(); } inline void clear() { base_itr_ = 0; s_itr_ = 0; s_end_ = 0; token_list_.clear(); token_itr_ = token_list_.end(); store_token_itr_ = token_list_.end(); } inline bool process(const std::string& str) { base_itr_ = str.data(); s_itr_ = str.data(); s_end_ = str.data() + str.size(); eof_token_.set_operator(token_t::e_eof,s_end_,s_end_,base_itr_); token_list_.clear(); while (!is_end(s_itr_)) { scan_token(); if (!token_list_.empty() && token_list_.back().is_error()) return false; } return true; } inline bool empty() const { return token_list_.empty(); } inline std::size_t size() const { return token_list_.size(); } inline void begin() { token_itr_ = token_list_.begin(); store_token_itr_ = token_list_.begin(); } inline void store() { store_token_itr_ = token_itr_; } inline void restore() { token_itr_ = store_token_itr_; } inline token_t& next_token() { if (token_list_.end() != token_itr_) { return *token_itr_++; } else return eof_token_; } inline token_t& peek_next_token() { if (token_list_.end() != token_itr_) { return *token_itr_; } else return eof_token_; } inline token_t& operator[](const std::size_t& index) { if (index < token_list_.size()) return token_list_[index]; else return eof_token_; } inline token_t operator[](const std::size_t& index) const { if (index < token_list_.size()) return token_list_[index]; else return eof_token_; } inline bool finished() const { return (token_list_.end() == token_itr_); } inline void insert_front(token_t::token_type tk_type) { if ( !token_list_.empty() && (token_list_.end() != token_itr_) ) { token_t t = *token_itr_; t.type = tk_type; token_itr_ = token_list_.insert(token_itr_,t); } } inline std::string substr(const std::size_t& begin, const std::size_t& end) const { 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(details::char_cptr itr) const { return (s_end_ == itr); } #ifndef exprtk_disable_comments inline bool is_comment_start(details::char_cptr itr) const { 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) const { return false; } #endif inline void skip_whitespace() { while (!is_end(s_itr_) && details::is_whitespace(*s_itr_)) { ++s_itr_; } } inline void skip_comments() { #ifndef exprtk_disable_comments // The following comment styles are supported: // 1. // .... \n // 2. # .... \n // 3. /* .... */ struct test { 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; } else if ('/' == c0) { if ('/' == c1) { mode = 1; incr = 2; } else if ('*' == c1) { mode = 2; incr = 2; } } return (0 != mode); } static inline bool comment_end(const char_t c0, const char_t c1, int& mode) { if ( ((1 == mode) && ('\n' == c0)) || ((2 == mode) && ( '*' == c0) && ('/' == c1)) ) { mode = 0; return true; } else return false; } }; int mode = 0; int increment = 0; if (is_end(s_itr_)) return; 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_)) { 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 (2 == mode) { 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() { 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_)) { scan_operator(); return; } else if (details::is_letter(*s_itr_)) { scan_symbol(); return; } else if (details::is_digit((*s_itr_)) || ('.' == (*s_itr_))) { scan_number(); return; } else if ('$' == (*s_itr_)) { scan_special_function(); return; } #ifndef exprtk_disable_string_capabilities else if ('\'' == (*s_itr_)) { scan_string(); return; } #endif else if ('~' == (*s_itr_)) { token_t t; t.set_symbol(s_itr_, s_itr_ + 1, base_itr_); token_list_.push_back(t); ++s_itr_; return; } else { token_t t; t.set_error(token::e_error, s_itr_, s_itr_ + 2, base_itr_); token_list_.push_back(t); ++s_itr_; } } inline void scan_operator() { token_t t; const char_t c0 = s_itr_[0]; if (!is_end(s_itr_ + 1)) { const char_t c1 = s_itr_[1]; if (!is_end(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_); token_list_.push_back(t); s_itr_ += 3; return; } } token_t::token_type ttype = token_t::e_none; if ((c0 == '<') && (c1 == '=')) ttype = token_t::e_lte; else if ((c0 == '>') && (c1 == '=')) ttype = token_t::e_gte; else if ((c0 == '<') && (c1 == '>')) ttype = token_t::e_ne; else if ((c0 == '!') && (c1 == '=')) ttype = token_t::e_ne; else if ((c0 == '=') && (c1 == '=')) ttype = token_t::e_eq; else if ((c0 == ':') && (c1 == '=')) ttype = token_t::e_assign; else if ((c0 == '<') && (c1 == '<')) ttype = token_t::e_shl; else if ((c0 == '>') && (c1 == '>')) ttype = token_t::e_shr; else if ((c0 == '+') && (c1 == '=')) ttype = token_t::e_addass; else if ((c0 == '-') && (c1 == '=')) ttype = token_t::e_subass; else if ((c0 == '*') && (c1 == '=')) ttype = token_t::e_mulass; else if ((c0 == '/') && (c1 == '=')) ttype = token_t::e_divass; else if ((c0 == '%') && (c1 == '=')) ttype = token_t::e_modass; if (token_t::e_none != ttype) { t.set_operator(ttype, s_itr_, s_itr_ + 2, base_itr_); token_list_.push_back(t); s_itr_ += 2; return; } } if ('<' == c0) 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_); else if (';' == c0) 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_); else if ('|' == c0) 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_); token_list_.push_back(t); ++s_itr_; } inline void scan_symbol() { details::char_cptr initial_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_; } token_t t; t.set_symbol(initial_itr,s_itr_,base_itr_); token_list_.push_back(t); } inline void scan_number() { /* Attempt to match a valid numeric value in one of the following formats: (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 */ 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_)) { if ('.' == (*s_itr_)) { if (dot_found) { t.set_error(token::e_err_number, initial_itr, s_itr_, base_itr_); token_list_.push_back(t); return; } dot_found = true; ++s_itr_; continue; } else if ('e' == std::tolower(*s_itr_)) { 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_); token_list_.push_back(t); return; } else if ( ('+' != c) && ('-' != c) && !details::is_digit(c) ) { t.set_error(token::e_err_number, initial_itr, s_itr_, base_itr_); token_list_.push_back(t); return; } e_found = true; ++s_itr_; continue; } 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_); token_list_.push_back(t); return; } 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_)) break; else ++s_itr_; } t.set_numeric(initial_itr, s_itr_, base_itr_); token_list_.push_back(t); return; } inline void scan_special_function() { 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, std::min(initial_itr + 11, s_end_), base_itr_); token_list_.push_back(t); return; } if ( !(('$' == *s_itr_) && (details::imatch ('f',*(s_itr_ + 1))) && (details::is_digit(*(s_itr_ + 2))) && (details::is_digit(*(s_itr_ + 3)))) ) { t.set_error( token::e_err_sfunc, initial_itr, std::min(initial_itr + 4, s_end_), base_itr_); token_list_.push_back(t); return; } s_itr_ += 4; // $fdd = 4chars t.set_symbol(initial_itr, s_itr_, base_itr_); token_list_.push_back(t); return; } #ifndef exprtk_disable_string_capabilities inline void scan_string() { details::char_cptr initial_itr = s_itr_ + 1; token_t t; if (std::distance(s_itr_,s_end_) < 2) { t.set_error(token::e_err_string, s_itr_, s_end_, base_itr_); token_list_.push_back(t); return; } ++s_itr_; bool escaped_found = false; bool escaped = false; while (!is_end(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; ++s_itr_; continue; } else if (!escaped) { if ('\'' == *s_itr_) break; } else if (escaped) { if ( !is_end(s_itr_) && ('0' == *(s_itr_)) && ((s_itr_ + 4) <= s_end_) ) { 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_); token_list_.push_back(t); return; } else s_itr_ += 3; } escaped = false; } ++s_itr_; } if (is_end(s_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_); else { std::string parsed_string(initial_itr,s_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); ++s_itr_; return; } #endif private: 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; friend class token_inserter; friend class token_joiner; }; // class generator class helper_interface { public: virtual void init() { } virtual void reset() { } virtual bool result() { return true; } virtual std::size_t process(generator&) { return 0; } virtual ~helper_interface() { } }; class token_scanner : public helper_interface { public: virtual ~token_scanner() {} explicit token_scanner(const std::size_t& stride) : stride_(stride) { if (stride > 4) { throw std::invalid_argument("token_scanner() - Invalid stride value"); } } inline std::size_t process(generator& g) exprtk_override { if (g.token_list_.size() >= stride_) { for (std::size_t i = 0; i < (g.token_list_.size() - stride_ + 1); ++i) { token t; switch (stride_) { case 1 : { const token& t0 = g.token_list_[i]; if (!operator()(t0)) { return i; } } break; case 2 : { const token& t0 = g.token_list_[i ]; const token& t1 = g.token_list_[i + 1]; if (!operator()(t0, t1)) { return i; } } break; case 3 : { const token& t0 = g.token_list_[i ]; const token& t1 = g.token_list_[i + 1]; const token& t2 = g.token_list_[i + 2]; if (!operator()(t0, t1, t2)) { return i; } } break; case 4 : { const token& t0 = g.token_list_[i ]; const token& t1 = g.token_list_[i + 1]; const token& t2 = g.token_list_[i + 2]; const token& t3 = g.token_list_[i + 3]; if (!operator()(t0, t1, t2, t3)) { return i; } } break; } } } return (g.token_list_.size() - stride_ + 1); } virtual bool operator() (const token&) { return false; } virtual bool operator() (const token&, const token&) { return false; } virtual bool operator() (const token&, const token&, const token&) { return false; } virtual bool operator() (const token&, const token&, const token&, const token&) { return false; } private: const std::size_t stride_; }; // class token_scanner class token_modifier : public helper_interface { public: inline std::size_t process(generator& g) exprtk_override { std::size_t changes = 0; for (std::size_t i = 0; i < g.token_list_.size(); ++i) { if (modify(g.token_list_[i])) changes++; } return changes; } virtual bool modify(token& t) = 0; }; class token_inserter : public helper_interface { public: explicit token_inserter(const std::size_t& stride) : stride_(stride) { if (stride > 5) { throw std::invalid_argument("token_inserter() - Invalid stride value"); } } inline std::size_t process(generator& g) exprtk_override { if (g.token_list_.empty()) return 0; else if (g.token_list_.size() < stride_) return 0; 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; token t; switch (stride_) { 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); break; 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); 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); break; } if ((insert_index >= 0) && (insert_index <= (static_cast(stride_) + 1))) { 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; } #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&) token_inserter_empty_body inline virtual int insert(const token&, const token&, const token&, token&) token_inserter_empty_body inline virtual int insert(const token&, const token&, const token&, const token&, token&) token_inserter_empty_body inline virtual int insert(const token&, const token&, const token&, const token&, const token&, token&) token_inserter_empty_body #undef token_inserter_empty_body private: const std::size_t stride_; }; class token_joiner : public helper_interface { public: explicit token_joiner(const std::size_t& stride) : stride_(stride) {} inline std::size_t process(generator& g) exprtk_override { if (g.token_list_.empty()) return 0; switch (stride_) { case 2 : return process_stride_2(g); case 3 : return process_stride_3(g); default : return 0; } } virtual bool join(const token&, const token&, token&) { return false; } virtual bool join(const token&, const token&, const token&, token&) { return false; } private: inline std::size_t process_stride_2(generator& g) { if (g.token_list_.size() < 2) return 0; std::size_t changes = 0; 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; for ( ; ; ) { 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() - 1)) break; } } token_list.push_back(g.token_list_.back()); assert(token_list.size() <= g.token_list_.size()); std::swap(token_list, g.token_list_); return changes; } inline std::size_t process_stride_3(generator& g) { if (g.token_list_.size() < 3) return 0; std::size_t changes = 0; 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; for ( ; ; ) { 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() - 2)) 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)); assert(token_list.size() <= g.token_list_.size()); std::swap(token_list, g.token_list_); return changes; } const std::size_t stride_; }; namespace helper { inline void dump(const lexer::generator& generator) { for (std::size_t i = 0; i < generator.size(); ++i) { const lexer::token& t = generator[i]; printf("Token[%02d] @ %03d %6s --> '%s'\n", static_cast(i), static_cast(t.position), t.to_str(t.type).c_str(), t.value.c_str()); } } class commutative_inserter : public lexer::token_inserter { public: using lexer::token_inserter::insert; commutative_inserter() : lexer::token_inserter(2) {} inline void ignore_symbol(const std::string& symbol) { ignore_set_.insert(symbol); } inline int insert(const lexer::token& t0, const lexer::token& t1, lexer::token& new_token) { bool match = false; new_token.type = lexer::token::e_mul; new_token.value = "*"; new_token.position = t1.position; if (t0.type == lexer::token::e_symbol) { if (ignore_set_.end() != ignore_set_.find(t0.value)) { return -1; } else if (!t0.value.empty() && ('$' == t0.value[0])) { return -1; } } if (t1.type == lexer::token::e_symbol) { if (ignore_set_.end() != ignore_set_.find(t1.value)) { return -1; } } if ((t0.type == lexer::token::e_number ) && (t1.type == lexer::token::e_symbol )) match = true; else if ((t0.type == lexer::token::e_number ) && (t1.type == lexer::token::e_lbracket )) match = true; else if ((t0.type == lexer::token::e_number ) && (t1.type == lexer::token::e_lcrlbracket)) match = true; else if ((t0.type == lexer::token::e_number ) && (t1.type == lexer::token::e_lsqrbracket)) match = true; else if ((t0.type == lexer::token::e_symbol ) && (t1.type == lexer::token::e_number )) match = true; else if ((t0.type == lexer::token::e_rbracket ) && (t1.type == lexer::token::e_number )) match = true; else if ((t0.type == lexer::token::e_rcrlbracket) && (t1.type == lexer::token::e_number )) match = true; else if ((t0.type == lexer::token::e_rsqrbracket) && (t1.type == lexer::token::e_number )) match = true; 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; } private: std::set ignore_set_; }; class operator_joiner : public token_joiner { public: explicit operator_joiner(const std::size_t& stride) : token_joiner(stride) {} inline bool join(const lexer::token& t0, const lexer::token& t1, lexer::token& t) { // ': =' --> ':=' if ((t0.type == lexer::token::e_colon) && (t1.type == lexer::token::e_eq)) { t.type = lexer::token::e_assign; t.value = ":="; t.position = t0.position; return true; } // '+ =' --> '+=' else if ((t0.type == lexer::token::e_add) && (t1.type == lexer::token::e_eq)) { t.type = lexer::token::e_addass; t.value = "+="; t.position = t0.position; return true; } // '- =' --> '-=' else if ((t0.type == lexer::token::e_sub) && (t1.type == lexer::token::e_eq)) { t.type = lexer::token::e_subass; t.value = "-="; t.position = t0.position; return true; } // '* =' --> '*=' else if ((t0.type == lexer::token::e_mul) && (t1.type == lexer::token::e_eq)) { t.type = lexer::token::e_mulass; t.value = "*="; t.position = t0.position; return true; } // '/ =' --> '/=' else if ((t0.type == lexer::token::e_div) && (t1.type == lexer::token::e_eq)) { t.type = lexer::token::e_divass; t.value = "/="; t.position = t0.position; return true; } // '% =' --> '%=' else if ((t0.type == lexer::token::e_mod) && (t1.type == lexer::token::e_eq)) { t.type = lexer::token::e_modass; t.value = "%="; t.position = t0.position; return true; } // '> =' --> '>=' else if ((t0.type == lexer::token::e_gt) && (t1.type == lexer::token::e_eq)) { t.type = lexer::token::e_gte; t.value = ">="; t.position = t0.position; return true; } // '< =' --> '<=' else if ((t0.type == lexer::token::e_lt) && (t1.type == lexer::token::e_eq)) { t.type = lexer::token::e_lte; t.value = "<="; t.position = t0.position; return true; } // '= =' --> '==' else if ((t0.type == lexer::token::e_eq) && (t1.type == lexer::token::e_eq)) { t.type = lexer::token::e_eq; t.value = "=="; t.position = t0.position; return true; } // '! =' --> '!=' else if ((static_cast(t0.type) == '!') && (t1.type == lexer::token::e_eq)) { t.type = lexer::token::e_ne; t.value = "!="; t.position = t0.position; return true; } // '< >' --> '<>' else if ((t0.type == lexer::token::e_lt) && (t1.type == lexer::token::e_gt)) { t.type = lexer::token::e_ne; t.value = "<>"; t.position = t0.position; return true; } // '<= >' --> '<=>' else if ((t0.type == lexer::token::e_lte) && (t1.type == lexer::token::e_gt)) { 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 return false; } inline bool join(const lexer::token& t0, const lexer::token& t1, const lexer::token& t2, lexer::token& t) { // '[ * ]' --> '[*]' if ( (t0.type == lexer::token::e_lsqrbracket) && (t1.type == lexer::token::e_mul ) && (t2.type == lexer::token::e_rsqrbracket) ) { t.type = lexer::token::e_symbol; t.value = "[*]"; t.position = t0.position; return true; } else return false; } }; class bracket_checker : public lexer::token_scanner { public: using lexer::token_scanner::operator(); bracket_checker() : token_scanner(1) , state_(true) {} bool result() { if (!stack_.empty()) { lexer::token t; t.value = stack_.top().first; t.position = stack_.top().second; error_token_ = t; state_ = false; return false; } else return state_; } lexer::token error_token() { return error_token_; } void reset() { // Why? because msvc doesn't support swap properly. stack_ = std::stack >(); state_ = true; error_token_.clear(); } bool operator() (const lexer::token& t) { if ( !t.value.empty() && (lexer::token::e_string != t.type) && (lexer::token::e_symbol != t.type) && exprtk::details::is_bracket(t.value[0]) ) { details::char_t c = t.value[0]; 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; error_token_ = t; return false; } else if (c != stack_.top().first) { state_ = false; error_token_ = t; return false; } else stack_.pop(); } } return true; } private: bool state_; std::stack > stack_; lexer::token error_token_; }; class numeric_checker : public lexer::token_scanner { public: using lexer::token_scanner::operator(); numeric_checker() : token_scanner (1) , current_index_(0) {} bool result() { return error_list_.empty(); } void reset() { error_list_.clear(); current_index_ = 0; } bool operator() (const lexer::token& t) { if (token::e_number == t.type) { double v; if (!exprtk::details::string_to_real(t.value,v)) { error_list_.push_back(current_index_); } } ++current_index_; return true; } std::size_t error_count() const { return error_list_.size(); } std::size_t error_index(const std::size_t& i) { if (i < error_list_.size()) return error_list_[i]; else return std::numeric_limits::max(); } void clear_errors() { error_list_.clear(); } private: std::size_t current_index_; std::vector error_list_; }; class symbol_replacer : public lexer::token_modifier { private: typedef std::map,details::ilesscompare> replace_map_t; public: bool remove(const std::string& target_symbol) { const replace_map_t::iterator itr = replace_map_.find(target_symbol); if (replace_map_.end() == itr) return false; replace_map_.erase(itr); return true; } bool add_replace(const std::string& target_symbol, const std::string& replace_symbol, const lexer::token::token_type token_type = lexer::token::e_symbol) { const replace_map_t::iterator itr = replace_map_.find(target_symbol); if (replace_map_.end() != itr) { return false; } replace_map_[target_symbol] = std::make_pair(replace_symbol,token_type); return true; } void clear() { replace_map_.clear(); } private: bool modify(lexer::token& t) { if (lexer::token::e_symbol == t.type) { if (replace_map_.empty()) return false; const replace_map_t::iterator itr = replace_map_.find(t.value); if (replace_map_.end() != itr) { t.value = itr->second.first; t.type = itr->second.second; return true; } } return false; } replace_map_t replace_map_; }; class sequence_validator : public lexer::token_scanner { private: typedef std::pair token_pair_t; typedef std::set set_t; 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_set1(lexer::token::e_assign ); add_invalid_set1(lexer::token::e_shr ); add_invalid_set1(lexer::token::e_shl ); add_invalid_set1(lexer::token::e_lte ); add_invalid_set1(lexer::token::e_ne ); add_invalid_set1(lexer::token::e_gte ); add_invalid_set1(lexer::token::e_lt ); add_invalid_set1(lexer::token::e_gt ); add_invalid_set1(lexer::token::e_eq ); add_invalid_set1(lexer::token::e_comma ); add_invalid_set1(lexer::token::e_add ); add_invalid_set1(lexer::token::e_sub ); add_invalid_set1(lexer::token::e_div ); add_invalid_set1(lexer::token::e_mul ); add_invalid_set1(lexer::token::e_mod ); add_invalid_set1(lexer::token::e_pow ); add_invalid_set1(lexer::token::e_colon ); add_invalid_set1(lexer::token::e_ternary); } bool result() { return error_list_.empty(); } bool operator() (const lexer::token& t0, const lexer::token& t1) { const set_t::value_type p = std::make_pair(t0.type,t1.type); if (invalid_bracket_check(t0.type,t1.type)) { error_list_.push_back(std::make_pair(t0,t1)); } else if (invalid_comb_.find(p) != invalid_comb_.end()) { error_list_.push_back(std::make_pair(t0,t1)); } return true; } std::size_t error_count() const { return error_list_.size(); } std::pair error(const std::size_t index) { if (index < error_list_.size()) { return error_list_[index]; } else { static const lexer::token error_token; return std::make_pair(error_token,error_token); } } void clear_errors() { error_list_.clear(); } private: void add_invalid(const lexer::token::token_type base, const lexer::token::token_type t) { invalid_comb_.insert(std::make_pair(base,t)); } void add_invalid_set1(const 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 ); } bool invalid_bracket_check(const lexer::token::token_type base, const lexer::token::token_type t) { if (details::is_right_bracket(static_cast(base))) { switch (t) { case lexer::token::e_assign : return (']' != base); case lexer::token::e_string : return (')' != base); default : return false; } } else if (details::is_left_bracket(static_cast(base))) { if (details::is_right_bracket(static_cast(t))) return false; else if (details::is_left_bracket(static_cast(t))) return false; else { switch (t) { case lexer::token::e_number : return false; case lexer::token::e_symbol : return false; case lexer::token::e_string : return false; case lexer::token::e_add : return false; case lexer::token::e_sub : return false; case lexer::token::e_colon : return false; case lexer::token::e_ternary : return false; default : return true ; } } } else if (details::is_right_bracket(static_cast(t))) { switch (base) { case lexer::token::e_number : return false; case lexer::token::e_symbol : return false; case lexer::token::e_string : return false; case lexer::token::e_eof : return false; case lexer::token::e_colon : return false; case lexer::token::e_ternary : return false; default : return true ; } } else if (details::is_left_bracket(static_cast(t))) { switch (base) { case lexer::token::e_rbracket : return true; case lexer::token::e_rsqrbracket : return true; case lexer::token::e_rcrlbracket : return true; default : return false; } } return false; } set_t invalid_comb_; std::vector > error_list_; }; class sequence_validator_3tokens : public lexer::token_scanner { private: typedef lexer::token::token_type token_t; typedef std::pair > token_triplet_t; typedef std::set set_t; public: using lexer::token_scanner::operator(); sequence_validator_3tokens() : lexer::token_scanner(3) { add_invalid(lexer::token::e_number , lexer::token::e_number , lexer::token::e_number); add_invalid(lexer::token::e_string , lexer::token::e_string , lexer::token::e_string); add_invalid(lexer::token::e_comma , lexer::token::e_comma , lexer::token::e_comma ); add_invalid(lexer::token::e_add , lexer::token::e_add , lexer::token::e_add ); add_invalid(lexer::token::e_sub , lexer::token::e_sub , lexer::token::e_sub ); add_invalid(lexer::token::e_div , lexer::token::e_div , lexer::token::e_div ); add_invalid(lexer::token::e_mul , lexer::token::e_mul , lexer::token::e_mul ); add_invalid(lexer::token::e_mod , lexer::token::e_mod , lexer::token::e_mod ); add_invalid(lexer::token::e_pow , lexer::token::e_pow , lexer::token::e_pow ); add_invalid(lexer::token::e_add , lexer::token::e_sub , lexer::token::e_add ); add_invalid(lexer::token::e_sub , lexer::token::e_add , lexer::token::e_sub ); add_invalid(lexer::token::e_div , lexer::token::e_mul , lexer::token::e_div ); add_invalid(lexer::token::e_mul , lexer::token::e_div , lexer::token::e_mul ); add_invalid(lexer::token::e_mod , lexer::token::e_pow , lexer::token::e_mod ); add_invalid(lexer::token::e_pow , lexer::token::e_mod , lexer::token::e_pow ); } bool result() { return error_list_.empty(); } bool operator() (const lexer::token& t0, const lexer::token& t1, const lexer::token& t2) { const set_t::value_type p = std::make_pair(t0.type,std::make_pair(t1.type,t2.type)); if (invalid_comb_.find(p) != invalid_comb_.end()) { error_list_.push_back(std::make_pair(t0,t1)); } return true; } std::size_t error_count() const { return error_list_.size(); } std::pair error(const std::size_t index) { if (index < error_list_.size()) { return error_list_[index]; } else { static const lexer::token error_token; return std::make_pair(error_token,error_token); } } void clear_errors() { error_list_.clear(); } private: void add_invalid(const token_t t0, const token_t t1, const 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 (), 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 (), 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 (), inserter)) { return false; } token_inserter_list.push_back(inserter); return true; } inline bool run_modifiers(lexer::generator& g) { error_token_modifier = reinterpret_cast(0); for (std::size_t i = 0; i < token_modifier_list.size(); ++i) { lexer::token_modifier& modifier = (*token_modifier_list[i]); modifier.reset(); modifier.process(g); if (!modifier.result()) { error_token_modifier = token_modifier_list[i]; return false; } } return true; } inline bool run_joiners(lexer::generator& g) { error_token_joiner = reinterpret_cast(0); for (std::size_t i = 0; i < token_joiner_list.size(); ++i) { lexer::token_joiner& joiner = (*token_joiner_list[i]); joiner.reset(); joiner.process(g); if (!joiner.result()) { error_token_joiner = token_joiner_list[i]; return false; } } return true; } inline bool run_inserters(lexer::generator& g) { error_token_inserter = reinterpret_cast(0); for (std::size_t i = 0; i < token_inserter_list.size(); ++i) { lexer::token_inserter& inserter = (*token_inserter_list[i]); inserter.reset(); inserter.process(g); if (!inserter.result()) { error_token_inserter = token_inserter_list[i]; return false; } } return true; } inline bool run_scanners(lexer::generator& g) { error_token_scanner = reinterpret_cast(0); for (std::size_t i = 0; i < token_scanner_list.size(); ++i) { lexer::token_scanner& scanner = (*token_scanner_list[i]); scanner.reset(); scanner.process(g); if (!scanner.result()) { error_token_scanner = token_scanner_list[i]; return false; } } return true; } std::vector token_scanner_list; std::vector token_modifier_list; std::vector token_joiner_list; std::vector token_inserter_list; lexer::token_scanner* error_token_scanner; lexer::token_modifier* error_token_modifier; lexer::token_joiner* error_token_joiner; 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_string }; type_store() : data(0) , size(0) , type(e_unknown) {} union { void* data; T* vec_data; }; std::size_t size; store_type type; class parameter_list { public: explicit parameter_list(std::vector& pl) : parameter_list_(pl) {} inline bool empty() const { return parameter_list_.empty(); } inline std::size_t size() const { return parameter_list_.size(); } inline type_store& operator[](const std::size_t& index) { return parameter_list_[index]; } inline const type_store& operator[](const std::size_t& index) const { return parameter_list_[index]; } inline type_store& front() { return parameter_list_[0]; } inline const type_store& front() const { return parameter_list_[0]; } inline type_store& back() { return parameter_list_.back(); } inline const type_store& back() const { return parameter_list_.back(); } private: std::vector& parameter_list_; friend class results_context; }; template struct type_view { typedef type_store type_store_t; typedef ViewType value_t; 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; } inline value_t& operator[](const std::size_t& i) { return data_[i]; } inline const value_t& operator[](const std::size_t& i) const { return data_[i]; } inline const value_t* begin() const { return data_; } inline value_t* begin() { return data_; } 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_; }; typedef type_view vector_view; typedef type_view string_view; struct scalar_view { typedef type_store type_store_t; typedef T value_t; explicit scalar_view(type_store_t& ts) : v_(*reinterpret_cast(ts.data)) {} explicit scalar_view(const type_store_t& ts) : v_(*reinterpret_cast(const_cast(ts).data)) {} inline value_t& operator() () { return v_; } 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_; }; }; template inline std::string to_str(const StringView& view) { 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 { e_default , e_null , e_add , e_sub , e_mul , e_div , e_mod , e_pow , e_atan2 , e_min , e_max , e_avg , e_sum , e_prod , e_lt , e_lte , e_eq , e_equal , e_ne , e_nequal , e_gte , e_gt , e_and , e_nand , e_or , e_nor , e_xor , e_xnor , e_mand , e_mor , e_scand , e_scor , e_shr , e_shl , 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_logn , e_neg , e_pos , e_round , e_roundn , e_root , e_sqrt , e_sin , e_sinc , e_sinh , e_sec , e_csc , e_tan , e_tanh , e_cot , e_clamp , e_iclamp , e_inrange , e_sgn , e_r2d , e_d2r , e_d2g , e_g2d , e_hypot , e_notl , 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_smulti , e_swap , // Do not add new functions/operators after this point. e_sf00 = 1000, e_sf01 = 1001, e_sf02 = 1002, e_sf03 = 1003, e_sf04 = 1004, e_sf05 = 1005, e_sf06 = 1006, e_sf07 = 1007, e_sf08 = 1008, e_sf09 = 1009, e_sf10 = 1010, e_sf11 = 1011, e_sf12 = 1012, e_sf13 = 1013, e_sf14 = 1014, e_sf15 = 1015, e_sf16 = 1016, e_sf17 = 1017, e_sf18 = 1018, e_sf19 = 1019, e_sf20 = 1020, e_sf21 = 1021, e_sf22 = 1022, e_sf23 = 1023, e_sf24 = 1024, e_sf25 = 1025, e_sf26 = 1026, e_sf27 = 1027, e_sf28 = 1028, e_sf29 = 1029, e_sf30 = 1030, e_sf31 = 1031, e_sf32 = 1032, e_sf33 = 1033, e_sf34 = 1034, e_sf35 = 1035, e_sf36 = 1036, e_sf37 = 1037, e_sf38 = 1038, e_sf39 = 1039, e_sf40 = 1040, e_sf41 = 1041, e_sf42 = 1042, e_sf43 = 1043, e_sf44 = 1044, e_sf45 = 1045, e_sf46 = 1046, e_sf47 = 1047, e_sf48 = 1048, e_sf49 = 1049, e_sf50 = 1050, e_sf51 = 1051, e_sf52 = 1052, e_sf53 = 1053, e_sf54 = 1054, e_sf55 = 1055, e_sf56 = 1056, e_sf57 = 1057, e_sf58 = 1058, e_sf59 = 1059, e_sf60 = 1060, e_sf61 = 1061, e_sf62 = 1062, e_sf63 = 1063, e_sf64 = 1064, e_sf65 = 1065, e_sf66 = 1066, e_sf67 = 1067, e_sf68 = 1068, e_sf69 = 1069, e_sf70 = 1070, e_sf71 = 1071, e_sf72 = 1072, e_sf73 = 1073, e_sf74 = 1074, e_sf75 = 1075, e_sf76 = 1076, e_sf77 = 1077, e_sf78 = 1078, e_sf79 = 1079, e_sf80 = 1080, e_sf81 = 1081, e_sf82 = 1082, e_sf83 = 1083, e_sf84 = 1084, e_sf85 = 1085, e_sf86 = 1086, e_sf87 = 1087, e_sf88 = 1088, e_sf89 = 1089, e_sf90 = 1090, e_sf91 = 1091, e_sf92 = 1092, e_sf93 = 1093, e_sf94 = 1094, e_sf95 = 1095, e_sf96 = 1096, e_sf97 = 1097, e_sf98 = 1098, e_sf99 = 1099, e_sffinal = 1100, e_sf4ext00 = 2000, e_sf4ext01 = 2001, e_sf4ext02 = 2002, e_sf4ext03 = 2003, e_sf4ext04 = 2004, e_sf4ext05 = 2005, e_sf4ext06 = 2006, e_sf4ext07 = 2007, e_sf4ext08 = 2008, e_sf4ext09 = 2009, e_sf4ext10 = 2010, e_sf4ext11 = 2011, e_sf4ext12 = 2012, e_sf4ext13 = 2013, e_sf4ext14 = 2014, e_sf4ext15 = 2015, e_sf4ext16 = 2016, e_sf4ext17 = 2017, e_sf4ext18 = 2018, e_sf4ext19 = 2019, e_sf4ext20 = 2020, e_sf4ext21 = 2021, e_sf4ext22 = 2022, e_sf4ext23 = 2023, e_sf4ext24 = 2024, e_sf4ext25 = 2025, e_sf4ext26 = 2026, e_sf4ext27 = 2027, e_sf4ext28 = 2028, e_sf4ext29 = 2029, e_sf4ext30 = 2030, e_sf4ext31 = 2031, e_sf4ext32 = 2032, e_sf4ext33 = 2033, e_sf4ext34 = 2034, e_sf4ext35 = 2035, e_sf4ext36 = 2036, e_sf4ext37 = 2037, e_sf4ext38 = 2038, e_sf4ext39 = 2039, e_sf4ext40 = 2040, e_sf4ext41 = 2041, e_sf4ext42 = 2042, e_sf4ext43 = 2043, 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_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) : type(t) , num_params(np) {} operator_type type; unsigned int num_params; }; namespace loop_unroll { #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 { 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&) exprtk_delete; control_block& operator=(const control_block&) exprtk_delete; 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() 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(const control_block* cb0, const 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) { case e_abs : return numeric::abs (arg); case e_acos : return numeric::acos (arg); case e_acosh : return numeric::acosh(arg); case e_asin : return numeric::asin (arg); case e_asinh : return numeric::asinh(arg); case e_atan : return numeric::atan (arg); case e_atanh : return numeric::atanh(arg); case e_ceil : return numeric::ceil (arg); case e_cos : return numeric::cos (arg); case e_cosh : return numeric::cosh (arg); case e_exp : return numeric::exp (arg); case e_expm1 : return numeric::expm1(arg); case e_floor : return numeric::floor(arg); case e_log : return numeric::log (arg); case e_log10 : return numeric::log10(arg); case e_log2 : return numeric::log2 (arg); case e_log1p : return numeric::log1p(arg); case e_neg : return numeric::neg (arg); case e_pos : return numeric::pos (arg); case e_round : return numeric::round(arg); case e_sin : return numeric::sin (arg); case e_sinc : return numeric::sinc (arg); case e_sinh : return numeric::sinh (arg); case e_sqrt : return numeric::sqrt (arg); case e_tan : return numeric::tan (arg); case e_tanh : return numeric::tanh (arg); case e_cot : return numeric::cot (arg); case e_sec : return numeric::sec (arg); case e_csc : return numeric::csc (arg); case e_r2d : return numeric::r2d (arg); case e_d2r : return numeric::d2r (arg); case e_d2g : return numeric::d2g (arg); case e_g2d : return numeric::g2d (arg); case e_notl : return numeric::notl (arg); case e_sgn : return numeric::sgn (arg); case e_erf : return numeric::erf (arg); case e_erfc : return numeric::erfc (arg); case e_ncdf : return numeric::ncdf (arg); case e_frac : return numeric::frac (arg); case e_trunc : return numeric::trunc(arg); default : exprtk_debug(("numeric::details::process_impl - Invalid unary operation.\n")); return std::numeric_limits::quiet_NaN(); } } template inline T process_impl(const operator_type operation, const T arg0, const T arg1) { switch (operation) { case e_add : return (arg0 + arg1); case e_sub : return (arg0 - arg1); case e_mul : return (arg0 * arg1); case e_div : return (arg0 / arg1); case e_mod : return modulus(arg0,arg1); case e_pow : return pow(arg0,arg1); case e_atan2 : return atan2(arg0,arg1); case e_min : return std::min(arg0,arg1); case e_max : return std::max(arg0,arg1); case e_logn : return logn(arg0,arg1); case e_lt : return (arg0 < arg1) ? T(1) : T(0); case e_lte : return (arg0 <= arg1) ? T(1) : T(0); case e_eq : return std::equal_to()(arg0,arg1) ? T(1) : T(0); 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_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_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 : exprtk_debug(("numeric::details::process_impl - Invalid binary operation.\n")); return std::numeric_limits::quiet_NaN(); } } template inline T process_impl(const operator_type operation, const T arg0, const T arg1, int_type_tag) { switch (operation) { case e_add : return (arg0 + arg1); case e_sub : return (arg0 - arg1); case e_mul : return (arg0 * arg1); case e_div : return (arg0 / arg1); case e_mod : return arg0 % arg1; case e_pow : return pow(arg0,arg1); case e_min : return std::min(arg0,arg1); case e_max : return std::max(arg0,arg1); case e_logn : return logn(arg0,arg1); case e_lt : return (arg0 < arg1) ? T(1) : T(0); case e_lte : return (arg0 <= arg1) ? T(1) : T(0); case e_eq : return (arg0 == arg1) ? T(1) : T(0); case e_ne : return (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 ((arg0 != T(0)) && (arg1 != T(0))) ? T(1) : T(0); case e_nand : return ((arg0 != T(0)) && (arg1 != T(0))) ? T(0) : T(1); case e_or : return ((arg0 != T(0)) || (arg1 != T(0))) ? T(1) : T(0); case e_nor : return ((arg0 != T(0)) || (arg1 != T(0))) ? T(0) : T(1); case e_xor : return arg0 ^ arg1; case e_xnor : return !(arg0 ^ arg1); case e_root : return root(arg0,arg1); case e_equal : return arg0 == arg1; case e_nequal : return arg0 != arg1; case e_hypot : return hypot(arg0,arg1); case e_shr : return arg0 >> arg1; case e_shl : return arg0 << arg1; default : exprtk_debug(("numeric::details::process_impl - Invalid binary operation.\n")); return std::numeric_limits::quiet_NaN(); } } } template inline T process(const operator_type operation, const T arg) { return exprtk::details::numeric::details::process_impl(operation,arg); } template inline T process(const operator_type operation, const T arg0, const T 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 : public node_collector_interface >, public node_depth_base > { public: enum node_type { e_none , e_null , e_constant , e_unary , e_binary , e_binary_ext , e_trinary , e_quaternary , e_vararg , e_conditional , e_while , e_repeat , e_for , e_switch , e_mswitch , e_return , e_retenv , e_variable , e_stringvar , e_stringconst , e_stringvarrng , e_cstringvarrng , e_strgenrange , e_strconcat , e_stringvarsize , e_strswap , e_stringsize , e_stringvararg , e_function , e_vafunction , e_genfunction , e_strfunction , e_strcondition , e_strccondition , e_add , e_sub , e_mul , e_div , e_mod , e_pow , e_lt , e_lte , e_gt , e_gte , e_eq , e_ne , e_and , e_nand , e_or , e_nor , e_xor , e_xnor , e_in , e_like , e_ilike , e_inranges , e_ipow , e_ipowinv , e_abs , e_acos , e_acosh , e_asin , e_asinh , e_atan , e_atanh , e_ceil , e_cos , e_cosh , e_exp , e_expm1 , e_floor , e_log , e_log10 , e_log2 , e_log1p , e_neg , e_pos , e_round , e_sin , e_sinc , e_sinh , e_sqrt , e_tan , e_tanh , e_cot , e_sec , e_csc , e_r2d , e_d2r , e_d2g , e_g2d , e_notl , e_sgn , e_erf , e_erfc , e_ncdf , e_frac , e_trunc , e_uvouv , e_vov , e_cov , e_voc , e_vob , e_bov , e_cob , e_boc , e_vovov , e_vovoc , e_vocov , e_covov , e_covoc , e_vovovov , e_vovovoc , e_vovocov , e_vocovov , e_covovov , e_covocov , e_vocovoc , e_covovoc , e_vococov , e_sf3ext , e_sf4ext , e_nulleq , e_strass , e_vector , e_vecelem , e_rbvecelem , e_rbveccelem , e_vecdefass , e_vecvalass , e_vecvecass , e_vecopvalass , e_vecopvecass , e_vecfunc , e_vecvecswap , e_vecvecineq , e_vecvalineq , e_valvecineq , e_vecvecarith , e_vecvalarith , e_valvecarith , e_vecunaryop , e_vecondition , 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() {} inline virtual T value() const { return std::numeric_limits::quiet_NaN(); } inline virtual expression_node* branch(const std::size_t& index = 0) const { return reinterpret_cast(index * 0); } inline virtual node_type type() const { return e_none; } }; // class expression_node template inline bool is_generally_string_node(const expression_node* node); inline bool is_true(const double v) { return std::not_equal_to()(0.0,v); } inline bool is_true(const long double v) { return std::not_equal_to()(0.0L,v); } inline bool is_true(const float v) { 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) { return node && (details::expression_node::e_unary == node->type()); } template inline bool is_neg_unary_node(const expression_node* node) { return node && (details::expression_node::e_neg == node->type()); } template inline bool is_binary_node(const expression_node* node) { return node && (details::expression_node::e_binary == node->type()); } template inline bool is_variable_node(const expression_node* node) { return node && (details::expression_node::e_variable == node->type()); } template inline bool is_ivariable_node(const expression_node* node) { return node && ( 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() ); } template inline bool is_vector_elem_node(const expression_node* node) { 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) { return node && (details::expression_node::e_vector == node->type()); } template inline bool is_ivector_node(const expression_node* node) { if (node) { switch (node->type()) { case details::expression_node::e_vector : case details::expression_node::e_vecvalass : case details::expression_node::e_vecvecass : case details::expression_node::e_vecopvalass : case details::expression_node::e_vecopvecass : case details::expression_node::e_vecvecswap : case details::expression_node::e_vecvecarith : case details::expression_node::e_vecvalarith : case details::expression_node::e_valvecarith : case details::expression_node::e_vecunaryop : case details::expression_node::e_vecondition : return true; default : return false; } } else return false; } template inline bool is_constant_node(const expression_node* node) { return node && (details::expression_node::e_constant == node->type()); } template inline bool is_null_node(const expression_node* node) { return node && (details::expression_node::e_null == node->type()); } template inline bool is_break_node(const expression_node* node) { return node && (details::expression_node::e_break == node->type()); } template inline bool is_continue_node(const expression_node* node) { return node && (details::expression_node::e_continue == node->type()); } template inline bool is_swap_node(const expression_node* node) { return node && (details::expression_node::e_swap == node->type()); } template inline bool is_function(const expression_node* node) { 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 inline bool is_negate_node(const expression_node* node) { if (node && is_unary_node(node)) { return (details::e_neg == static_cast*>(node)->operation()); } else return false; } template inline bool branch_deletable(expression_node* node) { return (0 != node) && !is_variable_node(node) && !is_string_node (node) ; } template inline bool all_nodes_valid(expression_node* (&b)[N]) { for (std::size_t i = 0; i < N; ++i) { if (0 == b[i]) return false; } return true; } template class Sequence> inline bool all_nodes_valid(const Sequence*,Allocator>& b) { for (std::size_t i = 0; i < b.size(); ++i) { if (0 == b[i]) return false; } return true; } template inline bool all_nodes_variables(expression_node* (&b)[N]) { for (std::size_t i = 0; i < N; ++i) { if (0 == b[i]) return false; else if (!is_variable_node(b[i])) return false; } return true; } template class Sequence> inline bool all_nodes_variables(Sequence*,Allocator>& b) { for (std::size_t i = 0; i < b.size(); ++i) { if (0 == b[i]) return false; else if (!is_variable_node(b[i])) return false; } 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]) { for (std::size_t i = 0; i < N; ++i) { free_node(node_allocator,b[i]); } } template class Sequence> inline void free_all_nodes(NodeAllocator& node_allocator, Sequence*,Allocator>& b) { for (std::size_t i = 0; i < b.size(); ++i) { free_node(node_allocator,b[i]); } b.clear(); } template inline void free_node(NodeAllocator&, expression_node*& node) { if ((0 == node) || is_variable_node(node) || is_string_node(node)) { return; } node_collection_destructor > ::delete_nodes(node); } template inline void destroy_node(expression_node*& node) { if (0 != node) { node_collection_destructor > ::delete_nodes(node); } } template struct node_depth_base { typedef Node* node_ptr_t; typedef std::pair nb_pair_t; node_depth_base() : depth_set(false) , depth(0) {} virtual ~node_depth_base() {} virtual std::size_t node_depth() const { return 1; } std::size_t compute_node_depth(const Node* const& node) const { if (!depth_set) { depth = 1 + (node ? node->node_depth() : 0); depth_set = true; } return depth; } std::size_t compute_node_depth(const nb_pair_t& branch) const { if (!depth_set) { depth = 1 + (branch.first ? branch.first->node_depth() : 0); depth_set = true; } return depth; } template std::size_t compute_node_depth(const nb_pair_t (&branch)[N]) const { if (!depth_set) { depth = 0; for (std::size_t i = 0; i < N; ++i) { if (branch[i].first) { depth = std::max(depth,branch[i].first->node_depth()); } } depth += 1; depth_set = true; } return depth; } template std::size_t compute_node_depth(const BranchType& n0, const BranchType& n1) const { if (!depth_set) { depth = 1 + std::max(compute_node_depth(n0), compute_node_depth(n1)); depth_set = true; } return depth; } template std::size_t compute_node_depth(const BranchType& n0, const BranchType& n1, const BranchType& n2) const { if (!depth_set) { depth = 1 + std::max( std::max(compute_node_depth(n0), compute_node_depth(n1)), compute_node_depth(n2)); depth_set = true; } return depth; } template std::size_t compute_node_depth(const BranchType& n0, const BranchType& n1, const BranchType& n2, const BranchType& n3) const { if (!depth_set) { depth = 1 + std::max( std::max(compute_node_depth(n0), compute_node_depth(n1)), std::max(compute_node_depth(n2), compute_node_depth(n3))); depth_set = true; } return depth; } template class Sequence> std::size_t compute_node_depth(const Sequence& branch_list) const { if (!depth_set) { for (std::size_t i = 0; i < branch_list.size(); ++i) { if (branch_list[i]) { depth = std::max(depth, compute_node_depth(branch_list[i])); } } depth_set = true; } return depth; } template class Sequence> std::size_t compute_node_depth(const Sequence& 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_ptr_t 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 nb_pair_t& 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 nb_pair_t(&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& 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 { return size_; } private: array_vector_impl(const array_vector_impl&) exprtk_delete; array_vector_impl& operator=(const array_vector_impl&) exprtk_delete; const Type* vec_; const std::size_t size_; }; template class Sequence> class sequence_vector_impl : public vector_holder_base { public: typedef Sequence sequence_t; sequence_vector_impl(sequence_t& seq) : sequence_(seq) {} protected: value_ptr value_at(const std::size_t& index) const { return (index < sequence_.size()) ? (&sequence_[index]) : const_value_ptr(0); } std::size_t vector_size() const { return sequence_.size(); } private: sequence_vector_impl(const sequence_vector_impl&) exprtk_delete; sequence_vector_impl& operator=(const sequence_vector_impl&) exprtk_delete; 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(const vector_view_impl&) exprtk_delete; vector_view_impl& operator=(const vector_view_impl&) exprtk_delete; 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)) {} 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 { return (*vector_holder_base_)[index]; } inline std::size_t size() const { 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_; uchar_t buffer[64]; }; template class null_node exprtk_final : public expression_node { public: inline T value() const exprtk_override { return std::numeric_limits::quiet_NaN(); } inline typename expression_node::node_type type() const exprtk_override { return expression_node::e_null; } }; 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 exprtk_final : public expression_node { public: typedef expression_node* expression_ptr; typedef std::pair branch_t; explicit null_eq_node(expression_ptr branch, const bool equality = true) : equality_(equality) { construct_branch_pair(branch_, branch); } inline T value() const exprtk_override { assert(branch_.first); const T v = branch_.first->value(); const bool result = details::numeric::is_nan(v); if (result) return (equality_) ? T(1) : T(0); else return (equality_) ? T(0) : T(1); } inline typename expression_node::node_type type() const exprtk_override { return expression_node::e_nulleq; } inline expression_node* branch(const std::size_t&) const exprtk_override { return branch_.first; } void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override { expression_node::ndb_t::collect(branch_, node_delete_list); } std::size_t node_depth() const exprtk_override { return expression_node::ndb_t::compute_node_depth(branch_); } private: bool equality_; branch_t branch_; }; template class literal_node exprtk_final : public expression_node { public: explicit literal_node(const T& v) : value_(v) {} inline T value() const exprtk_override { return value_; } inline typename expression_node::node_type type() const exprtk_override { return expression_node::e_constant; } inline expression_node* branch(const std::size_t&) const exprtk_override { return reinterpret_cast*>(0); } private: literal_node(const literal_node&) exprtk_delete; literal_node& operator=(const literal_node&) exprtk_delete; const T value_; }; template struct range_pack; template struct range_data_type; template class range_interface { public: 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 { public: typedef range_data_type range_data_type_t; virtual ~string_base_node() {} virtual std::string str () const = 0; virtual char_cptr base() const = 0; virtual std::size_t size() const = 0; }; template class string_literal_node exprtk_final : public expression_node , public string_base_node, public range_interface { public: typedef range_pack range_t; explicit string_literal_node(const std::string& v) : value_(v) { rp_.n0_c = std::make_pair(true,0); rp_.n1_c = std::make_pair(true,v.size() - 1); rp_.cache.first = rp_.n0_c.second; rp_.cache.second = rp_.n1_c.second; } inline T value() const exprtk_override { return std::numeric_limits::quiet_NaN(); } inline typename expression_node::node_type type() const exprtk_override { return expression_node::e_stringconst; } inline expression_node* branch(const std::size_t&) const exprtk_override { return reinterpret_cast*>(0); } std::string str() const exprtk_override { return value_; } char_cptr base() const exprtk_override { return value_.data(); } std::size_t size() const exprtk_override { return value_.size(); } range_t& range_ref() exprtk_override { return rp_; } const range_t& range_ref() const exprtk_override { return rp_; } private: string_literal_node(const string_literal_node&) exprtk_delete; string_literal_node& operator=(const string_literal_node&) exprtk_delete; const std::string value_; range_t rp_; }; #endif template class unary_node : public expression_node { public: typedef expression_node* expression_ptr; typedef std::pair branch_t; unary_node(const operator_type& opr, expression_ptr branch) : operation_(opr) { construct_branch_pair(branch_,branch); } inline T value() const exprtk_override { assert(branch_.first); const T arg = branch_.first->value(); return numeric::process(operation_,arg); } inline typename expression_node::node_type type() const exprtk_override { return expression_node::e_unary; } inline operator_type operation() { return operation_; } inline expression_node* branch(const std::size_t&) const exprtk_override { return branch_.first; } inline void release() { branch_.second = false; } void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override { expression_node::ndb_t::collect(branch_, node_delete_list); } std::size_t node_depth() const exprtk_override exprtk_final { return expression_node::ndb_t::compute_node_depth(branch_); } protected: operator_type operation_; branch_t branch_; }; 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); } inline T value() const exprtk_override { 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); } inline typename expression_node::node_type type() const exprtk_override { return expression_node::e_binary; } inline operator_type operation() { return operation_; } inline expression_node* branch(const std::size_t& index = 0) const exprtk_override { if (0 == index) return branch_[0].first; else if (1 == index) return branch_[1].first; else return reinterpret_cast(0); } void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override { expression_node::ndb_t::template collect(branch_, node_delete_list); } std::size_t node_depth() const exprtk_override exprtk_final { return expression_node::ndb_t::template compute_node_depth<2>(branch_); } protected: operator_type operation_; branch_t branch_[2]; }; template class binary_ext_node exprtk_final : public expression_node { public: typedef expression_node* expression_ptr; typedef std::pair branch_t; binary_ext_node(expression_ptr branch0, expression_ptr branch1) { init_branches<2>(branch_, branch0, branch1); } inline T value() const exprtk_override { 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); } inline typename expression_node::node_type type() const exprtk_override { return expression_node::e_binary_ext; } inline operator_type operation() { return Operation::operation(); } inline expression_node* branch(const std::size_t& index = 0) const exprtk_override { if (0 == index) return branch_[0].first; else if (1 == index) return branch_[1].first; else return reinterpret_cast(0); } void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override { expression_node::ndb_t::template collect(branch_, node_delete_list); } std::size_t node_depth() const exprtk_override { return expression_node::ndb_t::template compute_node_depth<2>(branch_); } protected: branch_t branch_[2]; }; template class trinary_node : public expression_node { public: typedef expression_node* expression_ptr; typedef std::pair branch_t; trinary_node(const operator_type& opr, expression_ptr branch0, expression_ptr branch1, expression_ptr branch2) : operation_(opr) { init_branches<3>(branch_, branch0, branch1, branch2); } inline T value() const exprtk_override { 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(); switch (operation_) { case e_inrange : return (arg1 < arg0) ? T(0) : ((arg1 > arg2) ? T(0) : T(1)); 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 : exprtk_debug(("trinary_node::value() - Error: Invalid operation\n")); return std::numeric_limits::quiet_NaN(); } } inline typename expression_node::node_type type() const exprtk_override { return expression_node::e_trinary; } void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override { expression_node::ndb_t::template collect(branch_, node_delete_list); } std::size_t node_depth() const exprtk_override exprtk_final { return expression_node::ndb_t::template compute_node_depth<3>(branch_); } protected: operator_type operation_; branch_t branch_[3]; }; template class quaternary_node : public expression_node { public: typedef expression_node* expression_ptr; typedef std::pair branch_t; quaternary_node(const operator_type& opr, expression_ptr branch0, expression_ptr branch1, expression_ptr branch2, expression_ptr branch3) : operation_(opr) { init_branches<4>(branch_, branch0, branch1, branch2, branch3); } inline T value() const exprtk_override { return std::numeric_limits::quiet_NaN(); } inline typename expression_node::node_type type() const exprtk_override { return expression_node::e_quaternary; } void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override { expression_node::ndb_t::template collect(branch_, node_delete_list); } std::size_t node_depth() const exprtk_override exprtk_final { return expression_node::ndb_t::template compute_node_depth<4>(branch_); } protected: operator_type operation_; branch_t branch_[4]; }; template class conditional_node exprtk_final : public expression_node { public: typedef expression_node* expression_ptr; typedef std::pair branch_t; conditional_node(expression_ptr condition, expression_ptr consequent, expression_ptr alternative) { construct_branch_pair(condition_ , condition ); construct_branch_pair(consequent_ , consequent ); construct_branch_pair(alternative_, alternative); } inline T value() const exprtk_override { assert(condition_ .first); assert(consequent_ .first); assert(alternative_.first); if (is_true(condition_)) return consequent_.first->value(); else return alternative_.first->value(); } inline typename expression_node::node_type type() const exprtk_override { return expression_node::e_conditional; } void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override { expression_node::ndb_t::collect(condition_ , node_delete_list); expression_node::ndb_t::collect(consequent_ , node_delete_list); expression_node::ndb_t::collect(alternative_ , node_delete_list); } std::size_t node_depth() const exprtk_override { return expression_node::ndb_t::compute_node_depth (condition_, consequent_, alternative_); } private: branch_t condition_; branch_t consequent_; branch_t alternative_; }; template class cons_conditional_node exprtk_final : public expression_node { public: // Consequent only conditional statement node typedef expression_node* expression_ptr; typedef std::pair branch_t; cons_conditional_node(expression_ptr condition, expression_ptr consequent) { construct_branch_pair(condition_ , condition ); construct_branch_pair(consequent_, consequent); } inline T value() const exprtk_override { assert(condition_ .first); assert(consequent_.first); if (is_true(condition_)) return consequent_.first->value(); else return std::numeric_limits::quiet_NaN(); } inline typename expression_node::node_type type() const exprtk_override { return expression_node::e_conditional; } void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override { expression_node::ndb_t::collect(condition_ , node_delete_list); expression_node::ndb_t::collect(consequent_ , node_delete_list); } std::size_t node_depth() const exprtk_override { return expression_node::ndb_t:: compute_node_depth(condition_, consequent_); } private: branch_t condition_; branch_t consequent_; }; #ifndef exprtk_disable_break_continue template class break_exception { public: explicit break_exception(const T& v) : value(v) {} T value; }; class continue_exception {}; template class break_node exprtk_final : public expression_node { public: typedef expression_node* expression_ptr; typedef std::pair branch_t; break_node(expression_ptr ret = expression_ptr(0)) { construct_branch_pair(return_, ret); } inline T value() const exprtk_override { const T result = return_.first ? return_.first->value() : std::numeric_limits::quiet_NaN(); throw break_exception(result); #ifndef _MSC_VER return std::numeric_limits::quiet_NaN(); #endif } inline typename expression_node::node_type type() const exprtk_override { return expression_node::e_break; } void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override { expression_node::ndb_t::collect(return_, node_delete_list); } std::size_t node_depth() const exprtk_override { return expression_node::ndb_t::compute_node_depth(return_); } private: branch_t return_; }; template class continue_node exprtk_final : public expression_node { public: inline T value() const exprtk_override { throw continue_exception(); #ifndef _MSC_VER return std::numeric_limits::quiet_NaN(); #endif } inline typename expression_node::node_type type() const exprtk_override { return expression_node::e_break; } }; #endif struct loop_runtime_checker { loop_runtime_checker(loop_runtime_check_ptr loop_runtime_check, loop_runtime_check::loop_types lp_typ = loop_runtime_check::e_invalid) : iteration_count_(0) , loop_runtime_check_(loop_runtime_check) , max_loop_iterations_(loop_runtime_check_->max_loop_iterations) , loop_type_(lp_typ) { assert(loop_runtime_check_); } inline void reset(const _uint64_t initial_value = 0) const { iteration_count_ = initial_value; } inline bool check() const { if ( (0 == loop_runtime_check_) || (++iteration_count_ <= max_loop_iterations_) ) { 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_; const details::_uint64_t& max_loop_iterations_; loop_runtime_check::loop_types loop_type_; }; template class while_loop_node : public expression_node { public: typedef expression_node* expression_ptr; typedef std::pair branch_t; while_loop_node(expression_ptr condition, expression_ptr loop_body) { construct_branch_pair(condition_, condition); construct_branch_pair(loop_body_, loop_body); } inline T value() const exprtk_override { assert(condition_.first); assert(loop_body_.first); T result = T(0); while (is_true(condition_)) { result = loop_body_.first->value(); } return result; } inline typename expression_node::node_type type() const exprtk_override { return expression_node::e_while; } void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override { 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 exprtk_override { return expression_node::ndb_t::compute_node_depth(condition_, loop_body_); } protected: branch_t condition_; branch_t loop_body_; }; template class while_loop_rtc_node exprtk_final : public while_loop_node , public loop_runtime_checker { public: typedef while_loop_node parent_t; typedef expression_node* expression_ptr; while_loop_rtc_node(expression_ptr condition, expression_ptr loop_body, loop_runtime_check_ptr loop_rt_chk) : parent_t(condition, loop_body) , loop_runtime_checker(loop_rt_chk, loop_runtime_check::e_while_loop) {} inline T value() const exprtk_override { assert(parent_t::condition_.first); assert(parent_t::loop_body_.first); T result = T(0); loop_runtime_checker::reset(); while (is_true(parent_t::condition_) && loop_runtime_checker::check()) { result = parent_t::loop_body_.first->value(); } return result; } }; template class repeat_until_loop_node : public expression_node { public: typedef expression_node* expression_ptr; typedef std::pair branch_t; repeat_until_loop_node(expression_ptr condition, expression_ptr loop_body) { construct_branch_pair(condition_, condition); construct_branch_pair(loop_body_, loop_body); } inline T value() const exprtk_override { assert(condition_.first); assert(loop_body_.first); T result = T(0); do { result = loop_body_.first->value(); } while (is_false(condition_.first)); return result; } inline typename expression_node::node_type type() const exprtk_override { return expression_node::e_repeat; } void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override { 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 exprtk_override { return expression_node::ndb_t::compute_node_depth(condition_, loop_body_); } protected: branch_t condition_; branch_t loop_body_; }; template class repeat_until_loop_rtc_node exprtk_final : public repeat_until_loop_node , public loop_runtime_checker { public: typedef repeat_until_loop_node parent_t; typedef expression_node* expression_ptr; repeat_until_loop_rtc_node(expression_ptr condition, expression_ptr loop_body, loop_runtime_check_ptr loop_rt_chk) : parent_t(condition, loop_body) , loop_runtime_checker(loop_rt_chk, loop_runtime_check::e_repeat_until_loop) {} inline T value() const exprtk_override { assert(parent_t::condition_.first); assert(parent_t::loop_body_.first); T result = T(0); loop_runtime_checker::reset(1); do { result = parent_t::loop_body_.first->value(); } while (is_false(parent_t::condition_.first) && loop_runtime_checker::check()); return result; } }; template class for_loop_node : public expression_node { 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) { 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 exprtk_override { assert(condition_.first); assert(loop_body_.first); T result = T(0); if (initialiser_.first) initialiser_.first->value(); if (incrementor_.first) { while (is_true(condition_)) { result = loop_body_.first->value(); incrementor_.first->value(); } } else { while (is_true(condition_)) { result = loop_body_.first->value(); } } return result; } inline typename expression_node::node_type type() const exprtk_override { return expression_node::e_for; } void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override { 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 exprtk_override { return expression_node::ndb_t::compute_node_depth (initialiser_, condition_, incrementor_, loop_body_); } protected: branch_t initialiser_; branch_t condition_ ; branch_t incrementor_; branch_t loop_body_ ; }; template class for_loop_rtc_node exprtk_final : public for_loop_node , public loop_runtime_checker { public: typedef for_loop_node parent_t; typedef expression_node* expression_ptr; for_loop_rtc_node(expression_ptr initialiser, expression_ptr condition, expression_ptr incrementor, expression_ptr loop_body, loop_runtime_check_ptr loop_rt_chk) : parent_t(initialiser, condition, incrementor, loop_body) , loop_runtime_checker(loop_rt_chk, loop_runtime_check::e_for_loop) {} inline T value() const exprtk_override { assert(parent_t::condition_.first); assert(parent_t::loop_body_.first); T result = T(0); loop_runtime_checker::reset(); if (parent_t::initialiser_.first) parent_t::initialiser_.first->value(); if (parent_t::incrementor_.first) { while (is_true(parent_t::condition_) && loop_runtime_checker::check()) { result = parent_t::loop_body_.first->value(); parent_t::incrementor_.first->value(); } } else { while (is_true(parent_t::condition_) && loop_runtime_checker::check()) { result = parent_t::loop_body_.first->value(); } } return result; } }; #ifndef exprtk_disable_break_continue template class while_loop_bc_node : public while_loop_node { public: typedef while_loop_node parent_t; typedef expression_node* expression_ptr; while_loop_bc_node(expression_ptr condition, expression_ptr loop_body) : parent_t(condition, loop_body) {} inline T value() const exprtk_override { assert(parent_t::condition_.first); assert(parent_t::loop_body_.first); T result = T(0); while (is_true(parent_t::condition_)) { try { result = parent_t::loop_body_.first->value(); } catch(const break_exception& e) { return e.value; } catch(const continue_exception&) {} } return result; } }; template class while_loop_bc_rtc_node exprtk_final : public while_loop_bc_node , public loop_runtime_checker { public: typedef while_loop_bc_node parent_t; typedef expression_node* expression_ptr; while_loop_bc_rtc_node(expression_ptr condition, expression_ptr loop_body, loop_runtime_check_ptr loop_rt_chk) : parent_t(condition, loop_body) , loop_runtime_checker(loop_rt_chk, loop_runtime_check::e_while_loop) {} inline T value() const exprtk_override { assert(parent_t::condition_.first); assert(parent_t::loop_body_.first); T result = T(0); loop_runtime_checker::reset(); while (is_true(parent_t::condition_) && loop_runtime_checker::check()) { try { result = parent_t::loop_body_.first->value(); } catch(const break_exception& e) { return e.value; } catch(const continue_exception&) {} } return result; } }; template class repeat_until_loop_bc_node : public repeat_until_loop_node { public: typedef repeat_until_loop_node parent_t; typedef expression_node* expression_ptr; repeat_until_loop_bc_node(expression_ptr condition, expression_ptr loop_body) : parent_t(condition, loop_body) {} inline T value() const exprtk_override { assert(parent_t::condition_.first); assert(parent_t::loop_body_.first); T result = T(0); do { try { result = parent_t::loop_body_.first->value(); } catch(const break_exception& e) { return e.value; } catch(const continue_exception&) {} } while (is_false(parent_t::condition_.first)); return result; } }; template class repeat_until_loop_bc_rtc_node exprtk_final : public repeat_until_loop_bc_node, public loop_runtime_checker { public: typedef repeat_until_loop_bc_node parent_t; typedef expression_node* expression_ptr; repeat_until_loop_bc_rtc_node(expression_ptr condition, expression_ptr loop_body, loop_runtime_check_ptr loop_rt_chk) : parent_t(condition, loop_body) , loop_runtime_checker(loop_rt_chk, loop_runtime_check::e_repeat_until_loop) {} inline T value() const exprtk_override { assert(parent_t::condition_.first); assert(parent_t::loop_body_.first); T result = T(0); loop_runtime_checker::reset(); do { try { result = parent_t::loop_body_.first->value(); } catch(const break_exception& e) { return e.value; } catch(const continue_exception&) {} } while (is_false(parent_t::condition_.first) && loop_runtime_checker::check()); return result; } }; template class for_loop_bc_node : public for_loop_node { public: typedef for_loop_node parent_t; typedef expression_node* expression_ptr; for_loop_bc_node(expression_ptr initialiser, expression_ptr condition, expression_ptr incrementor, expression_ptr loop_body) : parent_t(initialiser, condition, incrementor, loop_body) {} inline T value() const exprtk_override { assert(parent_t::condition_.first); assert(parent_t::loop_body_.first); T result = T(0); if (parent_t::initialiser_.first) parent_t::initialiser_.first->value(); if (parent_t::incrementor_.first) { while (is_true(parent_t::condition_)) { try { result = parent_t::loop_body_.first->value(); } catch(const break_exception& e) { return e.value; } catch(const continue_exception&) {} parent_t::incrementor_.first->value(); } } else { while (is_true(parent_t::condition_)) { try { result = parent_t::loop_body_.first->value(); } catch(const break_exception& e) { return e.value; } catch(const continue_exception&) {} } } return result; } }; template class for_loop_bc_rtc_node exprtk_final : public for_loop_bc_node , public loop_runtime_checker { public: typedef for_loop_bc_node parent_t; typedef expression_node* expression_ptr; for_loop_bc_rtc_node(expression_ptr initialiser, expression_ptr condition, expression_ptr incrementor, expression_ptr loop_body, loop_runtime_check_ptr loop_rt_chk) : parent_t(initialiser, condition, incrementor, loop_body) , loop_runtime_checker(loop_rt_chk, loop_runtime_check::e_for_loop) {} inline T value() const exprtk_override { assert(parent_t::condition_.first); assert(parent_t::loop_body_.first); T result = T(0); loop_runtime_checker::reset(); if (parent_t::initialiser_.first) parent_t::initialiser_.first->value(); if (parent_t::incrementor_.first) { while (is_true(parent_t::condition_) && loop_runtime_checker::check()) { try { result = parent_t::loop_body_.first->value(); } catch(const break_exception& e) { return e.value; } catch(const continue_exception&) {} parent_t::incrementor_.first->value(); } } else { while (is_true(parent_t::condition_) && loop_runtime_checker::check()) { try { result = parent_t::loop_body_.first->value(); } catch(const break_exception& e) { return e.value; } catch(const continue_exception&) {} } } return result; } }; #endif template class switch_node : public expression_node { public: typedef expression_node* expression_ptr; typedef std::pair branch_t; template class Sequence> explicit switch_node(const Sequence& arg_list) { if (1 != (arg_list.size() & 1)) return; arg_list_.resize(arg_list.size()); for (std::size_t i = 0; i < arg_list.size(); ++i) { if (arg_list[i]) { construct_branch_pair(arg_list_[i], arg_list[i]); } else { arg_list_.clear(); return; } } } inline T value() const exprtk_override { if (!arg_list_.empty()) { const std::size_t upper_bound = (arg_list_.size() - 1); for (std::size_t i = 0; i < upper_bound; i += 2) { expression_ptr condition = arg_list_[i ].first; expression_ptr consequent = arg_list_[i + 1].first; if (is_true(condition)) { return consequent->value(); } } return arg_list_[upper_bound].first->value(); } else return std::numeric_limits::quiet_NaN(); } inline typename expression_node::node_type type() const exprtk_override exprtk_final { return expression_node::e_switch; } void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override { expression_node::ndb_t::collect(arg_list_, node_delete_list); } std::size_t node_depth() const exprtk_override exprtk_final { return expression_node::ndb_t::compute_node_depth(arg_list_); } protected: std::vector arg_list_; }; template class switch_n_node exprtk_final : 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 exprtk_override { return Switch_N::process(switch_node::arg_list_); } }; template class multi_switch_node exprtk_final : public expression_node { public: typedef expression_node* expression_ptr; typedef std::pair branch_t; template class Sequence> explicit multi_switch_node(const Sequence& arg_list) { if (0 != (arg_list.size() & 1)) return; arg_list_.resize(arg_list.size()); for (std::size_t i = 0; i < arg_list.size(); ++i) { if (arg_list[i]) { construct_branch_pair(arg_list_[i], arg_list[i]); } else { arg_list_.clear(); return; } } } inline T value() const exprtk_override { T result = T(0); if (arg_list_.empty()) { return std::numeric_limits::quiet_NaN(); } const std::size_t upper_bound = (arg_list_.size() - 1); for (std::size_t i = 0; i < upper_bound; i += 2) { expression_ptr condition = arg_list_[i ].first; expression_ptr consequent = arg_list_[i + 1].first; if (is_true(condition)) { result = consequent->value(); } } return result; } inline typename expression_node::node_type type() const exprtk_override { return expression_node::e_mswitch; } void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override { expression_node::ndb_t::collect(arg_list_, node_delete_list); } std::size_t node_depth() const exprtk_override exprtk_final { return expression_node::ndb_t::compute_node_depth(arg_list_); } private: std::vector arg_list_; }; template class ivariable { public: virtual ~ivariable() {} virtual T& ref() = 0; virtual const T& ref() const = 0; }; template class variable_node exprtk_final : public expression_node, public ivariable { public: static T null_value; explicit variable_node() : value_(&null_value) {} explicit variable_node(T& v) : value_(&v) {} inline bool operator <(const variable_node& v) const { return this < (&v); } inline T value() const exprtk_override { return (*value_); } inline T& ref() exprtk_override { return (*value_); } inline const T& ref() const exprtk_override { return (*value_); } inline typename expression_node::node_type type() const exprtk_override { return expression_node::e_variable; } private: T* value_; }; template T variable_node::null_value = T(std::numeric_limits::quiet_NaN()); template struct range_pack { typedef expression_node* expression_node_ptr; typedef std::pair cached_range_t; range_pack() : n0_e (std::make_pair(false,expression_node_ptr(0))) , n1_e (std::make_pair(false,expression_node_ptr(0))) , n0_c (std::make_pair(false,0)) , n1_c (std::make_pair(false,0)) , cache(std::make_pair(0,0)) {} void clear() { n0_e = std::make_pair(false,expression_node_ptr(0)); n1_e = std::make_pair(false,expression_node_ptr(0)); n0_c = std::make_pair(false,0); n1_c = std::make_pair(false,0); cache = std::make_pair(0,0); } void free() { if (n0_e.first && n0_e.second) { n0_e.first = false; if ( !is_variable_node(n0_e.second) && !is_string_node (n0_e.second) ) { destroy_node(n0_e.second); } } if (n1_e.first && n1_e.second) { n1_e.first = false; if ( !is_variable_node(n1_e.second) && !is_string_node (n1_e.second) ) { destroy_node(n1_e.second); } } } bool const_range() const { return ( n0_c.first && n1_c.first) && (!n0_e.first && !n1_e.first); } 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 { if (n0_c.first) r0 = n0_c.second; else if (n0_e.first) { r0 = static_cast(details::numeric::to_int64(n0_e.second->value())); } else return false; if (n1_c.first) r1 = n1_c.second; else if (n1_e.first) { r1 = static_cast(details::numeric::to_int64(n1_e.second->value())); } else return false; if ( (std::numeric_limits::max() != size) && (std::numeric_limits::max() == r1 ) ) { r1 = size - 1; } cache.first = r0; cache.second = r1; #ifndef exprtk_enable_range_runtime_checks return (r0 <= r1); #else return range_runtime_check(r0, r1, size); #endif } inline std::size_t const_size() const { return (n1_c.second - n0_c.second + 1); } inline std::size_t cache_size() const { return (cache.second - cache.first + 1); } std::pair n0_e; std::pair n1_e; std::pair n0_c; std::pair n1_c; mutable cached_range_t cache; #ifdef exprtk_enable_range_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 class string_base_node; template struct range_data_type { typedef range_pack range_t; typedef string_base_node* strbase_ptr_t; range_data_type() : range(0) , data (0) , size (0) , type_size(0) , str_node (0) {} range_t* range; void* data; std::size_t size; std::size_t type_size; strbase_ptr_t str_node; }; template class vector_node; template class vector_interface { public: 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 vds_t& vds () = 0; virtual const vds_t& vds () const = 0; virtual bool side_effect () const { return false; } }; template class vector_node exprtk_final : public expression_node , public vector_interface { public: typedef expression_node* expression_ptr; typedef vector_holder vector_holder_t; typedef vector_node* vector_node_ptr; typedef vec_data_store vds_t; explicit vector_node(vector_holder_t* vh) : vector_holder_(vh) , vds_((*vector_holder_).size(),(*vector_holder_)[0]) { vector_holder_->set_ref(&vds_.ref()); } vector_node(const vds_t& vds, vector_holder_t* vh) : vector_holder_(vh) , vds_(vds) {} inline T value() const exprtk_override { return vds().data()[0]; } vector_node_ptr vec() const exprtk_override { return const_cast(this); } vector_node_ptr vec() exprtk_override { return this; } inline typename expression_node::node_type type() const exprtk_override { return expression_node::e_vector; } std::size_t size() const exprtk_override { return vds().size(); } vds_t& vds() exprtk_override { return vds_; } const vds_t& vds() const exprtk_override { 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 exprtk_final : 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 std::pair branch_t; vector_elem_node(expression_ptr index, vector_holder_ptr vec_holder) : vec_holder_(vec_holder) , vector_base_((*vec_holder)[0]) { construct_branch_pair(index_, index); } inline T value() const exprtk_override { return *(vector_base_ + static_cast(details::numeric::to_int64(index_.first->value()))); } inline T& ref() exprtk_override { return *(vector_base_ + static_cast(details::numeric::to_int64(index_.first->value()))); } inline const T& ref() const exprtk_override { return *(vector_base_ + static_cast(details::numeric::to_int64(index_.first->value()))); } inline typename expression_node::node_type type() const exprtk_override { 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) exprtk_override { expression_node::ndb_t::collect(index_, node_delete_list); } std::size_t node_depth() const exprtk_override { return expression_node::ndb_t::compute_node_depth(index_); } private: vector_holder_ptr vec_holder_; T* vector_base_; branch_t index_; }; template class rebasevector_elem_node exprtk_final : 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; typedef std::pair branch_t; rebasevector_elem_node(expression_ptr index, vector_holder_ptr vec_holder) : vector_holder_(vec_holder) , vds_((*vector_holder_).size(),(*vector_holder_)[0]) { vector_holder_->set_ref(&vds_.ref()); construct_branch_pair(index_, index); } inline T value() const exprtk_override { return *(vds_.data() + static_cast(details::numeric::to_int64(index_.first->value()))); } inline T& ref() exprtk_override { return *(vds_.data() + static_cast(details::numeric::to_int64(index_.first->value()))); } inline const T& ref() const exprtk_override { return *(vds_.data() + static_cast(details::numeric::to_int64(index_.first->value()))); } inline typename expression_node::node_type type() const exprtk_override { return expression_node::e_rbvecelem; } inline vector_holder_t& vec_holder() { return (*vector_holder_); } void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override { expression_node::ndb_t::template collect(index_, node_delete_list); } std::size_t node_depth() const exprtk_override { 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 exprtk_final : 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 exprtk_override { return *(vds_.data() + index_); } inline T& ref() exprtk_override { return *(vds_.data() + index_); } inline const T& ref() const exprtk_override { return *(vds_.data() + index_); } inline typename expression_node::node_type type() const exprtk_override { 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 exprtk_final : 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 exprtk_override { if (single_value_initialse_) { for (std::size_t i = 0; i < size_; ++i) { *(vector_base_ + i) = initialiser_list_[0]->value(); } } else { const std::size_t initialiser_list_size = initialiser_list_.size(); for (std::size_t i = 0; i < initialiser_list_size; ++i) { *(vector_base_ + i) = initialiser_list_[i]->value(); } if (initialiser_list_size < size_) { for (std::size_t i = initialiser_list_size; i < size_; ++i) { *(vector_base_ + i) = T(0); } } } return *(vector_base_); } inline typename expression_node::node_type type() const exprtk_override { return expression_node::e_vecdefass; } void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override { expression_node::ndb_t::collect(initialiser_list_, node_delete_list); } std::size_t node_depth() const exprtk_override { return expression_node::ndb_t::compute_node_depth(initialiser_list_); } private: vector_assignment_node(const vector_assignment_node&) exprtk_delete; vector_assignment_node& operator=(const vector_assignment_node&) exprtk_delete; mutable T* vector_base_; std::vector initialiser_list_; const std::size_t size_; const bool single_value_initialse_; }; template class swap_node exprtk_final : public expression_node { public: typedef expression_node* expression_ptr; typedef variable_node* variable_node_ptr; swap_node(variable_node_ptr var0, variable_node_ptr var1) : var0_(var0) , var1_(var1) {} inline T value() const exprtk_override { std::swap(var0_->ref(),var1_->ref()); return var1_->ref(); } inline typename expression_node::node_type type() const exprtk_override { return expression_node::e_swap; } private: variable_node_ptr var0_; variable_node_ptr var1_; }; template class swap_generic_node exprtk_final : public binary_node { public: typedef expression_node* expression_ptr; typedef ivariable* ivariable_ptr; swap_generic_node(expression_ptr var0, expression_ptr var1) : binary_node(details::e_swap, var0, var1) , var0_(dynamic_cast(var0)) , var1_(dynamic_cast(var1)) {} inline T value() const exprtk_override { std::swap(var0_->ref(),var1_->ref()); return var1_->ref(); } inline typename expression_node::node_type type() const exprtk_override { return expression_node::e_swap; } private: ivariable_ptr var0_; ivariable_ptr var1_; }; template class swap_vecvec_node exprtk_final : public binary_node , public vector_interface { public: 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) , vec0_node_ptr_(0) , vec1_node_ptr_(0) , vec_size_ (0) , initialised_ (false) { if (is_ivector_node(binary_node::branch_[0].first)) { vector_interface* vi = reinterpret_cast*>(0); if (0 != (vi = dynamic_cast*>(binary_node::branch_[0].first))) { vec0_node_ptr_ = vi->vec(); vds() = vi->vds(); } } 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(); } } if (vec0_node_ptr_ && vec1_node_ptr_) { vec_size_ = std::min(vec0_node_ptr_->vds().size(), vec1_node_ptr_->vds().size()); initialised_ = true; } assert(initialised_); } inline T value() const exprtk_override { if (initialised_) { assert(binary_node::branch_[0].first); assert(binary_node::branch_[1].first); binary_node::branch_[0].first->value(); binary_node::branch_[1].first->value(); T* vec0 = vec0_node_ptr_->vds().data(); T* vec1 = vec1_node_ptr_->vds().data(); for (std::size_t i = 0; i < vec_size_; ++i) { std::swap(vec0[i],vec1[i]); } return vec1_node_ptr_->value(); } else return std::numeric_limits::quiet_NaN(); } vector_node_ptr vec() const exprtk_override { return vec0_node_ptr_; } vector_node_ptr vec() exprtk_override { return vec0_node_ptr_; } inline typename expression_node::node_type type() const exprtk_override { return expression_node::e_vecvecswap; } std::size_t size() const exprtk_override { return vec_size_; } vds_t& vds() exprtk_override { return vds_; } const vds_t& vds() const exprtk_override { 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 template class stringvar_node exprtk_final : public expression_node , public string_base_node, public range_interface { public: typedef typename range_interface::range_t range_t; static std::string null_value; explicit stringvar_node() : value_(&null_value) {} explicit stringvar_node(std::string& v) : value_(&v) { rp_.n0_c = std::make_pair(true,0); rp_.n1_c = std::make_pair(true,v.size() - 1); rp_.cache.first = rp_.n0_c.second; rp_.cache.second = rp_.n1_c.second; } inline bool operator <(const stringvar_node& v) const { return this < (&v); } inline T value() const exprtk_override { rp_.n1_c.second = (*value_).size() - 1; rp_.cache.second = rp_.n1_c.second; return std::numeric_limits::quiet_NaN(); } std::string str() const exprtk_override { return ref(); } char_cptr base() const exprtk_override { return &(*value_)[0]; } std::size_t size() const exprtk_override { return ref().size(); } std::string& ref() { return (*value_); } const std::string& ref() const { return (*value_); } range_t& range_ref() exprtk_override { return rp_; } const range_t& range_ref() const exprtk_override { return rp_; } inline typename expression_node::node_type type() const exprtk_override { return expression_node::e_stringvar; } void rebase(std::string& s) { value_ = &s; rp_.n0_c = std::make_pair(true,0); rp_.n1_c = std::make_pair(true,value_->size() - 1); rp_.cache.first = rp_.n0_c.second; rp_.cache.second = rp_.n1_c.second; } private: std::string* value_; mutable range_t rp_; }; template std::string stringvar_node::null_value = std::string(""); template class string_range_node exprtk_final : public expression_node , public string_base_node, public range_interface { public: typedef typename range_interface::range_t range_t; static std::string null_value; explicit string_range_node(std::string& v, const range_t& rp) : value_(&v) , rp_(rp) {} virtual ~string_range_node() { rp_.free(); } inline bool operator <(const string_range_node& v) const { return this < (&v); } inline T value() const exprtk_override { return std::numeric_limits::quiet_NaN(); } inline std::string str() const exprtk_override { return (*value_); } char_cptr base() const exprtk_override { return &(*value_)[0]; } std::size_t size() const exprtk_override { return ref().size(); } inline range_t range() const { return rp_; } inline virtual std::string& ref() { return (*value_); } inline virtual const std::string& ref() const { return (*value_); } inline range_t& range_ref() exprtk_override { return rp_; } inline const range_t& range_ref() const exprtk_override { return rp_; } inline typename expression_node::node_type type() const exprtk_override { return expression_node::e_stringvarrng; } private: std::string* value_; range_t rp_; }; template std::string string_range_node::null_value = std::string(""); template class const_string_range_node exprtk_final : public expression_node , public string_base_node, public range_interface { public: typedef typename range_interface::range_t range_t; explicit const_string_range_node(const std::string& v, const range_t& rp) : value_(v) , rp_(rp) {} ~const_string_range_node() { rp_.free(); } inline T value() const exprtk_override { return std::numeric_limits::quiet_NaN(); } std::string str() const exprtk_override { return value_; } char_cptr base() const exprtk_override { return value_.data(); } std::size_t size() const exprtk_override { return value_.size(); } range_t range() const { return rp_; } range_t& range_ref() exprtk_override { return rp_; } const range_t& range_ref() const exprtk_override { return rp_; } inline typename expression_node::node_type type() const exprtk_override { return expression_node::e_cstringvarrng; } private: const_string_range_node(const const_string_range_node&) exprtk_delete; const_string_range_node& operator=(const const_string_range_node&) exprtk_delete; const std::string value_; range_t rp_; }; template class generic_string_range_node exprtk_final : public expression_node , public string_base_node, public range_interface { public: typedef expression_node * expression_ptr; typedef stringvar_node * strvar_node_ptr; typedef string_base_node* str_base_ptr; typedef typename range_interface::range_t range_t; typedef range_t* range_ptr; typedef range_interface irange_t; typedef irange_t* irange_ptr; typedef std::pair branch_t; generic_string_range_node(expression_ptr str_branch, const range_t& brange) : initialised_(false) , str_base_ptr_ (0) , str_range_ptr_(0) , base_range_(brange) { 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; construct_branch_pair(branch_, str_branch); if (is_generally_string_node(branch_.first)) { str_base_ptr_ = dynamic_cast(branch_.first); if (0 == str_base_ptr_) return; str_range_ptr_ = dynamic_cast(branch_.first); if (0 == str_range_ptr_) return; } initialised_ = (str_base_ptr_ && str_range_ptr_); assert(initialised_); } ~generic_string_range_node() { base_range_.free(); } inline T value() const exprtk_override { if (initialised_) { assert(branch_.first); branch_.first->value(); std::size_t str_r0 = 0; std::size_t str_r1 = 0; std::size_t r0 = 0; std::size_t r1 = 0; 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 - str_r0) ) { const std::size_t size = (r1 - r0) + 1; range_.n1_c.second = size - 1; range_.cache.second = range_.n1_c.second; value_.assign(str_base_ptr_->base() + str_r0 + r0, size); } } return std::numeric_limits::quiet_NaN(); } std::string str() const exprtk_override { return value_; } char_cptr base() const exprtk_override { return &value_[0]; } std::size_t size() const exprtk_override { return value_.size(); } range_t& range_ref() exprtk_override { return range_; } const range_t& range_ref() const exprtk_override { return range_; } inline typename expression_node::node_type type() const exprtk_override { return expression_node::e_strgenrange; } void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override { expression_node::ndb_t::collect(branch_, node_delete_list); } std::size_t node_depth() const exprtk_override { return expression_node::ndb_t::compute_node_depth(branch_); } private: 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 class string_concat_node exprtk_final : public binary_node , public string_base_node, public range_interface { public: typedef typename range_interface::range_t range_t; typedef range_interface irange_t; typedef irange_t* irange_ptr; typedef range_t* range_ptr; typedef expression_node * expression_ptr; typedef string_base_node* str_base_ptr; string_concat_node(const operator_type& opr, expression_ptr branch0, expression_ptr branch1) : binary_node(opr, branch0, branch1) , initialised_(false) , str0_base_ptr_ (0) , str1_base_ptr_ (0) , str0_range_ptr_(0) , str1_range_ptr_(0) { 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; 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; str0_range_ptr_ = dynamic_cast(binary_node::branch_[0].first); if (0 == str0_range_ptr_) return; } 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; str1_range_ptr_ = dynamic_cast(binary_node::branch_[1].first); if (0 == str1_range_ptr_) return; } initialised_ = str0_base_ptr_ && str1_base_ptr_ && str0_range_ptr_ && str1_range_ptr_ ; assert(initialised_); } inline T value() const exprtk_override { 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_->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()) ) { const std::size_t size0 = (str0_r1 - str0_r0) + 1; const std::size_t size1 = (str1_r1 - str1_r0) + 1; value_.assign(str0_base_ptr_->base() + str0_r0, size0); value_.append(str1_base_ptr_->base() + str1_r0, size1); range_.n1_c.second = value_.size() - 1; range_.cache.second = range_.n1_c.second; } } return std::numeric_limits::quiet_NaN(); } std::string str() const exprtk_override { return value_; } char_cptr base() const exprtk_override { return &value_[0]; } std::size_t size() const exprtk_override { return value_.size(); } range_t& range_ref() exprtk_override { return range_; } const range_t& range_ref() const exprtk_override { return range_; } inline typename expression_node::node_type type() const exprtk_override { return expression_node::e_strconcat; } private: 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_; }; template class swap_string_node exprtk_final : public binary_node , public string_base_node, public range_interface { public: typedef typename range_interface::range_t range_t; typedef range_t* range_ptr; typedef range_interface irange_t; typedef irange_t* irange_ptr; typedef expression_node * expression_ptr; typedef stringvar_node * strvar_node_ptr; typedef string_base_node* str_base_ptr; swap_string_node(expression_ptr branch0, expression_ptr branch1) : binary_node(details::e_swap, branch0, branch1), initialised_(false), str0_node_ptr_(0), str1_node_ptr_(0) { if (is_string_node(binary_node::branch_[0].first)) { str0_node_ptr_ = static_cast(binary_node::branch_[0].first); } if (is_string_node(binary_node::branch_[1].first)) { str1_node_ptr_ = static_cast(binary_node::branch_[1].first); } initialised_ = (str0_node_ptr_ && str1_node_ptr_); assert(initialised_); } inline T value() const exprtk_override { 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()); } return std::numeric_limits::quiet_NaN(); } std::string str() const exprtk_override { return str0_node_ptr_->str(); } char_cptr base() const exprtk_override { return str0_node_ptr_->base(); } std::size_t size() const exprtk_override { return str0_node_ptr_->size(); } range_t& range_ref() exprtk_override { return str0_node_ptr_->range_ref(); } const range_t& range_ref() const exprtk_override { return str0_node_ptr_->range_ref(); } inline typename expression_node::node_type type() const exprtk_override { return expression_node::e_strswap; } private: bool initialised_; strvar_node_ptr str0_node_ptr_; strvar_node_ptr str1_node_ptr_; }; template class swap_genstrings_node exprtk_final : public binary_node { public: typedef typename range_interface::range_t range_t; typedef range_t* range_ptr; typedef range_interface irange_t; typedef irange_t* irange_ptr; typedef expression_node * expression_ptr; typedef string_base_node* str_base_ptr; 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_ ; assert(initialised_); } inline T value() const exprtk_override { 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 exprtk_override { return expression_node::e_strswap; } private: swap_genstrings_node(const swap_genstrings_node&) exprtk_delete; swap_genstrings_node& operator=(const swap_genstrings_node&) exprtk_delete; 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 exprtk_final : public expression_node { public: static std::string null_value; explicit stringvar_size_node() : value_(&null_value) {} explicit stringvar_size_node(std::string& v) : value_(&v) {} inline T value() const exprtk_override { return T((*value_).size()); } inline typename expression_node::node_type type() const exprtk_override { return expression_node::e_stringvarsize; } private: std::string* value_; }; template std::string stringvar_size_node::null_value = std::string(""); template class string_size_node exprtk_final : public expression_node { public: typedef expression_node * expression_ptr; typedef string_base_node* str_base_ptr; typedef std::pair branch_t; explicit string_size_node(expression_ptr branch) : str_base_ptr_(0) { construct_branch_pair(branch_, branch); if (is_generally_string_node(branch_.first)) { str_base_ptr_ = dynamic_cast(branch_.first); if (0 == str_base_ptr_) return; } } inline T value() const exprtk_override { T result = std::numeric_limits::quiet_NaN(); if (str_base_ptr_) { branch_.first->value(); result = T(str_base_ptr_->size()); } return result; } inline typename expression_node::node_type type() const exprtk_override { return expression_node::e_stringsize; } void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override { expression_node::ndb_t::collect(branch_, node_delete_list); } std::size_t node_depth() const exprtk_override { return expression_node::ndb_t::compute_node_depth(branch_); } private: branch_t branch_; str_base_ptr str_base_ptr_; }; struct asn_assignment { 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, char_cptr data, const std::size_t size) { s.append(data,size); } }; template class assignment_string_node exprtk_final : public binary_node , public string_base_node, public range_interface { public: typedef typename range_interface::range_t range_t; typedef range_t* range_ptr; typedef range_interface irange_t; typedef irange_t* irange_ptr; typedef expression_node * expression_ptr; typedef stringvar_node * strvar_node_ptr; typedef string_base_node* str_base_ptr; assignment_string_node(const operator_type& opr, expression_ptr branch0, expression_ptr branch1) : binary_node(opr, branch0, branch1) , initialised_(false) , str0_base_ptr_ (0) , str1_base_ptr_ (0) , str0_node_ptr_ (0) , str1_range_ptr_(0) { if (is_string_node(binary_node::branch_[0].first)) { str0_node_ptr_ = static_cast(binary_node::branch_[0].first); str0_base_ptr_ = dynamic_cast(binary_node::branch_[0].first); } 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_node_ptr_ && str1_range_ptr_ ; assert(initialised_); } inline T value() const exprtk_override { 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; const range_t& range = (*str1_range_ptr_); if (range(r0, r1, str1_base_ptr_->size())) { AssignmentProcess::execute(str0_node_ptr_->ref(), str1_base_ptr_->base() + r0, (r1 - r0) + 1); binary_node::branch_[0].first->value(); } } return std::numeric_limits::quiet_NaN(); } std::string str() const exprtk_override { return str0_node_ptr_->str(); } char_cptr base() const exprtk_override { return str0_node_ptr_->base(); } std::size_t size() const exprtk_override { return str0_node_ptr_->size(); } range_t& range_ref() exprtk_override { return str0_node_ptr_->range_ref(); } const range_t& range_ref() const exprtk_override { return str0_node_ptr_->range_ref(); } inline typename expression_node::node_type type() const exprtk_override { return expression_node::e_strass; } private: bool initialised_; str_base_ptr str0_base_ptr_; str_base_ptr str1_base_ptr_; strvar_node_ptr str0_node_ptr_; range_ptr str1_range_ptr_; }; template class assignment_string_range_node exprtk_final : public binary_node , public string_base_node, public range_interface { public: typedef typename range_interface::range_t range_t; typedef range_t* range_ptr; typedef range_interface irange_t; typedef irange_t* irange_ptr; typedef expression_node * expression_ptr; typedef stringvar_node * strvar_node_ptr; typedef string_range_node* str_rng_node_ptr; typedef string_base_node * str_base_ptr; assignment_string_range_node(const operator_type& opr, expression_ptr branch0, expression_ptr branch1) : binary_node(opr, branch0, branch1) , initialised_(false) , str0_base_ptr_ (0) , str1_base_ptr_ (0) , str0_rng_node_ptr_(0) , str0_range_ptr_ (0) , str1_range_ptr_ (0) { if (is_string_range_node(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 = 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_rng_node_ptr_ && str0_range_ptr_ && str1_range_ptr_ ; assert(initialised_); } inline T value() const exprtk_override { 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 s0_r0 = 0; std::size_t s0_r1 = 0; std::size_t s1_r0 = 0; std::size_t s1_r1 = 0; 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()) ) { 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)); } } return std::numeric_limits::quiet_NaN(); } std::string str() const exprtk_override { return str0_base_ptr_->str(); } char_cptr base() const exprtk_override { return str0_base_ptr_->base(); } std::size_t size() const exprtk_override { return str0_base_ptr_->size(); } range_t& range_ref() exprtk_override { return str0_rng_node_ptr_->range_ref(); } const range_t& range_ref() const exprtk_override { return str0_rng_node_ptr_->range_ref(); } inline typename expression_node::node_type type() const exprtk_override { return expression_node::e_strass; } private: bool initialised_; str_base_ptr str0_base_ptr_; str_base_ptr str1_base_ptr_; str_rng_node_ptr str0_rng_node_ptr_; range_ptr str0_range_ptr_; range_ptr str1_range_ptr_; }; template class conditional_string_node exprtk_final : public trinary_node , public string_base_node, public range_interface { public: typedef typename range_interface::range_t range_t; typedef range_t* range_ptr; typedef range_interface irange_t; typedef irange_t* irange_ptr; typedef expression_node * expression_ptr; typedef string_base_node* str_base_ptr; 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); range_.cache.first = range_.n0_c.second; range_.cache.second = range_.n1_c.second; if (is_generally_string_node(trinary_node::branch_[0].first)) { str0_base_ptr_ = dynamic_cast(trinary_node::branch_[0].first); if (0 == str0_base_ptr_) return; str0_range_ptr_ = dynamic_cast(trinary_node::branch_[0].first); if (0 == str0_range_ptr_) return; } if (is_generally_string_node(trinary_node::branch_[1].first)) { str1_base_ptr_ = dynamic_cast(trinary_node::branch_[1].first); if (0 == str1_base_ptr_) return; str1_range_ptr_ = dynamic_cast(trinary_node::branch_[1].first); if (0 == str1_range_ptr_) return; } initialised_ = str0_base_ptr_ && str1_base_ptr_ && str0_range_ptr_ && str1_range_ptr_ ; assert(initialised_); } inline T value() const exprtk_override { if (initialised_) { assert(condition_ ); assert(consequent_ ); assert(alternative_); std::size_t r0 = 0; std::size_t r1 = 0; if (is_true(condition_)) { consequent_->value(); const range_t& range = str0_range_ptr_->range_ref(); 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); } } else { alternative_->value(); const range_t& range = str1_range_ptr_->range_ref(); if (range(r0, r1, str1_base_ptr_->size())) { const std::size_t size = (r1 - r0) + 1; value_.assign(str1_base_ptr_->base() + r0, size); range_.n1_c.second = value_.size() - 1; range_.cache.second = range_.n1_c.second; return T(0); } } } return std::numeric_limits::quiet_NaN(); } std::string str() const exprtk_override { return value_; } char_cptr base() const exprtk_override { return &value_[0]; } std::size_t size() const exprtk_override { return value_.size(); } range_t& range_ref() exprtk_override { return range_; } const range_t& range_ref() const exprtk_override { return range_; } inline typename expression_node::node_type type() const exprtk_override { return expression_node::e_strcondition; } private: 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_; expression_ptr condition_; expression_ptr consequent_; expression_ptr alternative_; }; template class cons_conditional_str_node exprtk_final : public binary_node , public string_base_node, public range_interface { public: typedef typename range_interface::range_t range_t; typedef range_t* range_ptr; typedef range_interface irange_t; typedef irange_t* irange_ptr; typedef expression_node * expression_ptr; typedef string_base_node* str_base_ptr; 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) { 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; 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; str0_range_ptr_ = dynamic_cast(binary_node::branch_[0].first); if (0 == str0_range_ptr_) return; } initialised_ = str0_base_ptr_ && str0_range_ptr_ ; assert(initialised_); } inline T value() const exprtk_override { if (initialised_) { assert(condition_ ); assert(consequent_); if (is_true(condition_)) { 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(); } std::string str() const { 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 exprtk_override { return expression_node::e_strccondition; } private: 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 str_vararg_node exprtk_final : public expression_node , public string_base_node, public range_interface { public: typedef typename range_interface::range_t range_t; typedef range_t* range_ptr; typedef range_interface irange_t; typedef irange_t* irange_ptr; typedef expression_node * expression_ptr; typedef string_base_node* str_base_ptr; typedef std::pair branch_t; template class Sequence> explicit str_vararg_node(const Sequence& arg_list) : initialised_(false) , str_base_ptr_ (0) , str_range_ptr_(0) { construct_branch_pair(final_node_, const_cast(arg_list.back())); 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) { 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) { if (arg_list[i]) { construct_branch_pair(arg_list_[i], arg_list[i]); } else { arg_list_.clear(); return; } } } } inline T value() const exprtk_override { if (!arg_list_.empty()) { VarArgFunction::process(arg_list_); } final_node_.first->value(); return std::numeric_limits::quiet_NaN(); } std::string str() const exprtk_override { return str_base_ptr_->str(); } char_cptr base() const exprtk_override { return str_base_ptr_->base(); } std::size_t size() const exprtk_override { return str_base_ptr_->size(); } range_t& range_ref() exprtk_override { return str_range_ptr_->range_ref(); } const range_t& range_ref() const exprtk_override { return str_range_ptr_->range_ref(); } inline typename expression_node::node_type type() const exprtk_override { return expression_node::e_stringvararg; } void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override { expression_node::ndb_t::collect(final_node_ , node_delete_list); expression_node::ndb_t::collect(arg_list_ , node_delete_list); } std::size_t node_depth() const exprtk_override { return std::max( expression_node::ndb_t::compute_node_depth(final_node_), expression_node::ndb_t::compute_node_depth(arg_list_ )); } private: 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(const T a, const T x) { // a*x^n return a * exprtk::details::numeric::fast_exp::result(x); } template inline T axnb(const T a, const T x, const T b) { // a*x^n+b return a * exprtk::details::numeric::fast_exp::result(x) + b; } 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; }; #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); \ } \ }; \ 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,"") #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); \ } \ }; \ 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))") 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)),"") 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") #undef define_sfop3 #undef define_sfop4 template class sf3_node exprtk_final : public trinary_node { public: typedef expression_node* expression_ptr; 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 exprtk_override { assert(trinary_node::branch_[0].first); assert(trinary_node::branch_[1].first); assert(trinary_node::branch_[2].first); const T x = trinary_node::branch_[0].first->value(); const T y = trinary_node::branch_[1].first->value(); const T z = trinary_node::branch_[2].first->value(); return SpecialFunction::process(x, y, z); } }; template class sf4_node exprtk_final : public quaternary_node { public: typedef expression_node* expression_ptr; 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 exprtk_override { assert(quaternary_node::branch_[0].first); assert(quaternary_node::branch_[1].first); assert(quaternary_node::branch_[2].first); assert(quaternary_node::branch_[3].first); const T x = quaternary_node::branch_[0].first->value(); const T y = quaternary_node::branch_[1].first->value(); const T z = quaternary_node::branch_[2].first->value(); const T w = quaternary_node::branch_[3].first->value(); return SpecialFunction::process(x, y, z, w); } }; template class sf3_var_node exprtk_final : 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 exprtk_override { return SpecialFunction::process(v0_, v1_, v2_); } inline typename expression_node::node_type type() const exprtk_override { return expression_node::e_trinary; } private: sf3_var_node(const sf3_var_node&) exprtk_delete; sf3_var_node& operator=(const sf3_var_node&) exprtk_delete; const T& v0_; const T& v1_; const T& v2_; }; template class sf4_var_node exprtk_final : 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 exprtk_override { return SpecialFunction::process(v0_, v1_, v2_, v3_); } inline typename expression_node::node_type type() const exprtk_override { return expression_node::e_trinary; } private: sf4_var_node(const sf4_var_node&) exprtk_delete; sf4_var_node& operator=(const sf4_var_node&) exprtk_delete; const T& v0_; const T& v1_; const T& v2_; const T& v3_; }; template class vararg_node exprtk_final : public expression_node { public: typedef expression_node* expression_ptr; typedef std::pair branch_t; template class Sequence> explicit vararg_node(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]) { construct_branch_pair(arg_list_[i],arg_list[i]); } else { arg_list_.clear(); return; } } } inline T value() const exprtk_override { return VarArgFunction::process(arg_list_); } inline typename expression_node::node_type type() const exprtk_override { return expression_node::e_vararg; } void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override { expression_node::ndb_t::collect(arg_list_, node_delete_list); } std::size_t node_depth() const exprtk_override { return expression_node::ndb_t::compute_node_depth(arg_list_); } private: std::vector arg_list_; }; template class vararg_varnode exprtk_final : 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])) { variable_node* var_node_ptr = static_cast*>(arg_list[i]); arg_list_[i] = (&var_node_ptr->ref()); } else { arg_list_.clear(); return; } } } inline T value() const exprtk_override { if (!arg_list_.empty()) return VarArgFunction::process(arg_list_); else return std::numeric_limits::quiet_NaN(); } inline typename expression_node::node_type type() const exprtk_override { return expression_node::e_vararg; } private: std::vector arg_list_; }; template class vectorize_node exprtk_final : public expression_node { public: typedef expression_node* expression_ptr; typedef std::pair branch_t; explicit vectorize_node(const expression_ptr v) : ivec_ptr_(0) { 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 exprtk_override { 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 exprtk_override { return expression_node::e_vecfunc; } void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override { expression_node::ndb_t::collect(v_, node_delete_list); } std::size_t node_depth() const exprtk_override { return expression_node::ndb_t::compute_node_depth(v_); } private: vector_interface* ivec_ptr_; branch_t v_; }; template class assignment_node exprtk_final : public binary_node { public: typedef expression_node* expression_ptr; 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); } } inline T value() const exprtk_override { if (var_node_ptr_) { assert(binary_node::branch_[1].first); T& result = var_node_ptr_->ref(); result = binary_node::branch_[1].first->value(); return result; } else return std::numeric_limits::quiet_NaN(); } private: variable_node* var_node_ptr_; }; template class assignment_vec_elem_node exprtk_final : public binary_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); } } inline T value() const exprtk_override { if (vec_node_ptr_) { assert(binary_node::branch_[1].first); T& result = vec_node_ptr_->ref(); result = binary_node::branch_[1].first->value(); return result; } else return std::numeric_limits::quiet_NaN(); } private: vector_elem_node* vec_node_ptr_; }; template class assignment_rebasevec_elem_node exprtk_final : public binary_node { public: typedef expression_node* expression_ptr; 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_rebasevector_elem_node(binary_node::branch_[0].first)) { rbvec_node_ptr_ = static_cast*>(binary_node::branch_[0].first); } } inline T value() const exprtk_override { 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: rebasevector_elem_node* rbvec_node_ptr_; }; template class assignment_rebasevec_celem_node exprtk_final : 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) { if (is_rebasevector_celem_node(binary_node::branch_[0].first)) { rbvec_node_ptr_ = static_cast*>(binary_node::branch_[0].first); } } inline T value() const exprtk_override { 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: rebasevector_celem_node* rbvec_node_ptr_; }; template class assignment_vec_node exprtk_final : 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_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 exprtk_override { 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) \ 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 : *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(); } vector_node_ptr vec() const exprtk_override { return vec_node_ptr_; } vector_node_ptr vec() exprtk_override { return vec_node_ptr_; } inline typename expression_node::node_type type() const exprtk_override { return expression_node::e_vecvalass; } std::size_t size() const exprtk_override { return vds().size(); } vds_t& vds() exprtk_override { return vds_; } const vds_t& vds() const exprtk_override { return vds_; } private: vector_node* vec_node_ptr_; vds_t vds_; }; template class assignment_vecvec_node exprtk_final : 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_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) , src_is_ivec_(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); 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 (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()); } } initialised_ = (vec0_node_ptr_ && vec1_node_ptr_); assert(initialised_); } inline T value() const exprtk_override { if (initialised_) { assert(binary_node::branch_[1].first); binary_node::branch_[1].first->value(); if (src_is_ivec_) return vec0_node_ptr_->value(); 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) { #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; } 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(); } vector_node_ptr vec() exprtk_override { return vec0_node_ptr_; } vector_node_ptr vec() const exprtk_override { return vec0_node_ptr_; } inline typename expression_node::node_type type() const exprtk_override { return expression_node::e_vecvecass; } std::size_t size() const exprtk_override { return vds().size(); } vds_t& vds() exprtk_override { return vds_; } const vds_t& vds() const exprtk_override { return vds_; } private: vector_node* vec0_node_ptr_; vector_node* vec1_node_ptr_; bool initialised_; bool src_is_ivec_; vds_t vds_; }; template class assignment_op_node exprtk_final : 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) , var_node_ptr_(0) { if (is_variable_node(binary_node::branch_[0].first)) { var_node_ptr_ = static_cast*>(binary_node::branch_[0].first); } } inline T value() const exprtk_override { if (var_node_ptr_) { assert(binary_node::branch_[1].first); T& v = var_node_ptr_->ref(); v = Operation::process(v,binary_node::branch_[1].first->value()); return v; } else return std::numeric_limits::quiet_NaN(); } private: variable_node* var_node_ptr_; }; template class assignment_vec_elem_op_node exprtk_final : 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) { if (is_vector_elem_node(binary_node::branch_[0].first)) { vec_node_ptr_ = static_cast*>(binary_node::branch_[0].first); } } inline T value() const exprtk_override { 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_elem_node* vec_node_ptr_; }; template class assignment_rebasevec_elem_op_node exprtk_final : public binary_node { public: typedef expression_node* expression_ptr; 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_rebasevector_elem_node(binary_node::branch_[0].first)) { rbvec_node_ptr_ = static_cast*>(binary_node::branch_[0].first); } } inline T value() const exprtk_override { 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_elem_node* rbvec_node_ptr_; }; template class assignment_rebasevec_celem_op_node exprtk_final : 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 exprtk_override { 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 exprtk_final : 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 exprtk_override { 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(); } vector_node_ptr vec() const exprtk_override { return vec_node_ptr_; } vector_node_ptr vec() exprtk_override { return vec_node_ptr_; } inline typename expression_node::node_type type() const exprtk_override { return expression_node::e_vecopvalass; } std::size_t size() const exprtk_override { return vds().size(); } vds_t& vds() exprtk_override { return vds_; } const vds_t& vds() const exprtk_override { return vds_; } bool side_effect() const exprtk_override { return true; } private: vector_node* vec_node_ptr_; vds_t vds_; }; template class assignment_vecvec_op_node exprtk_final : 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_); assert(initialised_); } inline T value() const exprtk_override { 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 exprtk_override { return vec0_node_ptr_; } vector_node_ptr vec() exprtk_override { return vec0_node_ptr_; } inline typename expression_node::node_type type() const exprtk_override { return expression_node::e_vecopvecass; } std::size_t size() const exprtk_override { return vds().size(); } vds_t& vds() exprtk_override { return vds_; } const vds_t& vds() const exprtk_override { return vds_; } bool side_effect() const exprtk_override { return true; } private: vector_node* vec0_node_ptr_; vector_node* vec1_node_ptr_; bool initialised_; vds_t vds_; }; template class vec_binop_vecvec_node exprtk_final : 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; 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) , temp_ (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); } else if (is_ivector_node(binary_node::branch_[0].first)) { vector_interface* vi = reinterpret_cast*>(0); if (0 != (vi = dynamic_cast*>(binary_node::branch_[0].first))) { vec0_node_ptr_ = vi->vec(); v0_is_ivec = true; } } 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 (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_->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_); initialised_ = true; } assert(initialised_); } ~vec_binop_vecvec_node() { delete temp_; delete temp_vec_node_; } inline T value() const exprtk_override { 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(); const T* vec0 = vec0_node_ptr_->vds().data(); const T* vec1 = vec1_node_ptr_->vds().data(); T* vec2 = vds().data(); loop_unroll::details lud(size()); const T* upper_bound = vec2 + lud.upper_bound; while (vec2 < upper_bound) { #define exprtk_loop(N) \ vec2[N] = Operation::process(vec0[N], vec1[N]); \ 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; exprtk_disable_fallthrough_begin switch (lud.remainder) { #define case_stmt(N) \ case N : { vec2[i] = Operation::process(vec0[i], vec1[i]); ++i; } \ #ifndef exprtk_disable_superscalar_unroll case_stmt(15) case_stmt(14) 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 exprtk_override { return temp_vec_node_; } vector_node_ptr vec() exprtk_override { return temp_vec_node_; } inline typename expression_node::node_type type() const exprtk_override { return expression_node::e_vecvecarith; } std::size_t size() const exprtk_override { return vds_.size(); } vds_t& vds() exprtk_override { return vds_; } const vds_t& vds() const exprtk_override { return vds_; } private: vector_node_ptr vec0_node_ptr_; vector_node_ptr vec1_node_ptr_; vector_holder_ptr temp_; vector_node_ptr temp_vec_node_; bool initialised_; vds_t vds_; }; template class vec_binop_vecval_node exprtk_final : 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; vec_binop_vecval_node(const operator_type& opr, expression_ptr branch0, expression_ptr branch1) : binary_node(opr, branch0, branch1) , vec0_node_ptr_(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); } else if (is_ivector_node(binary_node::branch_[0].first)) { vector_interface* vi = reinterpret_cast*>(0); if (0 != (vi = dynamic_cast*>(binary_node::branch_[0].first))) { vec0_node_ptr_ = vi->vec(); v0_is_ivec = true; } } if (vec0_node_ptr_) { if (v0_is_ivec) vds() = vec0_node_ptr_->vds(); else vds() = vds_t(vec0_node_ptr_->size()); temp_ = new vector_holder(vds()); temp_vec_node_ = new vector_node (vds(),temp_); } } ~vec_binop_vecval_node() { delete temp_; delete temp_vec_node_; } inline T value() const exprtk_override { 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(); const T* vec0 = vec0_node_ptr_->vds().data(); T* vec1 = vds().data(); loop_unroll::details lud(size()); const T* upper_bound = vec0 + lud.upper_bound; while (vec0 < upper_bound) { #define exprtk_loop(N) \ vec1[N] = Operation::process(vec0[N], v); \ 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 : { vec1[i] = Operation::process(vec0[i], v); ++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 exprtk_override { return temp_vec_node_; } vector_node_ptr vec() exprtk_override { return temp_vec_node_; } inline typename expression_node::node_type type() const exprtk_override { return expression_node::e_vecvalarith; } std::size_t size() const exprtk_override { return vds().size(); } vds_t& vds() exprtk_override { return vds_; } const vds_t& vds() const exprtk_override { return vds_; } private: vector_node_ptr vec0_node_ptr_; vector_holder_ptr temp_; vector_node_ptr temp_vec_node_; vds_t vds_; }; template class vec_binop_valvec_node exprtk_final : 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; vec_binop_valvec_node(const operator_type& opr, expression_ptr branch0, expression_ptr branch1) : binary_node(opr, branch0, branch1) , vec1_node_ptr_(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); } 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(); v1_is_ivec = true; } } if (vec1_node_ptr_) { if (v1_is_ivec) vds() = vec1_node_ptr_->vds(); else vds() = vds_t(vec1_node_ptr_->size()); temp_ = new vector_holder(vds()); temp_vec_node_ = new vector_node (vds(),temp_); } } ~vec_binop_valvec_node() { delete temp_; delete temp_vec_node_; } inline T value() const exprtk_override { if (vec1_node_ptr_) { assert(binary_node::branch_[0].first); assert(binary_node::branch_[1].first); const T v = binary_node::branch_[0].first->value(); binary_node::branch_[1].first->value(); T* vec0 = vds().data(); const T* vec1 = vec1_node_ptr_->vds().data(); loop_unroll::details lud(size()); const T* upper_bound = vec0 + lud.upper_bound; while (vec0 < upper_bound) { #define exprtk_loop(N) \ vec0[N] = Operation::process(v, vec1[N]); \ 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(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 exprtk_override { return temp_vec_node_; } vector_node_ptr vec() exprtk_override { return temp_vec_node_; } inline typename expression_node::node_type type() const exprtk_override { return expression_node::e_vecvalarith; } std::size_t size() const exprtk_override { return vds().size(); } vds_t& vds() exprtk_override { return vds_; } const vds_t& vds() const exprtk_override { return vds_; } private: vector_node_ptr vec1_node_ptr_; vector_holder_ptr temp_; vector_node_ptr temp_vec_node_; vds_t vds_; }; template class unary_vector_node exprtk_final : public unary_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; unary_vector_node(const operator_type& opr, expression_ptr branch0) : unary_node(opr, branch0) , vec0_node_ptr_(0) , temp_ (0) , temp_vec_node_(0) { bool vec0_is_ivec = false; if (is_vector_node(unary_node::branch_.first)) { vec0_node_ptr_ = static_cast(unary_node::branch_.first); } else if (is_ivector_node(unary_node::branch_.first)) { vector_interface* vi = reinterpret_cast*>(0); if (0 != (vi = dynamic_cast*>(unary_node::branch_.first))) { vec0_node_ptr_ = vi->vec(); vec0_is_ivec = true; } } if (vec0_node_ptr_) { if (vec0_is_ivec) vds_ = vec0_node_ptr_->vds(); else vds_ = vds_t(vec0_node_ptr_->size()); temp_ = new vector_holder(vds()); temp_vec_node_ = new vector_node (vds(),temp_); } } ~unary_vector_node() { delete temp_; delete temp_vec_node_; } inline T value() const exprtk_override { assert(unary_node::branch_.first); unary_node::branch_.first->value(); if (vec0_node_ptr_) { const T* vec0 = vec0_node_ptr_->vds().data(); T* vec1 = vds().data(); loop_unroll::details lud(size()); const T* upper_bound = vec0 + lud.upper_bound; while (vec0 < upper_bound) { #define exprtk_loop(N) \ vec1[N] = Operation::process(vec0[N]); \ 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 : { vec1[i] = Operation::process(vec0[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 exprtk_override { return temp_vec_node_; } vector_node_ptr vec() exprtk_override { return temp_vec_node_; } inline typename expression_node::node_type type() const exprtk_override { return expression_node::e_vecunaryop; } std::size_t size() const exprtk_override { return vds().size(); } vds_t& vds() exprtk_override { return vds_; } const vds_t& vds() const exprtk_override { return vds_; } private: vector_node_ptr vec0_node_ptr_; vector_holder_ptr temp_; vector_node_ptr temp_vec_node_; vds_t vds_; }; template class conditional_vector_node exprtk_final : public expression_node , public vector_interface { public: typedef expression_node * expression_ptr; typedef vector_interface* vec_interface_ptr; typedef vector_node * vector_node_ptr; typedef vector_holder * vector_holder_ptr; typedef vec_data_store vds_t; typedef std::pair branch_t; conditional_vector_node(expression_ptr condition, expression_ptr consequent, expression_ptr alternative) : consequent_node_ptr_ (0) , alternative_node_ptr_(0) , temp_vec_node_ (0) , temp_ (0) , vec_size_ (0) , initialised_ (false) { construct_branch_pair(condition_ , condition ); construct_branch_pair(consequent_ , consequent ); construct_branch_pair(alternative_, alternative); if (details::is_ivector_node(consequent_.first)) { vec_interface_ptr ivec_ptr = dynamic_cast(consequent_.first); if (0 != ivec_ptr) { consequent_node_ptr_ = ivec_ptr->vec(); } } if (details::is_ivector_node(alternative_.first)) { vec_interface_ptr ivec_ptr = dynamic_cast(alternative_.first); if (0 != ivec_ptr) { alternative_node_ptr_ = ivec_ptr->vec(); } } if (consequent_node_ptr_ && alternative_node_ptr_) { vec_size_ = std::min(consequent_node_ptr_ ->vds().size(), alternative_node_ptr_->vds().size()); vds_ = vds_t(vec_size_); temp_ = new vector_holder(vds_); temp_vec_node_ = new vector_node (vds(),temp_); initialised_ = true; } assert(initialised_ && (vec_size_ > 0)); } ~conditional_vector_node() { delete temp_; delete temp_vec_node_; } inline T value() const exprtk_override { if (initialised_) { assert(condition_ .first); assert(consequent_ .first); assert(alternative_.first); T result = T(0); T* source_vector = 0; T* result_vector = vds().data(); if (is_true(condition_)) { result = consequent_.first->value(); source_vector = consequent_node_ptr_->vds().data(); } else { result = alternative_.first->value(); source_vector = alternative_node_ptr_->vds().data(); } for (std::size_t i = 0; i < vec_size_; ++i) { result_vector[i] = source_vector[i]; } return result; } return std::numeric_limits::quiet_NaN(); } vector_node_ptr vec() const exprtk_override { return temp_vec_node_; } vector_node_ptr vec() exprtk_override { return temp_vec_node_; } inline typename expression_node::node_type type() const exprtk_override { return expression_node::e_vecondition; } std::size_t size() const exprtk_override { return vec_size_; } vds_t& vds() exprtk_override { return vds_; } const vds_t& vds() const exprtk_override { return vds_; } void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override { expression_node::ndb_t::collect(condition_ , node_delete_list); expression_node::ndb_t::collect(consequent_ , node_delete_list); expression_node::ndb_t::collect(alternative_ , node_delete_list); } std::size_t node_depth() const exprtk_override { return expression_node::ndb_t::compute_node_depth (condition_, consequent_, alternative_); } private: branch_t condition_; branch_t consequent_; branch_t alternative_; vector_node_ptr consequent_node_ptr_; vector_node_ptr alternative_node_ptr_; vector_node_ptr temp_vec_node_; vector_holder_ptr temp_; vds_t vds_; std::size_t vec_size_; bool initialised_; }; template class scand_node exprtk_final : public binary_node { public: typedef expression_node* expression_ptr; scand_node(const operator_type& opr, expression_ptr branch0, expression_ptr branch1) : binary_node(opr, branch0, branch1) {} inline T value() const exprtk_override { 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()) && std::not_equal_to() (T(0),binary_node::branch_[1].first->value()) ) ? T(1) : T(0); } }; template class scor_node exprtk_final : public binary_node { public: typedef expression_node* expression_ptr; scor_node(const operator_type& opr, expression_ptr branch0, expression_ptr branch1) : binary_node(opr, branch0, branch1) {} inline T value() const exprtk_override { 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()) || std::not_equal_to() (T(0),binary_node::branch_[1].first->value()) ) ? T(1) : T(0); } }; template class function_N_node exprtk_final : public expression_node { public: // Function of N paramters. typedef expression_node* expression_ptr; typedef std::pair branch_t; typedef IFunction ifunction; explicit function_N_node(ifunction* func) : function_((N == func->param_count) ? func : reinterpret_cast(0)) , parameter_count_(func->param_count) {} template bool init_branches(expression_ptr (&b)[NumBranches]) { // Needed for incompetent and broken msvc compiler versions #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable: 4127) #endif if (N != NumBranches) return false; else { for (std::size_t i = 0; i < NumBranches; ++i) { if (b[i]) branch_[i] = std::make_pair(b[i],branch_deletable(b[i])); else return false; } return true; } #ifdef _MSC_VER #pragma warning(pop) #endif } inline bool operator <(const function_N_node& fn) const { return this < (&fn); } inline T value() const exprtk_override { // Needed for incompetent and broken msvc compiler versions #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable: 4127) #endif if ((0 == function_) || (0 == N)) return std::numeric_limits::quiet_NaN(); else { T v[N]; evaluate_branches::execute(v,branch_); return invoke::execute(*function_,v); } #ifdef _MSC_VER #pragma warning(pop) #endif } inline typename expression_node::node_type type() const exprtk_override { return expression_node::e_function; } void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override { expression_node::ndb_t::template collect(branch_, node_delete_list); } std::size_t node_depth() const exprtk_override { return expression_node::ndb_t::template compute_node_depth(branch_); } template struct evaluate_branches { static inline void execute(T_ (&v)[BranchCount], const branch_t (&b)[BranchCount]) { for (std::size_t i = 0; i < BranchCount; ++i) { v[i] = b[i].first->value(); } } }; template struct evaluate_branches { static inline void execute(T_ (&v)[5], const branch_t (&b)[5]) { v[0] = b[0].first->value(); v[1] = b[1].first->value(); v[2] = b[2].first->value(); v[3] = b[3].first->value(); v[4] = b[4].first->value(); } }; template struct evaluate_branches { static inline void execute(T_ (&v)[4], const branch_t (&b)[4]) { v[0] = b[0].first->value(); v[1] = b[1].first->value(); v[2] = b[2].first->value(); v[3] = b[3].first->value(); } }; template struct evaluate_branches { static inline void execute(T_ (&v)[3], const branch_t (&b)[3]) { v[0] = b[0].first->value(); v[1] = b[1].first->value(); v[2] = b[2].first->value(); } }; template struct evaluate_branches { static inline void execute(T_ (&v)[2], const branch_t (&b)[2]) { v[0] = b[0].first->value(); v[1] = b[1].first->value(); } }; template struct evaluate_branches { static inline void execute(T_ (&v)[1], const branch_t (&b)[1]) { v[0] = b[0].first->value(); } }; template struct invoke { static inline T execute(ifunction&, branch_t (&)[ParamCount]) { return std::numeric_limits::quiet_NaN(); } }; template struct invoke { static inline T_ execute(ifunction& f, T_ (&v)[20]) { return f(v[0],v[1],v[2],v[3],v[4],v[5],v[6],v[7],v[8],v[9],v[10],v[11],v[12],v[13],v[14],v[15],v[16],v[17],v[18],v[19]); } }; template struct invoke { static inline T_ execute(ifunction& f, T_ (&v)[19]) { return f(v[0],v[1],v[2],v[3],v[4],v[5],v[6],v[7],v[8],v[9],v[10],v[11],v[12],v[13],v[14],v[15],v[16],v[17],v[18]); } }; template struct invoke { static inline T_ execute(ifunction& f, T_ (&v)[18]) { return f(v[0], v[1], v[2], v[3], v[4], v[5], v[6], v[7], v[8], v[9], v[10], v[11], v[12], v[13], v[14], v[15], v[16], v[17]); } }; template struct invoke { static inline T_ execute(ifunction& f, T_ (&v)[17]) { return f(v[0], v[1], v[2], v[3], v[4], v[5], v[6], v[7], v[8], v[9], v[10], v[11], v[12], v[13], v[14], v[15], v[16]); } }; template struct invoke { static inline T_ execute(ifunction& f, T_ (&v)[16]) { return f(v[0], v[1], v[2], v[3], v[4], v[5], v[6], v[7], v[8], v[9], v[10], v[11], v[12], v[13], v[14], v[15]); } }; template struct invoke { static inline T_ execute(ifunction& f, T_ (&v)[15]) { return f(v[0], v[1], v[2], v[3], v[4], v[5], v[6], v[7], v[8], v[9], v[10], v[11], v[12], v[13], v[14]); } }; template struct invoke { static inline T_ execute(ifunction& f, T_ (&v)[14]) { return f(v[0], v[1], v[2], v[3], v[4], v[5], v[6], v[7], v[8], v[9], v[10], v[11], v[12], v[13]); } }; template struct invoke { static inline T_ execute(ifunction& f, T_ (&v)[13]) { return f(v[0], v[1], v[2], v[3], v[4], v[5], v[6], v[7], v[8], v[9], v[10], v[11], v[12]); } }; template struct invoke { static inline T_ execute(ifunction& f, T_ (&v)[12]) { return f(v[0], v[1], v[2], v[3], v[4], v[5], v[6], v[7], v[8], v[9], v[10], v[11]); } }; template struct invoke { static inline T_ execute(ifunction& f, T_ (&v)[11]) { return f(v[0], v[1], v[2], v[3], v[4], v[5], v[6], v[7], v[8], v[9], v[10]); } }; template struct invoke { static inline T_ execute(ifunction& f, T_ (&v)[10]) { return f(v[0], v[1], v[2], v[3], v[4], v[5], v[6], v[7], v[8], v[9]); } }; template struct invoke { static inline T_ execute(ifunction& f, T_ (&v)[9]) { return f(v[0], v[1], v[2], v[3], v[4], v[5], v[6], v[7], v[8]); } }; template struct invoke { static inline T_ execute(ifunction& f, T_ (&v)[8]) { return f(v[0], v[1], v[2], v[3], v[4], v[5], v[6], v[7]); } }; template struct invoke { static inline T_ execute(ifunction& f, T_ (&v)[7]) { return f(v[0], v[1], v[2], v[3], v[4], v[5], v[6]); } }; template struct invoke { static inline T_ execute(ifunction& f, T_ (&v)[6]) { return f(v[0], v[1], v[2], v[3], v[4], v[5]); } }; template struct invoke { static inline T_ execute(ifunction& f, T_ (&v)[5]) { return f(v[0], v[1], v[2], v[3], v[4]); } }; template struct invoke { static inline T_ execute(ifunction& f, T_ (&v)[4]) { return f(v[0], v[1], v[2], v[3]); } }; template struct invoke { static inline T_ execute(ifunction& f, T_ (&v)[3]) { return f(v[0], v[1], v[2]); } }; template struct invoke { static inline T_ execute(ifunction& f, T_ (&v)[2]) { return f(v[0], v[1]); } }; template struct invoke { static inline T_ execute(ifunction& f, T_ (&v)[1]) { return f(v[0]); } }; private: ifunction* function_; std::size_t parameter_count_; branch_t branch_[N]; }; template class function_N_node exprtk_final : public expression_node { public: typedef expression_node* expression_ptr; typedef IFunction ifunction; explicit function_N_node(ifunction* func) : function_((0 == func->param_count) ? func : reinterpret_cast(0)) {} inline bool operator <(const function_N_node& fn) const { return this < (&fn); } inline T value() const exprtk_override { if (function_) return (*function_)(); else return std::numeric_limits::quiet_NaN(); } inline typename expression_node::node_type type() const exprtk_override { return expression_node::e_function; } private: ifunction* function_; }; template class vararg_function_node exprtk_final : public expression_node { public: typedef expression_node* expression_ptr; vararg_function_node(VarArgFunction* func, const std::vector& arg_list) : function_(func) , arg_list_(arg_list) { value_list_.resize(arg_list.size(),std::numeric_limits::quiet_NaN()); } inline bool operator <(const vararg_function_node& fn) const { return this < (&fn); } inline T value() const exprtk_override { if (function_) { populate_value_list(); return (*function_)(value_list_); } else return std::numeric_limits::quiet_NaN(); } inline typename expression_node::node_type type() const exprtk_override { return expression_node::e_vafunction; } void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override { 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 exprtk_override { return expression_node::ndb_t::compute_node_depth(arg_list_); } private: inline void populate_value_list() const { for (std::size_t i = 0; i < arg_list_.size(); ++i) { value_list_[i] = arg_list_[i]->value(); } } VarArgFunction* function_; std::vector arg_list_; mutable std::vector value_list_; }; template class generic_function_node : public expression_node { public: 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 typename range_interface::range_t 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) {} virtual ~generic_function_node() {} void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override { expression_node::ndb_t::collect(branch_, node_delete_list); } std::size_t node_depth() const exprtk_override exprtk_final { return expression_node::ndb_t::compute_node_depth(branch_); } virtual bool init_branches() { 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(reinterpret_cast(0),false)); for (std::size_t i = 0; i < arg_list_.size(); ++i) { type_store_t& ts = typestore_list_[i]; if (0 == arg_list_[i]) return false; else if (is_ivector_node(arg_list_[i])) { vector_interface* vi = reinterpret_cast*>(0); if (0 == (vi = dynamic_cast*>(arg_list_[i]))) return false; ts.size = vi->size(); ts.data = vi->vds().data(); ts.type = type_store_t::e_vector; vi->vec()->vec_holder().set_ref(&ts.vec_data); } #ifndef exprtk_disable_string_capabilities else if (is_generally_string_node(arg_list_[i])) { string_base_node* sbn = reinterpret_cast*>(0); if (0 == (sbn = dynamic_cast*>(arg_list_[i]))) return false; ts.size = sbn->size(); ts.data = reinterpret_cast(const_cast(sbn->base())); ts.type = type_store_t::e_string; range_list_[i].data = ts.data; range_list_[i].size = ts.size; range_list_[i].type_size = sizeof(char); range_list_[i].str_node = sbn; range_interface_t* ri = reinterpret_cast(0); if (0 == (ri = dynamic_cast(arg_list_[i]))) return false; 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()); } #endif else if (is_variable_node(arg_list_[i])) { variable_node_ptr_t var = variable_node_ptr_t(0); if (0 == (var = dynamic_cast(arg_list_[i]))) return false; ts.size = 1; ts.data = &var->ref(); ts.type = type_store_t::e_scalar; } else { ts.size = 1; ts.data = reinterpret_cast(&expr_as_vec1_store_[i]); ts.type = type_store_t::e_scalar; } branch_[i] = std::make_pair(arg_list_[i],branch_deletable(arg_list_[i])); } return true; } inline bool operator <(const generic_function_node& fn) const { return this < (&fn); } inline T value() const exprtk_override { if (function_) { if (populate_value_list()) { typedef typename GenericFunction::parameter_list_t parameter_list_t; return (*function_)(parameter_list_t(typestore_list_)); } } return std::numeric_limits::quiet_NaN(); } inline typename expression_node::node_type type() const exprtk_override { return expression_node::e_genfunction; } protected: inline virtual bool populate_value_list() const { for (std::size_t i = 0; i < branch_.size(); ++i) { expr_as_vec1_store_[i] = branch_[i].first->value(); } for (std::size_t i = 0; i < branch_.size(); ++i) { range_data_type_t& rdt = range_list_[i]; if (rdt.range) { const range_t& rp = (*rdt.range); std::size_t r0 = 0; std::size_t r1 = 0; 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; else #endif ts.data = static_cast(rdt.data) + (rp.cache.first * rdt.type_size); } else return false; } } return true; } GenericFunction* function_; mutable typestore_list_t typestore_list_; private: std::vector arg_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, public range_interface { public: typedef generic_function_node gen_function_t; typedef typename range_interface::range_t range_t; string_function_node(StringFunction* func, const std::vector& arg_list) : gen_function_t(arg_list,func) { 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; } inline bool operator <(const string_function_node& fn) const { return this < (&fn); } inline T value() const exprtk_override { if (gen_function_t::function_) { if (gen_function_t::populate_value_list()) { typedef typename StringFunction::parameter_list_t parameter_list_t; 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; return result; } } return std::numeric_limits::quiet_NaN(); } inline typename expression_node::node_type type() const exprtk_override { return expression_node::e_strfunction; } std::string str() const exprtk_override { return ret_string_; } char_cptr base() const exprtk_override { return &ret_string_[0]; } std::size_t size() const exprtk_override { return ret_string_.size(); } range_t& range_ref() exprtk_override { return range_; } const range_t& range_ref() const exprtk_override { return range_; } protected: 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 typename gen_function_t::range_t range_t; multimode_genfunction_node(GenericFunction* func, const std::size_t& param_seq_index, const std::vector& arg_list) : gen_function_t(arg_list,func) , param_seq_index_(param_seq_index) {} inline T value() const exprtk_override { 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 std::numeric_limits::quiet_NaN(); } inline typename expression_node::node_type type() const exprtk_override exprtk_final { return expression_node::e_genfunction; } private: std::size_t param_seq_index_; }; #ifndef exprtk_disable_string_capabilities template class multimode_strfunction_node exprtk_final : public string_function_node { public: typedef string_function_node str_function_t; typedef typename str_function_t::range_t range_t; multimode_strfunction_node(StringFunction* func, const std::size_t& param_seq_index, const std::vector& arg_list) : str_function_t(func,arg_list) , param_seq_index_(param_seq_index) {} inline T value() const exprtk_override { if (str_function_t::function_) { if (str_function_t::populate_value_list()) { typedef typename StringFunction::parameter_list_t parameter_list_t; 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; return result; } } return std::numeric_limits::quiet_NaN(); } inline typename expression_node::node_type type() const exprtk_override { return expression_node::e_strfunction; } private: 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 exprtk_final : public generic_function_node > { public: typedef results_context results_context_t; typedef null_igenfunc igeneric_function_t; typedef igeneric_function_t* igeneric_function_ptr; typedef generic_function_node gen_function_t; return_node(const std::vector& arg_list, results_context_t& rc) : gen_function_t (arg_list) , results_context_(&rc) {} inline T value() const exprtk_override { 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 exprtk_override { return expression_node::e_return; } private: results_context_t* results_context_; }; template class return_envelope_node exprtk_final : 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 exprtk_override { 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 exprtk_override { return expression_node::e_retenv; } inline bool* retinvk_ptr() { return &return_invoked_; } void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override { expression_node::ndb_t::collect(body_, node_delete_list); } std::size_t node_depth() const exprtk_override { 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; \ 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 ) exprtk_define_unary_op(acosh) exprtk_define_unary_op(asin ) exprtk_define_unary_op(asinh) exprtk_define_unary_op(atan ) exprtk_define_unary_op(atanh) exprtk_define_unary_op(ceil ) exprtk_define_unary_op(cos ) exprtk_define_unary_op(cosh ) exprtk_define_unary_op(cot ) exprtk_define_unary_op(csc ) exprtk_define_unary_op(d2g ) exprtk_define_unary_op(d2r ) exprtk_define_unary_op(erf ) exprtk_define_unary_op(erfc ) exprtk_define_unary_op(exp ) exprtk_define_unary_op(expm1) exprtk_define_unary_op(floor) exprtk_define_unary_op(frac ) exprtk_define_unary_op(g2d ) exprtk_define_unary_op(log ) exprtk_define_unary_op(log10) exprtk_define_unary_op(log2 ) exprtk_define_unary_op(log1p) exprtk_define_unary_op(ncdf ) exprtk_define_unary_op(neg ) exprtk_define_unary_op(notl ) exprtk_define_unary_op(pos ) exprtk_define_unary_op(r2d ) exprtk_define_unary_op(round) exprtk_define_unary_op(sec ) exprtk_define_unary_op(sgn ) exprtk_define_unary_op(sin ) exprtk_define_unary_op(sinc ) exprtk_define_unary_op(sinh ) exprtk_define_unary_op(sqrt ) exprtk_define_unary_op(tan ) exprtk_define_unary_op(tanh ) exprtk_define_unary_op(trunc) #undef exprtk_define_unary_op template struct opr_base { 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::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; } }; template struct mul_op : public opr_base { 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; } }; template struct sub_op : public opr_base { 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; } }; template struct div_op : public opr_base { 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; } }; template struct mod_op : public opr_base { 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; } }; template struct pow_op : public opr_base { 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; } }; template 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; } static inline details::operator_type operation() { return details::e_lt; } }; template 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; } static inline details::operator_type operation() { return details::e_lte; } }; template 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; } static inline details::operator_type operation() { return details::e_gt; } }; template 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; } static inline details::operator_type operation() { return details::e_gte; } }; template struct eq_op : public opr_base { typedef typename opr_base::Type Type; static inline T process(Type t1, Type t2) { return (std::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_eq; } 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; } static inline details::operator_type operation() { return details::e_ne; } }; template 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; } }; template 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; } }; template 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; } }; template 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; } }; template 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; } }; template 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; } }; template 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; } static inline details::operator_type operation() { return details::e_in; } }; template 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; } static inline details::operator_type operation() { return details::e_like; } }; template 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; } static inline details::operator_type operation() { return details::e_ilike; } }; template 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) { return ((t0 <= t1) && (t1 <= t2)) ? T(1) : T(0); } static inline typename expression_node::node_type type() { return expression_node::e_inranges; } static inline details::operator_type operation() { return details::e_inrange; } }; template inline T value(details::expression_node* n) { return n->value(); } template 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 { typedef typename opr_base::Type Type; template class Sequence> static inline T process(const Sequence& arg_list) { switch (arg_list.size()) { case 0 : return T(0); case 1 : return process_1(arg_list); case 2 : return process_2(arg_list); case 3 : return process_3(arg_list); case 4 : return process_4(arg_list); case 5 : return process_5(arg_list); default : { T result = T(0); for (std::size_t i = 0; i < arg_list.size(); ++i) { result += value(arg_list[i]); } return result; } } } template static inline T process_1(const Sequence& arg_list) { return value(arg_list[0]); } template static inline T process_2(const Sequence& arg_list) { return value(arg_list[0]) + value(arg_list[1]); } template static inline T process_3(const Sequence& arg_list) { return value(arg_list[0]) + value(arg_list[1]) + 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]) ; } template static inline T process_5(const Sequence& arg_list) { return value(arg_list[0]) + value(arg_list[1]) + value(arg_list[2]) + value(arg_list[3]) + value(arg_list[4]) ; } }; template struct vararg_mul_op : public opr_base { typedef typename opr_base::Type Type; template class Sequence> static inline T process(const Sequence& arg_list) { switch (arg_list.size()) { case 0 : return T(0); case 1 : return process_1(arg_list); case 2 : return process_2(arg_list); case 3 : return process_3(arg_list); case 4 : return process_4(arg_list); case 5 : return process_5(arg_list); default : { T result = T(value(arg_list[0])); for (std::size_t i = 1; i < arg_list.size(); ++i) { result *= value(arg_list[i]); } return result; } } } template static inline T process_1(const Sequence& arg_list) { return value(arg_list[0]); } template static inline T process_2(const Sequence& arg_list) { return value(arg_list[0]) * value(arg_list[1]); } template static inline T process_3(const Sequence& arg_list) { return value(arg_list[0]) * value(arg_list[1]) * 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]) ; } template static inline T process_5(const Sequence& arg_list) { return value(arg_list[0]) * value(arg_list[1]) * value(arg_list[2]) * value(arg_list[3]) * value(arg_list[4]) ; } }; template struct vararg_avg_op : public opr_base { typedef typename opr_base::Type Type; template class Sequence> static inline T process(const Sequence& arg_list) { switch (arg_list.size()) { case 0 : return T(0); case 1 : return process_1(arg_list); case 2 : return process_2(arg_list); case 3 : return process_3(arg_list); case 4 : return process_4(arg_list); case 5 : return process_5(arg_list); default : return vararg_add_op::process(arg_list) / arg_list.size(); } } template static inline T process_1(const Sequence& arg_list) { return value(arg_list[0]); } template static inline T process_2(const Sequence& arg_list) { return (value(arg_list[0]) + value(arg_list[1])) / T(2); } template static inline T process_3(const Sequence& arg_list) { return (value(arg_list[0]) + value(arg_list[1]) + value(arg_list[2])) / T(3); } 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])) / T(4); } template static inline T process_5(const Sequence& arg_list) { return (value(arg_list[0]) + value(arg_list[1]) + value(arg_list[2]) + value(arg_list[3]) + value(arg_list[4])) / T(5); } }; template struct vararg_min_op : public opr_base { typedef typename opr_base::Type Type; template class Sequence> static inline T process(const Sequence& arg_list) { switch (arg_list.size()) { case 0 : return T(0); case 1 : return process_1(arg_list); case 2 : return process_2(arg_list); case 3 : return process_3(arg_list); case 4 : return process_4(arg_list); case 5 : return process_5(arg_list); default : { T result = T(value(arg_list[0])); for (std::size_t i = 1; i < arg_list.size(); ++i) { const T v = value(arg_list[i]); if (v < result) result = v; } return result; } } } template static inline T process_1(const Sequence& arg_list) { return value(arg_list[0]); } template static inline T process_2(const Sequence& arg_list) { return std::min(value(arg_list[0]),value(arg_list[1])); } template static inline T process_3(const Sequence& arg_list) { return std::min(std::min(value(arg_list[0]),value(arg_list[1])),value(arg_list[2])); } template 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]))); } 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]))), value(arg_list[4])); } }; template struct vararg_max_op : public opr_base { typedef typename opr_base::Type Type; template class Sequence> static inline T process(const Sequence& arg_list) { switch (arg_list.size()) { case 0 : return T(0); case 1 : return process_1(arg_list); case 2 : return process_2(arg_list); case 3 : return process_3(arg_list); case 4 : return process_4(arg_list); case 5 : return process_5(arg_list); default : { T result = T(value(arg_list[0])); for (std::size_t i = 1; i < arg_list.size(); ++i) { const T v = value(arg_list[i]); if (v > result) result = v; } return result; } } } template static inline T process_1(const Sequence& arg_list) { return value(arg_list[0]); } template static inline T process_2(const Sequence& arg_list) { return std::max(value(arg_list[0]),value(arg_list[1])); } template static inline T process_3(const Sequence& arg_list) { return std::max(std::max(value(arg_list[0]),value(arg_list[1])),value(arg_list[2])); } template 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]))); } 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]))), value(arg_list[4])); } }; template struct vararg_mand_op : public opr_base { typedef typename opr_base::Type Type; template class Sequence> static inline T process(const Sequence& arg_list) { switch (arg_list.size()) { case 1 : return process_1(arg_list); case 2 : return process_2(arg_list); case 3 : return process_3(arg_list); case 4 : return process_4(arg_list); case 5 : return process_5(arg_list); default : { for (std::size_t i = 0; i < arg_list.size(); ++i) { if (std::equal_to()(T(0), value(arg_list[i]))) return T(0); } return T(1); } } } template static inline T process_1(const Sequence& arg_list) { return std::not_equal_to() (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])) ) ? T(1) : T(0); } template 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])) ) ? T(1) : T(0); } template 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])) ) ? T(1) : T(0); } template 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])) ) ? T(1) : T(0); } }; template struct vararg_mor_op : public opr_base { typedef typename opr_base::Type Type; template class Sequence> static inline T process(const Sequence& arg_list) { switch (arg_list.size()) { case 1 : return process_1(arg_list); case 2 : return process_2(arg_list); case 3 : return process_3(arg_list); case 4 : return process_4(arg_list); case 5 : return process_5(arg_list); default : { for (std::size_t i = 0; i < arg_list.size(); ++i) { if (std::not_equal_to()(T(0), value(arg_list[i]))) return T(1); } return T(0); } } } template static inline T process_1(const Sequence& arg_list) { return std::not_equal_to() (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])) ) ? T(1) : T(0); } template 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])) ) ? T(1) : T(0); } template 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])) ) ? T(1) : T(0); } template 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])) ) ? T(1) : T(0); } }; template struct vararg_multi_op : public opr_base { typedef typename opr_base::Type Type; template class Sequence> static inline T process(const Sequence& arg_list) { switch (arg_list.size()) { case 0 : return std::numeric_limits::quiet_NaN(); case 1 : return process_1(arg_list); case 2 : return process_2(arg_list); case 3 : return process_3(arg_list); case 4 : return process_4(arg_list); case 5 : return process_5(arg_list); case 6 : return process_6(arg_list); case 7 : return process_7(arg_list); case 8 : return process_8(arg_list); default : { for (std::size_t i = 0; i < (arg_list.size() - 1); ++i) { value(arg_list[i]); } return value(arg_list.back()); } } } template static inline T process_1(const Sequence& arg_list) { return value(arg_list[0]); } template static inline T process_2(const Sequence& arg_list) { value(arg_list[0]); return value(arg_list[1]); } template static inline T process_3(const Sequence& arg_list) { value(arg_list[0]); value(arg_list[1]); return value(arg_list[2]); } template static inline T process_4(const Sequence& arg_list) { value(arg_list[0]); value(arg_list[1]); value(arg_list[2]); return value(arg_list[3]); } template static inline T process_5(const Sequence& arg_list) { value(arg_list[0]); value(arg_list[1]); value(arg_list[2]); value(arg_list[3]); return value(arg_list[4]); } template static inline T process_6(const Sequence& arg_list) { value(arg_list[0]); value(arg_list[1]); value(arg_list[2]); value(arg_list[3]); value(arg_list[4]); return value(arg_list[5]); } template static inline T process_7(const Sequence& arg_list) { value(arg_list[0]); value(arg_list[1]); value(arg_list[2]); value(arg_list[3]); value(arg_list[4]); value(arg_list[5]); return value(arg_list[6]); } template static inline T process_8(const Sequence& arg_list) { value(arg_list[0]); value(arg_list[1]); value(arg_list[2]); value(arg_list[3]); value(arg_list[4]); value(arg_list[5]); value(arg_list[6]); return value(arg_list[7]); } }; template struct vec_add_op { typedef vector_interface* ivector_ptr; static inline T process(const ivector_ptr v) { const T* vec = v->vec()->vds().data(); const std::size_t vec_size = v->vec()->vds().size(); 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]; \ 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 ; } }; template struct vec_mul_op { typedef vector_interface* ivector_ptr; static inline T process(const ivector_ptr v) { const T* vec = v->vec()->vds().data(); const std::size_t vec_size = v->vec()->vds().size(); loop_unroll::details lud(vec_size); if (vec_size <= static_cast(lud.batch_size)) { 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; } 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 ; } }; template struct vec_avg_op { typedef vector_interface* ivector_ptr; static inline T process(const ivector_ptr v) { const std::size_t vec_size = v->vec()->vds().size(); return vec_add_op::process(v) / vec_size; } }; template struct vec_min_op { typedef vector_interface* ivector_ptr; static inline T process(const ivector_ptr v) { const T* vec = v->vec()->vds().data(); const std::size_t vec_size = v->vec()->vds().size(); T result = vec[0]; for (std::size_t i = 1; i < vec_size; ++i) { const T v_i = vec[i]; if (v_i < result) result = v_i; } return result; } }; template struct vec_max_op { typedef vector_interface* ivector_ptr; static inline T process(const ivector_ptr v) { const T* vec = v->vec()->vds().data(); const std::size_t vec_size = v->vec()->vds().size(); T result = vec[0]; for (std::size_t i = 1; i < vec_size; ++i) { const T v_i = vec[i]; if (v_i > result) result = v_i; } return result; } }; template class vov_base_node : public expression_node { public: virtual ~vov_base_node() {} inline virtual operator_type operation() const { return details::e_default; } virtual const T& v0() const = 0; virtual const T& v1() const = 0; }; template class cov_base_node : public expression_node { public: virtual ~cov_base_node() {} inline virtual operator_type operation() const { return details::e_default; } virtual const T c() const = 0; virtual const T& v() const = 0; }; template class voc_base_node : public expression_node { public: virtual ~voc_base_node() {} inline virtual operator_type operation() const { return details::e_default; } virtual const T c() const = 0; virtual const T& v() const = 0; }; template class vob_base_node : public expression_node { public: virtual ~vob_base_node() {} virtual const T& v() const = 0; }; template class bov_base_node : public expression_node { public: virtual ~bov_base_node() {} virtual const T& v() const = 0; }; template class cob_base_node : public expression_node { public: virtual ~cob_base_node() {} inline virtual operator_type operation() const { return details::e_default; } virtual const T c() const = 0; virtual void set_c(const T) = 0; virtual expression_node* move_branch(const std::size_t& index) = 0; }; template class boc_base_node : public expression_node { public: virtual ~boc_base_node() {} inline virtual operator_type operation() const { return details::e_default; } virtual const T c() const = 0; virtual void set_c(const T) = 0; virtual expression_node* move_branch(const std::size_t& index) = 0; }; template class uv_base_node : public expression_node { public: virtual ~uv_base_node() {} inline virtual operator_type operation() const { return details::e_default; } virtual const T& v() const = 0; }; template class sos_base_node : public expression_node { public: virtual ~sos_base_node() {} inline virtual operator_type operation() const { return details::e_default; } }; template class sosos_base_node : public expression_node { public: virtual ~sosos_base_node() {} inline virtual operator_type operation() const { return details::e_default; } }; template class T0oT1oT2_base_node : public expression_node { public: virtual ~T0oT1oT2_base_node() {} virtual std::string type_id() const = 0; }; template class T0oT1oT2oT3_base_node : public expression_node { public: virtual ~T0oT1oT2oT3_base_node() {} virtual std::string type_id() const = 0; }; template class unary_variable_node exprtk_final : public uv_base_node { public: typedef expression_node* expression_ptr; typedef Operation operation_t; explicit unary_variable_node(const T& var) : v_(var) {} inline T value() const exprtk_override { return Operation::process(v_); } inline typename expression_node::node_type type() const exprtk_override { return Operation::type(); } inline operator_type operation() const exprtk_override { return Operation::operation(); } inline const T& v() const exprtk_override { return v_; } private: unary_variable_node(const unary_variable_node&) exprtk_delete; unary_variable_node& operator=(const unary_variable_node&) exprtk_delete; const T& v_; }; template class uvouv_node exprtk_final : public expression_node { public: // UOpr1(v0) Op UOpr2(v1) typedef typename details::functor_t functor_t; typedef typename functor_t::bfunc_t bfunc_t; typedef typename functor_t::ufunc_t ufunc_t; typedef expression_node* expression_ptr; explicit uvouv_node(const T& var0,const T& var1, ufunc_t uf0, ufunc_t uf1, bfunc_t bf) : v0_(var0) , v1_(var1) , u0_(uf0 ) , u1_(uf1 ) , f_ (bf ) {} inline T value() const exprtk_override { return f_(u0_(v0_),u1_(v1_)); } inline typename expression_node::node_type type() const exprtk_override { return expression_node::e_uvouv; } inline const T& v0() { return v0_; } inline const T& v1() { return v1_; } inline ufunc_t u0() { return u0_; } inline ufunc_t u1() { return u1_; } inline ufunc_t f() { return f_; } private: uvouv_node(const uvouv_node&) exprtk_delete; uvouv_node& operator=(const uvouv_node&) exprtk_delete; const T& v0_; const T& v1_; const ufunc_t u0_; const ufunc_t u1_; const bfunc_t f_; }; template class unary_branch_node exprtk_final : public expression_node { public: typedef Operation operation_t; typedef expression_node* expression_ptr; typedef std::pair branch_t; explicit unary_branch_node(expression_ptr branch) { construct_branch_pair(branch_, branch); } inline T value() const exprtk_override { return Operation::process(branch_.first->value()); } inline typename expression_node::node_type type() const exprtk_override { return Operation::type(); } inline operator_type operation() { return Operation::operation(); } inline expression_node* branch(const std::size_t&) const exprtk_override { return branch_.first; } inline void release() { branch_.second = false; } void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override { expression_node::ndb_t::collect(branch_, node_delete_list); } std::size_t node_depth() const exprtk_override { return expression_node::ndb_t::compute_node_depth(branch_); } private: unary_branch_node(const unary_branch_node&) exprtk_delete; unary_branch_node& operator=(const unary_branch_node&) exprtk_delete; branch_t branch_; }; template struct is_const { enum {result = 0}; }; template struct is_const { enum {result = 1}; }; template struct is_const_ref { enum {result = 0}; }; template struct is_const_ref { enum {result = 1}; }; template struct is_ref { enum {result = 0}; }; template struct is_ref { enum {result = 1}; }; template struct is_ref { enum {result = 0}; }; template struct param_to_str { static std::string result() { static const std::string r("v"); return r; } }; template <> struct param_to_str<0> { static std::string result() { static const std::string r("c"); return r; } }; #define exprtk_crtype(Type) \ param_to_str::result>::result() \ template struct T0oT1oT2process { typedef typename details::functor_t functor_t; typedef typename functor_t::bfunc_t bfunc_t; struct mode0 { static inline T process(const T& t0, const T& t1, const T& t2, const bfunc_t bf0, const bfunc_t bf1) { // (T0 o0 T1) o1 T2 return bf1(bf0(t0,t1),t2); } template static inline std::string id() { static const std::string result = "(" + exprtk_crtype(T0) + "o" + exprtk_crtype(T1) + ")o(" + exprtk_crtype(T2) + ")" ; return result; } }; struct mode1 { static inline T process(const T& t0, const T& t1, const T& t2, const bfunc_t bf0, const bfunc_t bf1) { // T0 o0 (T1 o1 T2) return bf0(t0,bf1(t1,t2)); } template static inline std::string id() { static const std::string result = "(" + exprtk_crtype(T0) + ")o(" + exprtk_crtype(T1) + "o" + exprtk_crtype(T2) + ")" ; return result; } }; }; template struct T0oT1oT20T3process { typedef typename details::functor_t functor_t; typedef typename functor_t::bfunc_t bfunc_t; struct mode0 { static inline T process(const T& t0, const T& t1, const T& t2, const T& t3, const bfunc_t bf0, const bfunc_t bf1, const bfunc_t bf2) { // (T0 o0 T1) o1 (T2 o2 T3) return bf1(bf0(t0,t1),bf2(t2,t3)); } template static inline std::string id() { static const std::string result = "(" + exprtk_crtype(T0) + "o" + exprtk_crtype(T1) + ")o" + "(" + exprtk_crtype(T2) + "o" + exprtk_crtype(T3) + ")" ; return result; } }; struct mode1 { static inline T process(const T& t0, const T& t1, const T& t2, const T& t3, const bfunc_t bf0, const bfunc_t bf1, const bfunc_t bf2) { // (T0 o0 (T1 o1 (T2 o2 T3)) return bf0(t0,bf1(t1,bf2(t2,t3))); } template static inline std::string id() { static const std::string result = "(" + exprtk_crtype(T0) + ")o((" + exprtk_crtype(T1) + ")o(" + exprtk_crtype(T2) + "o" + exprtk_crtype(T3) + "))" ; return result; } }; struct mode2 { static inline T process(const T& t0, const T& t1, const T& t2, const T& t3, const bfunc_t bf0, const bfunc_t bf1, const bfunc_t bf2) { // (T0 o0 ((T1 o1 T2) o2 T3) return bf0(t0,bf2(bf1(t1,t2),t3)); } template static inline std::string id() { static const std::string result = "(" + exprtk_crtype(T0) + ")o((" + exprtk_crtype(T1) + "o" + exprtk_crtype(T2) + ")o(" + exprtk_crtype(T3) + "))" ; return result; } }; struct mode3 { static inline T process(const T& t0, const T& t1, const T& t2, const T& t3, const bfunc_t bf0, const bfunc_t bf1, const bfunc_t bf2) { // (((T0 o0 T1) o1 T2) o2 T3) return bf2(bf1(bf0(t0,t1),t2),t3); } template static inline std::string id() { static const std::string result = "((" + exprtk_crtype(T0) + "o" + exprtk_crtype(T1) + ")o(" + exprtk_crtype(T2) + "))o(" + exprtk_crtype(T3) + ")"; return result; } }; struct mode4 { static inline T process(const T& t0, const T& t1, const T& t2, const T& t3, const bfunc_t bf0, const bfunc_t bf1, const bfunc_t bf2) { // ((T0 o0 (T1 o1 T2)) o2 T3 return bf2(bf0(t0,bf1(t1,t2)),t3); } template static inline std::string id() { static const std::string result = "((" + exprtk_crtype(T0) + ")o(" + exprtk_crtype(T1) + "o" + exprtk_crtype(T2) + "))o(" + exprtk_crtype(T3) + ")" ; return result; } }; }; #undef exprtk_crtype template struct nodetype_T0oT1 { static const typename expression_node::node_type result; }; template const typename expression_node::node_type nodetype_T0oT1::result = expression_node::e_none; #define synthesis_node_type_define(T0_, T1_, v_) \ template \ struct nodetype_T0oT1 { static const typename expression_node::node_type result; }; \ 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) #undef synthesis_node_type_define template struct nodetype_T0oT1oT2 { static const typename expression_node::node_type result; }; template const typename expression_node::node_type nodetype_T0oT1oT2::result = expression_node::e_none; #define synthesis_node_type_define(T0_, T1_, T2_, v_) \ template \ struct nodetype_T0oT1oT2 { static const typename expression_node::node_type result; }; \ 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 ) #undef synthesis_node_type_define template struct nodetype_T0oT1oT2oT3 { static const typename expression_node::node_type result; }; template const typename expression_node::node_type nodetype_T0oT1oT2oT3::result = expression_node::e_none; #define synthesis_node_type_define(T0_, T1_, T2_, T3_, v_) \ template \ struct nodetype_T0oT1oT2oT3 { static const typename expression_node::node_type result; }; \ 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 ) #undef synthesis_node_type_define template class T0oT1 exprtk_final : public expression_node { public: typedef typename details::functor_t functor_t; typedef typename functor_t::bfunc_t bfunc_t; typedef T value_type; typedef T0oT1 node_type; T0oT1(T0 p0, T1 p1, const bfunc_t p2) : t0_(p0) , t1_(p1) , f_ (p2) {} inline typename expression_node::node_type type() const exprtk_override { static const typename expression_node::node_type result = nodetype_T0oT1::result; return result; } inline operator_type operation() const exprtk_override { return e_default; } inline T value() const exprtk_override { return f_(t0_,t1_); } inline T0 t0() const { return t0_; } inline T1 t1() const { return t1_; } inline bfunc_t f() const { return f_; } template static inline expression_node* allocate(Allocator& allocator, T0 p0, T1 p1, bfunc_t p2) { return allocator .template allocate_type (p0, p1, p2); } private: T0oT1(const T0oT1&) exprtk_delete; T0oT1& operator=(const T0oT1&) { return (*this); } T0 t0_; T1 t1_; const bfunc_t f_; }; template class T0oT1oT2 exprtk_final : public T0oT1oT2_base_node { public: typedef typename details::functor_t functor_t; typedef typename functor_t::bfunc_t bfunc_t; typedef T value_type; typedef T0oT1oT2 node_type; typedef ProcessMode process_mode_t; T0oT1oT2(T0 p0, T1 p1, T2 p2, const bfunc_t p3, const bfunc_t p4) : t0_(p0) , t1_(p1) , t2_(p2) , f0_(p3) , f1_(p4) {} inline typename expression_node::node_type type() const exprtk_override { static const typename expression_node::node_type result = nodetype_T0oT1oT2::result; return result; } inline operator_type operation() { return e_default; } inline T value() const exprtk_override { return ProcessMode::process(t0_, t1_, t2_, f0_, f1_); } inline T0 t0() const { return t0_; } inline T1 t1() const { return t1_; } inline T2 t2() const { return t2_; } bfunc_t f0() const { return f0_; } bfunc_t f1() const { return f1_; } std::string type_id() const exprtk_override { return id(); } static inline std::string id() { return process_mode_t::template id(); } 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); } private: T0oT1oT2(const node_type&) exprtk_delete; node_type& operator=(const node_type&) { return (*this); } T0 t0_; T1 t1_; T2 t2_; const bfunc_t f0_; const bfunc_t f1_; }; template class T0oT1oT2oT3 exprtk_final : public T0oT1oT2oT3_base_node { public: typedef typename details::functor_t functor_t; typedef typename functor_t::bfunc_t bfunc_t; typedef T value_type; typedef T0_ T0; typedef T1_ T1; typedef T2_ T2; typedef T3_ T3; typedef T0oT1oT2oT3 node_type; typedef ProcessMode process_mode_t; T0oT1oT2oT3(T0 p0, T1 p1, T2 p2, T3 p3, bfunc_t p4, bfunc_t p5, bfunc_t p6) : t0_(p0) , t1_(p1) , t2_(p2) , t3_(p3) , f0_(p4) , f1_(p5) , f2_(p6) {} inline T value() const exprtk_override { return ProcessMode::process(t0_, t1_, t2_, t3_, f0_, f1_, f2_); } inline T0 t0() const { return t0_; } inline T1 t1() const { return t1_; } inline T2 t2() const { return t2_; } inline T3 t3() const { return t3_; } inline bfunc_t f0() const { return f0_; } inline bfunc_t f1() const { return f1_; } inline bfunc_t f2() const { return f2_; } inline std::string type_id() const exprtk_override { return id(); } static inline std::string id() { return process_mode_t::template id(); } template static inline expression_node* allocate(Allocator& allocator, 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); } private: T0oT1oT2oT3(const node_type&) exprtk_delete; node_type& operator=(const node_type&) { return (*this); } T0 t0_; T1 t1_; T2 t2_; T3 t3_; const bfunc_t f0_; const bfunc_t f1_; const bfunc_t f2_; }; template class T0oT1oT2_sf3 exprtk_final : public T0oT1oT2_base_node { public: typedef typename details::functor_t functor_t; typedef typename functor_t::tfunc_t tfunc_t; typedef T value_type; typedef T0oT1oT2_sf3 node_type; T0oT1oT2_sf3(T0 p0, T1 p1, T2 p2, const tfunc_t p3) : t0_(p0) , t1_(p1) , t2_(p2) , f_ (p3) {} inline typename expression_node::node_type type() const exprtk_override { static const typename expression_node::node_type result = nodetype_T0oT1oT2::result; return result; } inline operator_type operation() const exprtk_override { return e_default; } inline T value() const exprtk_override { return f_(t0_, t1_, t2_); } inline T0 t0() const { return t0_; } inline T1 t1() const { return t1_; } inline T2 t2() const { return t2_; } tfunc_t f() const { return f_; } std::string type_id() const { return id(); } static inline std::string id() { return "sf3"; } 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); } private: T0oT1oT2_sf3(const node_type&) exprtk_delete; node_type& operator=(const node_type&) { return (*this); } T0 t0_; T1 t1_; T2 t2_; const tfunc_t f_; }; template class sf3ext_type_node : public T0oT1oT2_base_node { public: virtual ~sf3ext_type_node() {} virtual T0 t0() const = 0; virtual T1 t1() const = 0; virtual T2 t2() const = 0; }; template class T0oT1oT2_sf3ext exprtk_final : public sf3ext_type_node { public: typedef typename details::functor_t functor_t; typedef typename functor_t::tfunc_t tfunc_t; typedef T value_type; typedef T0oT1oT2_sf3ext node_type; T0oT1oT2_sf3ext(T0 p0, T1 p1, T2 p2) : t0_(p0) , t1_(p1) , t2_(p2) {} inline typename expression_node::node_type type() const exprtk_override { static const typename expression_node::node_type result = nodetype_T0oT1oT2::result; return result; } inline operator_type operation() { return e_default; } inline T value() const exprtk_override { return SF3Operation::process(t0_, t1_, t2_); } T0 t0() const exprtk_override { return t0_; } T1 t1() const exprtk_override { return t1_; } T2 t2() const exprtk_override { return t2_; } std::string type_id() const exprtk_override { return id(); } static inline std::string id() { return SF3Operation::id(); } template static inline expression_node* allocate(Allocator& allocator, T0 p0, T1 p1, T2 p2) { return allocator .template allocate_type (p0, p1, p2); } private: T0oT1oT2_sf3ext(const node_type&) exprtk_delete; node_type& operator=(const node_type&) { return (*this); } T0 t0_; T1 t1_; T2 t2_; }; template inline bool is_sf3ext_node(const expression_node* n) { switch (n->type()) { case expression_node::e_vovov : return true; case expression_node::e_vovoc : return true; case expression_node::e_vocov : return true; case expression_node::e_covov : return true; case expression_node::e_covoc : return true; default : return false; } } template class T0oT1oT2oT3_sf4 exprtk_final : public T0oT1oT2_base_node { public: typedef typename details::functor_t functor_t; typedef typename functor_t::qfunc_t qfunc_t; typedef T value_type; typedef T0oT1oT2oT3_sf4 node_type; T0oT1oT2oT3_sf4(T0 p0, T1 p1, T2 p2, T3 p3, const qfunc_t p4) : t0_(p0) , t1_(p1) , t2_(p2) , t3_(p3) , f_ (p4) {} inline typename expression_node::node_type type() const exprtk_override { static const typename expression_node::node_type result = nodetype_T0oT1oT2oT3::result; return result; } inline operator_type operation() const exprtk_override { return e_default; } inline T value() const exprtk_override { return f_(t0_, t1_, t2_, t3_); } inline T0 t0() const { return t0_; } inline T1 t1() const { return t1_; } inline T2 t2() const { return t2_; } inline T3 t3() const { return t3_; } qfunc_t f() const { return f_; } std::string type_id() const { return id(); } static inline std::string id() { return "sf4"; } 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); } private: T0oT1oT2oT3_sf4(const node_type&) exprtk_delete; node_type& operator=(const node_type&) { return (*this); } T0 t0_; T1 t1_; T2 t2_; T3 t3_; const qfunc_t f_; }; template class T0oT1oT2oT3_sf4ext exprtk_final : public T0oT1oT2oT3_base_node { public: typedef typename details::functor_t functor_t; typedef typename functor_t::tfunc_t tfunc_t; typedef T value_type; typedef T0oT1oT2oT3_sf4ext node_type; T0oT1oT2oT3_sf4ext(T0 p0, T1 p1, T2 p2, T3 p3) : t0_(p0) , t1_(p1) , t2_(p2) , t3_(p3) {} inline typename expression_node::node_type type() const exprtk_override { static const typename expression_node::node_type result = nodetype_T0oT1oT2oT3::result; return result; } inline T value() const exprtk_override { return SF4Operation::process(t0_, t1_, t2_, t3_); } inline T0 t0() const { return t0_; } inline T1 t1() const { return t1_; } inline T2 t2() const { return t2_; } inline T3 t3() const { return t3_; } std::string type_id() const exprtk_override { return id(); } static inline std::string id() { return SF4Operation::id(); } 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); } private: T0oT1oT2oT3_sf4ext(const node_type&) exprtk_delete; node_type& operator=(const node_type&) { return (*this); } T0 t0_; T1 t1_; T2 t2_; T3 t3_; }; template inline bool is_sf4ext_node(const expression_node* n) { switch (n->type()) { case expression_node::e_vovovov : return true; case expression_node::e_vovovoc : return true; case expression_node::e_vovocov : return true; case expression_node::e_vocovov : return true; case expression_node::e_covovov : return true; case expression_node::e_covocov : return true; case expression_node::e_vocovoc : return true; case expression_node::e_covovoc : return true; case expression_node::e_vococov : return true; default : return false; } } template struct T0oT1_define { 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; }; 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; }; template class vov_node exprtk_final : public vov_base_node { public: typedef expression_node* expression_ptr; typedef Operation operation_t; // variable op variable node explicit vov_node(const T& var0, const T& var1) : v0_(var0) , v1_(var1) {} inline T value() const exprtk_override { return Operation::process(v0_,v1_); } inline typename expression_node::node_type type() const exprtk_override { return Operation::type(); } inline operator_type operation() const exprtk_override { return Operation::operation(); } inline const T& v0() const exprtk_override { return v0_; } inline const T& v1() const exprtk_override { return v1_; } protected: const T& v0_; const T& v1_; private: vov_node(const vov_node&) exprtk_delete; vov_node& operator=(const vov_node&) exprtk_delete; }; template class cov_node exprtk_final : public cov_base_node { public: typedef expression_node* expression_ptr; typedef Operation operation_t; // constant op variable node explicit cov_node(const T& const_var, const T& var) : c_(const_var) , v_(var) {} inline T value() const exprtk_override { return Operation::process(c_,v_); } inline typename expression_node::node_type type() const exprtk_override { return Operation::type(); } inline operator_type operation() const exprtk_override { return Operation::operation(); } inline const T c() const exprtk_override { return c_; } inline const T& v() const exprtk_override { return v_; } protected: const T c_; const T& v_; private: cov_node(const cov_node&) exprtk_delete; cov_node& operator=(const cov_node&) exprtk_delete; }; template class voc_node exprtk_final : public voc_base_node { public: typedef expression_node* expression_ptr; typedef Operation operation_t; // variable op constant node explicit voc_node(const T& var, const T& const_var) : v_(var) , c_(const_var) {} inline T value() const exprtk_override { return Operation::process(v_,c_); } inline operator_type operation() const exprtk_override { return Operation::operation(); } inline const T c() const exprtk_override { return c_; } inline const T& v() const exprtk_override { return v_; } protected: const T& v_; const T c_; private: voc_node(const voc_node&) exprtk_delete; voc_node& operator=(const voc_node&) exprtk_delete; }; template class vob_node exprtk_final : public vob_base_node { public: typedef expression_node* expression_ptr; typedef std::pair branch_t; typedef Operation operation_t; // variable op constant node explicit vob_node(const T& var, const expression_ptr branch) : v_(var) { construct_branch_pair(branch_, branch); } inline T value() const exprtk_override { assert(branch_.first); return Operation::process(v_,branch_.first->value()); } inline const T& v() const exprtk_override { return v_; } inline expression_node* branch(const std::size_t&) const exprtk_override { return branch_.first; } void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override { expression_node::ndb_t::template collect(branch_, node_delete_list); } std::size_t node_depth() const exprtk_override { return expression_node::ndb_t::compute_node_depth(branch_); } private: vob_node(const vob_node&) exprtk_delete; vob_node& operator=(const vob_node&) exprtk_delete; const T& v_; branch_t branch_; }; template class bov_node exprtk_final : public bov_base_node { public: typedef expression_node* expression_ptr; typedef std::pair branch_t; typedef Operation operation_t; // variable op constant node explicit bov_node(const expression_ptr branch, const T& var) : v_(var) { construct_branch_pair(branch_, branch); } inline T value() const exprtk_override { assert(branch_.first); return Operation::process(branch_.first->value(),v_); } inline const T& v() const exprtk_override { return v_; } inline expression_node* branch(const std::size_t&) const exprtk_override { return branch_.first; } void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override { expression_node::ndb_t::template collect(branch_, node_delete_list); } std::size_t node_depth() const exprtk_override { return expression_node::ndb_t::compute_node_depth(branch_); } private: bov_node(const bov_node&) exprtk_delete; bov_node& operator=(const bov_node&) exprtk_delete; const T& v_; branch_t branch_; }; template class cob_node exprtk_final : public cob_base_node { public: typedef expression_node* expression_ptr; typedef std::pair branch_t; typedef Operation operation_t; // variable op constant node explicit cob_node(const T const_var, const expression_ptr branch) : c_(const_var) { construct_branch_pair(branch_, branch); } inline T value() const exprtk_override { assert(branch_.first); return Operation::process(c_,branch_.first->value()); } inline operator_type operation() const exprtk_override { return Operation::operation(); } inline const T c() const exprtk_override { return c_; } inline void set_c(const T new_c) exprtk_override { (*const_cast(&c_)) = new_c; } inline expression_node* branch(const std::size_t&) const exprtk_override { return branch_.first; } inline expression_node* move_branch(const std::size_t&) exprtk_override { branch_.second = false; return branch_.first; } void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override { expression_node::ndb_t::template collect(branch_, node_delete_list); } std::size_t node_depth() const exprtk_override { return expression_node::ndb_t::compute_node_depth(branch_); } private: cob_node(const cob_node&) exprtk_delete; cob_node& operator=(const cob_node&) exprtk_delete; const T c_; branch_t branch_; }; template class boc_node exprtk_final : public boc_base_node { public: typedef expression_node* expression_ptr; typedef std::pair branch_t; typedef Operation operation_t; // variable op constant node explicit boc_node(const expression_ptr branch, const T const_var) : c_(const_var) { construct_branch_pair(branch_, branch); } inline T value() const exprtk_override { assert(branch_.first); return Operation::process(branch_.first->value(),c_); } inline operator_type operation() const exprtk_override { return Operation::operation(); } inline const T c() const exprtk_override { return c_; } inline void set_c(const T new_c) exprtk_override { (*const_cast(&c_)) = new_c; } inline expression_node* branch(const std::size_t&) const exprtk_override { return branch_.first; } inline expression_node* move_branch(const std::size_t&) exprtk_override { branch_.second = false; return branch_.first; } void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override { expression_node::ndb_t::template collect(branch_, node_delete_list); } std::size_t node_depth() const exprtk_override { return expression_node::ndb_t::compute_node_depth(branch_); } private: boc_node(const boc_node&) exprtk_delete; boc_node& operator=(const boc_node&) exprtk_delete; const T c_; branch_t branch_; }; #ifndef exprtk_disable_string_capabilities template class sos_node exprtk_final : public sos_base_node { public: typedef expression_node* expression_ptr; typedef Operation operation_t; // string op string node explicit sos_node(SType0 p0, SType1 p1) : s0_(p0) , s1_(p1) {} inline T value() const exprtk_override { return Operation::process(s0_,s1_); } inline typename expression_node::node_type type() const exprtk_override { return Operation::type(); } inline operator_type operation() const exprtk_override { return Operation::operation(); } inline std::string& s0() { return s0_; } inline std::string& s1() { return s1_; } protected: SType0 s0_; SType1 s1_; private: sos_node(const sos_node&) exprtk_delete; sos_node& operator=(const sos_node&) exprtk_delete; }; template class str_xrox_node exprtk_final : public sos_base_node { public: typedef expression_node* expression_ptr; typedef Operation operation_t; typedef str_xrox_node node_type; // string-range op string node explicit str_xrox_node(SType0 p0, SType1 p1, RangePack rp0) : s0_ (p0 ) , s1_ (p1 ) , rp0_(rp0) {} ~str_xrox_node() { rp0_.free(); } inline T value() const exprtk_override { 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_); else return T(0); } inline typename expression_node::node_type type() const exprtk_override { return Operation::type(); } inline operator_type operation() const exprtk_override { return Operation::operation(); } inline std::string& s0() { return s0_; } inline std::string& s1() { return s1_; } protected: SType0 s0_; SType1 s1_; RangePack rp0_; private: str_xrox_node(const node_type&) exprtk_delete; node_type& operator=(const node_type&) exprtk_delete; }; template class str_xoxr_node exprtk_final : public sos_base_node { public: typedef expression_node* expression_ptr; typedef Operation operation_t; typedef str_xoxr_node node_type; // string op string range node explicit str_xoxr_node(SType0 p0, SType1 p1, RangePack rp1) : s0_ (p0 ) , s1_ (p1 ) , rp1_(rp1) {} ~str_xoxr_node() { rp1_.free(); } inline T value() const exprtk_override { 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)); else return T(0); } inline typename expression_node::node_type type() const exprtk_override { return Operation::type(); } inline operator_type operation() const exprtk_override { return Operation::operation(); } inline std::string& s0() { return s0_; } inline std::string& s1() { return s1_; } protected: SType0 s0_; SType1 s1_; RangePack rp1_; private: str_xoxr_node(const node_type&) exprtk_delete; node_type& operator=(const node_type&) exprtk_delete; }; template class str_xroxr_node exprtk_final : public sos_base_node { public: typedef expression_node* expression_ptr; typedef Operation operation_t; typedef str_xroxr_node node_type; // string-range op string-range node explicit str_xroxr_node(SType0 p0, SType1 p1, RangePack rp0, RangePack rp1) : s0_ (p0 ) , s1_ (p1 ) , rp0_(rp0) , rp1_(rp1) {} ~str_xroxr_node() { rp0_.free(); rp1_.free(); } inline T value() const exprtk_override { std::size_t r0_0 = 0; 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()) ) { return Operation::process( s0_.substr(r0_0, (r1_0 - r0_0) + 1), s1_.substr(r0_1, (r1_1 - r0_1) + 1) ); } else return T(0); } inline typename expression_node::node_type type() const exprtk_override { return Operation::type(); } inline operator_type operation() const exprtk_override { return Operation::operation(); } inline std::string& s0() { return s0_; } inline std::string& s1() { return s1_; } protected: SType0 s0_; SType1 s1_; RangePack rp0_; RangePack rp1_; private: str_xroxr_node(const node_type&) exprtk_delete; node_type& operator=(const node_type&) exprtk_delete; }; template class str_sogens_node exprtk_final : 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; str_sogens_node(const operator_type& opr, expression_ptr branch0, expression_ptr branch1) : binary_node(opr, branch0, branch1) , str0_base_ptr_ (0) , str1_base_ptr_ (0) , str0_range_ptr_(0) , str1_range_ptr_(0) { 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()); } } inline T value() const exprtk_override { if ( str0_base_ptr_ && str1_base_ptr_ && str0_range_ptr_ && str1_range_ptr_ ) { 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()) ) { return Operation::process( str0_base_ptr_->str().substr(str0_r0,(str0_r1 - str0_r0) + 1), str1_base_ptr_->str().substr(str1_r0,(str1_r1 - str1_r0) + 1) ); } } return std::numeric_limits::quiet_NaN(); } inline typename expression_node::node_type type() const exprtk_override { return Operation::type(); } private: str_sogens_node(const str_sogens_node&) exprtk_delete; str_sogens_node& operator=(const str_sogens_node&) exprtk_delete; str_base_ptr str0_base_ptr_; str_base_ptr str1_base_ptr_; range_ptr str0_range_ptr_; range_ptr str1_range_ptr_; }; template class sosos_node exprtk_final : public sosos_base_node { public: typedef expression_node* expression_ptr; typedef Operation operation_t; typedef sosos_node node_type; // variable op variable node explicit sosos_node(SType0 p0, SType1 p1, SType2 p2) : s0_(p0) , s1_(p1) , s2_(p2) {} inline T value() const exprtk_override { return Operation::process(s0_, s1_, s2_); } inline typename expression_node::node_type type() const exprtk_override { return Operation::type(); } inline operator_type operation() const exprtk_override { return Operation::operation(); } inline std::string& s0() { return s0_; } inline std::string& s1() { return s1_; } inline std::string& s2() { return s2_; } protected: SType0 s0_; SType1 s1_; SType2 s2_; private: sosos_node(const node_type&) exprtk_delete; node_type& operator=(const node_type&) exprtk_delete; }; #endif template class ipow_node exprtk_final: public expression_node { public: typedef expression_node* expression_ptr; typedef PowOp operation_t; explicit ipow_node(const T& v) : v_(v) {} inline T value() const exprtk_override { return PowOp::result(v_); } inline typename expression_node::node_type type() const exprtk_override { return expression_node::e_ipow; } private: ipow_node(const ipow_node&) exprtk_delete; ipow_node& operator=(const ipow_node&) exprtk_delete; const T& v_; }; template class bipow_node exprtk_final : 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 exprtk_override { assert(branch_.first); return PowOp::result(branch_.first->value()); } inline typename expression_node::node_type type() const exprtk_override { return expression_node::e_ipow; } void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override { expression_node::ndb_t::collect(branch_, node_delete_list); } std::size_t node_depth() const exprtk_override { return expression_node::ndb_t::compute_node_depth(branch_); } private: bipow_node(const bipow_node&) exprtk_delete; bipow_node& operator=(const bipow_node&) exprtk_delete; branch_t branch_; }; template class ipowinv_node exprtk_final : public expression_node { public: typedef expression_node* expression_ptr; typedef PowOp operation_t; explicit ipowinv_node(const T& v) : v_(v) {} inline T value() const exprtk_override { return (T(1) / PowOp::result(v_)); } inline typename expression_node::node_type type() const exprtk_override { return expression_node::e_ipowinv; } private: ipowinv_node(const ipowinv_node&) exprtk_delete; ipowinv_node& operator=(const ipowinv_node&) exprtk_delete; const T& v_; }; template class bipowninv_node exprtk_final : 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 exprtk_override { assert(branch_.first); return (T(1) / PowOp::result(branch_.first->value())); } inline typename expression_node::node_type type() const exprtk_override { return expression_node::e_ipowinv; } void collect_nodes(typename expression_node::noderef_list_t& node_delete_list) exprtk_override { expression_node::ndb_t::template collect(branch_, node_delete_list); } std::size_t node_depth() const exprtk_override { return expression_node::ndb_t::compute_node_depth(branch_); } private: bipowninv_node(const bipowninv_node&) exprtk_delete; bipowninv_node& operator=(const bipowninv_node&) exprtk_delete; branch_t branch_; }; template inline bool is_vov_node(const expression_node* node) { return (0 != dynamic_cast*>(node)); } template inline bool is_cov_node(const expression_node* node) { return (0 != dynamic_cast*>(node)); } template inline bool is_voc_node(const expression_node* node) { return (0 != dynamic_cast*>(node)); } template inline bool is_cob_node(const expression_node* node) { return (0 != dynamic_cast*>(node)); } template inline bool is_boc_node(const expression_node* node) { return (0 != dynamic_cast*>(node)); } template inline bool is_t0ot1ot2_node(const expression_node* node) { return (0 != dynamic_cast*>(node)); } template inline bool is_t0ot1ot2ot3_node(const expression_node* node) { return (0 != dynamic_cast*>(node)); } template inline bool is_uv_node(const expression_node* node) { return (0 != dynamic_cast*>(node)); } template inline bool is_string_node(const expression_node* node) { return node && (expression_node::e_stringvar == node->type()); } template inline bool is_string_range_node(const expression_node* node) { return node && (expression_node::e_stringvarrng == node->type()); } template inline bool is_const_string_node(const expression_node* node) { return node && (expression_node::e_stringconst == node->type()); } template inline bool is_const_string_range_node(const expression_node* node) { return node && (expression_node::e_cstringvarrng == node->type()); } template inline bool is_string_assignment_node(const expression_node* node) { return node && (expression_node::e_strass == node->type()); } template inline bool is_string_concat_node(const expression_node* node) { return node && (expression_node::e_strconcat == node->type()); } template inline bool is_string_function_node(const expression_node* node) { 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) { return node && (expression_node::e_strgenrange == node->type()); } template inline bool is_generally_string_node(const expression_node* node) { if (node) { switch (node->type()) { case expression_node::e_stringvar : case expression_node::e_stringconst : case expression_node::e_stringvarrng : case expression_node::e_cstringvarrng : case expression_node::e_strgenrange : case expression_node::e_strass : case expression_node::e_strconcat : 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; } } return false; } class node_allocator { public: template inline expression_node* allocate(OpType& operation, ExprNode (&branch)[1]) { expression_node* result = allocate(operation, branch[0]); result->node_depth(); return result; } template inline expression_node* allocate(OpType& operation, ExprNode (&branch)[2]) { expression_node* result = allocate(operation, branch[0], branch[1]); result->node_depth(); return result; } template inline expression_node* allocate(OpType& operation, ExprNode (&branch)[3]) { 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]) { 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]) { 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]) { 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()); } template class Sequence> inline expression_node* allocate(const Sequence& seq) const { expression_node* result = (new node_type(seq)); result->node_depth(); return result; } template inline expression_node* allocate(T1& t1) const { expression_node* result = (new node_type(t1)); result->node_depth(); return result; } template inline expression_node* allocate_c(const T1& t1) const { expression_node* result = (new node_type(t1)); result->node_depth(); return result; } template inline expression_node* allocate(const T1& t1, const T2& t2) const { 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 { 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 { expression_node* result = (new node_type(t1, t2)); result->node_depth(); return result; } template inline expression_node* allocate_rr(T1& t1, T2& t2) const { expression_node* result = (new node_type(t1, t2)); result->node_depth(); return result; } template inline expression_node* allocate_tt(T1 t1, T2 t2) const { 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 { 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 { 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 { 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 { 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 { expression_node* result = (new node_type(t1, t2, t3, t4, t5)); result->node_depth(); return result; } template inline expression_node* allocate(const T1& t1, const T2& t2, const T3& t3) const { expression_node* result = (new node_type(t1, t2, t3)); result->node_depth(); return result; } template inline expression_node* allocate(const T1& t1, const T2& t2, const T3& t3, const T4& t4) const { expression_node* result = (new node_type(t1, t2, t3, t4)); result->node_depth(); return result; } template inline expression_node* allocate(const T1& t1, const T2& t2, const T3& t3, const T4& t4, const T5& t5) const { expression_node* result = (new node_type(t1, t2, t3, t4, t5)); result->node_depth(); return result; } template inline expression_node* allocate(const T1& t1, const T2& t2, const T3& t3, const T4& t4, const T5& t5, const T6& t6) const { expression_node* result = (new node_type(t1, t2, t3, t4, t5, t6)); result->node_depth(); return result; } template inline expression_node* allocate(const T1& t1, const T2& t2, const T3& t3, const T4& t4, const T5& t5, const T6& t6, const T7& t7) const { expression_node* result = (new node_type(t1, t2, t3, t4, t5, t6, t7)); result->node_depth(); return result; } template inline expression_node* allocate(const T1& t1, const T2& t2, const T3& t3, const T4& t4, const T5& t5, const T6& t6, const T7& t7, const T8& t8) const { expression_node* result = (new node_type(t1, t2, t3, t4, t5, t6, t7, t8)); result->node_depth(); return result; } template inline expression_node* allocate(const T1& t1, const T2& t2, const T3& t3, const T4& t4, const T5& t5, const T6& t6, const T7& t7, const T8& t8, const T9& t9) const { expression_node* result = (new node_type(t1, t2, t3, t4, t5, t6, t7, t8, t9)); result->node_depth(); return result; } template inline expression_node* allocate(const T1& t1, const T2& t2, const T3& t3, const T4& t4, const T5& t5, const T6& t6, const T7& t7, const T8& t8, const T9& t9, const T10& t10) const { expression_node* 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 { expression_node* result = (new node_type(t1, t2, t3)); result->node_depth(); return result; } template inline expression_node* allocate_type(T1 t1, T2 t2, T3 t3, T4 t4) const { expression_node* result = (new node_type(t1, t2, t3, t4)); result->node_depth(); return result; } template inline expression_node* allocate_type(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5) const { expression_node* result = (new node_type(t1, t2, t3, t4, t5)); result->node_depth(); return result; } template inline expression_node* allocate_type(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6) const { expression_node* result = (new node_type(t1, t2, t3, t4, t5, t6)); result->node_depth(); return result; } 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; } }; inline void load_operations_map(std::multimap& m) { #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) #undef register_op } } // namespace details class function_traits { public: function_traits() : allow_zero_parameters_(false) , has_side_effects_(true) , min_num_args_(0) , max_num_args_(std::numeric_limits::max()) {} inline bool& allow_zero_parameters() { return allow_zero_parameters_; } inline bool& has_side_effects() { return has_side_effects_; } std::size_t& min_num_args() { return min_num_args_; } std::size_t& max_num_args() { return max_num_args_; } private: bool allow_zero_parameters_; bool has_side_effects_; std::size_t min_num_args_; std::size_t max_num_args_; }; template void enable_zero_parameters(FunctionType& func) { func.allow_zero_parameters() = true; if (0 != func.min_num_args()) { func.min_num_args() = 0; } } template void disable_zero_parameters(FunctionType& func) { func.allow_zero_parameters() = false; } template void enable_has_side_effects(FunctionType& func) { func.has_side_effects() = true; } template void disable_has_side_effects(FunctionType& func) { func.has_side_effects() = false; } template void set_min_num_args(FunctionType& func, const std::size_t& num_args) { func.min_num_args() = num_args; if ((0 != func.min_num_args()) && func.allow_zero_parameters()) func.allow_zero_parameters() = false; } template void set_max_num_args(FunctionType& func, const std::size_t& num_args) { func.max_num_args() = num_args; } template class ifunction : public function_traits { public: explicit ifunction(const std::size_t& pc) : param_count(pc) {} virtual ~ifunction() {} #define empty_method_body(N) \ { \ exprtk_debug(("ifunction::operator() - Operator(" #N ") has not been overridden\n")); \ return std::numeric_limits::quiet_NaN(); \ } \ inline virtual T operator() () empty_method_body(0) inline virtual T operator() (const T&) empty_method_body(1) 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; }; template class ivararg_function : public function_traits { public: virtual ~ivararg_function() {} inline virtual T operator() (const std::vector&) { exprtk_debug(("ivararg_function::operator() - Operator has not been overridden\n")); return std::numeric_limits::quiet_NaN(); } }; template 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 return_type rtr_type = e_rtrn_scalar) : parameter_sequence(param_seq) , rtrn_type(rtr_type) {} virtual ~igeneric_function() {} #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) igeneric_function_empty_body(2) // f(psi,i_0,i_1,....,i_N) --> Scalar inline virtual T operator() (const std::size_t&, parameter_list_t) 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) igeneric_function_empty_body(4) std::string parameter_sequence; return_type rtrn_type; }; #ifndef exprtk_disable_string_capabilities template class stringvar_base { public: typedef typename details::stringvar_node stringvar_node_t; stringvar_base(const std::string& name, stringvar_node_t* svn) : name_(name) , string_varnode_(svn) {} bool valid() const { return !name_.empty() && (0 != string_varnode_); } std::string name() const { assert(string_varnode_); return name_; } void rebase(std::string& s) { assert(string_varnode_); string_varnode_->rebase(s); } private: std::string name_; stringvar_node_t* string_varnode_; }; #endif template class parser; template class expression_helper; template class symbol_table { public: typedef T (*ff00_functor)(); typedef T (*ff01_functor)(T); typedef T (*ff02_functor)(T, T); typedef T (*ff03_functor)(T, T, T); typedef T (*ff04_functor)(T, T, T, T); typedef T (*ff05_functor)(T, T, T, T, T); typedef T (*ff06_functor)(T, T, T, T, T, T); typedef T (*ff07_functor)(T, T, T, T, T, T, T); typedef T (*ff08_functor)(T, T, T, T, T, T, T, T); typedef T (*ff09_functor)(T, T, T, T, T, T, T, T, T); typedef T (*ff10_functor)(T, T, T, T, T, T, T, T, T, T); typedef T (*ff11_functor)(T, T, T, T, T, T, T, T, T, T, T); typedef T (*ff12_functor)(T, T, T, T, T, T, T, T, T, T, T, T); typedef T (*ff13_functor)(T, T, T, T, T, T, T, T, T, T, T, T, T); typedef T (*ff14_functor)(T, T, T, T, T, T, T, T, T, T, T, T, T, T); typedef T (*ff15_functor)(T, T, T, T, T, T, T, T, T, T, T, T, T, T, T); 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 { typedef details::expression_node* expression_ptr; typedef typename details::variable_node variable_node_t; typedef ifunction ifunction_t; typedef ivararg_function ivararg_function_t; typedef igeneric_function igeneric_function_t; typedef details::vector_holder vector_t; #ifndef exprtk_disable_string_capabilities typedef typename details::stringvar_node stringvar_node_t; #endif typedef Type type_t; typedef type_t* type_ptr; typedef std::pair type_pair_t; typedef std::map type_map_t; typedef typename type_map_t::iterator tm_itr_t; typedef typename type_map_t::const_iterator tm_const_itr_t; enum { lut_size = 256 }; type_map_t map; std::size_t size; type_store() : 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()) return false; else if (map.end() != map.find(symbol_name)) return true; else return false; } template inline std::string entity_name(const PtrType& ptr) const { if (map.empty()) return std::string(); tm_const_itr_t itr = map.begin(); while (map.end() != itr) { if (itr->second.second == ptr) { return itr->first; } else ++itr; } return std::string(); } inline bool is_constant(const std::string& symbol_name) const { if (symbol_name.empty()) return false; else { const tm_const_itr_t itr = map.find(symbol_name); if (map.end() == itr) return false; else return (*itr).second.first; } } template inline bool add_impl(const std::string& symbol_name, RType t, const bool is_const) { 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; } } } const tm_itr_t itr = map.find(symbol_name); if (map.end() == itr) { map[symbol_name] = Tie::make(t,is_const); ++size; } return true; } struct tie_array { 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)); } }; struct tie_stdvec { template static inline std::pair make(std::vector& v, const bool is_const = false) { 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)); } }; struct tie_stddeq { template static inline std::pair make(std::deque& v, const bool is_const = false) { 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); } 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); } 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); } 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); } inline bool add(const std::string& symbol_name, RawType& t_, const bool is_const = false) { struct tie { static inline std::pair make(T& t, const bool is_constant = false) { return std::make_pair(is_constant, new variable_node_t(t)); } #ifndef exprtk_disable_string_capabilities static inline std::pair make(std::string& t, const bool is_constant = false) { return std::make_pair(is_constant, new stringvar_node_t(t)); } #endif static inline std::pair make(function_t& t, const bool is_constant = false) { return std::make_pair(is_constant,&t); } static inline std::pair make(vararg_function_t& t, const bool is_constant = false) { return std::make_pair(is_constant,&t); } static inline std::pair make(generic_function_t& t, const bool is_constant = false) { return std::make_pair(is_constant,&t); } }; const tm_itr_t itr = map.find(symbol_name); if (map.end() == itr) { map[symbol_name] = tie::make(t_,is_const); ++size; } return true; } inline type_ptr get(const std::string& symbol_name) const { const tm_const_itr_t itr = map.find(symbol_name); if (map.end() == itr) return reinterpret_cast(0); else return itr->second.second; } template struct ptr_match { static inline bool test(const PtrType, const void*) { return false; } }; template struct ptr_match { static inline bool test(const variable_node_t* p, const void* ptr) { exprtk_debug(("ptr_match::test() - %p <--> %p\n",(void*)(&(p->ref())),ptr)); return (&(p->ref()) == ptr); } }; inline type_ptr get_from_varptr(const void* ptr) const { tm_const_itr_t itr = map.begin(); while (map.end() != itr) { type_ptr ret_ptr = itr->second.second; if (ptr_match::test(ret_ptr,ptr)) { return ret_ptr; } ++itr; } return type_ptr(0); } inline bool remove(const std::string& symbol_name, const bool delete_node = true) { const tm_itr_t itr = map.find(symbol_name); if (map.end() != itr) { if (delete_node) { deleter::process((*itr).second); } map.erase(itr); --size; return true; } else return false; } inline RawType& type_ref(const std::string& symbol_name) { struct init_type { static inline double set(double) { return (0.0); } static inline double set(long double) { return (0.0); } static inline float set(float) { return (0.0f); } static inline std::string set(std::string) { return std::string(""); } }; static RawType null_type = init_type::set(RawType()); const tm_const_itr_t itr = map.find(symbol_name); if (map.end() == itr) return null_type; else return itr->second.second->ref(); } inline void clear(const bool delete_node = true) { if (!map.empty()) { if (delete_node) { tm_itr_t itr = map.begin(); tm_itr_t end = map.end (); while (end != itr) { deleter::process((*itr).second); ++itr; } } map.clear(); } size = 0; } template class Sequence> inline std::size_t get_list(Sequence,Allocator>& list) const { std::size_t count = 0; if (!map.empty()) { tm_const_itr_t itr = map.begin(); tm_const_itr_t end = map.end (); while (end != itr) { list.push_back(std::make_pair((*itr).first,itr->second.second->ref())); ++itr; ++count; } } return count; } template class Sequence> inline std::size_t get_list(Sequence& vlist) const { std::size_t count = 0; if (!map.empty()) { tm_const_itr_t itr = map.begin(); tm_const_itr_t end = map.end (); while (end != itr) { vlist.push_back((*itr).first); ++itr; ++count; } } return count; } }; 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; #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; static const std::size_t lut_size = 256; // Symbol Table Holder struct control_block { struct st_data { 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 stringvar_store; #endif st_data() { for (std::size_t i = 0; i < details::reserved_words_size; ++i) { reserved_symbol_table_.insert(details::reserved_words[i]); } for (std::size_t i = 0; i < details::reserved_symbols_size; ++i) { reserved_symbol_table_.insert(details::reserved_symbols[i]); } } ~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)); } 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_; }; control_block() : ref_count(1) , data_(st_data::create()) {} explicit control_block(st_data* data) : ref_count(1) , data_(data) {} ~control_block() { if (data_ && (0 == ref_count)) { 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; } } std::size_t ref_count; st_data* data_; }; public: symbol_table() : control_block_(control_block::create()) { clear(); } ~symbol_table() { control_block::destroy(control_block_,this); } symbol_table(const symbol_table& st) { control_block_ = st.control_block_; control_block_->ref_count++; } inline symbol_table& operator=(const symbol_table& st) { if (this != &st) { control_block::destroy(control_block_,reinterpret_cast*>(0)); control_block_ = st.control_block_; control_block_->ref_count++; } return (*this); } inline bool operator==(const symbol_table& st) const { return (this == &st) || (control_block_ == st.control_block_); } inline void clear_variables(const bool delete_node = true) { local_data().variable_store.clear(delete_node); } inline void clear_functions() { local_data().function_store.clear(); } inline void clear_strings() { #ifndef exprtk_disable_string_capabilities local_data().stringvar_store.clear(); #endif } inline void clear_vectors() { 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_local_constants(); } inline std::size_t variable_count() const { if (valid()) return local_data().variable_store.size; else return 0; } #ifndef exprtk_disable_string_capabilities inline std::size_t stringvar_count() const { if (valid()) return local_data().stringvar_store.size; else return 0; } #endif inline std::size_t function_count() const { if (valid()) return local_data().function_store.size; else return 0; } inline std::size_t vector_count() const { if (valid()) return local_data().vector_store.size; else return 0; } inline variable_ptr get_variable(const std::string& variable_name) const { if (!valid()) return reinterpret_cast(0); else if (!valid_symbol(variable_name)) return reinterpret_cast(0); else return local_data().variable_store.get(variable_name); } inline variable_ptr get_variable(const T& var_ref) const { if (!valid()) return reinterpret_cast(0); else return local_data().variable_store.get_from_varptr( reinterpret_cast(&var_ref)); } #ifndef exprtk_disable_string_capabilities inline stringvar_ptr get_stringvar(const std::string& string_name) const { if (!valid()) return reinterpret_cast(0); else if (!valid_symbol(string_name)) return reinterpret_cast(0); else return local_data().stringvar_store.get(string_name); } inline stringvar_base get_stringvar_base(const std::string& string_name) const { static stringvar_base null_stringvar_base("",reinterpret_cast(0)); if (!valid()) return null_stringvar_base; else if (!valid_symbol(string_name)) return null_stringvar_base; stringvar_ptr stringvar = local_data().stringvar_store.get(string_name); if (0 == stringvar) { return null_stringvar_base; } return stringvar_base(string_name,stringvar); } #endif inline function_ptr get_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().function_store.get(function_name); } inline vararg_function_ptr get_vararg_function(const std::string& vararg_function_name) const { if (!valid()) return reinterpret_cast(0); else if (!valid_symbol(vararg_function_name)) return reinterpret_cast(0); else return local_data().vararg_function_store.get(vararg_function_name); } inline generic_function_ptr get_generic_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().generic_function_store.get(function_name); } inline generic_function_ptr get_string_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().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 { if (!valid()) return reinterpret_cast(0); else if (!valid_symbol(vector_name)) return reinterpret_cast(0); else return local_data().vector_store.get(vector_name); } inline T& variable_ref(const std::string& symbol_name) { static T null_var = T(0); if (!valid()) return null_var; else if (!valid_symbol(symbol_name)) return null_var; else return local_data().variable_store.type_ref(symbol_name); } #ifndef exprtk_disable_string_capabilities inline std::string& stringvar_ref(const std::string& symbol_name) { static std::string null_stringvar; if (!valid()) return null_stringvar; else if (!valid_symbol(symbol_name)) return null_stringvar; else return local_data().stringvar_store.type_ref(symbol_name); } #endif inline bool is_constant_node(const std::string& symbol_name) const { if (!valid()) return false; else if (!valid_symbol(symbol_name)) return false; else return local_data().variable_store.is_constant(symbol_name); } #ifndef exprtk_disable_string_capabilities inline bool is_constant_string(const std::string& symbol_name) const { if (!valid()) return false; else if (!valid_symbol(symbol_name)) return false; else if (!local_data().stringvar_store.symbol_exists(symbol_name)) return false; else return local_data().stringvar_store.is_constant(symbol_name); } #endif inline bool create_variable(const std::string& variable_name, const T& value = T(0)) { if (!valid()) return false; else if (!valid_symbol(variable_name)) return false; else if (symbol_exists(variable_name)) return false; local_data().local_symbol_list_.push_back(value); T& t = local_data().local_symbol_list_.back(); return add_variable(variable_name,t); } #ifndef exprtk_disable_string_capabilities inline bool create_stringvar(const std::string& stringvar_name, const std::string& value = std::string("")) { if (!valid()) return false; else if (!valid_symbol(stringvar_name)) return false; else if (symbol_exists(stringvar_name)) return false; local_data().local_stringvar_list_.push_back(value); std::string& s = local_data().local_stringvar_list_.back(); return add_stringvar(stringvar_name,s); } #endif inline bool add_variable(const std::string& variable_name, T& t, const bool is_constant = false) { if (!valid()) return false; else if (!valid_symbol(variable_name)) return false; else if (symbol_exists(variable_name)) return false; else return local_data().variable_store.add(variable_name, t, is_constant); } inline bool add_constant(const std::string& constant_name, const T& value) { if (!valid()) return false; else if (!valid_symbol(constant_name)) return false; else if (symbol_exists(constant_name)) return false; local_data().local_symbol_list_.push_back(value); T& t = local_data().local_symbol_list_.back(); return add_variable(constant_name, t, true); } #ifndef exprtk_disable_string_capabilities inline bool add_stringvar(const std::string& stringvar_name, std::string& s, const bool is_constant = false) { if (!valid()) return false; else if (!valid_symbol(stringvar_name)) return false; else if (symbol_exists(stringvar_name)) return false; else return local_data().stringvar_store.add(stringvar_name, s, is_constant); } #endif inline bool add_function(const std::string& function_name, function_t& function) { if (!valid()) return false; else if (!valid_symbol(function_name)) return false; else if (symbol_exists(function_name)) return false; else return local_data().function_store.add(function_name,function); } inline bool add_function(const std::string& vararg_function_name, vararg_function_t& vararg_function) { if (!valid()) return false; else if (!valid_symbol(vararg_function_name)) return false; else if (symbol_exists(vararg_function_name)) return false; else return local_data().vararg_function_store.add(vararg_function_name,vararg_function); } inline bool add_function(const std::string& function_name, generic_function_t& function) { if (!valid()) return false; else if (!valid_symbol(function_name)) return false; else if (symbol_exists(function_name)) 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; } #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 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 inline bool add_vector(const std::string& vector_name, T (&v)[N]) { if (!valid()) return false; else if (!valid_symbol(vector_name)) return false; else if (symbol_exists(vector_name)) return false; else return local_data().vector_store.add(vector_name,v); } inline bool add_vector(const std::string& vector_name, T* v, const std::size_t& v_size) { if (!valid()) return false; else if (!valid_symbol(vector_name)) 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); } template inline bool add_vector(const std::string& vector_name, std::vector& v) { if (!valid()) return false; else if (!valid_symbol(vector_name)) 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); } inline bool add_vector(const std::string& vector_name, exprtk::vector_view& v) { if (!valid()) return false; else if (!valid_symbol(vector_name)) 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); } inline bool remove_variable(const std::string& variable_name, const bool delete_node = true) { if (!valid()) return false; else return local_data().variable_store.remove(variable_name, delete_node); } #ifndef exprtk_disable_string_capabilities inline bool remove_stringvar(const std::string& string_name) { if (!valid()) return false; else return local_data().stringvar_store.remove(string_name); } #endif inline bool remove_function(const std::string& function_name) { if (!valid()) return false; else return local_data().function_store.remove(function_name); } inline bool remove_vararg_function(const std::string& vararg_function_name) { if (!valid()) return false; else return local_data().vararg_function_store.remove(vararg_function_name); } inline bool remove_vector(const std::string& vector_name) { if (!valid()) return false; else return local_data().vector_store.remove(vector_name); } inline bool add_constants() { return add_pi () && add_epsilon () && add_infinity() ; } inline bool add_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); } inline bool add_epsilon() { static const T local_epsilon = details::numeric::details::epsilon_type::value(); return add_constant("epsilon",local_epsilon); } inline bool add_infinity() { static const T local_infinity = std::numeric_limits::infinity(); 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 { if (!valid()) return 0; else return local_data().variable_store.get_list(vlist); } template class Sequence> inline std::size_t get_variable_list(Sequence& vlist) const { if (!valid()) return 0; else return local_data().variable_store.get_list(vlist); } #ifndef exprtk_disable_string_capabilities template class Sequence> inline std::size_t get_stringvar_list(Sequence,Allocator>& svlist) const { if (!valid()) return 0; else return local_data().stringvar_store.get_list(svlist); } template class Sequence> inline std::size_t get_stringvar_list(Sequence& svlist) const { if (!valid()) return 0; else return local_data().stringvar_store.get_list(svlist); } #endif template class Sequence> inline std::size_t get_vector_list(Sequence& vlist) const { if (!valid()) return 0; else return local_data().vector_store.get_list(vlist); } inline bool symbol_exists(const std::string& symbol_name, const bool check_reserved_symb = true) const { /* 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; else if (local_data().variable_store.symbol_exists(symbol_name)) return true; #ifndef exprtk_disable_string_capabilities else if (local_data().stringvar_store.symbol_exists(symbol_name)) return true; #endif else if (local_data().vector_store.symbol_exists(symbol_name)) return true; else if (local_data().function_store.symbol_exists(symbol_name)) return true; else if (check_reserved_symb && local_data().is_reserved_symbol(symbol_name)) return true; else return false; } inline bool is_variable(const std::string& variable_name) const { if (!valid()) return false; else return local_data().variable_store.symbol_exists(variable_name); } #ifndef exprtk_disable_string_capabilities inline bool is_stringvar(const std::string& stringvar_name) const { if (!valid()) return false; else return local_data().stringvar_store.symbol_exists(stringvar_name); } inline bool is_conststr_stringvar(const std::string& symbol_name) const { if (!valid()) return false; else if (!valid_symbol(symbol_name)) return false; else if (!local_data().stringvar_store.symbol_exists(symbol_name)) return false; return ( local_data().stringvar_store.symbol_exists(symbol_name) || local_data().stringvar_store.is_constant (symbol_name) ); } #endif inline bool is_function(const std::string& function_name) const { if (!valid()) return false; else return local_data().function_store.symbol_exists(function_name); } inline bool is_vararg_function(const std::string& vararg_function_name) const { if (!valid()) return false; else return local_data().vararg_function_store.symbol_exists(vararg_function_name); } inline bool is_vector(const std::string& vector_name) const { if (!valid()) return false; else return local_data().vector_store.symbol_exists(vector_name); } inline std::string get_variable_name(const expression_ptr& ptr) const { return local_data().variable_store.entity_name(ptr); } inline std::string get_vector_name(const vector_holder_ptr& ptr) const { return local_data().vector_store.entity_name(ptr); } #ifndef exprtk_disable_string_capabilities inline std::string get_stringvar_name(const expression_ptr& ptr) const { return local_data().stringvar_store.entity_name(ptr); } inline std::string get_conststr_stringvar_name(const expression_ptr& ptr) const { return local_data().stringvar_store.entity_name(ptr); } #endif inline bool valid() const { // Symbol table sanity check. return control_block_ && control_block_->data_; } inline void load_from(const symbol_table& st) { { std::vector name_list; st.local_data().function_store.get_list(name_list); if (!name_list.empty()) { for (std::size_t i = 0; i < name_list.size(); ++i) { exprtk::ifunction& ifunc = *st.get_function(name_list[i]); add_function(name_list[i],ifunc); } } } { std::vector name_list; st.local_data().vararg_function_store.get_list(name_list); if (!name_list.empty()) { for (std::size_t i = 0; i < name_list.size(); ++i) { exprtk::ivararg_function& ivafunc = *st.get_vararg_function(name_list[i]); add_function(name_list[i],ivafunc); } } } { std::vector name_list; st.local_data().generic_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_generic_function(name_list[i]); add_function(name_list[i],ifunc); } } } { std::vector name_list; st.local_data().string_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_string_function(name_list[i]); 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); } } } } private: inline bool valid_symbol(const std::string& symbol, const bool check_reserved_symb = true) 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 (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 true; } typedef typename control_block::st_data local_data_t; inline local_data_t& local_data() { return *(control_block_->data_); } inline const local_data_t& local_data() const { return *(control_block_->data_); } control_block* control_block_; friend class parser; }; // class symbol_table template class function_compositor; template class expression { private: typedef details::expression_node* expression_ptr; typedef details::vector_holder* vector_holder_ptr; typedef std::vector > symtab_list_t; struct control_block { enum data_type { e_unknown , e_expr , e_vecholder, e_data , e_vecdata , e_string }; struct data_pack { data_pack() : pointer(0) , type(e_unknown) , size(0) {} data_pack(void* ptr, const data_type dt, const std::size_t sz = 0) : pointer(ptr) , type(dt) , size(sz) {} void* pointer; data_type type; std::size_t size; }; typedef std::vector local_data_list_t; typedef results_context results_context_t; typedef control_block* cntrl_blck_ptr_t; control_block() : ref_count(0) , expr (0) , results (0) , retinv_null(false) , return_invoked(&retinv_null) {} explicit control_block(expression_ptr e) : ref_count(1) , expr (e) , results (0) , retinv_null(false) , return_invoked(&retinv_null) {} ~control_block() { if (expr && details::branch_deletable(expr)) { destroy_node(expr); } if (!local_data_list.empty()) { for (std::size_t i = 0; i < local_data_list.size(); ++i) { switch (local_data_list[i].type) { case e_expr : delete reinterpret_cast(local_data_list[i].pointer); break; case e_vecholder : delete reinterpret_cast(local_data_list[i].pointer); break; case e_data : delete reinterpret_cast(local_data_list[i].pointer); break; case e_vecdata : delete [] reinterpret_cast(local_data_list[i].pointer); break; case e_string : delete reinterpret_cast(local_data_list[i].pointer); break; default : break; } } } if (results) { delete results; } } static inline cntrl_blck_ptr_t create(expression_ptr e) { return new control_block(e); } static inline void destroy(cntrl_blck_ptr_t& 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; }; public: expression() : control_block_(0) { set_expression(new details::null_node()); } expression(const expression& e) : 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) { set_expression(new details::null_node()); symbol_table_list_.push_back(symbol_table); } inline expression& operator=(const expression& e) { if (this != &e) { if (control_block_) { if ( (0 != control_block_->ref_count) && (0 == --control_block_->ref_count) ) { delete control_block_; } control_block_ = 0; } control_block_ = e.control_block_; control_block_->ref_count++; symbol_table_list_ = e.symbol_table_list_; } return *this; } inline bool operator==(const expression& e) const { return (this == &e); } inline bool operator!() const { return ( (0 == control_block_ ) || (0 == control_block_->expr) ); } inline expression& release() { control_block::destroy(control_block_); return (*this); } ~expression() { control_block::destroy(control_block_); } inline T value() const { assert(control_block_ ); assert(control_block_->expr); return control_block_->expr->value(); } inline T operator() () const { return value(); } inline operator T() const { return value(); } inline operator bool() const { return details::is_true(value()); } inline void register_symbol_table(symbol_table& st) { symbol_table_list_.push_back(st); } inline const symbol_table& get_symbol_table(const std::size_t& index = 0) const { return symbol_table_list_[index]; } inline symbol_table& get_symbol_table(const std::size_t& index = 0) { 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 (control_block_) { if (0 == --control_block_->ref_count) { delete control_block_; } } control_block_ = control_block::create(expr); } } inline void register_local_var(expression_ptr expr) { if (expr) { if (control_block_) { control_block_-> local_data_list.push_back( typename expression::control_block:: data_pack(reinterpret_cast(expr), control_block::e_expr)); } } } inline void register_local_var(vector_holder_ptr vec_holder) { if (vec_holder) { if (control_block_) { control_block_-> local_data_list.push_back( typename expression::control_block:: data_pack(reinterpret_cast(vec_holder), control_block::e_vecholder)); } } } inline void register_local_data(void* data, const std::size_t& size = 0, const std::size_t data_mode = 0) { if (data) { if (control_block_) { 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::control_block:: data_pack(reinterpret_cast(data), dt, size)); } } } inline const typename control_block::local_data_list_t& local_data_list() { if (control_block_) { return control_block_->local_data_list; } else { static typename control_block::local_data_list_t null_local_data_list; return null_local_data_list; } } 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; friend class function_compositor; }; // class expression template class expression_helper { public: static inline bool is_constant(const expression& expr) { return details::is_constant_node(expr.control_block_->expr); } static inline bool is_variable(const expression& expr) { return details::is_variable_node(expr.control_block_->expr); } static inline bool is_unary(const expression& expr) { return details::is_unary_node(expr.control_block_->expr); } static inline bool is_binary(const expression& expr) { return details::is_binary_node(expr.control_block_->expr); } static inline bool is_function(const expression& 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 { e_unknown = 0, e_syntax = 1, e_token = 2, e_numeric = 4, e_symtab = 5, e_lexer = 6, e_helper = 7, e_parser = 8 }; struct type { type() : mode(parser_error::e_unknown) , line_no (0) , column_no(0) {} 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(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; t.src_location = src_location; exprtk_debug(("%s\n",diagnostic .c_str())); return t; } 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; t.src_location = src_location; exprtk_debug(("%s\n",diagnostic .c_str())); return t; } inline std::string to_str(error_mode mode) { switch (mode) { case e_unknown : return std::string("Unknown Error"); case e_syntax : return std::string("Syntax Error" ); case e_token : return std::string("Token Error" ); case e_numeric : return std::string("Numeric Error"); 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"); } } inline bool update_error(type& error, const std::string& expression) { if ( expression.empty() || (error.token.position > expression.size()) || (std::numeric_limits::max() == error.token.position) ) { return false; } std::size_t error_line_start = 0; for (std::size_t i = error.token.position; i > 0; --i) { const details::char_t c = expression[i]; if (('\n' == c) || ('\r' == c)) { error_line_start = i + 1; break; } } std::size_t next_nl_position = std::min(expression.size(), expression.find_first_of('\n',error.token.position + 1)); error.column_no = error.token.position - error_line_start; error.error_line = expression.substr(error_line_start, next_nl_position - error_line_start); error.line_no = 0; for (std::size_t i = 0; i < next_nl_position; ++i) { if ('\n' == expression[i]) ++error.line_no; } return true; } inline void dump_error(const type& error) { printf("Position: %02d Type: [%s] Msg: %s\n", static_cast(error.token.position), exprtk::parser_error::to_str(error.mode).c_str(), error.diagnostic.c_str()); } } namespace details { template inline void disable_type_checking(Parser& p) { p.state_.type_check_enabled = false; } } template class parser : public lexer::parser_helper { private: enum precedence_level { e_level00, e_level01, e_level02, e_level03, e_level04, e_level05, e_level06, e_level07, e_level08, e_level09, e_level10, e_level11, e_level12, e_level13, e_level14 }; typedef const T& cref_t; typedef const T const_t; typedef ifunction F; typedef ivararg_function VAF; typedef igeneric_function GF; typedef ifunction ifunction_t; typedef ivararg_function ivararg_function_t; typedef igeneric_function igeneric_function_t; typedef details::expression_node expression_node_t; typedef details::literal_node literal_node_t; typedef details::unary_node unary_node_t; typedef details::binary_node binary_node_t; typedef details::trinary_node trinary_node_t; typedef details::quaternary_node quaternary_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; typedef details::repeat_until_loop_node repeat_until_loop_node_t; typedef details::for_loop_node for_loop_node_t; typedef details::while_loop_rtc_node while_loop_rtc_node_t; typedef details::repeat_until_loop_rtc_node repeat_until_loop_rtc_node_t; typedef details::for_loop_rtc_node for_loop_rtc_node_t; #ifndef exprtk_disable_break_continue typedef details::while_loop_bc_node while_loop_bc_node_t; typedef details::repeat_until_loop_bc_node repeat_until_loop_bc_node_t; typedef details::for_loop_bc_node for_loop_bc_node_t; typedef details::while_loop_bc_rtc_node while_loop_bc_rtc_node_t; typedef details::repeat_until_loop_bc_rtc_node repeat_until_loop_bc_rtc_node_t; typedef details::for_loop_bc_rtc_node for_loop_bc_rtc_node_t; #endif 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::stringvar_node stringvar_node_t; typedef details::string_literal_node string_literal_node_t; typedef details::string_range_node string_range_node_t; typedef details::const_string_range_node const_string_range_node_t; typedef details::generic_string_range_node generic_string_range_node_t; 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_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::conditional_vector_node conditional_vector_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 details::operator_type operator_t; typedef std::map unary_op_map_t; typedef std::map binary_op_map_t; typedef std::map trinary_op_map_t; typedef std::map > sf3_map_t; typedef std::map > sf4_map_t; 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 results_context results_context_t; typedef parser_helper prsrhlpr_t; struct scope_element { enum element_type { e_none , e_variable, e_vector , e_vecelem , e_string }; typedef details::vector_holder vector_holder_t; 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("???") , size (std::numeric_limits::max()) , index(std::numeric_limits::max()) , depth(std::numeric_limits::max()) , ref_count(0) , ip_index (0) , type (e_none) , active(false) , data (0) , var_node (0) , vec_node (0) #ifndef exprtk_disable_string_capabilities , str_node(0) #endif {} bool operator < (const scope_element& se) const { if (ip_index < se.ip_index) return true; else if (ip_index > se.ip_index) return false; else if (depth < se.depth) return true; else if (depth > se.depth) return false; else if (index < se.index) return true; else if (index > se.index) return false; else 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; std::size_t depth; std::size_t ref_count; std::size_t ip_index; element_type type; bool active; void* data; 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 expression_node_t* expression_node_ptr; typedef variable_node_t* variable_node_ptr; typedef parser parser_t; explicit scope_element_manager(parser& p) : parser_(p) , input_param_cnt_(0) {} inline std::size_t size() const { return element_.size(); } inline bool empty() const { return element_.empty(); } inline scope_element& get_element(const std::size_t& index) { if (index < element_.size()) return element_[index]; else return null_element_; } 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 > current_depth) continue; else if ( details::imatch(se.name, var_name) && (se.index == index) ) return se; } 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 i = 0; i < element_.size(); ++i) { scope_element& cse = element_[i]; if ( 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; } element_.push_back(se); std::sort(element_.begin(),element_.end()); return true; } inline void deactivate(const std::size_t& scope_depth) { exprtk_debug(("deactivate() - Scope depth: %d\n", static_cast(parser_.state_.scope_depth))); for (std::size_t i = 0; i < element_.size(); ++i) { scope_element& se = element_[i]; if (se.active && (se.depth >= scope_depth)) { exprtk_debug(("deactivate() - element[%02d] '%s'\n", static_cast(i), se.name.c_str())); se.active = false; } } } inline void free_element(scope_element& se) { exprtk_debug(("free_element() - se[%s]\n", se.name.c_str())); switch (se.type) { case scope_element::e_variable : delete reinterpret_cast(se.data); delete se.var_node; break; case scope_element::e_vector : delete[] reinterpret_cast(se.data); delete se.vec_node; break; case scope_element::e_vecelem : delete se.var_node; 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(); input_param_cnt_ = 0; } inline std::size_t next_ip_index() { return ++input_param_cnt_; } 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 && details::is_variable_node(se.var_node) ) { variable_node_ptr vn = reinterpret_cast(se.var_node); if (&(vn->ref()) == (&v)) { return se.var_node; } } } return expression_node_ptr(0); } private: scope_element_manager(const scope_element_manager&) exprtk_delete; scope_element_manager& operator=(const scope_element_manager&) exprtk_delete; parser_t& parser_; std::vector element_; scope_element null_element_; std::size_t input_param_cnt_; }; class scope_handler { public: typedef parser parser_t; explicit scope_handler(parser& p) : parser_(p) { parser_.state_.scope_depth++; #ifdef exprtk_enable_debugging 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_.sem_.deactivate(parser_.state_.scope_depth); parser_.state_.scope_depth--; #ifdef exprtk_enable_debugging 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 } private: scope_handler(const scope_handler&) exprtk_delete; scope_handler& operator=(const scope_handler&) exprtk_delete; parser_t& parser_; }; class stack_limit_handler { public: typedef parser parser_t; explicit stack_limit_handler(parser& p) : parser_(p) , limit_exceeded_(false) { if (++parser_.state_.stack_depth > parser_.settings_.max_stack_depth_) { limit_exceeded_ = true; parser_.set_error( make_error(parser_error::e_parser, "ERR000 - Current stack depth " + details::to_str(parser_.state_.stack_depth) + " exceeds maximum allowed stack depth of " + details::to_str(parser_.settings_.max_stack_depth_), exprtk_error_location)); } } ~stack_limit_handler() { parser_.state_.stack_depth--; } bool operator!() { return limit_exceeded_; } private: stack_limit_handler(const stack_limit_handler&) exprtk_delete; stack_limit_handler& operator=(const stack_limit_handler&) exprtk_delete; parser_t& parser_; bool limit_exceeded_; }; struct symtab_store { symbol_table_list_t symtab_list_; 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; inline bool empty() const { return symtab_list_.empty(); } inline void clear() { symtab_list_.clear(); } inline bool valid() const { if (!empty()) { for (std::size_t i = 0; i < symtab_list_.size(); ++i) { if (symtab_list_[i].valid()) return true; } } return false; } inline bool valid_symbol(const std::string& symbol) const { if (!symtab_list_.empty()) return symtab_list_[0].valid_symbol(symbol); else return false; } inline bool valid_function_name(const std::string& symbol) const { if (!symtab_list_.empty()) return symtab_list_[0].valid_function(symbol); else return false; } 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) { if (!symtab_list_[i].valid()) continue; else result = local_data(i) .variable_store.get(variable_name); if (result) break; } return result; } inline variable_ptr get_variable(const T& var_ref) const { variable_ptr result = reinterpret_cast(0); for (std::size_t i = 0; i < symtab_list_.size(); ++i) { if (!symtab_list_[i].valid()) continue; else result = local_data(i).variable_store .get_from_varptr(reinterpret_cast(&var_ref)); if (result) break; } return result; } #ifndef exprtk_disable_string_capabilities inline stringvar_ptr get_stringvar(const std::string& string_name) const { if (!valid_symbol(string_name)) return reinterpret_cast(0); stringvar_ptr result = reinterpret_cast(0); for (std::size_t i = 0; i < symtab_list_.size(); ++i) { if (!symtab_list_[i].valid()) continue; else result = local_data(i) .stringvar_store.get(string_name); if (result) break; } return result; } #endif inline function_ptr get_function(const std::string& function_name) const { 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) { if (!symtab_list_[i].valid()) continue; else result = local_data(i) .function_store.get(function_name); if (result) break; } return result; } 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); vararg_function_ptr result = reinterpret_cast(0); for (std::size_t i = 0; i < symtab_list_.size(); ++i) { if (!symtab_list_[i].valid()) continue; else result = local_data(i) .vararg_function_store.get(vararg_function_name); if (result) break; } return result; } inline generic_function_ptr get_generic_function(const std::string& function_name) const { if (!valid_function_name(function_name)) return reinterpret_cast(0); generic_function_ptr result = reinterpret_cast(0); for (std::size_t i = 0; i < symtab_list_.size(); ++i) { if (!symtab_list_[i].valid()) continue; else result = local_data(i) .generic_function_store.get(function_name); if (result) break; } return result; } inline generic_function_ptr get_string_function(const std::string& function_name) const { if (!valid_function_name(function_name)) return reinterpret_cast(0); generic_function_ptr result = reinterpret_cast(0); for (std::size_t i = 0; i < symtab_list_.size(); ++i) { if (!symtab_list_[i].valid()) continue; else result = local_data(i).string_function_store.get(function_name); if (result) break; } return result; } inline generic_function_ptr get_overload_function(const std::string& function_name) const { if (!valid_function_name(function_name)) return reinterpret_cast(0); generic_function_ptr result = reinterpret_cast(0); for (std::size_t i = 0; i < symtab_list_.size(); ++i) { if (!symtab_list_[i].valid()) continue; else result = local_data(i).overload_function_store.get(function_name); if (result) break; } return result; } inline vector_holder_ptr get_vector(const std::string& vector_name) const { if (!valid_symbol(vector_name)) return reinterpret_cast(0); vector_holder_ptr result = reinterpret_cast(0); for (std::size_t i = 0; i < symtab_list_.size(); ++i) { if (!symtab_list_[i].valid()) continue; else result = local_data(i).vector_store.get(vector_name); if (result) break; } return result; } inline bool is_constant_node(const std::string& symbol_name) const { if (!valid_symbol(symbol_name)) return false; 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; } #ifndef exprtk_disable_string_capabilities inline bool is_constant_string(const std::string& symbol_name) const { if (!valid_symbol(symbol_name)) return false; 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; } return false; } #endif inline bool symbol_exists(const std::string& symbol) const { 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 false; } inline bool is_variable(const std::string& variable_name) const { for (std::size_t i = 0; i < symtab_list_.size(); ++i) { if (!symtab_list_[i].valid()) continue; else if ( symtab_list_[i].local_data().variable_store .symbol_exists(variable_name) ) return true; } return false; } #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) { if (!symtab_list_[i].valid()) continue; else if ( symtab_list_[i].local_data().stringvar_store .symbol_exists(stringvar_name) ) return true; } return false; } inline bool is_conststr_stringvar(const std::string& symbol_name) const { for (std::size_t i = 0; i < symtab_list_.size(); ++i) { if (!symtab_list_[i].valid()) continue; else if ( symtab_list_[i].local_data().stringvar_store .symbol_exists(symbol_name) ) { return ( local_data(i).stringvar_store.symbol_exists(symbol_name) || local_data(i).stringvar_store.is_constant (symbol_name) ); } } 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 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; } return false; } 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; } return false; } inline std::string get_variable_name(const expression_node_ptr& ptr) const { return local_data().variable_store.entity_name(ptr); } inline std::string get_vector_name(const vector_holder_ptr& ptr) const { return local_data().vector_store.entity_name(ptr); } #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 std::string get_conststr_stringvar_name(const expression_node_ptr& ptr) const { return local_data().stringvar_store.entity_name(ptr); } #endif inline local_data_t& local_data(const std::size_t& index = 0) { return symtab_list_[index].local_data(); } inline const local_data_t& local_data(const std::size_t& index = 0) const { return symtab_list_[index].local_data(); } inline symbol_table_t& get_symbol_table(const std::size_t& index = 0) { return symtab_list_[index]; } }; struct parser_state { parser_state() : type_check_enabled(true) { reset(); } void reset() { parsing_return_stmt = false; parsing_break_stmt = false; return_stmt_present = false; side_effect_present = false; scope_depth = 0; stack_depth = 0; parsing_loop_stmt_count = 0; } #ifndef exprtk_enable_debugging void activate_side_effect(const std::string&) #else void activate_side_effect(const std::string& source) #endif { if (!side_effect_present) { side_effect_present = true; exprtk_debug(("activate_side_effect() - caller: %s\n",source.c_str())); } } 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; }; public: struct unknown_symbol_resolver { 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; st = e_usr_variable_type; default_value = T(0); error_message.clear(); return true; } virtual bool process(const std::string& /* unknown_symbol */, symbol_table_t& /* symbol_table */, std::string& /* error_message */) { return false; } }; enum collect_type { e_ct_none = 0, e_ct_variables = 1, e_ct_functions = 2, e_ct_assignments = 4 }; enum symbol_type { 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 }; class dependent_entity_collector { public: typedef std::pair symbol_t; typedef std::vector symbol_list_t; 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) {} 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; for (std::size_t i = 0; i < symbol_name_list_.size(); ++i) { details::case_normalise(symbol_name_list_[i].first); } 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 symbols_list.size(); } 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; for (std::size_t i = 0; i < assignment_name_list_.size(); ++i) { details::case_normalise(assignment_name_list_[i].first); } 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)); return assignment_list.size(); } void clear() { symbol_name_list_ .clear(); assignment_name_list_.clear(); retparam_list_ .clear(); return_present_ = false; final_stmt_return_ = false; } bool& collect_variables() { return collect_variables_; } 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) { 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; case e_st_function : if (collect_functions_) symbol_name_list_ .push_back(std::make_pair(symbol, st)); break; default : return; } } inline void add_assignment(const std::string& symbol, const symbol_type st) { switch (st) { 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; } } 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_; friend class parser; }; class settings_store { 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 { 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); } settings_store& enable_all_base_functions() { disabled_func_set_.clear(); return (*this); } settings_store& enable_all_control_structures() { disabled_ctrl_set_.clear(); return (*this); } settings_store& enable_all_logic_ops() { disabled_logic_set_.clear(); return (*this); } settings_store& enable_all_arithmetic_ops() { disabled_arithmetic_set_.clear(); return (*this); } settings_store& enable_all_assignment_ops() { disabled_assignment_set_.clear(); return (*this); } settings_store& enable_all_inequality_ops() { disabled_inequality_set_.clear(); return (*this); } settings_store& enable_local_vardef() { disable_vardef_ = false; return (*this); } 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); } 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); } 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); } 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); } 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); } 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); } settings_store& disable_local_vardef() { disable_vardef_ = true; return (*this); } 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_; } bool function_enabled(const std::string& function_name) const { if (disabled_func_set_.empty()) return true; else return (disabled_func_set_.end() == disabled_func_set_.find(function_name)); } bool control_struct_enabled(const std::string& control_struct) const { if (disabled_ctrl_set_.empty()) return true; else return (disabled_ctrl_set_.end() == disabled_ctrl_set_.find(control_struct)); } 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 { if (disabled_assignment_set_.empty()) return true; else return disabled_assignment_set_.end() == disabled_assignment_set_ .find(assign_opr_to_string(assignment)); } 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)); } 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)); } 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)); } 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)); } 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)); } bool logic_disabled(const details::operator_type logic_operation) const { if (disabled_logic_set_.empty()) return false; else return disabled_logic_set_.end() != disabled_logic_set_ .find(logic_opr_to_string(logic_operation)); } bool arithmetic_disabled(const details::operator_type arithmetic_operation) const { if (disabled_arithmetic_set_.empty()) return false; else return disabled_arithmetic_set_.end() != disabled_arithmetic_set_ .find(arith_opr_to_string(arithmetic_operation)); } 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)); } 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]); } return (*this); } settings_store& disable_control_structure(settings_control_structs ctrl_struct) { if ( (e_ctrl_unknown != ctrl_struct) && (static_cast(ctrl_struct) < (details::cntrl_struct_list_size + 1)) ) { disabled_ctrl_set_.insert(details::cntrl_struct_list[ctrl_struct - 1]); } return (*this); } 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]); } return (*this); } 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]); } return (*this); } settings_store& disable_assignment_operation(settings_assignment_opr assignment) { if ( (e_assign_unknown != assignment) && (static_cast(assignment) < (details::assignment_ops_list_size + 1)) ) { disabled_assignment_set_.insert(details::assignment_ops_list[assignment - 1]); } return (*this); } 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]); } return (*this); } 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]); if (disabled_func_set_.end() != itr) { disabled_func_set_.erase(itr); } } return (*this); } settings_store& enable_control_structure(settings_control_structs ctrl_struct) { if ( (e_ctrl_unknown != ctrl_struct) && (static_cast(ctrl_struct) < (details::cntrl_struct_list_size + 1)) ) { const des_itr_t itr = disabled_ctrl_set_.find(details::cntrl_struct_list[ctrl_struct - 1]); if (disabled_ctrl_set_.end() != itr) { disabled_ctrl_set_.erase(itr); } } return (*this); } 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]); if (disabled_logic_set_.end() != itr) { disabled_logic_set_.erase(itr); } } return (*this); } settings_store& enable_arithmetic_operation(settings_arithmetic_opr arithmetic) { 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]); if (disabled_arithmetic_set_.end() != itr) { disabled_arithmetic_set_.erase(itr); } } return (*this); } settings_store& enable_assignment_operation(settings_assignment_opr assignment) { 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]); if (disabled_assignment_set_.end() != itr) { disabled_assignment_set_.erase(itr); } } return (*this); } settings_store& enable_inequality_operation(settings_inequality_opr inequality) { 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]); if (disabled_inequality_set_.end() != itr) { disabled_inequality_set_.erase(itr); } } return (*this); } void set_max_stack_depth(const std::size_t max_stack_depth) { max_stack_depth_ = max_stack_depth; } void set_max_node_depth(const std::size_t max_node_depth) { max_node_depth_ = max_node_depth; } private: void load_compile_options(const std::size_t compile_options) { 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; } std::string assign_opr_to_string(details::operator_type opr) const { switch (opr) { 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 "" ; } } 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 "" ; } } std::string inequality_opr_to_string(details::operator_type opr) const { 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 "" ; } } 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_; friend class parser; }; 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) { init_precompilation(); 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_ ); 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()); } ~parser() {} inline void init_precompilation() { dec_.collect_variables() = settings_.collect_variables_enabled(); dec_.collect_functions() = settings_.collect_functions_enabled(); dec_.collect_assignments() = settings_.collect_assignments_enabled(); if (settings_.replacer_enabled()) { symbol_replacer_.clear(); symbol_replacer_.add_replace("true" , "1", lexer::token::e_number); symbol_replacer_.add_replace("false", "0", lexer::token::e_number); helper_assembly_.token_modifier_list.clear(); helper_assembly_.register_modifier(&symbol_replacer_); } if (settings_.commutative_check_enabled()) { for (std::size_t i = 0; i < details::reserved_words_size; ++i) { commutative_inserter_.ignore_symbol(details::reserved_words[i]); } helper_assembly_.token_inserter_list.clear(); helper_assembly_.register_inserter(&commutative_inserter_); } if (settings_.joiner_enabled()) { helper_assembly_.token_joiner_list.clear(); helper_assembly_.register_joiner(&operator_joiner_2_); helper_assembly_.register_joiner(&operator_joiner_3_); } if ( settings_.numeric_check_enabled () || settings_.bracket_check_enabled () || settings_.sequence_check_enabled() ) { helper_assembly_.token_scanner_list.clear(); if (settings_.numeric_check_enabled()) { helper_assembly_.register_scanner(&numeric_checker_); } if (settings_.bracket_check_enabled()) { helper_assembly_.register_scanner(&bracket_checker_); } if (settings_.sequence_check_enabled()) { helper_assembly_.register_scanner(&sequence_validator_ ); helper_assembly_.register_scanner(&sequence_validator_3tkns_); } } } inline bool compile(const std::string& expression_string, expression& expr) { state_ .reset(); error_list_ .clear(); brkcnt_list_ .clear(); synthesis_error_.clear(); sem_ .cleanup(); return_cleanup(); expression_generator_.set_allocator(node_allocator_); if (expression_string.empty()) { set_error( make_error(parser_error::e_syntax, "ERR001 - Empty expression!", exprtk_error_location)); return false; } if (!init(expression_string)) { process_lexer_errors(); return false; } if (lexer().empty()) { set_error( make_error(parser_error::e_syntax, "ERR002 - Empty expression!", exprtk_error_location)); return false; } if (!run_assemblies()) { return false; } symtab_store_.symtab_list_ = expr.get_symbol_table_list(); dec_.clear(); lexer().begin(); next_token(); expression_node_ptr e = parse_corpus(); if ((0 != e) && (token_t::e_eof == current_token().type)) { bool* retinvk_ptr = 0; if (state_.return_stmt_present) { 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 (error_list_.empty()) { set_error( make_error(parser_error::e_syntax, current_token(), "ERR003 - Invalid expression encountered", exprtk_error_location)); } if ((0 != e) && branch_deletable(e)) { destroy_node(e); } dec_.clear (); sem_.cleanup (); return_cleanup(); return false; } } inline expression_t compile(const std::string& expression_string, symbol_table_t& symtab) { expression_t expression; expression.register_symbol_table(symtab); compile(expression_string,expression); return expression; } void process_lexer_errors() { for (std::size_t i = 0; i < lexer().size(); ++i) { if (lexer()[i].is_error()) { std::string diagnostic = "ERR004 - "; switch (lexer()[i].type) { 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; default : diagnostic += "Unknown compiler error"; } set_error( make_error(parser_error::e_lexer, lexer()[i], diagnostic + ": " + lexer()[i].value, exprtk_error_location)); } } } inline bool run_assemblies() { if (settings_.commutative_check_enabled()) { helper_assembly_.run_inserters(lexer()); } if (settings_.joiner_enabled()) { helper_assembly_.run_joiners(lexer()); } if (settings_.replacer_enabled()) { helper_assembly_.run_modifiers(lexer()); } 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; 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)]; set_error( make_error(parser_error::e_token, error_token, "ERR006 - Invalid numeric token: '" + error_token.value + "'", exprtk_error_location)); } 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); 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)); } 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); set_error( make_error(parser_error::e_token, error_token.first, "ERR008 - Invalid token sequence: '" + error_token.first.value + "' and '" + error_token.second.value + "'", exprtk_error_location)); } if (sequence_validator3_ptr->error_count()) { sequence_validator3_ptr->clear_errors(); } } } return false; } } return true; } inline settings_store& settings() { return settings_; } inline parser_error::type get_error(const std::size_t& index) const { if (index < error_list_.size()) return error_list_[index]; else throw std::invalid_argument("parser::get_error() - Invalid error index specificed"); } inline std::string error() const { if (!error_list_.empty()) { return error_list_[0].diagnostic; } else return std::string("No Error"); } inline std::size_t error_count() const { return error_list_.size(); } inline dependent_entity_collector& dec() { return dec_; } 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); } 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); } inline void enable_unknown_symbol_resolver(unknown_symbol_resolver* usr = reinterpret_cast(0)) { resolve_unknown_symbol_ = true; if (usr) unknown_symbol_resolver_ = usr; else unknown_symbol_resolver_ = &default_usr_; } inline void enable_unknown_symbol_resolver(unknown_symbol_resolver& usr) { enable_unknown_symbol_resolver(&usr); } inline void disable_unknown_symbol_resolver() { resolve_unknown_symbol_ = false; unknown_symbol_resolver_ = &default_usr_; } inline void register_loop_runtime_check(loop_runtime_check& lrtchk) { loop_runtime_check_ = &lrtchk; } inline void clear_loop_runtime_check() { loop_runtime_check_ = loop_runtime_check_ptr(0); } private: inline bool valid_base_operation(const std::string& symbol) const { 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 settings_.function_enabled(symbol) && (base_ops_map_.end() != base_ops_map_.find(symbol)); } inline bool valid_vararg_operation(const std::string& symbol) const { static const std::string s_sum = "sum" ; static const std::string s_mul = "mul" ; 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) ) && settings_.function_enabled(symbol); } bool is_invalid_logic_operation(const details::operator_type operation) const { return settings_.logic_disabled(operation); } bool is_invalid_arithmetic_operation(const details::operator_type operation) const { return settings_.arithmetic_disabled(operation); } bool is_invalid_assignment_operation(const details::operator_type operation) const { return settings_.assignment_disabled(operation); } bool is_invalid_inequality_operation(const details::operator_type operation) const { return settings_.inequality_disabled(operation); } #ifdef exprtk_enable_debugging inline void next_token() { 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 inline expression_node_ptr parse_corpus() { std::vector arg_list; std::vector side_effect_list; scoped_vec_delete sdd((*this),arg_list); lexer::token begin_token; lexer::token end_token; for ( ; ; ) { state_.side_effect_present = false; begin_token = current_token(); expression_node_ptr arg = parse_expression(); if (0 == arg) { if (error_list_.empty()) { set_error( make_error(parser_error::e_syntax, current_token(), "ERR009 - Invalid expression encountered", exprtk_error_location)); } return error_node(); } else { arg_list.push_back(arg); side_effect_list.push_back(state_.side_effect_present); end_token = current_token(); const std::string sub_expr = construct_subexpr(begin_token, end_token); exprtk_debug(("parse_corpus(%02d) Subexpr: %s\n", static_cast(arg_list.size() - 1), sub_expr.c_str())); exprtk_debug(("parse_corpus(%02d) - Side effect present: %s\n", static_cast(arg_list.size() - 1), state_.side_effect_present ? "true" : "false")); exprtk_debug(("-------------------------------------------------\n")); } if (lexer().finished()) break; else if (token_is(token_t::e_eof,prsrhlpr_t::e_hold)) { if (lexer().finished()) break; else next_token(); } } if ( !arg_list.empty() && is_return_node(arg_list.back()) ) { dec_.final_stmt_return_ = true; } const expression_node_ptr result = simplify(arg_list,side_effect_list); sdd.delete_ptr = (0 == result); return result; } std::string construct_subexpr(lexer::token& begin_token, lexer::token& end_token) { std::string result = lexer().substr(begin_token.position,end_token.position); for (std::size_t i = 0; i < result.size(); ++i) { if (details::is_whitespace(result[i])) result[i] = ' '; } return result; } 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) { left = l; right = r; operation = o; } inline void reset() { left = e_level00; right = e_level00; operation = details::e_default; } precedence_level left; precedence_level right; details::operator_type operation; }; inline expression_node_ptr parse_expression(precedence_level precedence = e_level00) { stack_limit_handler slh(*this); if (!slh) { return error_node(); } expression_node_ptr expression = parse_branch(precedence); if (0 == expression) { return error_node(); } bool break_loop = false; state_t current_state; for ( ; ; ) { current_state.reset(); 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 right_branch = error_node(); expression_node_ptr new_expression = error_node(); if (is_invalid_logic_operation(current_state.operation)) { free_node(node_allocator_,expression); set_error( make_error(parser_error::e_syntax, prev_token, "ERR010 - Invalid or disabled logic operation '" + details::to_str(current_state.operation) + "'", exprtk_error_location)); return error_node(); } else if (is_invalid_arithmetic_operation(current_state.operation)) { free_node(node_allocator_,expression); set_error( make_error(parser_error::e_syntax, prev_token, "ERR011 - Invalid or disabled arithmetic operation '" + details::to_str(current_state.operation) + "'", exprtk_error_location)); return error_node(); } else if (is_invalid_inequality_operation(current_state.operation)) { free_node(node_allocator_,expression); set_error( make_error(parser_error::e_syntax, prev_token, "ERR012 - Invalid inequality operation '" + details::to_str(current_state.operation) + "'", exprtk_error_location)); return error_node(); } else if (is_invalid_assignment_operation(current_state.operation)) { free_node(node_allocator_,expression); 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 (0 != (right_branch = parse_expression(current_state.right))) { 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, prev_token, "ERR014 - Return statements cannot be part of sub-expressions", exprtk_error_location)); return error_node(); } new_expression = expression_generator_ ( current_state.operation, expression, right_branch ); } if (0 == new_expression) { if (error_list_.empty()) { set_error( make_error(parser_error::e_syntax, prev_token, !synthesis_error_.empty() ? synthesis_error_ : "ERR015 - General parsing error at token: '" + prev_token.value + "'", exprtk_error_location)); } 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) && (e_level00 == precedence) ) { expression = parse_ternary_conditional_statement(new_expression); } else expression = new_expression; parse_pending_string_rangesize(expression); } } if ((0 != expression) && (expression->node_depth() > settings_.max_node_depth_)) { set_error( make_error(parser_error::e_syntax, current_token(), "ERR016 - Expression depth of " + details::to_str(static_cast(expression->node_depth())) + " exceeds maximum allowed expression depth of " + details::to_str(static_cast(settings_.max_node_depth_)), exprtk_error_location)); free_node(node_allocator_,expression); return error_node(); } return expression; } bool simplify_unary_negation_branch(expression_node_ptr& node) { { typedef details::unary_branch_node > ubn_t; ubn_t* n = dynamic_cast(node); if (n) { expression_node_ptr un_r = n->branch(0); n->release(); free_node(node_allocator_,node); node = un_r; return true; } } { typedef details::unary_variable_node > uvn_t; uvn_t* n = dynamic_cast(node); if (n) { const T& v = n->v(); expression_node_ptr return_node = 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; } } } return false; } static inline expression_node_ptr error_node() { return reinterpret_cast(0); } struct scoped_expression_delete { scoped_expression_delete(parser& pr, expression_node_ptr& expression) : delete_ptr(true) , parser_(pr) , expression_(expression) {} ~scoped_expression_delete() { if (delete_ptr) { free_node(parser_.node_allocator_, expression_); } } bool delete_ptr; parser& parser_; expression_node_ptr& expression_; private: scoped_expression_delete(const scoped_expression_delete&) exprtk_delete; scoped_expression_delete& operator=(const scoped_expression_delete&) exprtk_delete; }; template struct scoped_delete { typedef Type* ptr_t; scoped_delete(parser& pr, ptr_t& p) : delete_ptr(true) , parser_(pr) , p_(&p) {} scoped_delete(parser& pr, ptr_t (&p)[N]) : delete_ptr(true) , parser_(pr) , p_(&p[0]) {} ~scoped_delete() { if (delete_ptr) { for (std::size_t i = 0; i < N; ++i) { free_node(parser_.node_allocator_, p_[i]); } } } bool delete_ptr; parser& parser_; ptr_t* p_; private: scoped_delete(const scoped_delete&) exprtk_delete; scoped_delete& operator=(const scoped_delete&) exprtk_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() { if (delete_ptr && !deq_.empty()) { for (std::size_t i = 0; i < deq_.size(); ++i) { free_node(parser_.node_allocator_,deq_[i]); } deq_.clear(); } } bool delete_ptr; parser& parser_; std::deque& deq_; private: scoped_deq_delete(const scoped_deq_delete&) exprtk_delete; scoped_deq_delete& operator=(const scoped_deq_delete&) exprtk_delete; }; template struct scoped_vec_delete { typedef Type* ptr_t; scoped_vec_delete(parser& pr, std::vector& vec) : delete_ptr(true) , parser_(pr) , vec_(vec) {} ~scoped_vec_delete() { if (delete_ptr && !vec_.empty()) { for (std::size_t i = 0; i < vec_.size(); ++i) { free_node(parser_.node_allocator_,vec_[i]); } vec_.clear(); } } bool delete_ptr; parser& parser_; std::vector& vec_; private: scoped_vec_delete(const scoped_vec_delete&) exprtk_delete; scoped_vec_delete& operator=(const scoped_vec_delete&) exprtk_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() { 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(); } } if (func_node) return func_node; else { set_error( make_error(parser_error::e_syntax, 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_delete sd((*this),branch); next_token(); if (!token_is(token_t::e_lbracket)) { set_error( make_error(parser_error::e_syntax, current_token(), "ERR021 - Expecting argument list for function: '" + function_name + "'", exprtk_error_location)); return error_node(); } for (int i = 0; i < static_cast(NumberofParameters); ++i) { branch[i] = parse_expression(); if (0 == branch[i]) { set_error( make_error(parser_error::e_syntax, 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(); } } } 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); return result; } inline expression_node_ptr parse_function_call_0(ifunction* function, const std::string& function_name) { 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(), "ERR025 - Expecting '()' to proceed call to function: '" + function_name + "'", exprtk_error_location)); free_node(node_allocator_,result); return error_node(); } else return result; } 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)); scoped_delete sd((*this),param_list); next_token(); if (!token_is(token_t::e_lbracket)) { 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 0; } if (token_is(token_t::e_rbracket, e_hold)) { set_error( make_error(parser_error::e_syntax, current_token(), "ERR027 - Expected at least one input parameter for function call '" + function_name + "'", exprtk_error_location)); return 0; } std::size_t param_index = 0; for (; param_index < MaxNumberofParameters; ++param_index) { param_list[param_index] = parse_expression(); 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)); return 0; } } if (sd.delete_ptr) { set_error( make_error(parser_error::e_syntax, current_token(), "ERR029 - Invalid number of input parameters passed to function '" + function_name + "'", exprtk_error_location)); return 0; } 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; const token_t diagnostic_token = current_token(); map_range_t itr_range = base_ops_map_.equal_range(operation_name); if (0 == std::distance(itr_range.first,itr_range.second)) { set_error( make_error(parser_error::e_syntax, diagnostic_token, "ERR030 - No entry found for base operation: " + operation_name, exprtk_error_location)); return error_node(); } static const std::size_t MaxNumberofParameters = 4; expression_node_ptr param_list[MaxNumberofParameters] = {0}; const std::size_t parameter_count = parse_base_function_call(param_list, operation_name); if ((parameter_count > 0) && (parameter_count <= MaxNumberofParameters)) { for (base_ops_map_t::iterator itr = itr_range.first; itr != itr_range.second; ++itr) { const 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); \ } \ base_opr_case(1) base_opr_case(2) base_opr_case(3) base_opr_case(4) #undef base_opr_case } } } } for (std::size_t i = 0; i < MaxNumberofParameters; ++i) { free_node(node_allocator_, param_list[i]); } 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)); return error_node(); } inline expression_node_ptr parse_conditional_statement_01(expression_node_ptr condition) { // Parse: [if][(][condition][,][consequent][,][alternative][)] expression_node_ptr consequent = error_node(); expression_node_ptr alternative = error_node(); bool result = true; if (!token_is(token_t::e_comma)) { set_error( make_error(parser_error::e_syntax, current_token(), "ERR032 - Expected ',' between if-statement condition and consequent", exprtk_error_location)); result = false; } else if (0 == (consequent = parse_expression())) { set_error( make_error(parser_error::e_syntax, current_token(), "ERR033 - Failed to parse consequent for if-statement", exprtk_error_location)); result = false; } else if (!token_is(token_t::e_comma)) { 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; } #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); 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(), "ERR037 - Return types of if-statement differ: string/non-string", exprtk_error_location)); result = false; } } #endif if (result) { const bool consq_is_vec = is_ivector_node(consequent ); const bool alter_is_vec = is_ivector_node(alternative); if (consq_is_vec || alter_is_vec) { if (consq_is_vec && alter_is_vec) { return expression_generator_ .conditional_vector(condition, consequent, alternative); } set_error( make_error(parser_error::e_syntax, current_token(), "ERR038 - Return types of if-statement differ: vector/non-vector", exprtk_error_location)); result = false; } } if (!result) { free_node(node_allocator_, condition ); free_node(node_allocator_, consequent ); free_node(node_allocator_, alternative); return error_node(); } else return expression_generator_ .conditional(condition, consequent, alternative); } 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(), "ERR039 - Failed to parse body of consequent for if-statement", exprtk_error_location)); result = false; } } else { if ( settings_.commutative_check_enabled() && token_is(token_t::e_mul,prsrhlpr_t::e_hold) ) { next_token(); } if (0 != (consequent = parse_expression())) { if (!token_is(token_t::e_eof)) { set_error( make_error(parser_error::e_syntax, current_token(), "ERR040 - Expected ';' at the end of the consequent for if-statement", exprtk_error_location)); result = false; } } else { set_error( make_error(parser_error::e_syntax, current_token(), "ERR041 - Failed to parse body of consequent for if-statement", exprtk_error_location)); result = false; } } if (result) { if (details::imatch(current_token().value,"else")) { next_token(); 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(), "ERR042 - Failed to parse body of the 'else' for if-statement", exprtk_error_location)); 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(), "ERR043 - Failed to parse body of if-else statement", exprtk_error_location)); 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(), "ERR044 - Expected ';' at the end of the 'else-if' for the if-statement", exprtk_error_location)); result = false; } } else { set_error( make_error(parser_error::e_syntax, current_token(), "ERR045 - Failed to parse body of the 'else' for if-statement", exprtk_error_location)); result = 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); 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(), "ERR046 - Return types of if-statement differ: string/non-string", exprtk_error_location)); result = false; } } #endif if (result) { const bool consq_is_vec = is_ivector_node(consequent ); const bool alter_is_vec = is_ivector_node(alternative); if (consq_is_vec || alter_is_vec) { if (consq_is_vec && alter_is_vec) { return expression_generator_ .conditional_vector(condition, consequent, alternative); } set_error( make_error(parser_error::e_syntax, current_token(), "ERR047 - Return types of if-statement differ: vector/non-vector", exprtk_error_location)); result = false; } } if (!result) { free_node(node_allocator_, condition ); free_node(node_allocator_, consequent ); free_node(node_allocator_, alternative); return error_node(); } else return expression_generator_ .conditional(condition, consequent, alternative); } inline expression_node_ptr parse_conditional_statement() { expression_node_ptr condition = error_node(); next_token(); if (!token_is(token_t::e_lbracket)) { set_error( make_error(parser_error::e_syntax, current_token(), "ERR048 - Expected '(' at start of if-statement, instead got: '" + current_token().value + "'", exprtk_error_location)); return error_node(); } else if (0 == (condition = parse_expression())) { set_error( make_error(parser_error::e_syntax, current_token(), "ERR049 - Failed to parse condition for if-statement", exprtk_error_location)); 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); } set_error( make_error(parser_error::e_syntax, current_token(), "ERR050 - Invalid if-statement", exprtk_error_location)); free_node(node_allocator_,condition); return error_node(); } 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(); bool result = true; if (0 == condition) { set_error( make_error(parser_error::e_syntax, current_token(), "ERR051 - Encountered invalid condition branch for ternary if-statement", exprtk_error_location)); return error_node(); } else if (!token_is(token_t::e_ternary)) { set_error( make_error(parser_error::e_syntax, current_token(), "ERR052 - Expected '?' after condition of ternary if-statement", exprtk_error_location)); result = false; } else if (0 == (consequent = parse_expression())) { set_error( make_error(parser_error::e_syntax, current_token(), "ERR053 - Failed to parse consequent for ternary if-statement", exprtk_error_location)); result = false; } else if (!token_is(token_t::e_colon)) { set_error( make_error(parser_error::e_syntax, current_token(), "ERR054 - Expected ':' between ternary 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(), "ERR055 - Failed to parse alternative for ternary if-statement", exprtk_error_location)); result = 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); 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(), "ERR056 - Return types of ternary differ: string/non-string", exprtk_error_location)); result = false; } } #endif if (result) { const bool consq_is_vec = is_ivector_node(consequent ); const bool alter_is_vec = is_ivector_node(alternative); if (consq_is_vec || alter_is_vec) { if (consq_is_vec && alter_is_vec) { return expression_generator_ .conditional_vector(condition, consequent, alternative); } set_error( make_error(parser_error::e_syntax, current_token(), "ERR057 - Return types of ternary differ: vector/non-vector", exprtk_error_location)); result = false; } } if (!result) { free_node(node_allocator_, condition ); free_node(node_allocator_, consequent ); free_node(node_allocator_, alternative); return error_node(); } else return expression_generator_ .conditional(condition, consequent, alternative); } inline expression_node_ptr parse_not_statement() { if (settings_.logic_disabled("not")) { set_error( make_error(parser_error::e_syntax, current_token(), "ERR058 - Invalid or disabled logic operation 'not'", exprtk_error_location)); return error_node(); } return parse_base_operation(); } inline expression_node_ptr parse_while_loop() { // Parse: [while][(][test expr][)][{][expression][}] expression_node_ptr condition = error_node(); expression_node_ptr branch = error_node(); expression_node_ptr result_node = error_node(); bool result = true; next_token(); if (!token_is(token_t::e_lbracket)) { set_error( make_error(parser_error::e_syntax, current_token(), "ERR059 - Expected '(' at start of while-loop condition statement", exprtk_error_location)); return error_node(); } else if (0 == (condition = parse_expression())) { set_error( make_error(parser_error::e_syntax, current_token(), "ERR060 - Failed to parse condition for while-loop", exprtk_error_location)); return error_node(); } else if (!token_is(token_t::e_rbracket)) { set_error( make_error(parser_error::e_syntax, current_token(), "ERR061 - Expected ')' at end of while-loop condition statement", exprtk_error_location)); result = false; } brkcnt_list_.push_front(false); if (result) { scoped_inc_dec sid(state_.parsing_loop_stmt_count); if (0 == (branch = parse_multi_sequence("while-loop"))) { set_error( make_error(parser_error::e_syntax, current_token(), "ERR062 - 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(), "ERR063 - Failed to synthesize while-loop", exprtk_error_location)); result = false; } } if (!result) { free_node(node_allocator_, branch ); free_node(node_allocator_, condition ); free_node(node_allocator_, result_node); brkcnt_list_.pop_front(); return error_node(); } else return result_node; } 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); if (details::imatch(current_token().value,"until")) { next_token(); branch = node_allocator_.allocate >(); } else { const token_t::token_type seperator = token_t::e_eof; scope_handler sh(*this); scoped_bool_or_restorer sbr(state_.side_effect_present); scoped_inc_dec sid(state_.parsing_loop_stmt_count); for ( ; ; ) { state_.side_effect_present = false; expression_node_ptr arg = parse_expression(); if (0 == arg) return error_node(); else { arg_list.push_back(arg); side_effect_list.push_back(state_.side_effect_present); } if (details::imatch(current_token().value,"until")) { next_token(); break; } const bool is_next_until = peek_token_is(token_t::e_symbol) && peek_token_is("until"); if (!token_is(seperator) && is_next_until) { set_error( make_error(parser_error::e_syntax, current_token(), "ERR064 - Expected '" + token_t::to_str(seperator) + "' in body of repeat until loop", exprtk_error_location)); return error_node(); } if (details::imatch(current_token().value,"until")) { next_token(); break; } } branch = simplify(arg_list,side_effect_list); sdd.delete_ptr = (0 == branch); if (sdd.delete_ptr) { brkcnt_list_.pop_front(); set_error( make_error(parser_error::e_syntax, current_token(), "ERR065 - Failed to parse body of repeat until loop", exprtk_error_location)); return error_node(); } } if (!token_is(token_t::e_lbracket)) { brkcnt_list_.pop_front(); set_error( make_error(parser_error::e_syntax, current_token(), "ERR066 - Expected '(' before condition statement of repeat until loop", exprtk_error_location)); free_node(node_allocator_,branch); return error_node(); } else if (0 == (condition = parse_expression())) { brkcnt_list_.pop_front(); set_error( make_error(parser_error::e_syntax, current_token(), "ERR067 - Failed to parse condition for repeat until loop", exprtk_error_location)); 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(), "ERR068 - 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; result = expression_generator_ .repeat_until_loop(condition, branch, brkcnt_list_.front()); if (0 == result) { set_error( make_error(parser_error::e_syntax, current_token(), "ERR069 - Failed to synthesize repeat until loop", exprtk_error_location)); free_node(node_allocator_,condition); brkcnt_list_.pop_front(); return error_node(); } else { brkcnt_list_.pop_front(); return result; } } inline expression_node_ptr parse_for_loop() { 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(); scope_element* se = 0; bool result = true; next_token(); scope_handler sh(*this); if (!token_is(token_t::e_lbracket)) { set_error( make_error(parser_error::e_syntax, current_token(), "ERR070 - Expected '(' at start of for-loop", exprtk_error_location)); return error_node(); } if (!token_is(token_t::e_eof)) { if ( !token_is(token_t::e_symbol,prsrhlpr_t::e_hold) && details::imatch(current_token().value,"var") ) { next_token(); if (!token_is(token_t::e_symbol,prsrhlpr_t::e_hold)) { set_error( make_error(parser_error::e_syntax, current_token(), "ERR071 - Expected a variable at the start of initialiser section of for-loop", exprtk_error_location)); return error_node(); } else if (!peek_token_is(token_t::e_assign)) { set_error( make_error(parser_error::e_syntax, current_token(), "ERR072 - Expected variable assignment of initialiser section of for-loop", exprtk_error_location)); return error_node(); } const std::string loop_counter_symbol = current_token().value; 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(), "ERR073 - 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) ) { 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)); if (!sem_.add_element(nse)) { set_error( make_error(parser_error::e_syntax, current_token(), "ERR074 - 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()"); } } } } if (0 == (initialiser = parse_expression())) { set_error( make_error(parser_error::e_syntax, current_token(), "ERR075 - Failed to parse initialiser of for-loop", exprtk_error_location)); result = false; } else if (!token_is(token_t::e_eof)) { set_error( make_error(parser_error::e_syntax, current_token(), "ERR076 - Expected ';' after initialiser of for-loop", exprtk_error_location)); result = false; } } if (!token_is(token_t::e_eof)) { if (0 == (condition = parse_expression())) { set_error( make_error(parser_error::e_syntax, current_token(), "ERR077 - Failed to parse condition of for-loop", exprtk_error_location)); result = false; } else if (!token_is(token_t::e_eof)) { set_error( make_error(parser_error::e_syntax, current_token(), "ERR078 - Expected ';' after condition section of for-loop", exprtk_error_location)); result = false; } } if (!token_is(token_t::e_rbracket)) { if (0 == (incrementor = parse_expression())) { set_error( make_error(parser_error::e_syntax, current_token(), "ERR079 - Failed to parse incrementor of for-loop", exprtk_error_location)); result = false; } else if (!token_is(token_t::e_rbracket)) { set_error( make_error(parser_error::e_syntax, current_token(), "ERR080 - Expected ')' after incrementor section of for-loop", exprtk_error_location)); result = false; } } if (result) { brkcnt_list_.push_front(false); scoped_inc_dec sid(state_.parsing_loop_stmt_count); if (0 == (loop_body = parse_multi_sequence("for-loop"))) { set_error( make_error(parser_error::e_syntax, current_token(), "ERR081 - Failed to parse body of for-loop", exprtk_error_location)); result = false; } } if (!result) { if (se) { se->ref_count--; } free_node(node_allocator_, initialiser); free_node(node_allocator_, condition ); free_node(node_allocator_, incrementor); free_node(node_allocator_, loop_body ); if (!brkcnt_list_.empty()) { brkcnt_list_.pop_front(); } return error_node(); } else { expression_node_ptr result_node = expression_generator_.for_loop(initialiser, condition, incrementor, loop_body, brkcnt_list_.front()); brkcnt_list_.pop_front(); return result_node; } } inline expression_node_ptr parse_switch_statement() { std::vector arg_list; expression_node_ptr result = error_node(); if (!details::imatch(current_token().value,"switch")) { set_error( make_error(parser_error::e_syntax, current_token(), "ERR082 - Expected keyword 'switch'", exprtk_error_location)); return error_node(); } scoped_vec_delete svd((*this),arg_list); next_token(); if (!token_is(token_t::e_lcrlbracket)) { set_error( make_error(parser_error::e_syntax, current_token(), "ERR083 - Expected '{' for call to switch statement", exprtk_error_location)); return error_node(); } expression_node_ptr default_statement = error_node(); scoped_expression_delete defstmt_delete((*this), default_statement); for ( ; ; ) { if (details::imatch("case",current_token().value)) { next_token(); expression_node_ptr condition = parse_expression(); if (0 == condition) return error_node(); else if (!token_is(token_t::e_colon)) { set_error( make_error(parser_error::e_syntax, current_token(), "ERR084 - Expected ':' for case of switch statement", exprtk_error_location)); free_node(node_allocator_, condition); return error_node(); } expression_node_ptr consequent = parse_expression(); if (0 == consequent) { free_node(node_allocator_, condition); 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 case for switch statement", exprtk_error_location)); 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(), "ERR086 - Multiple default cases for switch statement", exprtk_error_location)); return error_node(); } next_token(); if (!token_is(token_t::e_colon)) { set_error( make_error(parser_error::e_syntax, current_token(), "ERR087 - Expected ':' for default of switch statement", exprtk_error_location)); return 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 (0 == default_statement) return error_node(); else if (!token_is(token_t::e_eof)) { set_error( make_error(parser_error::e_syntax, current_token(), "ERR088 - Expected ';' at end of default for switch statement", exprtk_error_location)); return error_node(); } } else if (token_is(token_t::e_rcrlbracket)) break; else { set_error( make_error(parser_error::e_syntax, current_token(), "ERR089 - Expected '}' at end of switch statement", exprtk_error_location)); return error_node(); } } const bool default_statement_present = (0 != default_statement); if (default_statement_present) { arg_list.push_back(default_statement); } result = expression_generator_.switch_statement(arg_list, (0 != default_statement)); svd.delete_ptr = (0 == result); defstmt_delete.delete_ptr = (0 == result); 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(), "ERR090 - Expected token '[*]'", exprtk_error_location)); return error_node(); } scoped_vec_delete svd((*this),arg_list); next_token(); if (!token_is(token_t::e_lcrlbracket)) { set_error( make_error(parser_error::e_syntax, current_token(), "ERR091 - Expected '{' for call to [*] statement", exprtk_error_location)); return error_node(); } for ( ; ; ) { if (!details::imatch("case",current_token().value)) { set_error( make_error(parser_error::e_syntax, current_token(), "ERR092 - Expected a 'case' statement for multi-switch", exprtk_error_location)); return error_node(); } next_token(); expression_node_ptr condition = parse_expression(); if (0 == condition) return error_node(); if (!token_is(token_t::e_colon)) { set_error( make_error(parser_error::e_syntax, current_token(), "ERR093 - Expected ':' for case of [*] statement", exprtk_error_location)); return error_node(); } expression_node_ptr consequent = parse_expression(); if (0 == consequent) return error_node(); if (!token_is(token_t::e_eof)) { set_error( make_error(parser_error::e_syntax, current_token(), "ERR094 - Expected ';' at end of case for [*] statement", exprtk_error_location)); 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); } if (token_is(token_t::e_rcrlbracket,prsrhlpr_t::e_hold)) { break; } } if (!token_is(token_t::e_rcrlbracket)) { set_error( make_error(parser_error::e_syntax, current_token(), "ERR095 - Expected '}' at end of [*] statement", exprtk_error_location)); return error_node(); } const expression_node_ptr result = expression_generator_.multi_switch_statement(arg_list); svd.delete_ptr = (0 == result); return result; } inline expression_node_ptr parse_vararg_function() { std::vector arg_list; details::operator_type opt_type = details::e_default; const std::string symbol = current_token().value; if (details::imatch(symbol,"~")) { next_token(); return parse_multi_sequence(); } else if (details::imatch(symbol,"[*]")) { 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 { set_error( make_error(parser_error::e_syntax, current_token(), "ERR096 - Unsupported vararg function: " + symbol, exprtk_error_location)); return error_node(); } 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(), "ERR097 - Expected '(' for call to vararg function: " + symbol, exprtk_error_location)); return error_node(); } 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(), "ERR098 - Expected ',' for call to vararg function: " + symbol, exprtk_error_location)); return error_node(); } } 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(), "ERR099 - 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_rsqrbracket)) { return node_allocator_.allocate >(expression); } range_t rp; if (!parse_range(rp,true)) { free_node(node_allocator_,expression); return error_node(); } expression_node_ptr result = expression_generator_(expression,rp); if (0 == result) { set_error( make_error(parser_error::e_syntax, current_token(), "ERR100 - Failed to generate string range node", exprtk_error_location)); free_node(node_allocator_,expression); rp.free(); } rp.clear(); return result; } #else inline expression_node_ptr parse_string_range_statement(expression_node_ptr&) { return error_node(); } #endif 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]; Sequence tmp_expression_list; bool return_node_present = false; for (std::size_t i = 0; i < (expression_list.size() - 1); ++i) { 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]) ) { tmp_expression_list.push_back(expression_list[i]); // Remove all subexpressions after first short-circuit // node has been encountered. 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 ( is_constant_node(expression_list[i]) || is_null_node (expression_list[i]) || !side_effect_list[i] ) { free_node(node_allocator_,expression_list[i]); continue; } else tmp_expression_list.push_back(expression_list[i]); } if (!return_node_present) { tmp_expression_list.push_back(expression_list.back()); } expression_list.swap(tmp_expression_list); 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()))); } if ( return_node_present || side_effect_list.back() || (expression_list.size() > 1) ) state_.activate_side_effect("simplify()"); 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_multi_sequence(const std::string& source = "") { 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(), "ERR101 - 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(); } } else if (token_is(token_t::e_rcrlbracket)) { return node_allocator_.allocate >(); } std::vector arg_list; std::vector side_effect_list; expression_node_ptr result = error_node(); scoped_vec_delete sdd((*this),arg_list); scope_handler sh(*this); scoped_bool_or_restorer sbr(state_.side_effect_present); for ( ; ; ) { state_.side_effect_present = false; expression_node_ptr arg = parse_expression(); if (0 == arg) return error_node(); else { arg_list.push_back(arg); side_effect_list.push_back(state_.side_effect_present); } if (token_is(close_bracket)) break; 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(), "ERR102 - Expected '" + details::to_str(seperator) + "' for call to multi-sequence section of " + source, exprtk_error_location)); return error_node(); } if (token_is(close_bracket)) break; } result = simplify(arg_list,side_effect_list,source.empty()); sdd.delete_ptr = (0 == result); return result; } inline bool parse_range(range_t& rp, const bool skip_lsqr = false) { // 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 rp.clear(); if (!skip_lsqr && !token_is(token_t::e_lsqrbracket)) { set_error( make_error(parser_error::e_syntax, current_token(), "ERR103 - Expected '[' for start of range", exprtk_error_location)); return false; } if (token_is(token_t::e_colon)) { rp.n0_c.first = true; rp.n0_c.second = 0; rp.cache.first = 0; } else { expression_node_ptr r0 = parse_expression(); if (0 == r0) { set_error( make_error(parser_error::e_syntax, current_token(), "ERR104 - Failed parse begin section of range", exprtk_error_location)); return false; } else if (is_constant_node(r0)) { const 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)) { set_error( make_error(parser_error::e_syntax, current_token(), "ERR105 - Range lower bound less than zero! Constraint: r0 >= 0", exprtk_error_location)); return false; } } 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(), "ERR106 - Expected ':' for break in range", exprtk_error_location)); rp.free(); return false; } } if (token_is(token_t::e_rsqrbracket)) { rp.n1_c.first = true; rp.n1_c.second = std::numeric_limits::max(); } else { expression_node_ptr r1 = parse_expression(); if (0 == r1) { set_error( make_error(parser_error::e_syntax, current_token(), "ERR107 - Failed parse end section of range", exprtk_error_location)); rp.free(); return false; } else if (is_constant_node(r1)) { const 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); if (r1_value < T(0)) { set_error( make_error(parser_error::e_syntax, current_token(), "ERR108 - Range upper bound less than zero! Constraint: r1 >= 0", exprtk_error_location)); rp.free(); return 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(), "ERR109 - Expected ']' for start of range", exprtk_error_location)); rp.free(); return false; } } if (rp.const_range()) { std::size_t r0 = 0; std::size_t r1 = 0; bool rp_result = false; try { rp_result = rp(r0, r1); } catch (std::runtime_error&) {} if (!rp_result || (r0 > r1)) { set_error( make_error(parser_error::e_syntax, current_token(), "ERR110 - Invalid range, Constraint: r0 <= r1", exprtk_error_location)); return false; } } return true; } inline void lodge_symbol(const std::string& symbol, const symbol_type st) { dec_.add_symbol(symbol,st); } #ifndef exprtk_disable_string_capabilities inline expression_node_ptr parse_string() { const std::string symbol = current_token().value; typedef details::stringvar_node* strvar_node_t; expression_node_ptr result = error_node(); strvar_node_t const_str_node = static_cast(0); scope_element& se = sem_.get_active_element(symbol); if (scope_element::e_string == se.type) { se.active = true; result = se.str_node; lodge_symbol(symbol, e_st_local_string); } else { if (!symtab_store_.is_conststr_stringvar(symbol)) { set_error( make_error(parser_error::e_syntax, current_token(), "ERR111 - Unknown string symbol", exprtk_error_location)); return error_node(); } result = symtab_store_.get_stringvar(symbol); if (symtab_store_.is_constant_string(symbol)) { const_str_node = static_cast(result); result = expression_generator_(const_str_node->str()); } lodge_symbol(symbol, e_st_string); } if (peek_token_is(token_t::e_lsqrbracket)) { next_token(); if (peek_token_is(token_t::e_rsqrbracket)) { next_token(); next_token(); if (const_str_node) { free_node(node_allocator_,result); return expression_generator_(T(const_str_node->size())); } else return node_allocator_.allocate > (static_cast*>(result)->ref()); } range_t rp; if (!parse_range(rp)) { free_node(node_allocator_,result); return error_node(); } else if (const_str_node) { free_node(node_allocator_,result); result = expression_generator_(const_str_node->ref(),rp); } else result = expression_generator_(static_cast*> (result)->ref(), rp); if (result) rp.clear(); } else next_token(); return result; } #else inline expression_node_ptr parse_string() { return error_node(); } #endif #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)) { next_token(); if (peek_token_is(token_t::e_rsqrbracket)) { next_token(); next_token(); free_node(node_allocator_,result); return expression_generator_(T(const_str.size())); } range_t rp; if (!parse_range(rp)) { free_node(node_allocator_,result); rp.free(); return error_node(); } free_node(node_allocator_,result); 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; } 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(), "ERR112 - Overflow in range for string: '" + const_str + "'[" + (rp.n0_c.first ? details::to_str(static_cast(rp.n0_c.second)) : "?") + ":" + (rp.n1_c.first ? details::to_str(static_cast(rp.n1_c.second)) : "?") + "]", exprtk_error_location)); rp.free(); return error_node(); } result = expression_generator_(const_str,rp); if (result) rp.clear(); } else next_token(); return result; } #else inline expression_node_ptr parse_const_string() { return error_node(); } #endif inline expression_node_ptr parse_vector() { const std::string symbol = current_token().value; vector_holder_ptr vec = vector_holder_ptr(0); const scope_element& se = sem_.get_active_element(symbol); 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(), "ERR113 - 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(); 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())) { set_error( make_error(parser_error::e_syntax, current_token(), "ERR114 - Failed to parse index for vector: '" + symbol + "'", exprtk_error_location)); return error_node(); } else if (!token_is(token_t::e_rsqrbracket)) { set_error( make_error(parser_error::e_syntax, current_token(), "ERR115 - Expected ']' for index of vector: '" + symbol + "'", exprtk_error_location)); free_node(node_allocator_,index_expr); return error_node(); } // Perform compile-time range check if (details::is_constant_node(index_expr)) { const std::size_t index = static_cast(details::numeric::to_int32(index_expr->value())); const std::size_t vec_size = vec->size(); if (index >= vec_size) { set_error( make_error(parser_error::e_syntax, current_token(), "ERR116 - Index of " + details::to_str(index) + " out of range for " "vector '" + symbol + "' of size " + details::to_str(vec_size), exprtk_error_location)); free_node(node_allocator_,index_expr); return error_node(); } } return expression_generator_.vector_element(symbol, vec, index_expr); } inline expression_node_ptr parse_vararg_function_call(ivararg_function* vararg_function, const std::string& vararg_function_name) { std::vector arg_list; expression_node_ptr result = error_node(); scoped_vec_delete sdd((*this),arg_list); 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(), "ERR117 - Zero parameter call to vararg function: " + vararg_function_name + " not allowed", exprtk_error_location)); return error_node(); } } else { 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(), "ERR118 - 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(), "ERR119 - Zero parameter call to vararg function: " + vararg_function_name + " not allowed", exprtk_error_location)); return error_node(); } if (arg_list.size() < vararg_function->min_num_args()) { set_error( make_error(parser_error::e_syntax, current_token(), "ERR120 - 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 if (arg_list.size() > vararg_function->max_num_args()) { set_error( make_error(parser_error::e_syntax, current_token(), "ERR121 - 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; } class type_checker { public: enum return_type_t { e_overload = ' ', e_numeric = 'T', e_string = 'S' }; struct function_prototype_t { return_type_t return_type; std::string param_seq; }; typedef parser parser_t; typedef std::vector 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; for (std::size_t i = 0; i < function_definition_list_.size(); ++i) { 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(), "ERR122 - Failed parameter type check for function '" + function_name_ + "', " "Expected '" + function_definition_list_[0].param_seq + "' call set: '" + param_seq + "'", exprtk_error_location)); } else { // 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; } } parser_. set_error( make_error(parser_error::e_syntax, parser_.current_token(), "ERR123 - 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; } std::size_t paramseq_count() const { return function_definition_list_.size(); } std::string paramseq(const std::size_t& index) const { return function_definition_list_[index].param_seq; } return_type_t return_type(const std::size_t& index) const { return function_definition_list_[index].return_type; } bool invalid() const { return !invalid_state_; } bool allow_zero_parameters() const { for (std::size_t i = 0; i < function_definition_list_.size(); ++i) { if (std::string::npos != function_definition_list_[i].param_seq.find("Z")) { return true; } } return false; } private: std::vector split_param_seq(const std::string& param_seq, const details::char_t delimiter = '|') const { std::string::const_iterator current_begin = param_seq.begin(); std::string::const_iterator iter = param_seq.begin(); std::vector result; while (iter != param_seq.end()) { if (*iter == delimiter) { result.push_back(std::string(current_begin, iter)); current_begin = ++iter; } else ++iter; } if (current_begin != iter) { result.push_back(std::string(current_begin, iter)); } return result; } inline bool is_valid_token(std::string param_seq, function_prototype_t& funcproto) const { // Determine return type funcproto.return_type = default_return_type_; if (param_seq.size() > 2) { if (':' == param_seq[1]) { // Note: Only overloaded igeneric functions can have return // type definitions. if (type_checker::e_overload != default_return_type_) return false; switch (param_seq[0]) { case 'T' : funcproto.return_type = type_checker::e_numeric; break; case 'S' : funcproto.return_type = type_checker::e_string; break; default : return false; } param_seq.erase(0,2); } } if ( (std::string::npos != param_seq.find("?*")) || (std::string::npos != param_seq.find("**")) ) { return false; } else if ( (std::string::npos == param_seq.find_first_not_of("STV*?|")) || ("Z" == param_seq) ) { funcproto.param_seq = param_seq; return true; } return false; } void parse_function_prototypes(const std::string& func_prototypes) { if (func_prototypes.empty()) return; std::vector param_seq_list = split_param_seq(func_prototypes); typedef std::map param_seq_map_t; param_seq_map_t param_seq_map; for (std::size_t i = 0; i < param_seq_list.size(); ++i) { function_prototype_t func_proto; if (!is_valid_token(param_seq_list[i], func_proto)) { invalid_state_ = false; parser_. set_error( make_error(parser_error::e_syntax, parser_.current_token(), "ERR124 - Invalid parameter sequence of '" + param_seq_list[i] + "' for function: " + function_name_, exprtk_error_location)); return; } param_seq_map_t::const_iterator seq_itr = param_seq_map.find(param_seq_list[i]); if (param_seq_map.end() != seq_itr) { invalid_state_ = false; parser_. set_error( make_error(parser_error::e_syntax, parser_.current_token(), "ERR125 - Function '" + function_name_ + "' has a parameter sequence conflict between " + "pseq_idx[" + details::to_str(seq_itr->second) + "] and" + "pseq_idx[" + details::to_str(i) + "] " + "param seq: " + param_seq_list[i], exprtk_error_location)); return; } function_definition_list_.push_back(func_proto); } } type_checker(const type_checker&) exprtk_delete; type_checker& operator=(const type_checker&) exprtk_delete; bool invalid_state_; parser_t& parser_; std::string function_name_; const return_type_t default_return_type_; function_definition_list_t function_definition_list_; }; inline expression_node_ptr parse_generic_function_call(igeneric_function* function, const std::string& function_name) { std::vector arg_list; scoped_vec_delete sdd((*this),arg_list); next_token(); std::string param_type_list; type_checker tc((*this), function_name, function->parameter_sequence, type_checker::e_string); if (tc.invalid()) { set_error( make_error(parser_error::e_syntax, current_token(), "ERR126 - Type checker instantiation failure for generic function: " + function_name, exprtk_error_location)); return error_node(); } if (token_is(token_t::e_lbracket)) { 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(), "ERR127 - Zero parameter call to generic function: " + function_name + " not allowed", exprtk_error_location)); return error_node(); } } else { 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 a scalar returning expression param_type_list += 'T'; 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(), "ERR128 - Expected ',' for call to generic function: " + function_name, exprtk_error_location)); return error_node(); } } } } else if ( !function->parameter_sequence.empty() && function->allow_zero_parameters () && !tc .allow_zero_parameters () ) { set_error( make_error(parser_error::e_syntax, current_token(), "ERR129 - Zero parameter call to generic function: " + function_name + " not allowed", exprtk_error_location)); return error_node(); } std::size_t param_seq_index = 0; if ( state_.type_check_enabled && !tc.verify(param_type_list, param_seq_index) ) { set_error( make_error(parser_error::e_syntax, current_token(), "ERR130 - Invalid input parameter sequence for call to generic function: " + function_name, exprtk_error_location)); return error_node(); } expression_node_ptr result = error_node(); 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); sdd.delete_ptr = (0 == result); return result; } 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)) { 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(), "ERR131 - Zero parameter call to generic function: " + function_name + " not allowed", exprtk_error_location)); return false; } } else { for ( ; ; ) { expression_node_ptr arg = parse_expression(); if (0 == arg) return false; 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'; 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(), "ERR132 - Expected ',' for call to string function: " + function_name, exprtk_error_location)); return false; } } } return true; } else return false; } #ifndef exprtk_disable_string_capabilities inline expression_node_ptr parse_string_function_call(igeneric_function* function, const std::string& function_name) { // Move pass the function name next_token(); std::string param_type_list; type_checker tc((*this), function_name, function->parameter_sequence, type_checker::e_string); if ( (!function->parameter_sequence.empty()) && (0 == tc.paramseq_count()) ) { return error_node(); } std::vector arg_list; scoped_vec_delete sdd((*this),arg_list); if (!parse_igeneric_function_params(param_type_list, arg_list, function_name, function, tc)) { return error_node(); } std::size_t param_seq_index = 0; if (!tc.verify(param_type_list, param_seq_index)) { set_error( make_error(parser_error::e_syntax, current_token(), "ERR133 - Invalid input parameter sequence for call to string function: " + function_name, exprtk_error_location)); return error_node(); } expression_node_ptr result = error_node(); 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); 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; type_checker tc((*this), function_name, function->parameter_sequence, type_checker::e_overload); if ( (!function->parameter_sequence.empty()) && (0 == tc.paramseq_count()) ) { return error_node(); } std::vector arg_list; scoped_vec_delete sdd((*this),arg_list); if (!parse_igeneric_function_params(param_type_list, arg_list, function_name, function, tc)) { return error_node(); } std::size_t param_seq_index = 0; if (!tc.verify(param_type_list, param_seq_index)) { set_error( make_error(parser_error::e_syntax, current_token(), "ERR134 - Invalid input parameter sequence for call to overloaded function: " + function_name, exprtk_error_location)); return error_node(); } expression_node_ptr result = error_node(); if (type_checker::e_numeric == tc.return_type(param_seq_index)) { if (tc.paramseq_count() <= 1) result = expression_generator_ .generic_function_call(function, arg_list); else result = expression_generator_ .generic_function_call(function, arg_list, param_seq_index); } else if (type_checker::e_string == tc.return_type(param_seq_index)) { if (tc.paramseq_count() <= 1) result = expression_generator_ .string_function_call(function, arg_list); else result = expression_generator_ .string_function_call(function, arg_list, param_seq_index); } else { set_error( make_error(parser_error::e_syntax, current_token(), "ERR135 - Invalid return type for call to overloaded function: " + function_name, exprtk_error_location)); } sdd.delete_ptr = (0 == result); return result; } #endif template struct parse_special_function_impl { static inline expression_node_ptr process(parser& p, const details::operator_type opt_type, 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)) { p.set_error( make_error(parser_error::e_syntax, p.current_token(), "ERR136 - Expected '(' for special function '" + sf_name + "'", exprtk_error_location)); return error_node(); } 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(), "ERR137 - 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(), "ERR138 - Invalid number of parameters for special function '" + sf_name + "'", exprtk_error_location)); return p.error_node(); } else result = p.expression_generator_.special_function(opt_type,branch); sd.delete_ptr = (0 == result); return result; } }; inline expression_node_ptr parse_special_function() { const std::string sf_name = current_token().value; // Expect: $fDD(expr0,expr1,expr2) or $fDD(expr0,expr1,expr2,expr3) if ( !details::is_digit(sf_name[2]) || !details::is_digit(sf_name[3]) ) { set_error( make_error(parser_error::e_token, current_token(), "ERR139 - Invalid special function[1]: " + sf_name, exprtk_error_location)); return error_node(); } const int id = (sf_name[2] - '0') * 10 + (sf_name[3] - '0'); if (id >= details::e_sffinal) { set_error( make_error(parser_error::e_token, current_token(), "ERR140 - Invalid special function[2]: " + sf_name, exprtk_error_location)); return error_node(); } 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) { 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 >(); } #ifndef exprtk_disable_break_continue inline expression_node_ptr parse_break_statement() { if (state_.parsing_break_stmt) { set_error( make_error(parser_error::e_syntax, current_token(), "ERR141 - Invoking 'break' within a break call is not allowed", exprtk_error_location)); return error_node(); } else if (0 == state_.parsing_loop_stmt_count) { set_error( make_error(parser_error::e_syntax, current_token(), "ERR142 - Invalid use of 'break', allowed only in the scope of a loop", exprtk_error_location)); return error_node(); } scoped_bool_negator sbn(state_.parsing_break_stmt); if (!brkcnt_list_.empty()) { next_token(); brkcnt_list_.front() = true; expression_node_ptr return_expr = error_node(); if (token_is(token_t::e_lsqrbracket)) { if (0 == (return_expr = parse_expression())) { set_error( make_error(parser_error::e_syntax, current_token(), "ERR143 - Failed to parse return expression for 'break' statement", exprtk_error_location)); return error_node(); } else if (!token_is(token_t::e_rsqrbracket)) { set_error( make_error(parser_error::e_syntax, current_token(), "ERR144 - Expected ']' at the completion of break's return expression", exprtk_error_location)); free_node(node_allocator_,return_expr); return error_node(); } } state_.activate_side_effect("parse_break_statement()"); return node_allocator_.allocate >(return_expr); } else { set_error( make_error(parser_error::e_syntax, current_token(), "ERR145 - Invalid use of 'break', allowed only in the scope of a loop", exprtk_error_location)); } return error_node(); } inline expression_node_ptr parse_continue_statement() { if (0 == state_.parsing_loop_stmt_count) { set_error( make_error(parser_error::e_syntax, current_token(), "ERR146 - Invalid use of 'continue', allowed only in the scope of a loop", exprtk_error_location)); return error_node(); } else { next_token(); brkcnt_list_.front() = true; state_.activate_side_effect("parse_continue_statement()"); return node_allocator_.allocate >(); } } #endif 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)) { set_error( make_error(parser_error::e_syntax, current_token(), "ERR147 - Expected '[' as part of vector size definition", exprtk_error_location)); return error_node(); } else if (0 == (size_expr = parse_expression())) { set_error( make_error(parser_error::e_syntax, current_token(), "ERR148 - Failed to determine size of vector '" + vec_name + "'", exprtk_error_location)); 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(), "ERR149 - Expected a literal number as size of vector '" + vec_name + "'", exprtk_error_location)); return error_node(); } 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) ) { set_error( make_error(parser_error::e_syntax, current_token(), "ERR150 - 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(); } std::vector vec_initilizer_list; scoped_vec_delete svd((*this),vec_initilizer_list); bool single_value_initialiser = false; bool vec_to_vec_initialiser = false; bool null_initialisation = false; if (!token_is(token_t::e_rsqrbracket)) { set_error( make_error(parser_error::e_syntax, current_token(), "ERR151 - Expected ']' as part of vector size definition", exprtk_error_location)); return error_node(); } else if (!token_is(token_t::e_eof)) { if (!token_is(token_t::e_assign)) { set_error( make_error(parser_error::e_syntax, current_token(), "ERR152 - Expected ':=' as part of vector definition", 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(), "ERR153 - Failed to parse single vector initialiser", exprtk_error_location)); return error_node(); } vec_initilizer_list.push_back(initialiser); if (!token_is(token_t::e_rsqrbracket)) { set_error( make_error(parser_error::e_syntax, current_token(), "ERR154 - Expected ']' to close single value vector initialiser", exprtk_error_location)); return error_node(); } single_value_initialiser = true; } else if (!token_is(token_t::e_lcrlbracket)) { expression_node_ptr initialiser = error_node(); // Is this a vector to vector assignment and initialisation? if (token_t::e_symbol == current_token().type) { // Is it a locally defined vector? const scope_element& se = sem_.get_active_element(current_token().value); 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; } if (!null_initialisation) { if (0 == initialiser) { set_error( make_error(parser_error::e_syntax, current_token(), "ERR155 - Expected '{' as part of vector initialiser list", exprtk_error_location)); return error_node(); } else vec_to_vec_initialiser = true; } } 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(), "ERR156 - Expected '{' as part of vector initialiser list", exprtk_error_location)); return error_node(); } else vec_initilizer_list.push_back(initialiser); if (token_is(token_t::e_rcrlbracket)) break; 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(), "ERR157 - Expected ',' between vector initialisers", exprtk_error_location)); return error_node(); } if (token_is(token_t::e_rcrlbracket)) break; } } 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 (!token_is(token_t::e_eof)) { set_error( make_error(parser_error::e_syntax, current_token(), "ERR158 - Expected ';' at end of vector definition", exprtk_error_location)); return error_node(); } } if (vec_initilizer_list.size() > vector_size) { set_error( make_error(parser_error::e_syntax, current_token(), "ERR159 - Initialiser list larger than the number of elements in the vector: '" + vec_name + "'", exprtk_error_location)); return error_node(); } } typename symbol_table_t::vector_holder_ptr vec_holder = typename symbol_table_t::vector_holder_ptr(0); const 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) { set_error( make_error(parser_error::e_syntax, current_token(), "ERR160 - Illegal redefinition of local vector: '" + vec_name + "'", exprtk_error_location)); 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++; } } if (0 == vec_holder) { 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); if (!sem_.add_element(nse)) { set_error( make_error(parser_error::e_syntax, current_token(), "ERR161 - Failed to add new local vector '" + vec_name + "' to SEM", exprtk_error_location)); sem_.free_element(nse); return error_node(); } vec_holder = nse.vec_node; exprtk_debug(("parse_define_vector_statement() - INFO - Added new local vector: %s[%d]\n", nse.name.c_str(), static_cast(nse.size))); } state_.activate_side_effect("parse_define_vector_statement()"); lodge_symbol(vec_name, e_st_local_vector); expression_node_ptr result = error_node(); if (null_initialisation) result = expression_generator_(T(0.0)); else if (vec_to_vec_initialiser) { expression_node_ptr vec_node = node_allocator_.allocate(vec_holder); result = expression_generator_( details::e_assign, vec_node, vec_initilizer_list[0]); } else result = node_allocator_ .allocate >( (*vec_holder)[0], vec_size, vec_initilizer_list, single_value_initialiser); svd.delete_ptr = (0 == result); return result; } #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 (se.active) { set_error( make_error(parser_error::e_syntax, current_token(), "ERR162 - Illegal redefinition of local variable: '" + str_name + "'", exprtk_error_location)); free_node(node_allocator_,initialisation_expression); return error_node(); } else if (scope_element::e_string == se.type) { str_node = se.str_node; se.active = true; se.depth = state_.scope_depth; se.ref_count++; } } if (0 == str_node) { 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)) { set_error( make_error(parser_error::e_syntax, current_token(), "ERR163 - 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(); } str_node = nse.str_node; exprtk_debug(("parse_define_string_statement() - INFO - Added new local string variable: %s\n",nse.name.c_str())); } lodge_symbol(str_name, e_st_local_string); state_.activate_side_effect("parse_define_string_statement()"); expression_node_ptr branch[2] = {0}; branch[0] = str_node; branch[1] = initialisation_expression; 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 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 parse_define_var_statement() { if (settings_.vardef_disabled()) { set_error( make_error(parser_error::e_syntax, current_token(), "ERR164 - Illegal variable definition", exprtk_error_location)); return error_node(); } else if (!details::imatch(current_token().value,"var")) { return error_node(); } 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(), "ERR165 - 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(), "ERR166 - Illegal redefinition of reserved keyword: '" + var_name + "'", exprtk_error_location)); return error_node(); } else if (symtab_store_.symbol_exists(var_name)) { set_error( make_error(parser_error::e_syntax, current_token(), "ERR167 - Illegal redefinition of variable '" + var_name + "'", exprtk_error_location)); return error_node(); } else if (local_variable_is_shadowed(var_name)) { set_error( make_error(parser_error::e_syntax, current_token(), "ERR168 - Illegal redefinition of local variable: '" + var_name + "'", exprtk_error_location)); 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())) { set_error( make_error(parser_error::e_syntax, current_token(), "ERR169 - Failed to parse initialisation expression", exprtk_error_location)); return error_node(); } } 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 (!token_is(token_t::e_eof,prsrhlpr_t::e_hold)) { set_error( make_error(parser_error::e_syntax, current_token(), "ERR170 - Expected ';' after variable definition", exprtk_error_location)); free_node(node_allocator_,initialisation_expression); return error_node(); } } if ( (0 != initialisation_expression) && details::is_generally_string_node(initialisation_expression) ) { return parse_define_string_statement(var_name,initialisation_expression); } expression_node_ptr var_node = reinterpret_cast(0); scope_element& se = sem_.get_element(var_name); if (se.name == var_name) { if (se.active) { set_error( make_error(parser_error::e_syntax, current_token(), "ERR171 - Illegal redefinition of local variable: '" + var_name + "'", exprtk_error_location)); free_node(node_allocator_, initialisation_expression); return error_node(); } else if (scope_element::e_variable == se.type) { var_node = se.var_node; se.active = true; se.depth = state_.scope_depth; se.ref_count++; } } 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 = state_.scope_depth; nse.data = new T(T(0)); nse.var_node = node_allocator_.allocate(*reinterpret_cast(nse.data)); if (!sem_.add_element(nse)) { set_error( make_error(parser_error::e_syntax, current_token(), "ERR172 - Failed to add new local variable '" + var_name + "' to SEM", exprtk_error_location)); free_node(node_allocator_, initialisation_expression); sem_.free_element(nse); 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())); } state_.activate_side_effect("parse_define_var_statement()"); 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) ) { set_error( make_error(parser_error::e_syntax, current_token(), "ERR173 - Expected a '{}' for uninitialised var definition", exprtk_error_location)); return error_node(); } else if (!token_is(token_t::e_eof,prsrhlpr_t::e_hold)) { set_error( make_error(parser_error::e_syntax, current_token(), "ERR174 - Expected ';' after uninitialised variable definition", exprtk_error_location)); return error_node(); } expression_node_ptr var_node = reinterpret_cast(0); scope_element& se = sem_.get_element(var_name); if (se.name == var_name) { if (se.active) { set_error( make_error(parser_error::e_syntax, current_token(), "ERR175 - Illegal redefinition of local variable: '" + var_name + "'", exprtk_error_location)); return error_node(); } else if (scope_element::e_variable == se.type) { var_node = se.var_node; se.active = true; se.ref_count++; } } 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 = 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 (!sem_.add_element(nse)) { set_error( make_error(parser_error::e_syntax, current_token(), "ERR176 - Failed to add new local variable '" + var_name + "' to SEM", exprtk_error_location)); sem_.free_element(nse); return error_node(); } exprtk_debug(("parse_uninitialised_var_statement() - INFO - Added new local variable: %s\n", nse.name.c_str())); } 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(); if (!token_is(token_t::e_lbracket)) { set_error( make_error(parser_error::e_syntax, current_token(), "ERR177 - Expected '(' at start of swap statement", exprtk_error_location)); return error_node(); } 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)) { set_error( make_error(parser_error::e_syntax, current_token(), "ERR178 - 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())) { set_error( make_error(parser_error::e_syntax, current_token(), "ERR179 - First parameter to swap is an invalid vector element: '" + var0_name + "'", exprtk_error_location)); return error_node(); } variable0_generated = true; } else { if (symtab_store_.is_variable(var0_name)) { variable0 = symtab_store_.get_variable(var0_name); } const scope_element& se = sem_.get_element(var0_name); if ( (se.active) && (se.name == var0_name) && (scope_element::e_variable == se.type) ) { variable0 = se.var_node; } lodge_symbol(var0_name, e_st_variable); if (0 == variable0) { set_error( make_error(parser_error::e_syntax, current_token(), "ERR180 - First parameter to swap is an invalid variable: '" + var0_name + "'", exprtk_error_location)); return error_node(); } else next_token(); } if (!token_is(token_t::e_comma)) { set_error( make_error(parser_error::e_syntax, current_token(), "ERR181 - Expected ',' between parameters to swap", exprtk_error_location)); if (variable0_generated) { free_node(node_allocator_,variable0); } return error_node(); } const std::string var1_name = current_token().value; if (!token_is(token_t::e_symbol,prsrhlpr_t::e_hold)) { set_error( make_error(parser_error::e_syntax, current_token(), "ERR182 - Expected a symbol for variable or vector element definition", exprtk_error_location)); if (variable0_generated) { free_node(node_allocator_,variable0); } 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(), "ERR183 - Second parameter to swap is an invalid vector element: '" + var1_name + "'", exprtk_error_location)); if (variable0_generated) { free_node(node_allocator_,variable0); } return error_node(); } variable1_generated = true; } else { if (symtab_store_.is_variable(var1_name)) { variable1 = symtab_store_.get_variable(var1_name); } const scope_element& se = sem_.get_element(var1_name); if ( (se.active) && (se.name == var1_name) && (scope_element::e_variable == se.type) ) { variable1 = se.var_node; } lodge_symbol(var1_name, e_st_variable); if (0 == variable1) { set_error( make_error(parser_error::e_syntax, current_token(), "ERR184 - Second parameter to swap is an invalid variable: '" + var1_name + "'", exprtk_error_location)); if (variable0_generated) { free_node(node_allocator_,variable0); } return error_node(); } else next_token(); } if (!token_is(token_t::e_rbracket)) { set_error( make_error(parser_error::e_syntax, current_token(), "ERR185 - Expected ')' at end of swap statement", exprtk_error_location)); if (variable0_generated) { free_node(node_allocator_,variable0); } if (variable1_generated) { free_node(node_allocator_,variable1); } return error_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))) ) { result = node_allocator_.allocate >(v0, v1); if (variable0_generated) { free_node(node_allocator_,variable0); } if (variable1_generated) { free_node(node_allocator_,variable1); } } else result = node_allocator_.allocate > (variable0, variable1); state_.activate_side_effect("parse_swap_statement()"); return result; } #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(), "ERR186 - Return call within a return call is not allowed", exprtk_error_location)); return error_node(); } scoped_bool_negator sbn(state_.parsing_return_stmt); std::vector arg_list; scoped_vec_delete sdd((*this),arg_list); if (!details::imatch(current_token().value,"return")) { return error_node(); } else next_token(); if (!token_is(token_t::e_lsqrbracket)) { set_error( make_error(parser_error::e_syntax, current_token(), "ERR187 - Expected '[' at start of return statement", exprtk_error_location)); return error_node(); } else if (!token_is(token_t::e_rsqrbracket)) { for ( ; ; ) { expression_node_ptr arg = parse_expression(); if (0 == arg) return error_node(); arg_list.push_back(arg); 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(), "ERR188 - Expected ',' between values during call to return", exprtk_error_location)); return error_node(); } } } else if (settings_.zero_return_disabled()) { set_error( make_error(parser_error::e_syntax, current_token(), "ERR189 - 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()) { set_error( make_error(parser_error::e_syntax, prev_token, "ERR190 - Invalid ']' found during return call", exprtk_error_location)); return error_node(); } } std::string ret_param_type_list; for (std::size_t i = 0; i < arg_list.size(); ++i) { 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'; } dec_.retparam_list_.push_back(ret_param_type_list); 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()) { set_error( make_error(parser_error::e_syntax, current_token(), "ERR191 - Invalid sequence of variable '"+ symbol + "' and bracket", 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) { bool implied_mul = false; if (details::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(), "ERR192 - Invalid sequence of brackets", 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 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 = symtab_store_.get_variable(symbol); if (variable) { if (symtab_store_.is_constant_node(symbol)) { variable = expression_generator_(variable->value()); } if (!post_variable_process(symbol)) return error_node(); lodge_symbol(symbol, e_st_variable); next_token(); return variable; } // Are we dealing with a locally defined variable, vector or string? if (!sem_.empty()) { scope_element& se = sem_.get_active_element(symbol); if (se.active && details::imatch(se.name, symbol)) { 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(); return se.var_node; } else if (scope_element::e_vector == se.type) { return parse_vector(); } #ifndef exprtk_disable_string_capabilities else if (scope_element::e_string == se.type) { return parse_string(); } #endif } } #ifndef exprtk_disable_string_capabilities // Are we dealing with a string variable? if (symtab_store_.is_stringvar(symbol)) { return parse_string(); } #endif { // Are we dealing with a function? ifunction* function = symtab_store_.get_function(symbol); if (function) { lodge_symbol(symbol, e_st_function); expression_node_ptr func_node = parse_function_invocation(function,symbol); if (func_node) return func_node; else { set_error( make_error(parser_error::e_syntax, current_token(), "ERR193 - Failed to generate node for function: '" + symbol + "'", exprtk_error_location)); return error_node(); } } } { // Are we dealing with a vararg function? ivararg_function* vararg_function = symtab_store_.get_vararg_function(symbol); if (vararg_function) { lodge_symbol(symbol, e_st_function); expression_node_ptr vararg_func_node = parse_vararg_function_call(vararg_function, symbol); if (vararg_func_node) return vararg_func_node; else { set_error( make_error(parser_error::e_syntax, current_token(), "ERR194 - Failed to generate node for vararg function: '" + symbol + "'", exprtk_error_location)); return error_node(); } } } { // Are we dealing with a vararg generic function? igeneric_function* generic_function = symtab_store_.get_generic_function(symbol); if (generic_function) { lodge_symbol(symbol, e_st_function); expression_node_ptr genericfunc_node = parse_generic_function_call(generic_function, symbol); if (genericfunc_node) return genericfunc_node; else { set_error( make_error(parser_error::e_syntax, current_token(), "ERR195 - Failed to generate node for generic function: '" + symbol + "'", exprtk_error_location)); return error_node(); } } } #ifndef exprtk_disable_string_capabilities { // Are we dealing with a vararg string returning function? igeneric_function* string_function = symtab_store_.get_string_function(symbol); if (string_function) { lodge_symbol(symbol, e_st_function); expression_node_ptr stringfunc_node = parse_string_function_call(string_function, symbol); if (stringfunc_node) return stringfunc_node; else { set_error( make_error(parser_error::e_syntax, current_token(), "ERR196 - Failed to generate node for string function: '" + symbol + "'", exprtk_error_location)); return error_node(); } } } { // Are we dealing with a vararg overloaded scalar/string returning function? igeneric_function* overload_function = symtab_store_.get_overload_function(symbol); if (overload_function) { lodge_symbol(symbol, e_st_function); expression_node_ptr overloadfunc_node = parse_overload_function_call(overload_function, symbol); if (overloadfunc_node) return overloadfunc_node; else { set_error( make_error(parser_error::e_syntax, current_token(), "ERR197 - Failed to generate node for overload function: '" + symbol + "'", exprtk_error_location)); return error_node(); } } } #endif // Are we dealing with a vector? if (symtab_store_.is_vector(symbol)) { lodge_symbol(symbol, e_st_vector); return parse_vector(); } if (details::is_reserved_symbol(symbol)) { if ( settings_.function_enabled(symbol) || !details::is_base_function(symbol) ) { set_error( make_error(parser_error::e_syntax, current_token(), "ERR198 - Invalid use of reserved symbol '" + symbol + "'", exprtk_error_location)); return error_node(); } } // Should we handle unknown symbols? if (resolve_unknown_symbol_ && unknown_symbol_resolver_) { if (!(settings_.rsrvd_sym_usr_disabled() && details::is_reserved_symbol(symbol))) { symbol_table_t& symtab = symtab_store_.get_symbol_table(); std::string error_message; if (unknown_symbol_resolver::e_usrmode_default == unknown_symbol_resolver_->mode) { T default_value = T(0); typename unknown_symbol_resolver::usr_symbol_type usr_symbol_type = unknown_symbol_resolver::e_usr_unknown_type; if (unknown_symbol_resolver_->process(symbol, usr_symbol_type, default_value, error_message)) { bool create_result = false; switch (usr_symbol_type) { case unknown_symbol_resolver::e_usr_variable_type : create_result = symtab.create_variable(symbol, default_value); break; case unknown_symbol_resolver::e_usr_constant_type : create_result = symtab.add_constant(symbol, default_value); break; default : create_result = false; } if (create_result) { expression_node_ptr var = symtab_store_.get_variable(symbol); if (var) { if (symtab_store_.is_constant_node(symbol)) { var = expression_generator_(var->value()); } lodge_symbol(symbol, e_st_variable); if (!post_variable_process(symbol)) return error_node(); next_token(); return var; } } } set_error( make_error(parser_error::e_symtab, current_token(), "ERR199 - Failed to create variable: '" + symbol + "'" + (error_message.empty() ? "" : " - " + error_message), exprtk_error_location)); } else if (unknown_symbol_resolver::e_usrmode_extended == unknown_symbol_resolver_->mode) { if (unknown_symbol_resolver_->process(symbol, symtab, error_message)) { expression_node_ptr result = parse_symtab_symbol(); if (result) { return result; } } set_error( make_error(parser_error::e_symtab, current_token(), "ERR200 - Failed to resolve symbol: '" + symbol + "'" + (error_message.empty() ? "" : " - " + error_message), exprtk_error_location)); } return error_node(); } } set_error( make_error(parser_error::e_syntax, current_token(), "ERR201 - Undefined symbol: '" + symbol + "'", exprtk_error_location)); 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" ; static const std::string symbol_return = "return" ; static const std::string symbol_not = "not" ; const std::string symbol = current_token().value; if (valid_vararg_operation(symbol)) { return parse_vararg_function(); } else if (details::imatch(symbol, symbol_not)) { return parse_not_statement(); } else if (valid_base_operation(symbol)) { return parse_base_operation(); } else if ( details::imatch(symbol, symbol_if) && settings_.control_struct_enabled(symbol) ) { return parse_conditional_statement(); } else if ( details::imatch(symbol, symbol_while) && settings_.control_struct_enabled(symbol) ) { return parse_while_loop(); } else if ( details::imatch(symbol, symbol_repeat) && settings_.control_struct_enabled(symbol) ) { return parse_repeat_until_loop(); } else if ( details::imatch(symbol, symbol_for) && settings_.control_struct_enabled(symbol) ) { return parse_for_loop(); } else if ( details::imatch(symbol, symbol_switch) && settings_.control_struct_enabled(symbol) ) { return parse_switch_statement(); } else if (details::is_valid_sf_symbol(symbol)) { return parse_special_function(); } else if (details::imatch(symbol, symbol_null)) { return parse_null_statement(); } #ifndef exprtk_disable_break_continue else if (details::imatch(symbol, symbol_break)) { return parse_break_statement(); } else if (details::imatch(symbol, symbol_continue)) { return parse_continue_statement(); } #endif else if (details::imatch(symbol, symbol_var)) { return parse_define_var_statement(); } else if (details::imatch(symbol, symbol_swap)) { return parse_swap_statement(); } #ifndef exprtk_disable_return_statement else if ( details::imatch(symbol, symbol_return) && settings_.control_struct_enabled(symbol) ) { return parse_return_statement(); } #endif else if (symtab_store_.valid() || !sem_.empty()) { return parse_symtab_symbol(); } else { set_error( make_error(parser_error::e_symtab, current_token(), "ERR202 - Variable or function detected, yet symbol-table is invalid, Symbol: " + symbol, exprtk_error_location)); return error_node(); } } inline expression_node_ptr parse_branch(precedence_level precedence = e_level00) { stack_limit_handler slh(*this); if (!slh) { return error_node(); } expression_node_ptr branch = error_node(); if (token_t::e_number == current_token().type) { T numeric_value = T(0); if (details::string_to_real(current_token().value, numeric_value)) { expression_node_ptr literal_exp = expression_generator_(numeric_value); if (0 == literal_exp) { set_error( make_error(parser_error::e_numeric, current_token(), "ERR203 - Failed generate node for scalar: '" + current_token().value + "'", exprtk_error_location)); return error_node(); } next_token(); branch = literal_exp; } else { set_error( make_error(parser_error::e_numeric, current_token(), "ERR204 - Failed to convert '" + current_token().value + "' to a number", exprtk_error_location)); return error_node(); } } else if (token_t::e_symbol == current_token().type) { branch = parse_symbol(); } #ifndef exprtk_disable_string_capabilities else if (token_t::e_string == current_token().type) { branch = parse_const_string(); } #endif else if (token_t::e_lbracket == current_token().type) { next_token(); 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(), "ERR205 - Expected ')' instead of: '" + current_token().value + "'", exprtk_error_location)); details::free_node(node_allocator_,branch); return error_node(); } else if (!post_bracket_process(token_t::e_lbracket,branch)) { details::free_node(node_allocator_,branch); return error_node(); } } else if (token_t::e_lsqrbracket == current_token().type) { next_token(); 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(), "ERR206 - Expected ']' instead of: '" + current_token().value + "'", exprtk_error_location)); details::free_node(node_allocator_,branch); return error_node(); } else if (!post_bracket_process(token_t::e_lsqrbracket,branch)) { details::free_node(node_allocator_,branch); return error_node(); } } else if (token_t::e_lcrlbracket == current_token().type) { next_token(); if (0 == (branch = parse_expression())) return error_node(); else if (!token_is(token_t::e_rcrlbracket)) { set_error( make_error(parser_error::e_syntax, current_token(), "ERR207 - Expected '}' instead of: '" + current_token().value + "'", exprtk_error_location)); details::free_node(node_allocator_,branch); return error_node(); } else if (!post_bracket_process(token_t::e_lcrlbracket,branch)) { details::free_node(node_allocator_,branch); return error_node(); } } 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) ) ) { expression_node_ptr result = expression_generator_(details::e_neg,branch); if (0 == result) { details::free_node(node_allocator_,branch); return error_node(); } else branch = result; } } 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(), "ERR208 - Premature end of expression[1]", exprtk_error_location)); return error_node(); } else { set_error( make_error(parser_error::e_syntax, current_token(), "ERR209 - Premature end of expression[2]", exprtk_error_location)); return error_node(); } if ( branch && (e_level00 == precedence) && token_is(token_t::e_ternary,prsrhlpr_t::e_hold) ) { branch = parse_ternary_conditional_statement(branch); } parse_pending_string_rangesize(branch); return branch; } template class expression_generator { public: 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; 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; #define register_synthezier(S) \ synthesize_map_[S ::node_type::id()] = S ::process; \ 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) 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) 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) 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) 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) 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 } inline void set_parser(parser_t& p) { parser_ = &p; } inline void set_uom(unary_op_map_t& unary_op_map) { unary_op_map_ = &unary_op_map; } inline void set_bom(binary_op_map_t& binary_op_map) { binary_op_map_ = &binary_op_map; } inline void set_ibom(inv_binary_op_map_t& inv_binary_op_map) { inv_binary_op_map_ = &inv_binary_op_map; } inline void set_sf3m(sf3_map_t& sf3_map) { sf3_map_ = &sf3_map; } inline void set_sf4m(sf4_map_t& sf4_map) { sf4_map_ = &sf4_map; } inline void set_allocator(details::node_allocator& na) { node_allocator_ = &na; } inline void set_strength_reduction_state(const bool enabled) { strength_reduction_enabled_ = enabled; } inline bool strength_reduction_enabled() const { return strength_reduction_enabled_; } inline bool valid_operator(const details::operator_type& operation, binary_functor_t& bop) { 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; return true; } 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; uop = uop_itr->second; return true; } inline details::operator_type get_operator(const binary_functor_t& bop) const { return (*inv_binary_op_map_).find(bop)->second; } inline expression_node_ptr operator() (const Type& v) const { return node_allocator_->allocate(v); } #ifndef exprtk_disable_string_capabilities inline expression_node_ptr operator() (const std::string& s) const { return node_allocator_->allocate(s); } inline expression_node_ptr operator() (std::string& s, range_t& rp) const { return node_allocator_->allocate_rr(s,rp); } inline expression_node_ptr operator() (const std::string& s, range_t& rp) const { return node_allocator_->allocate_tt(s,rp); } 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); else return error_node(); } #endif inline bool unary_optimisable(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_optimisable(const std::string& sf3id, trinary_functor_t& tfunc) const { typename sf3_map_t::const_iterator itr = sf3_map_->find(sf3id); if (sf3_map_->end() == itr) return false; else tfunc = itr->second.first; return true; } inline bool sf4_optimisable(const std::string& sf4id, quaternary_functor_t& qfunc) const { typename sf4_map_t::const_iterator itr = sf4_map_->find(sf4id); if (sf4_map_->end() == itr) return false; else qfunc = itr->second.first; return true; } inline bool sf3_optimisable(const std::string& sf3id, details::operator_type& operation) const { typename sf3_map_t::const_iterator itr = sf3_map_->find(sf3id); if (sf3_map_->end() == itr) return false; else operation = itr->second.second; return true; } inline bool sf4_optimisable(const std::string& sf4id, details::operator_type& operation) const { typename sf4_map_t::const_iterator itr = sf4_map_->find(sf4id); if (sf4_map_->end() == itr) return false; else operation = itr->second.second; return true; } 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_optimisable(operation) && details::is_variable_node(branch[0])) { return synthesize_uv_expression(operation,branch); } else if (unary_optimisable(operation) && details::is_ivector_node(branch[0])) { return synthesize_uvec_expression(operation,branch); } else return synthesize_unary_expression(operation,branch); } inline bool is_assignment_operation(const details::operator_type& operation) const { return ( (details::e_addass == operation) || (details::e_subass == operation) || (details::e_mulass == operation) || (details::e_divass == operation) || (details::e_modass == operation) ) && parser_->settings_.assignment_enabled(operation); } #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 inline std::string to_str(const details::operator_type& operation) const { 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"; } } inline bool operation_optimisable(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) ; } inline std::string branch_to_id(expression_node_ptr branch) const { static const std::string null_str ("(null)" ); static const std::string const_str ("(c)" ); 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)"); 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"; } inline std::string branch_to_id(expression_node_ptr (&branch)[2]) const { return branch_to_id(branch[0]) + std::string("o") + branch_to_id(branch[1]); } inline bool cov_optimisable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const { if (!operation_optimisable(operation)) return false; else return details::is_constant_node(branch[0]) && details::is_variable_node(branch[1]) ; } inline bool voc_optimisable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const { if (!operation_optimisable(operation)) return false; else return details::is_variable_node(branch[0]) && details::is_constant_node(branch[1]) ; } inline bool vov_optimisable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const { if (!operation_optimisable(operation)) return false; else return details::is_variable_node(branch[0]) && details::is_variable_node(branch[1]) ; } inline bool cob_optimisable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const { if (!operation_optimisable(operation)) return false; else return details::is_constant_node(branch[0]) && !details::is_constant_node(branch[1]) ; } inline bool boc_optimisable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const { if (!operation_optimisable(operation)) return false; else return !details::is_constant_node(branch[0]) && details::is_constant_node(branch[1]) ; } inline bool cocob_optimisable(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) ) { 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; } inline bool coboc_optimisable(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) ) { 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])) ; } else return false; } inline bool uvouv_optimisable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const { if (!operation_optimisable(operation)) return false; else return details::is_uv_node(branch[0]) && details::is_uv_node(branch[1]) ; } inline bool vob_optimisable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const { if (!operation_optimisable(operation)) return false; else return details::is_variable_node(branch[0]) && !details::is_variable_node(branch[1]) ; } inline bool bov_optimisable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const { if (!operation_optimisable(operation)) return false; else return !details::is_variable_node(branch[0]) && details::is_variable_node(branch[1]) ; } inline bool binext_optimisable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const { if (!operation_optimisable(operation)) return false; else return !details::is_constant_node(branch[0]) || !details::is_constant_node(branch[1]) ; } inline bool is_invalid_assignment_op(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const { if (is_assignment_operation(operation)) { const bool b1_is_genstring = details::is_generally_string_node(branch[1]); 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_rebasevector_elem_node (branch[0]) && !details::is_rebasevector_celem_node(branch[0]) && !details::is_vector_node (branch[0]) ) || b1_is_genstring; } else return false; } inline bool is_constpow_operation(const details::operator_type& operation, expression_node_ptr(&branch)[2]) const { if ( !details::is_constant_node(branch[1]) || details::is_constant_node(branch[0]) || details::is_variable_node(branch[0]) || details::is_vector_node (branch[0]) || details::is_generally_string_node(branch[0]) ) return false; const Type c = static_cast*>(branch[1])->value(); return cardinal_pow_optimisable(operation, c); } inline bool is_invalid_break_continue_op(expression_node_ptr (&branch)[2]) const { 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]) ); } inline bool is_invalid_string_op(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const { const bool b0_string = is_generally_string_node(branch[0]); const bool b1_string = is_generally_string_node(branch[1]); bool result = false; if (b0_string != b1_string) result = true; else if (!valid_string_operation(operation) && b0_string && b1_string) result = true; if (result) { 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 { 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]); bool result = false; 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; if (result) { parser_->set_synthesis_error("Invalid string operation"); } return result; } inline bool is_string_operation(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const { const bool b0_string = is_generally_string_node(branch[0]); const bool b1_string = is_generally_string_node(branch[1]); return (b0_string && b1_string && valid_string_operation(operation)); } inline bool is_string_operation(const details::operator_type& operation, expression_node_ptr (&branch)[3]) const { const bool b0_string = is_generally_string_node(branch[0]); const bool b1_string = is_generally_string_node(branch[1]); const bool b2_string = is_generally_string_node(branch[2]); return (b0_string && b1_string && b2_string && (details::e_inrange == operation)); } #ifndef exprtk_disable_sc_andor inline bool is_shortcircuit_expression(const details::operator_type& operation) const { return ( (details::e_scand == operation) || (details::e_scor == operation) ); } #else inline bool is_shortcircuit_expression(const details::operator_type&) const { return false; } #endif inline bool is_null_present(expression_node_ptr (&branch)[2]) const { return ( details::is_null_node(branch[0]) || details::is_null_node(branch[1]) ); } inline bool is_vector_eqineq_logic_operation(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const { if (!is_ivector_node(branch[0]) && !is_ivector_node(branch[1])) return false; else return ( (details::e_lt == operation) || (details::e_lte == operation) || (details::e_gt == operation) || (details::e_gte == operation) || (details::e_eq == operation) || (details::e_ne == operation) || (details::e_equal == operation) || (details::e_and == operation) || (details::e_nand == operation) || (details::e_or == operation) || (details::e_nor == operation) || (details::e_xor == operation) || (details::e_xnor == operation) ); } inline bool is_vector_arithmetic_operation(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const { if (!is_ivector_node(branch[0]) && !is_ivector_node(branch[1])) return false; 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_logic_operation(operation, branch)) { return synthesize_veceqineqlogic_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); } #ifndef exprtk_disable_cardinal_pow_optimisation else if (is_constpow_operation(operation, branch)) { return cardinal_pow_optimisation(branch); } #endif expression_node_ptr result = error_node(); #ifndef exprtk_disable_enhanced_features if (synthesize_expression(operation, branch, result)) { return result; } else #endif { /* 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(); if (cocob_optimisable(operation, branch)) { result = synthesize_cocob_expression::process((*this), operation, branch); } else if (coboc_optimisable(operation, branch) && (0 == result)) { result = synthesize_coboc_expression::process((*this), operation, branch); } if (result) return result; } if (uvouv_optimisable(operation, branch)) { return synthesize_uvouv_expression(operation, branch); } else if (vob_optimisable(operation, branch)) { return synthesize_vob_expression::process((*this), operation, branch); } else if (bov_optimisable(operation, branch)) { return synthesize_bov_expression::process((*this), operation, branch); } else if (cob_optimisable(operation, branch)) { return synthesize_cob_expression::process((*this), operation, branch); } else if (boc_optimisable(operation, branch)) { return synthesize_boc_expression::process((*this), operation, branch); } #ifndef exprtk_disable_enhanced_features else if (cov_optimisable(operation, branch)) { return synthesize_cov_expression::process((*this), operation, branch); } #endif else if (binext_optimisable(operation, branch)) { return synthesize_binary_ext_expression::process((*this), operation, branch); } else return synthesize_expression(operation, branch); } inline expression_node_ptr operator() (const details::operator_type& operation, expression_node_ptr (&branch)[3]) { if ( (0 == branch[0]) || (0 == branch[1]) || (0 == branch[2]) ) { details::free_all_nodes(*node_allocator_,branch); 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); } inline expression_node_ptr operator() (const details::operator_type& operation, expression_node_ptr b0) { expression_node_ptr branch[1] = { b0 }; return (*this)(operation,branch); } inline expression_node_ptr operator() (const details::operator_type& operation, expression_node_ptr& b0, expression_node_ptr& b1) { expression_node_ptr result = error_node(); if ((0 != b0) && (0 != b1)) { expression_node_ptr branch[2] = { b0, b1 }; result = expression_generator::operator()(operation, branch); b0 = branch[0]; b1 = branch[1]; } return result; } inline expression_node_ptr conditional(expression_node_ptr condition, expression_node_ptr consequent, expression_node_ptr alternative) const { if ((0 == condition) || (0 == consequent)) { details::free_node(*node_allocator_, condition ); details::free_node(*node_allocator_, consequent ); details::free_node(*node_allocator_, alternative); return error_node(); } // Can the condition be immediately evaluated? if so optimise. else if (details::is_constant_node(condition)) { // True branch if (details::is_true(condition)) { details::free_node(*node_allocator_, condition ); details::free_node(*node_allocator_, alternative); return consequent; } // False branch else { details::free_node(*node_allocator_, condition ); details::free_node(*node_allocator_, consequent); if (alternative) return alternative; else return node_allocator_->allocate >(); } } else if ((0 != consequent) && (0 != alternative)) { return node_allocator_-> allocate(condition, consequent, alternative); } else return node_allocator_-> allocate(condition, consequent); } #ifndef exprtk_disable_string_capabilities inline expression_node_ptr conditional_string(expression_node_ptr condition, expression_node_ptr consequent, expression_node_ptr alternative) const { if ((0 == condition) || (0 == consequent)) { details::free_node(*node_allocator_, condition ); details::free_node(*node_allocator_, consequent ); details::free_node(*node_allocator_, alternative); return error_node(); } // Can the condition be immediately evaluated? if so optimise. else if (details::is_constant_node(condition)) { // True branch if (details::is_true(condition)) { details::free_node(*node_allocator_, condition ); details::free_node(*node_allocator_, alternative); return consequent; } // False branch else { details::free_node(*node_allocator_, condition ); details::free_node(*node_allocator_, consequent); if (alternative) return alternative; else return node_allocator_-> allocate_c >(""); } } else if ((0 != consequent) && (0 != alternative)) return node_allocator_-> allocate(condition, consequent, alternative); else return error_node(); } #else inline expression_node_ptr conditional_string(expression_node_ptr, expression_node_ptr, expression_node_ptr) const { return error_node(); } #endif inline expression_node_ptr conditional_vector(expression_node_ptr condition, expression_node_ptr consequent, expression_node_ptr alternative) const { if ((0 == condition) || (0 == consequent)) { details::free_node(*node_allocator_, condition ); details::free_node(*node_allocator_, consequent ); details::free_node(*node_allocator_, alternative); return error_node(); } // Can the condition be immediately evaluated? if so optimise. else if (details::is_constant_node(condition)) { // True branch if (details::is_true(condition)) { details::free_node(*node_allocator_, condition ); details::free_node(*node_allocator_, alternative); return consequent; } // False branch else { details::free_node(*node_allocator_, condition ); details::free_node(*node_allocator_, consequent); if (alternative) return alternative; else return node_allocator_->allocate >(); } } else if ((0 != consequent) && (0 != alternative)) { return node_allocator_-> allocate(condition, consequent, alternative); } else return error_node(); } inline loop_runtime_check_ptr get_loop_runtime_check(const loop_runtime_check::loop_types loop_type) const { if ( parser_->loop_runtime_check_ && (loop_type == (parser_->loop_runtime_check_->loop_set & loop_type)) ) { return parser_->loop_runtime_check_; } return loop_runtime_check_ptr(0); } inline expression_node_ptr while_loop(expression_node_ptr& condition, expression_node_ptr& branch, const bool break_continue_present = false) const { if (!break_continue_present && 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 >(); details::free_node(*node_allocator_, condition); details::free_node(*node_allocator_, branch ); return result; } else if (details::is_null_node(condition)) { details::free_node(*node_allocator_,condition); return branch; } loop_runtime_check_ptr rtc = get_loop_runtime_check(loop_runtime_check::e_while_loop); if (!break_continue_present) { if (rtc) return node_allocator_->allocate (condition, branch, rtc); else return node_allocator_->allocate (condition, branch); } #ifndef exprtk_disable_break_continue else { if (rtc) return node_allocator_->allocate (condition, branch, rtc); 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 break_continue_present = false) const { if (!break_continue_present && details::is_constant_node(condition)) { if ( details::is_true(condition) && details::is_constant_node(branch) ) { free_node(*node_allocator_,condition); return branch; } details::free_node(*node_allocator_, condition); details::free_node(*node_allocator_, branch ); return error_node(); } else if (details::is_null_node(condition)) { details::free_node(*node_allocator_,condition); return branch; } loop_runtime_check_ptr rtc = get_loop_runtime_check(loop_runtime_check::e_repeat_until_loop); if (!break_continue_present) { if (rtc) return node_allocator_->allocate (condition, branch, rtc); else return node_allocator_->allocate (condition, branch); } #ifndef exprtk_disable_break_continue else { if (rtc) return node_allocator_->allocate (condition, branch, rtc); 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 break_continue_present = false) const { if (!break_continue_present && 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 >(); details::free_node(*node_allocator_, initialiser); details::free_node(*node_allocator_, condition ); details::free_node(*node_allocator_, incrementor); details::free_node(*node_allocator_, loop_body ); return result; } else if (details::is_null_node(condition) || (0 == condition)) { details::free_node(*node_allocator_, initialiser); details::free_node(*node_allocator_, condition ); details::free_node(*node_allocator_, incrementor); return loop_body; } loop_runtime_check_ptr rtc = get_loop_runtime_check(loop_runtime_check::e_for_loop); if (!break_continue_present) { if (rtc) return node_allocator_->allocate ( initialiser, condition, incrementor, loop_body, rtc ); else return node_allocator_->allocate ( initialiser, condition, incrementor, loop_body ); } #ifndef exprtk_disable_break_continue else { if (rtc) return node_allocator_->allocate ( initialiser, condition, incrementor, loop_body, rtc ); else return node_allocator_->allocate ( initialiser, condition, incrementor, loop_body ); } #else return error_node(); #endif } template class Sequence> inline expression_node_ptr const_optimise_switch(Sequence& arg_list) { expression_node_ptr result = error_node(); 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]; if ((0 == result) && details::is_true(condition)) { result = consequent; break; } } if (0 == result) { result = arg_list.back(); } 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); } } return result; } template class Sequence> inline expression_node_ptr const_optimise_mswitch(Sequence& arg_list) { expression_node_ptr result = error_node(); 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]; if (details::is_true(condition)) { result = consequent; } } if (0 == result) { T zero = T(0); result = node_allocator_->allocate(zero); } 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)) { details::free_node(*node_allocator_,current_expr); } } return result; } struct switch_nodes { typedef std::vector > arg_list_t; #define case_stmt(N) \ if (is_true(arg[(2 * N)].first)) { return arg[(2 * N) + 1].first->value(); } \ struct switch_impl_1 { static inline T process(const arg_list_t& arg) { case_stmt(0) assert(arg.size() == ((2 * 1) + 1)); return arg.back().first->value(); } }; struct switch_impl_2 { static inline T process(const arg_list_t& arg) { case_stmt(0) case_stmt(1) assert(arg.size() == ((2 * 2) + 1)); return arg.back().first->value(); } }; struct switch_impl_3 { static inline T process(const arg_list_t& arg) { case_stmt(0) case_stmt(1) case_stmt(2) assert(arg.size() == ((2 * 3) + 1)); return arg.back().first->value(); } }; struct switch_impl_4 { static inline T process(const arg_list_t& arg) { case_stmt(0) case_stmt(1) case_stmt(2) case_stmt(3) assert(arg.size() == ((2 * 4) + 1)); return arg.back().first->value(); } }; struct switch_impl_5 { static inline T process(const arg_list_t& arg) { case_stmt(0) case_stmt(1) case_stmt(2) case_stmt(3) case_stmt(4) assert(arg.size() == ((2 * 5) + 1)); return arg.back().first->value(); } }; struct switch_impl_6 { static inline T process(const arg_list_t& arg) { case_stmt(0) case_stmt(1) case_stmt(2) case_stmt(3) case_stmt(4) case_stmt(5) assert(arg.size() == ((2 * 6) + 1)); return arg.back().first->value(); } }; struct switch_impl_7 { static inline T process(const arg_list_t& arg) { case_stmt(0) case_stmt(1) case_stmt(2) case_stmt(3) case_stmt(4) case_stmt(5) case_stmt(6) assert(arg.size() == ((2 * 7) + 1)); return arg.back().first->value(); } }; #undef case_stmt }; template class Sequence> inline expression_node_ptr switch_statement(Sequence& arg_list, const bool default_statement_present) { if (arg_list.empty()) return error_node(); else if ( !all_nodes_valid(arg_list) || (!default_statement_present && (arg_list.size() < 2)) ) { details::free_all_nodes(*node_allocator_,arg_list); return error_node(); } else if (is_constant_foldable(arg_list)) return const_optimise_switch(arg_list); switch ((arg_list.size() - 1) / 2) { #define case_stmt(N) \ case N : \ return node_allocator_-> \ allocate >(arg_list); \ case_stmt(1) case_stmt(2) case_stmt(3) case_stmt(4) case_stmt(5) case_stmt(6) case_stmt(7) #undef case_stmt default : return node_allocator_->allocate >(arg_list); } } template class Sequence> inline expression_node_ptr multi_switch_statement(Sequence& arg_list) { if (!all_nodes_valid(arg_list)) { details::free_all_nodes(*node_allocator_,arg_list); return error_node(); } else if (is_constant_foldable(arg_list)) return const_optimise_mswitch(arg_list); else return node_allocator_->allocate >(arg_list); } #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) \ inline expression_node_ptr synthesize_uv_expression(const details::operator_type& operation, expression_node_ptr (&branch)[1]) { T& v = static_cast*>(branch[0])->ref(); switch (operation) { #define case_stmt(op0, op1) \ case op0 : return node_allocator_-> \ allocate > >(v); \ unary_opr_switch_statements #undef case_stmt default : return error_node(); } } 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]); \ unary_opr_switch_statements #undef case_stmt default : return error_node(); } } inline expression_node_ptr synthesize_unary_expression(const details::operator_type& operation, expression_node_ptr (&branch)[1]) { switch (operation) { #define case_stmt(op0, op1) \ case op0 : return node_allocator_-> \ allocate > >(branch[0]); \ unary_opr_switch_statements #undef case_stmt default : return error_node(); } } inline expression_node_ptr const_optimise_sf3(const details::operator_type& operation, expression_node_ptr (&branch)[3]) { expression_node_ptr temp_node = error_node(); switch (operation) { #define case_stmt(op) \ case details::e_sf##op : temp_node = node_allocator_-> \ allocate > > \ (operation, branch); \ break; \ case_stmt(00) case_stmt(01) case_stmt(02) case_stmt(03) case_stmt(04) case_stmt(05) case_stmt(06) case_stmt(07) case_stmt(08) case_stmt(09) case_stmt(10) case_stmt(11) case_stmt(12) case_stmt(13) case_stmt(14) case_stmt(15) case_stmt(16) case_stmt(17) case_stmt(18) case_stmt(19) case_stmt(20) case_stmt(21) case_stmt(22) case_stmt(23) case_stmt(24) case_stmt(25) case_stmt(26) case_stmt(27) case_stmt(28) case_stmt(29) case_stmt(30) case_stmt(31) case_stmt(32) case_stmt(33) case_stmt(34) case_stmt(35) case_stmt(36) case_stmt(37) case_stmt(38) case_stmt(39) case_stmt(40) case_stmt(41) case_stmt(42) case_stmt(43) case_stmt(44) case_stmt(45) case_stmt(46) case_stmt(47) #undef case_stmt default : return error_node(); } const T v = temp_node->value(); details::free_node(*node_allocator_,temp_node); return node_allocator_->allocate(v); } inline expression_node_ptr varnode_optimise_sf3(const details::operator_type& operation, expression_node_ptr (&branch)[3]) { 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(); switch (operation) { #define case_stmt(op) \ case details::e_sf##op : return node_allocator_-> \ allocate_rrr > > \ (v0, v1, v2); \ case_stmt(00) case_stmt(01) case_stmt(02) case_stmt(03) case_stmt(04) case_stmt(05) case_stmt(06) case_stmt(07) case_stmt(08) case_stmt(09) case_stmt(10) case_stmt(11) case_stmt(12) case_stmt(13) case_stmt(14) case_stmt(15) case_stmt(16) case_stmt(17) case_stmt(18) case_stmt(19) case_stmt(20) case_stmt(21) case_stmt(22) case_stmt(23) case_stmt(24) case_stmt(25) case_stmt(26) case_stmt(27) case_stmt(28) case_stmt(29) case_stmt(30) case_stmt(31) case_stmt(32) case_stmt(33) case_stmt(34) case_stmt(35) case_stmt(36) case_stmt(37) case_stmt(38) case_stmt(39) case_stmt(40) case_stmt(41) case_stmt(42) case_stmt(43) case_stmt(44) case_stmt(45) case_stmt(46) case_stmt(47) #undef case_stmt default : return error_node(); } } inline expression_node_ptr special_function(const details::operator_type& operation, expression_node_ptr (&branch)[3]) { if (!all_nodes_valid(branch)) return error_node(); else if (is_constant_foldable(branch)) return const_optimise_sf3(operation,branch); else if (all_nodes_variables(branch)) return varnode_optimise_sf3(operation,branch); else { switch (operation) { #define case_stmt(op) \ case details::e_sf##op : return node_allocator_-> \ allocate > > \ (operation, branch); \ case_stmt(00) case_stmt(01) case_stmt(02) case_stmt(03) case_stmt(04) case_stmt(05) case_stmt(06) case_stmt(07) case_stmt(08) case_stmt(09) case_stmt(10) case_stmt(11) case_stmt(12) case_stmt(13) case_stmt(14) case_stmt(15) case_stmt(16) case_stmt(17) case_stmt(18) case_stmt(19) case_stmt(20) case_stmt(21) case_stmt(22) case_stmt(23) case_stmt(24) case_stmt(25) case_stmt(26) case_stmt(27) case_stmt(28) case_stmt(29) case_stmt(30) case_stmt(31) case_stmt(32) case_stmt(33) case_stmt(34) case_stmt(35) case_stmt(36) case_stmt(37) case_stmt(38) case_stmt(39) case_stmt(40) case_stmt(41) case_stmt(42) case_stmt(43) case_stmt(44) case_stmt(45) case_stmt(46) case_stmt(47) #undef case_stmt default : return error_node(); } } } inline expression_node_ptr const_optimise_sf4(const details::operator_type& operation, expression_node_ptr (&branch)[4]) { expression_node_ptr temp_node = error_node(); switch (operation) { #define case_stmt(op) \ case details::e_sf##op : temp_node = node_allocator_-> \ allocate > > \ (operation, branch); \ break; \ case_stmt(48) case_stmt(49) case_stmt(50) case_stmt(51) case_stmt(52) case_stmt(53) case_stmt(54) case_stmt(55) case_stmt(56) case_stmt(57) case_stmt(58) case_stmt(59) case_stmt(60) case_stmt(61) case_stmt(62) case_stmt(63) case_stmt(64) case_stmt(65) case_stmt(66) case_stmt(67) case_stmt(68) case_stmt(69) case_stmt(70) case_stmt(71) case_stmt(72) case_stmt(73) case_stmt(74) case_stmt(75) case_stmt(76) case_stmt(77) case_stmt(78) case_stmt(79) case_stmt(80) case_stmt(81) case_stmt(82) case_stmt(83) case_stmt(84) case_stmt(85) case_stmt(86) case_stmt(87) case_stmt(88) case_stmt(89) case_stmt(90) case_stmt(91) case_stmt(92) case_stmt(93) case_stmt(94) case_stmt(95) case_stmt(96) case_stmt(97) case_stmt(98) case_stmt(99) #undef case_stmt default : return error_node(); } const T v = temp_node->value(); details::free_node(*node_allocator_,temp_node); return node_allocator_->allocate(v); } inline expression_node_ptr varnode_optimise_sf4(const details::operator_type& operation, expression_node_ptr (&branch)[4]) { 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) { #define case_stmt(op) \ case details::e_sf##op : return node_allocator_-> \ allocate_rrrr > > \ (v0, v1, v2, v3); \ case_stmt(48) case_stmt(49) case_stmt(50) case_stmt(51) case_stmt(52) case_stmt(53) case_stmt(54) case_stmt(55) case_stmt(56) case_stmt(57) case_stmt(58) case_stmt(59) case_stmt(60) case_stmt(61) case_stmt(62) case_stmt(63) case_stmt(64) case_stmt(65) case_stmt(66) case_stmt(67) case_stmt(68) case_stmt(69) case_stmt(70) case_stmt(71) case_stmt(72) case_stmt(73) case_stmt(74) case_stmt(75) case_stmt(76) case_stmt(77) case_stmt(78) case_stmt(79) case_stmt(80) case_stmt(81) case_stmt(82) case_stmt(83) case_stmt(84) case_stmt(85) case_stmt(86) case_stmt(87) case_stmt(88) case_stmt(89) case_stmt(90) case_stmt(91) case_stmt(92) case_stmt(93) case_stmt(94) case_stmt(95) case_stmt(96) case_stmt(97) case_stmt(98) case_stmt(99) #undef case_stmt default : return error_node(); } } 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_optimise_sf4(operation,branch); else if (all_nodes_variables(branch)) return varnode_optimise_sf4(operation,branch); switch (operation) { #define case_stmt(op) \ case details::e_sf##op : return node_allocator_-> \ allocate > > \ (operation, branch); \ case_stmt(48) case_stmt(49) case_stmt(50) case_stmt(51) case_stmt(52) case_stmt(53) case_stmt(54) case_stmt(55) case_stmt(56) case_stmt(57) case_stmt(58) case_stmt(59) case_stmt(60) case_stmt(61) case_stmt(62) case_stmt(63) case_stmt(64) case_stmt(65) case_stmt(66) case_stmt(67) case_stmt(68) case_stmt(69) case_stmt(70) case_stmt(71) case_stmt(72) case_stmt(73) case_stmt(74) case_stmt(75) case_stmt(76) case_stmt(77) case_stmt(78) case_stmt(79) case_stmt(80) case_stmt(81) case_stmt(82) case_stmt(83) case_stmt(84) case_stmt(85) case_stmt(86) case_stmt(87) case_stmt(88) case_stmt(89) case_stmt(90) case_stmt(91) case_stmt(92) case_stmt(93) case_stmt(94) case_stmt(95) case_stmt(96) case_stmt(97) case_stmt(98) case_stmt(99) #undef case_stmt default : return error_node(); } } template class Sequence> inline expression_node_ptr const_optimise_varargfunc(const details::operator_type& operation, Sequence& arg_list) { expression_node_ptr temp_node = error_node(); switch (operation) { #define case_stmt(op0, op1) \ case op0 : temp_node = node_allocator_-> \ allocate > > \ (arg_list); \ break; \ 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(); } const T v = temp_node->value(); details::free_node(*node_allocator_,temp_node); return node_allocator_->allocate(v); } inline bool special_one_parameter_vararg(const details::operator_type& operation) const { return ( (details::e_sum == operation) || (details::e_prod == operation) || (details::e_avg == operation) || (details::e_min == operation) || (details::e_max == operation) ); } template class Sequence> inline expression_node_ptr varnode_optimise_varargfunc(const details::operator_type& operation, Sequence& arg_list) { switch (operation) { #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(); } } template class Sequence> inline expression_node_ptr vectorize_func(const details::operator_type& operation, Sequence& arg_list) { if (1 == arg_list.size()) { switch (operation) { #define case_stmt(op0, op1) \ case op0 : return node_allocator_-> \ allocate > >(arg_list[0]); \ 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(); } template class Sequence> inline expression_node_ptr vararg_function(const details::operator_type& operation, Sequence& arg_list) { if (!all_nodes_valid(arg_list)) { details::free_all_nodes(*node_allocator_,arg_list); return error_node(); } else if (is_constant_foldable(arg_list)) return const_optimise_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_optimise_varargfunc(operation,arg_list); #ifndef exprtk_disable_string_capabilities if (details::e_smulti == operation) { return node_allocator_-> allocate > >(arg_list); } else #endif { switch (operation) { #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(); } } } template inline expression_node_ptr function(ifunction_t* f, expression_node_ptr (&b)[N]) { typedef typename details::function_N_node function_N_node_t; expression_node_ptr result = synthesize_expression(f,b); if (0 == result) return error_node(); else { // Can the function call be completely optimised? if (details::is_constant_node(result)) return result; else if (!all_nodes_valid(b)) { details::free_node(*node_allocator_,result); std::fill_n(b, N, reinterpret_cast(0)); return error_node(); } else if (N != f->param_count) { details::free_node(*node_allocator_,result); std::fill_n(b, N, reinterpret_cast(0)); return error_node(); } function_N_node_t* func_node_ptr = reinterpret_cast(result); if (!func_node_ptr->init_branches(b)) { details::free_node(*node_allocator_,result); std::fill_n(b, N, reinterpret_cast(0)); return error_node(); } return result; } } inline expression_node_ptr function(ifunction_t* f) { typedef typename details::function_N_node function_N_node_t; return node_allocator_->allocate(f); } inline expression_node_ptr vararg_function_call(ivararg_function_t* vaf, std::vector& arg_list) { if (!all_nodes_valid(arg_list)) { details::free_all_nodes(*node_allocator_,arg_list); return error_node(); } typedef details::vararg_function_node alloc_type; expression_node_ptr result = node_allocator_->allocate(vaf,arg_list); if ( !arg_list.empty() && !vaf->has_side_effects() && is_constant_foldable(arg_list) ) { const Type v = result->value(); details::free_node(*node_allocator_,result); result = node_allocator_->allocate(v); } parser_->state_.activate_side_effect("vararg_function_call()"); return result; } 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)) { details::free_all_nodes(*node_allocator_,arg_list); return error_node(); } 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(arg_list,gf); else result = node_allocator_->allocate(gf, param_seq_index, arg_list); alloc_type1* genfunc_node_ptr = static_cast(result); if ( !arg_list.empty() && !gf->has_side_effects() && parser_->state_.type_check_enabled && is_constant_foldable(arg_list) ) { genfunc_node_ptr->init_branches(); const Type v = result->value(); details::free_node(*node_allocator_,result); return node_allocator_->allocate(v); } else if (genfunc_node_ptr->init_branches()) { parser_->state_.activate_side_effect("generic_function_call()"); return result; } else { details::free_node(*node_allocator_, result); details::free_all_nodes(*node_allocator_, arg_list); return error_node(); } } #ifndef exprtk_disable_string_capabilities 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()) { if (!all_nodes_valid(arg_list)) { details::free_all_nodes(*node_allocator_,arg_list); return error_node(); } typedef details::string_function_node alloc_type1; typedef details::multimode_strfunction_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* strfunc_node_ptr = static_cast(result); if ( !arg_list.empty() && !gf->has_side_effects() && is_constant_foldable(arg_list) ) { strfunc_node_ptr->init_branches(); const Type v = result->value(); details::free_node(*node_allocator_,result); return node_allocator_->allocate(v); } else if (strfunc_node_ptr->init_branches()) { parser_->state_.activate_side_effect("string_function_call()"); return result; } else { details::free_node (*node_allocator_,result ); details::free_all_nodes(*node_allocator_,arg_list); return error_node(); } } #endif #ifndef exprtk_disable_return_statement inline expression_node_ptr return_call(std::vector& arg_list) { if (!all_nodes_valid(arg_list)) { details::free_all_nodes(*node_allocator_,arg_list); return error_node(); } typedef details::return_node alloc_type; expression_node_ptr result = node_allocator_-> allocate_rr(arg_list,parser_->results_ctx()); alloc_type* return_node_ptr = static_cast(result); if (return_node_ptr->init_branches()) { parser_->state_.activate_side_effect("return_call()"); return result; } else { details::free_node (*node_allocator_, result ); details::free_all_nodes(*node_allocator_, arg_list); return error_node(); } } inline expression_node_ptr return_envelope(expression_node_ptr body, results_context_t* rc, bool*& return_invoked) { typedef details::return_envelope_node alloc_type; expression_node_ptr result = node_allocator_-> allocate_cr(body,(*rc)); return_invoked = static_cast(result)->retinvk_ptr(); return result; } #else inline expression_node_ptr return_call(std::vector&) { return error_node(); } inline expression_node_ptr return_envelope(expression_node_ptr, results_context_t*, bool*&) { return error_node(); } #endif 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(); if (details::is_constant_node(index)) { std::size_t i = static_cast(details::numeric::to_int64(index->value())); details::free_node(*node_allocator_,index); if (vector_base->rebaseable()) { return node_allocator_->allocate(i,vector_base); } const scope_element& se = parser_->sem_.get_element(symbol,i); if (se.index == i) { result = se.var_node; } else { scope_element nse; nse.name = symbol; nse.active = true; nse.ref_count = 1; nse.type = scope_element::e_vecelem; nse.index = i; nse.depth = parser_->state_.scope_depth; nse.data = 0; nse.var_node = node_allocator_->allocate((*(*vector_base)[i])); if (!parser_->sem_.add_element(nse)) { parser_->set_synthesis_error("Failed to add new local vector element to SEM [1]"); parser_->sem_.free_element(nse); result = error_node(); } exprtk_debug(("vector_element() - INFO - Added new local vector element: %s\n",nse.name.c_str())); parser_->state_.activate_side_effect("vector_element()"); result = nse.var_node; } } else if (vector_base->rebaseable()) result = node_allocator_->allocate(index,vector_base); else result = node_allocator_->allocate(index,vector_base); return result; } private: template inline bool is_constant_foldable(NodePtr (&b)[N]) const { for (std::size_t i = 0; i < N; ++i) { if (0 == b[i]) return false; else if (!details::is_constant_node(b[i])) return false; } 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 (0 == b[i]) return false; else if (!details::is_constant_node(b[i])) return false; } return true; } void lodge_assignment(symbol_type cst, expression_node_ptr node) { parser_->state_.activate_side_effect("lodge_assignment()"); if (!parser_->dec_.collect_assignments()) return; std::string symbol_name; switch (cst) { case e_st_variable : symbol_name = parser_->symtab_store_ .get_variable_name(node); break; #ifndef exprtk_disable_string_capabilities case e_st_string : symbol_name = parser_->symtab_store_ .get_stringvar_name(node); break; #endif case e_st_vector : { typedef details::vector_holder vector_holder_t; vector_holder_t& vh = static_cast(node)->vec_holder(); symbol_name = parser_->symtab_store_.get_vector_name(&vh); } break; case e_st_vecelem : { typedef details::vector_holder vector_holder_t; vector_holder_t& vh = static_cast(node)->vec_holder(); symbol_name = parser_->symtab_store_.get_vector_name(&vh); cst = e_st_vector; } break; default : return; } if (!symbol_name.empty()) { parser_->dec_.add_assignment(symbol_name,cst); } } inline expression_node_ptr synthesize_assignment_expression(const details::operator_type& operation, expression_node_ptr (&branch)[2]) { if (details::is_variable_node(branch[0])) { lodge_assignment(e_st_variable,branch[0]); return synthesize_expression(operation,branch); } else if (details::is_vector_elem_node(branch[0])) { lodge_assignment(e_st_vecelem,branch[0]); return synthesize_expression(operation, branch); } else if (details::is_rebasevector_elem_node(branch[0])) { lodge_assignment(e_st_vecelem,branch[0]); return synthesize_expression(operation, branch); } else if (details::is_rebasevector_celem_node(branch[0])) { lodge_assignment(e_st_vecelem,branch[0]); return synthesize_expression(operation, branch); } #ifndef exprtk_disable_string_capabilities else if (details::is_string_node(branch[0])) { lodge_assignment(e_st_string,branch[0]); return synthesize_expression(operation, branch); } else if (details::is_string_range_node(branch[0])) { lodge_assignment(e_st_string,branch[0]); return synthesize_expression(operation, branch); } #endif else if (details::is_vector_node(branch[0])) { lodge_assignment(e_st_vector,branch[0]); if (details::is_ivector_node(branch[1])) return synthesize_expression(operation, branch); else return synthesize_expression(operation, branch); } else { parser_->set_synthesis_error("Invalid assignment operation.[1]"); return error_node(); } } inline expression_node_ptr synthesize_assignment_operation_expression(const details::operator_type& operation, expression_node_ptr (&branch)[2]) { if (details::is_variable_node(branch[0])) { lodge_assignment(e_st_variable,branch[0]); switch (operation) { #define case_stmt(op0, op1) \ case op0 : return node_allocator_-> \ template allocate_rrr > > \ (operation, branch[0], branch[1]); \ 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])) { lodge_assignment(e_st_vecelem,branch[0]); switch (operation) { #define case_stmt(op0, op1) \ case op0 : return node_allocator_-> \ template allocate_rrr > > \ (operation, branch[0], branch[1]); \ 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_rebasevector_elem_node(branch[0])) { lodge_assignment(e_st_vecelem,branch[0]); switch (operation) { #define case_stmt(op0, op1) \ case op0 : return node_allocator_-> \ template allocate_rrr > > \ (operation, branch[0], branch[1]); \ 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_rebasevector_celem_node(branch[0])) { lodge_assignment(e_st_vecelem,branch[0]); switch (operation) { #define case_stmt(op0, op1) \ case op0 : return node_allocator_-> \ template allocate_rrr > > \ (operation, branch[0], branch[1]); \ 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_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]); \ 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]); \ 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(); } } } #ifndef exprtk_disable_string_capabilities else if ( (details::e_addass == operation) && details::is_string_node(branch[0]) ) { typedef details::assignment_string_node addass_t; lodge_assignment(e_st_string,branch[0]); return synthesize_expression(operation,branch); } #endif else { parser_->set_synthesis_error("Invalid assignment operation[2]"); return error_node(); } } inline expression_node_ptr synthesize_veceqineqlogic_operation_expression(const details::operator_type& operation, expression_node_ptr (&branch)[2]) { const bool is_b0_ivec = details::is_ivector_node(branch[0]); const bool is_b1_ivec = details::is_ivector_node(branch[1]); #define batch_eqineq_logic_case \ 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_equal , details::equal_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 ) \ 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]); \ batch_eqineq_logic_case #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]); \ batch_eqineq_logic_case #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]); \ batch_eqineq_logic_case #undef case_stmt default : return error_node(); } } else return error_node(); #undef batch_eqineq_logic_case } inline expression_node_ptr synthesize_vecarithmetic_operation_expression(const details::operator_type& operation, expression_node_ptr (&branch)[2]) { const bool is_b0_ivec = details::is_ivector_node(branch[0]); const bool is_b1_ivec = details::is_ivector_node(branch[1]); #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) \ 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]); \ 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]); \ 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]); \ vector_ops #undef case_stmt default : 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]); #ifndef exprtk_disable_string_capabilities const bool v0_is_str = details::is_generally_string_node(branch[0]); const bool v1_is_str = details::is_generally_string_node(branch[1]); #endif expression_node_ptr result = error_node(); if (v0_is_ivar && v1_is_ivar) { typedef details::variable_node* variable_node_ptr; variable_node_ptr v0 = variable_node_ptr(0); variable_node_ptr v1 = variable_node_ptr(0); if ( (0 != (v0 = dynamic_cast(branch[0]))) && (0 != (v1 = dynamic_cast(branch[1]))) ) { result = node_allocator_->allocate >(v0,v1); } else result = node_allocator_->allocate >(branch[0],branch[1]); } else if (v0_is_ivec && v1_is_ivec) { result = node_allocator_->allocate >(branch[0],branch[1]); } #ifndef exprtk_disable_string_capabilities else if (v0_is_str && v1_is_str) { if (is_string_node(branch[0]) && is_string_node(branch[1])) result = node_allocator_->allocate > (branch[0], branch[1]); else result = node_allocator_->allocate > (branch[0], branch[1]); } #endif else { parser_->set_synthesis_error("Only variables, strings, vectors or vector elements can be swapped"); return error_node(); } parser_->state_.activate_side_effect("synthesize_swap_expression()"); return result; } #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(); if (details::is_constant_node(branch[0])) { 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)); } 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)); } if (result) { details::free_node(*node_allocator_, branch[0]); details::free_node(*node_allocator_, branch[1]); return result; } 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 class IPowNode> inline expression_node_ptr cardinal_pow_optimisation_impl(const TType& v, const unsigned int& p) { switch (p) { #define case_stmt(cp) \ case cp : return node_allocator_-> \ allocate > >(v); \ case_stmt( 1) case_stmt( 2) case_stmt( 3) case_stmt( 4) case_stmt( 5) case_stmt( 6) case_stmt( 7) case_stmt( 8) case_stmt( 9) case_stmt(10) case_stmt(11) case_stmt(12) case_stmt(13) case_stmt(14) case_stmt(15) case_stmt(16) case_stmt(17) case_stmt(18) case_stmt(19) case_stmt(20) case_stmt(21) case_stmt(22) case_stmt(23) case_stmt(24) case_stmt(25) case_stmt(26) case_stmt(27) case_stmt(28) case_stmt(29) case_stmt(30) case_stmt(31) case_stmt(32) case_stmt(33) case_stmt(34) case_stmt(35) case_stmt(36) case_stmt(37) case_stmt(38) case_stmt(39) case_stmt(40) case_stmt(41) case_stmt(42) case_stmt(43) case_stmt(44) case_stmt(45) case_stmt(46) case_stmt(47) case_stmt(48) case_stmt(49) case_stmt(50) case_stmt(51) case_stmt(52) case_stmt(53) case_stmt(54) case_stmt(55) case_stmt(56) case_stmt(57) case_stmt(58) case_stmt(59) case_stmt(60) #undef case_stmt default : return error_node(); } } inline expression_node_ptr cardinal_pow_optimisation(const T& v, const T& c) { const bool not_recipricol = (c >= T(0)); const unsigned int p = static_cast(details::numeric::to_int32(details::numeric::abs(c))); if (0 == p) return node_allocator_->allocate_c(T(1)); else if (std::equal_to()(T(2),c)) { return node_allocator_-> template allocate_rr > >(v,v); } else { if (not_recipricol) return cardinal_pow_optimisation_impl(v,p); else return cardinal_pow_optimisation_impl(v,p); } } inline bool cardinal_pow_optimisable(const details::operator_type& operation, const T& c) const { return (details::e_pow == operation) && (details::numeric::abs(c) <= T(60)) && details::numeric::is_integer(c); } inline expression_node_ptr cardinal_pow_optimisation(expression_node_ptr (&branch)[2]) { const Type c = static_cast*>(branch[1])->value(); const bool not_recipricol = (c >= T(0)); const unsigned int p = static_cast(details::numeric::to_int32(details::numeric::abs(c))); node_allocator_->free(branch[1]); if (0 == p) { details::free_all_nodes(*node_allocator_, branch); return node_allocator_->allocate_c(T(1)); } else if (not_recipricol) return cardinal_pow_optimisation_impl(branch[0],p); else return cardinal_pow_optimisation_impl(branch[0],p); } #else inline expression_node_ptr cardinal_pow_optimisation(T&, const T&) { return error_node(); } inline bool cardinal_pow_optimisable(const details::operator_type&, const T&) { return false; } inline expression_node_ptr cardinal_pow_optimisation(expression_node_ptr(&)[2]) { return error_node(); } #endif struct synthesize_binary_ext_expression { static inline expression_node_ptr process(expression_generator& expr_gen, const details::operator_type& operation, expression_node_ptr (&branch)[2]) { const bool left_neg = is_neg_unary_node(branch[0]); const bool right_neg = is_neg_unary_node(branch[1]); if (left_neg && right_neg) { if ( (details::e_add == operation) || (details::e_sub == operation) || (details::e_mul == operation) || (details::e_div == operation) ) { if ( !expr_gen.parser_->simplify_unary_negation_branch(branch[0]) || !expr_gen.parser_->simplify_unary_negation_branch(branch[1]) ) { details::free_all_nodes(*expr_gen.node_allocator_,branch); return error_node(); } } switch (operation) { // -f(x + 1) + -g(y + 1) --> -(f(x + 1) + g(y + 1)) case details::e_add : return expr_gen(details::e_neg, expr_gen.node_allocator_-> template allocate > > (branch[0],branch[1])); // -f(x + 1) - -g(y + 1) --> g(y + 1) - f(x + 1) case details::e_sub : return expr_gen.node_allocator_-> template allocate > > (branch[1],branch[0]); default : break; } } else if (left_neg && !right_neg) { if ( (details::e_add == operation) || (details::e_sub == operation) || (details::e_mul == operation) || (details::e_div == operation) ) { if (!expr_gen.parser_->simplify_unary_negation_branch(branch[0])) { details::free_all_nodes(*expr_gen.node_allocator_,branch); return error_node(); } switch (operation) { // -f(x + 1) + g(y + 1) --> g(y + 1) - f(x + 1) case details::e_add : return expr_gen.node_allocator_-> template allocate > > (branch[1], branch[0]); // -f(x + 1) - g(y + 1) --> -(f(x + 1) + g(y + 1)) case details::e_sub : return expr_gen(details::e_neg, expr_gen.node_allocator_-> template allocate > > (branch[0], branch[1])); // -f(x + 1) * g(y + 1) --> -(f(x + 1) * g(y + 1)) case details::e_mul : return expr_gen(details::e_neg, expr_gen.node_allocator_-> template allocate > > (branch[0], branch[1])); // -f(x + 1) / g(y + 1) --> -(f(x + 1) / g(y + 1)) case details::e_div : return expr_gen(details::e_neg, expr_gen.node_allocator_-> template allocate > > (branch[0], branch[1])); default : return error_node(); } } } else if (!left_neg && right_neg) { if ( (details::e_add == operation) || (details::e_sub == operation) || (details::e_mul == operation) || (details::e_div == operation) ) { if (!expr_gen.parser_->simplify_unary_negation_branch(branch[1])) { details::free_all_nodes(*expr_gen.node_allocator_,branch); return error_node(); } switch (operation) { // f(x + 1) + -g(y + 1) --> f(x + 1) - g(y + 1) case details::e_add : return expr_gen.node_allocator_-> template allocate > > (branch[0], branch[1]); // f(x + 1) - - g(y + 1) --> f(x + 1) + g(y + 1) case details::e_sub : return expr_gen.node_allocator_-> template allocate > > (branch[0], branch[1]); // f(x + 1) * -g(y + 1) --> -(f(x + 1) * g(y + 1)) case details::e_mul : return expr_gen(details::e_neg, expr_gen.node_allocator_-> template allocate > > (branch[0], branch[1])); // f(x + 1) / -g(y + 1) --> -(f(x + 1) / g(y + 1)) case details::e_div : return expr_gen(details::e_neg, expr_gen.node_allocator_-> template allocate > > (branch[0], branch[1])); default : return error_node(); } } } switch (operation) { #define case_stmt(op0, op1) \ case op0 : return expr_gen.node_allocator_-> \ template allocate > > \ (branch[0], branch[1]); \ basic_opr_switch_statements extended_opr_switch_statements #undef case_stmt default : return error_node(); } } }; struct synthesize_vob_expression { static inline expression_node_ptr process(expression_generator& expr_gen, const details::operator_type& operation, expression_node_ptr (&branch)[2]) { const Type& v = static_cast*>(branch[0])->ref(); #ifndef exprtk_disable_enhanced_features if (details::is_sf3ext_node(branch[1])) { expression_node_ptr result = error_node(); const bool synthesis_result = synthesize_sf4ext_expression::template compile_right (expr_gen, v, operation, branch[1], result); if (synthesis_result) { details::free_node(*expr_gen.node_allocator_,branch[1]); return result; } } #endif if ( (details::e_mul == operation) || (details::e_div == operation) ) { if (details::is_uv_node(branch[1])) { typedef details::uv_base_node* uvbn_ptr_t; details::operator_type o = static_cast(branch[1])->operation(); if (details::e_neg == o) { const Type& v1 = static_cast(branch[1])->v(); details::free_node(*expr_gen.node_allocator_,branch[1]); switch (operation) { case details::e_mul : return expr_gen(details::e_neg, expr_gen.node_allocator_-> template allocate_rr > >(v,v1)); case details::e_div : return expr_gen(details::e_neg, expr_gen.node_allocator_-> template allocate_rr > >(v,v1)); default : break; } } } } switch (operation) { #define case_stmt(op0, op1) \ case op0 : return expr_gen.node_allocator_-> \ template allocate_rc > > \ (v, branch[1]); \ basic_opr_switch_statements extended_opr_switch_statements #undef case_stmt default : return error_node(); } } }; struct synthesize_bov_expression { static inline expression_node_ptr process(expression_generator& expr_gen, const details::operator_type& operation, expression_node_ptr (&branch)[2]) { const Type& v = static_cast*>(branch[1])->ref(); #ifndef exprtk_disable_enhanced_features if (details::is_sf3ext_node(branch[0])) { expression_node_ptr result = error_node(); const bool synthesis_result = synthesize_sf4ext_expression::template compile_left (expr_gen, v, operation, branch[0], result); if (synthesis_result) { details::free_node(*expr_gen.node_allocator_, branch[0]); return result; } } #endif if ( (details::e_add == operation) || (details::e_sub == operation) || (details::e_mul == operation) || (details::e_div == operation) ) { if (details::is_uv_node(branch[0])) { typedef details::uv_base_node* uvbn_ptr_t; details::operator_type o = static_cast(branch[0])->operation(); if (details::e_neg == o) { const Type& v0 = static_cast(branch[0])->v(); details::free_node(*expr_gen.node_allocator_,branch[0]); switch (operation) { case details::e_add : return expr_gen.node_allocator_-> template allocate_rr > >(v,v0); case details::e_sub : return expr_gen(details::e_neg, expr_gen.node_allocator_-> template allocate_rr > >(v0,v)); case details::e_mul : return expr_gen(details::e_neg, expr_gen.node_allocator_-> template allocate_rr > >(v0,v)); case details::e_div : return expr_gen(details::e_neg, expr_gen.node_allocator_-> template allocate_rr > >(v0,v)); default : break; } } } } switch (operation) { #define case_stmt(op0, op1) \ case op0 : return expr_gen.node_allocator_-> \ template allocate_cr > > \ (branch[0], v); \ basic_opr_switch_statements extended_opr_switch_statements #undef case_stmt default : return error_node(); } } }; struct synthesize_cob_expression { static inline expression_node_ptr process(expression_generator& expr_gen, const details::operator_type& operation, expression_node_ptr (&branch)[2]) { const Type c = static_cast*>(branch[0])->value(); details::free_node(*expr_gen.node_allocator_,branch[0]); if (std::equal_to()(T(0),c) && (details::e_mul == operation)) { details::free_node(*expr_gen.node_allocator_,branch[1]); return expr_gen(T(0)); } else if (std::equal_to()(T(0),c) && (details::e_div == operation)) { details::free_node(*expr_gen.node_allocator_, branch[1]); return expr_gen(T(0)); } else if (std::equal_to()(T(0),c) && (details::e_add == operation)) return branch[1]; else if (std::equal_to()(T(1),c) && (details::e_mul == operation)) return branch[1]; if (details::is_cob_node(branch[1])) { // Simplify expressions of the form: // 1. (1 * (2 * (3 * (4 * (5 * (6 * (7 * (8 * (9 + x))))))))) --> 40320 * (9 + x) // 2. (1 + (2 + (3 + (4 + (5 + (6 + (7 + (8 + (9 + x))))))))) --> 45 + x if ( (details::e_mul == operation) || (details::e_add == operation) ) { details::cob_base_node* cobnode = static_cast*>(branch[1]); if (operation == cobnode->operation()) { switch (operation) { case details::e_add : cobnode->set_c(c + cobnode->c()); break; case details::e_mul : cobnode->set_c(c * cobnode->c()); break; default : return error_node(); } return cobnode; } } if (operation == details::e_mul) { details::cob_base_node* cobnode = static_cast*>(branch[1]); details::operator_type cob_opr = cobnode->operation(); if ( (details::e_div == cob_opr) || (details::e_mul == cob_opr) ) { switch (cob_opr) { case details::e_div : cobnode->set_c(c * cobnode->c()); break; case details::e_mul : cobnode->set_c(cobnode->c() / c); break; default : return error_node(