/* ****************************************************************** * C++ Mathematical Expression Toolkit Library * * * * Author: Arash Partow (1999-2015) * * URL: http://www.partow.net/programming/exprtk/index.html * * * * Copyright notice: * * Free use of the C++ Mathematical Expression Toolkit Library is * * permitted under the guidelines and in accordance with the most * * current version of the Common Public License. * * http://www.opensource.org/licenses/cpl1.0.php * * * * 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 namespace exprtk { #if exprtk_enable_debugging #define exprtk_debug(params) printf params #else #define exprtk_debug(params) (void)0 #endif namespace details { inline bool is_whitespace(const char c) { return (' ' == c) || ('\n' == c) || ('\r' == c) || ('\t' == c) || ('\b' == c) || ('\v' == c) || ('\f' == c) ; } inline bool is_operator_char(const char 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 c) { return (('a' <= c) && (c <= 'z')) || (('A' <= c) && (c <= 'Z')) ; } inline bool is_digit(const char c) { return ('0' <= c) && (c <= '9'); } inline bool is_letter_or_digit(const char c) { return is_letter(c) || is_digit(c); } inline bool is_left_bracket(const char c) { return ('(' == c) || ('[' == c) || ('{' == c); } inline bool is_right_bracket(const char c) { return (')' == c) || (']' == c) || ('}' == c); } inline bool is_bracket(const char c) { return is_left_bracket(c) || is_right_bracket(c); } inline bool is_sign(const char c) { return ('+' == c) || ('-' == c); } inline bool is_invalid(const char c) { return !is_whitespace (c) && !is_operator_char(c) && !is_letter (c) && !is_digit (c) && ('.' != c) && ('_' != c) && ('$' != c) && ('~' != c) && ('\'' != c); } inline bool imatch(const char c1, const char 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; } 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 std::string to_str(int i) { if (0 == i) return std::string("0"); std::string result; bool negative = (i < 0); if (negative) i *= -1; while (i) { char digit = '0' + char(i % 10); result = (digit + result); i /= 10; } if (negative) result = "-" + result; return result; } inline bool is_hex_digit(const std::string::value_type digit) { return (('0' <= digit) && (digit <= '9')) || (('A' <= digit) && (digit <= 'F')) || (('a' <= digit) && (digit <= 'f')) ; } inline unsigned char hex_to_bin(unsigned char h) { if (('0' <= h) && (h <= '9')) return (h - '0'); else return (std::toupper(h) - 'A'); } template inline void parse_hex(Iterator& itr, Iterator end, std::string::value_type& result) { if ( (end != (itr )) && (end != (itr + 1)) && (end != (itr + 2)) && (end != (itr + 3)) && ('0' == *(itr )) && ( ('x' == *(itr + 1)) || ('X' == *(itr + 1)) ) && (is_hex_digit(*(itr + 2))) && (is_hex_digit(*(itr + 3))) ) { result = hex_to_bin(*(itr + 2)) << 4 | hex_to_bin(*(itr + 3)); itr += 3; } else result = '\0'; } inline void cleanup_escapes(std::string& s) { std::string::iterator itr1 = s.begin(); std::string::iterator itr2 = s.begin(); std::string::iterator end = s.end (); std::size_t removal_count = 0; while (end != itr1) { if ('\\' == (*itr1)) { ++removal_count; if (end == ++itr1) break; else if ('\\' != (*itr1)) { switch (*itr1) { case 'n' : (*itr1) = '\n'; break; case 'r' : (*itr1) = '\r'; break; case 't' : (*itr1) = '\t'; break; case '0' : parse_hex(itr1,end,(*itr1)); removal_count += 3; break; } continue; } } if (itr1 != itr2) { (*itr2) = (*itr1); } ++itr1; ++itr2; } s.resize(s.size() - removal_count); } 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 << (const char* 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_; }; struct ilesscompare { inline bool operator()(const std::string& s1, const std::string& s2) const { const std::size_t length = std::min(s1.size(),s2.size()); for (std::size_t i = 0; i < length; ++i) { const char c1 = static_cast(std::tolower(s1[i])); const char c2 = static_cast(std::tolower(s2[i])); if (c1 > c2) return false; else if (c1 < c2) return true; } return s1.size() < s2.size(); } }; static const std::string reserved_words[] = { "break", "case", "continue", "default", "false", "for", "if", "else", "ilike", "in", "like", "and", "nand", "nor", "not", "null", "or", "repeat", "shl", "shr", "swap", "switch", "true", "until", "var", "while", "xnor", "xor", "&", "|" }; 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", "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); 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; } struct cs_match { static inline bool cmp(const char c0, const char c1) { return (c0 == c1); } }; struct cis_match { static inline bool cmp(const char c0, const char 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& zero_or_one) { if (0 == std::distance(data_begin,data_end)) { return false; } Iterator d_itr = data_begin; Iterator p_itr = pattern_begin; Iterator c_itr = data_begin; Iterator m_itr = data_begin; while ((data_end != d_itr) && (zero_or_more != (*p_itr))) { if ((!Compare::cmp((*p_itr),(*d_itr))) && (zero_or_one != (*p_itr))) { return false; } ++p_itr; ++d_itr; } while (data_end != d_itr) { if (zero_or_more == (*p_itr)) { if (pattern_end == (++p_itr)) { return true; } m_itr = p_itr; c_itr = d_itr; ++c_itr; } else if ((Compare::cmp((*p_itr),(*d_itr))) || (zero_or_one == (*p_itr))) { ++p_itr; ++d_itr; } else { p_itr = m_itr; d_itr = c_itr++; } } while ((p_itr != pattern_end) && (zero_or_more == (*p_itr))) { ++p_itr; } return (p_itr == pattern_end); } 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& diff_value) { if (str.empty() || pattern.empty()) return false; 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(); itr_t p_end = pattern.end(); itr_t s_end = str .end(); while ((s_end != s_itr) && (p_end != p_itr)) { if ('*' == (*p_itr)) { const char target = std::toupper(*(p_itr - 1)); if ('*' == target) { diff_index = std::distance(str.begin(),s_itr); diff_value = 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 = std::distance(str.begin(),s_itr); diff_value = 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.718281828459045235360; static const double pi = 3.141592653589793238462; static const double pi_2 = 1.570796326794896619231; static const double pi_4 = 0.785398163397448309616; static const double pi_180 = 0.017453292519943295769; static const double _1_pi = 0.318309886183790671538; static const double _2_pi = 0.636619772367581343076; static const double _180_pi = 57.295779513082320876798; static const double log2 = 0.693147180559945309417; static const double sqrt2 = 1.414213562373095048801; } namespace details { struct unknown_type_tag {}; struct real_type_tag {}; struct int_type_tag {}; template struct number_type { typedef unknown_type_tag type; }; #define exprtk_register_real_type_tag(T) \ template<> struct number_type { typedef real_type_tag type; }; \ #define exprtk_register_int_type_tag(T) \ template<> struct number_type { typedef int_type_tag type; }; \ exprtk_register_real_type_tag(double ) exprtk_register_real_type_tag(long double) exprtk_register_real_type_tag(float ) exprtk_register_int_type_tag(short ) exprtk_register_int_type_tag(int ) exprtk_register_int_type_tag(long long int ) exprtk_register_int_type_tag(unsigned short ) exprtk_register_int_type_tag(unsigned int ) exprtk_register_int_type_tag(unsigned long long int) #undef exprtk_register_real_type_tag #undef exprtk_register_int_type_tag template struct epsilon_type { static inline T value() { const T epsilon = T(0.0000000001); return epsilon; } }; template <> struct epsilon_type { static inline float value() { const float epsilon = float(0.000001f); return epsilon; } }; template <> struct epsilon_type { static inline long double value() { const long double epsilon = (long double)(0.000000000001); return epsilon; } }; 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 long long int to_int64_impl(const T v, real_type_tag) { return static_cast(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) { 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 nequal_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 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) { return std::pow(v0,T(1) / v1); } 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, (int)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); } template inline T erf_impl(T v, real_type_tag) { #if defined(_WIN32) || defined(__WIN32__) || defined(WIN32) // Credits: Abramowitz & Stegun Equations 7.1.25-28 const T t = T(1) / (T(1) + T(0.5) * abs_impl(v,real_type_tag())); static const T c[] = { T( 1.26551223), T(1.00002368), T( 0.37409196), T(0.09678418), T(-0.18628806), T(0.27886807), T(-1.13520398), T(1.48851587), T(-0.82215223), T(0.17087277) }; T result = T(1) - t * std::exp((-v * v) - c[0] + t * (c[1] + t * (c[2] + t * (c[3] + t * (c[4] + t * (c[5] + t * (c[6] + t * (c[7] + t * (c[8] + t * (c[9])))))))))); return (v >= T(0)) ? result : -result; #else return ::erf(v); #endif } template inline T erf_impl(T v, int_type_tag) { return erf_impl(static_cast(v),real_type_tag()); } template inline T erfc_impl(T v, real_type_tag) { #if defined(_WIN32) || defined(__WIN32__) || defined(WIN32) return T(1) - erf_impl(v,real_type_tag()); #else return ::erfc(v); #endif } template inline T erfc_impl(T v, int_type_tag) { return erfc_impl(static_cast(v),real_type_tag()); } template inline T ncdf_impl(T v, real_type_tag) { 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(T v, int_type_tag) { return ncdf_impl(static_cast(v),real_type_tag()); } template inline T sinc_impl(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(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) - 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(20.0/9.0)); } template inline T g2d_impl(const T v, real_type_tag) { return (v * T(9.0/20.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 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) { typename details::number_type::type num_type; return to_int32_impl(v,num_type); } template inline long long int to_int64(const T v) { typename details::number_type::type num_type; return to_int64_impl(v,num_type); } template inline bool is_nan(const T v) { typename details::number_type::type num_type; return is_nan_impl(v,num_type); } template inline T min(const T v0, const T v1) { typename details::number_type::type num_type; return min_impl(v0,v1,num_type); } template inline T max(const T v0, const T v1) { typename details::number_type::type num_type; return max_impl(v0,v1,num_type); } template inline T equal(const T v0, const T v1) { typename details::number_type::type num_type; return equal_impl(v0,v1,num_type); } template inline T nequal(const T v0, const T v1) { typename details::number_type::type num_type; return nequal_impl(v0,v1,num_type); } template inline T modulus(const T v0, const T v1) { typename details::number_type::type num_type; return modulus_impl(v0,v1,num_type); } template inline T pow(const T v0, const T v1) { typename details::number_type::type num_type; return pow_impl(v0,v1,num_type); } template inline T logn(const T v0, const T v1) { typename details::number_type::type num_type; return logn_impl(v0,v1,num_type); } template inline T root(const T v0, const T v1) { typename details::number_type::type num_type; return root_impl(v0,v1,num_type); } template inline T roundn(const T v0, const T v1) { typename details::number_type::type num_type; return roundn_impl(v0,v1,num_type); } template inline T hypot(const T v0, const T v1) { typename details::number_type::type num_type; return hypot_impl(v0,v1,num_type); } template inline T atan2(const T v0, const T v1) { typename details::number_type::type num_type; return atan2_impl(v0,v1,num_type); } template inline T shr(const T v0, const T v1) { typename details::number_type::type num_type; return shr_impl(v0,v1,num_type); } template inline T shl(const T v0, const T v1) { typename details::number_type::type num_type; return shl_impl(v0,v1,num_type); } template inline T and_opr(const T v0, const T v1) { typename details::number_type::type num_type; return and_impl(v0,v1,num_type); } template inline T nand_opr(const T v0, const T v1) { typename details::number_type::type num_type; return nand_impl(v0,v1,num_type); } template inline T or_opr(const T v0, const T v1) { typename details::number_type::type num_type; return or_impl(v0,v1,num_type); } template inline T nor_opr(const T v0, const T v1) { typename details::number_type::type num_type; return nor_impl(v0,v1,num_type); } template inline T xor_opr(const T v0, const T v1) { typename details::number_type::type num_type; return xor_impl(v0,v1,num_type); } template inline T xnor_opr(const T v0, const T v1) { typename details::number_type::type num_type; return xnor_impl(v0,v1,num_type); } template inline bool is_integer(const T v) { 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 (k & 1) { l *= v; --k; } v *= v; k >>= 1; } return l; } }; template struct fast_exp { static inline T result(T v) { T v_5 = fast_exp::result(v); return v_5 * v_5; } }; template struct fast_exp { static inline T result(T v) { return fast_exp::result(v) * v; } }; template struct fast_exp { static inline T result(T v) { T v_4 = fast_exp::result(v); return v_4 * v_4; } }; template struct fast_exp { static inline T result(T v) { return fast_exp::result(v) * v; } }; template struct fast_exp { static inline T result(T v) { T v_3 = fast_exp::result(v); return v_3 * v_3; } }; template struct fast_exp { static inline T result(T v) { return fast_exp::result(v) * v; } }; template struct fast_exp { static inline T result(T v) { T v_2 = v * v; return v_2 * v_2; } }; template struct fast_exp { static inline T result(T v) { return v * v * v; } }; template struct fast_exp { static inline T result(T v) { return v * v; } }; template struct fast_exp { static inline T result(T v) { return v; } }; template struct fast_exp { static inline T result(T ) { return T(1); } }; #define exprtk_define_unary_function(FunctionName) \ template \ inline T FunctionName (const T v) \ { \ typename details::number_type::type num_type; \ return FunctionName##_impl(v,num_type); \ } \ 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; bool negative = ('-' == (*itr)); if (negative || ('+' == (*itr))) { if (end == ++itr) return false; } while ((end != itr) && ('0' == (*itr))) ++itr; bool return_result = true; unsigned int digit = 0; const std::size_t length = std::distance(itr,end); if (length <= 4) { 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++ - '0')) < 10) result = result * 10 + (digit); else { return_result = false; break; } #endif case 4 : exprtk_process_digit case 3 : exprtk_process_digit case 2 : exprtk_process_digit case 1 : if ((digit = (*itr - '0'))>= 10) { digit = 0; return_result = false; } #undef exprtk_process_digit } } 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, bool negative) { static const char inf_uc[] = "INFINITY"; static const char inf_lc[] = "infinity"; static const std::size_t inf_length = 8; const std::size_t length = std::distance(itr,end); if ((3 != length) && (inf_length != length)) return false; const char* 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 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); bool negative = ('-' == (*itr)); if (negative || '+' == (*itr)) { if (end == ++itr) return false; } bool instate = false; #define parse_digit_1(d) \ if ((digit = (*itr - '0')) < 10) { d = d * T(10) + digit; } else break; if (end == ++itr) break; \ #define parse_digit_2(d) \ if ((digit = (*itr - '0')) < 10) { d = d * T(10) + digit; } else break; ++itr; \ if ('.' != (*itr)) { const Iterator curr = itr; while ((end != itr) && ('0' == (*itr))) ++itr; unsigned int digit; while (end != itr) { // Note: For 'physical' superscalar architectures it // is advised that the following loop be: 4xPD1 and 1xPD2 #ifdef exprtk_enable_superscalar parse_digit_1(d) parse_digit_1(d) #endif 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; unsigned int digit; T tmp_d = T(0); while (end != itr) { #ifdef exprtk_enable_superscalar parse_digit_1(tmp_d) parse_digit_1(tmp_d) parse_digit_1(tmp_d) #endif parse_digit_1(tmp_d) parse_digit_1(tmp_d) parse_digit_2(tmp_d) } if (curr != itr) { instate = true; d += compute_pow10(tmp_d,-std::distance(curr,itr)); } #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 (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 char* begin = s.data(); const char* end = s.data() + s.size(); typename numeric::details::number_type::type num_type; return string_to_real(begin,end,t,num_type); } 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 (*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 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 = 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 = 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 = 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 = 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 = 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 std::vector::iterator token_list_itr_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()) return true; else if (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); } } private: inline bool is_end(const char* itr) { return (s_end_ == itr); } 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 c0, const char 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 c0, const char c1, const int mode) { return ( ((1 == mode) && ('\n' == c0)) || ((2 == mode) && ( '*' == c0) && ('/' == c1)) ); } }; int mode = 0; int increment = 0; if (is_end(s_itr_) || is_end((s_itr_ + 1))) return; else if (!test::comment_start(*s_itr_,*(s_itr_ + 1),mode,increment)) return; s_itr_ += increment; while (!is_end(s_itr_) && !test::comment_end(*s_itr_,*(s_itr_ + 1),mode)) { ++s_itr_; } if (!is_end(s_itr_)) { s_itr_ += mode; skip_whitespace(); skip_comments(); } #endif } inline void scan_token() { skip_whitespace(); skip_comments(); if (is_end(s_itr_)) { 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 c0 = s_itr_[0]; if (!is_end(s_itr_ + 1)) { const char c1 = s_itr_[1]; if (!is_end(s_itr_ + 2)) { const char 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() { const char* initial_itr = s_itr_; while ( (!is_end(s_itr_)) && (details::is_letter_or_digit(*s_itr_) || ((*s_itr_) == '_')) ) { ++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: 1. 123456 2. 123.456 3. 123.456e3 4. 123.456E3 5. 123.456e+3 6. 123.456E+3 7. 123.456e-3 8. 123.456E-3 */ const char* initial_itr = s_itr_; bool dot_found = false; bool e_found = false; bool post_e_sign_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 (details::imatch('e',(*s_itr_))) { const char& 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_)) { 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 (('.' != (*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() { const char* initial_itr = s_itr_; token_t t; // $fdd(x,x,x) = at least 11 chars if (std::distance(s_itr_,s_end_) < 11) { t.set_error(token::e_err_sfunc,initial_itr,s_itr_,base_itr_); 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,s_itr_,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() { const char* 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 ('\\' == *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_))) { if ( is_end(s_itr_ + 1) || is_end(s_itr_ + 2) || is_end(s_itr_ + 3) || ( ('x' != *(s_itr_ + 1)) && ('X' != *(s_itr_ + 1)) ) || (!details::is_hex_digit(*(s_itr_ + 2))) || (!details::is_hex_digit(*(s_itr_ + 3))) ) { 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_); details::cleanup_escapes(parsed_string); t.set_string(parsed_string, 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_; const char* base_itr_; const char* s_itr_; const char* s_end_; friend class token_scanner; friend class token_modifier; friend class token_inserter; friend class token_joiner; }; 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) { 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: std::size_t stride_; }; class token_modifier : public helper_interface { public: inline std::size_t process(generator& g) { 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) { if (g.token_list_.empty()) return 0; else if (g.token_list_.size() < stride_) return 0; std::size_t changes = 0; 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))) { g.token_list_.insert(g.token_list_.begin() + (i + insert_index),t); changes++; } } return changes; } inline virtual int insert(const token&, token& ) { return -1; } inline virtual int insert(const token&, const token&, token&) { return -1; } inline virtual int insert(const token&, const token&, const token&, token&) { return -1; } inline virtual int insert(const token&, const token&, const token&, const token&, token&) { return -1; } inline virtual int insert(const token&, const token&, const token&, const token&, const token&, token&) { return -1; } private: std::size_t stride_; }; class token_joiner : public helper_interface { public: token_joiner(const std::size_t& stride) : stride_(stride) {} inline std::size_t process(generator& g) { 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; for (std::size_t i = 0; i < g.token_list_.size() - 1; ++i) { token t; while (join(g.token_list_[i],g.token_list_[i + 1],t)) { g.token_list_[i] = t; g.token_list_.erase(g.token_list_.begin() + (i + 1)); ++changes; } } return changes; } inline std::size_t process_stride_3(generator& g) { if (g.token_list_.size() < 3) return 0; std::size_t changes = 0; for (std::size_t i = 0; i < g.token_list_.size() - 2; ++i) { token t; while (join(g.token_list_[i],g.token_list_[i + 1],g.token_list_[i + 2],t)) { g.token_list_[i] = t; g.token_list_.erase(g.token_list_.begin() + (i + 1), g.token_list_.begin() + (i + 3)); ++changes; } } return changes; } std::size_t stride_; }; namespace helper { inline void dump(lexer::generator& generator) { for (std::size_t i = 0; i < generator.size(); ++i) { 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: 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; return (match) ? 1 : -1; } private: std::set ignore_set_; }; class operator_joiner : public token_joiner { public: 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 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: 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]) ) { char 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: 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) { 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) { 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; 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: sequence_validator() : lexer::token_scanner(2) { add_invalid(lexer::token::e_number ,lexer::token::e_number ); add_invalid(lexer::token::e_string ,lexer::token::e_string ); add_invalid(lexer::token::e_number ,lexer::token::e_string ); add_invalid(lexer::token::e_string ,lexer::token::e_number ); add_invalid(lexer::token::e_string ,lexer::token::e_colon ); add_invalid(lexer::token::e_string ,lexer::token::e_ternary); add_invalid(lexer::token::e_colon ,lexer::token::e_string ); add_invalid(lexer::token::e_ternary,lexer::token::e_string ); add_invalid_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) { 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() { 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(lexer::token::token_type base, lexer::token::token_type t) { invalid_comb_.insert(std::make_pair(base,t)); } void add_invalid_set1(lexer::token::token_type t) { add_invalid(t,lexer::token::e_assign); add_invalid(t,lexer::token::e_shr ); add_invalid(t,lexer::token::e_shl ); add_invalid(t,lexer::token::e_lte ); add_invalid(t,lexer::token::e_ne ); add_invalid(t,lexer::token::e_gte ); add_invalid(t,lexer::token::e_lt ); add_invalid(t,lexer::token::e_gt ); add_invalid(t,lexer::token::e_eq ); add_invalid(t,lexer::token::e_comma ); add_invalid(t,lexer::token::e_div ); add_invalid(t,lexer::token::e_mul ); add_invalid(t,lexer::token::e_mod ); add_invalid(t,lexer::token::e_pow ); add_invalid(t,lexer::token::e_colon ); } bool invalid_bracket_check(lexer::token::token_type base, 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 true; 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_; }; 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); bool result = true; 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 result; } inline bool run_joiners(lexer::generator& g) { error_token_joiner = reinterpret_cast(0); bool result = true; for (std::size_t i = 0; i < token_joiner_list.size(); ++i) { 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 result; } inline bool run_inserters(lexer::generator& g) { error_token_inserter = reinterpret_cast(0); bool result = true; for (std::size_t i = 0; i < token_inserter_list.size(); ++i) { 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 result; } inline bool run_scanners(lexer::generator& g) { error_token_scanner = reinterpret_cast(0); bool result = true; for (std::size_t i = 0; i < token_scanner_list.size(); ++i) { 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 result; } 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; }; } } template struct type_store { enum store_type { e_unknown, e_scalar, e_vector, e_string }; type_store() : size(0), data(0), type(e_unknown) {} std::size_t size; void* data; store_type type; class parameter_list { public: 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_[size() - 1]; } inline const type_store& back() const { return parameter_list_[size() - 1]; } private: std::vector& parameter_list_; }; template struct type_view { typedef type_store type_store_t; typedef ViewType value_t; type_view(type_store_t& ts) : ts_(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 data_ + ts_.size; } inline value_t* end() { return 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; scalar_view(type_store_t& ts) : v_(*reinterpret_cast(ts.data)) {} value_t& operator()() { return v_; } const value_t& operator()() const { return v_; } T& v_; }; }; template inline std::string to_str(const StringView& view) { return std::string(view.begin(),view.size()); } 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_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 }; 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 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 : 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 : 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 : 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 class expression_node { public: enum node_type { e_none , e_null , e_constant , e_unary , e_binary , e_binary_ext , e_trinary , e_quaternary , e_quinary , e_senary , e_vararg , e_conditional , e_while , e_repeat , e_for , e_switch , e_mswitch , e_variable , e_stringvar , e_stringconst , e_stringvarrng , e_cstringvarrng, e_strgenrange , e_strconcat , e_stringvarsize, e_strswap , e_stringsize , e_function , e_vafunction , e_genfunction , e_strfunction , e_add , e_sub , e_mul , e_div , e_mod , e_pow , e_lt , e_lte , e_gt , e_gte , e_eq , e_ne , e_and , e_nand , e_or , e_nor , e_xor , e_xnor , e_in , e_like , e_ilike , e_inranges , e_ipow , e_ipowinv , e_abs , e_acos , e_acosh , e_asin , e_asinh , e_atan , e_atanh , e_ceil , e_cos , e_cosh , e_exp , e_expm1 , e_floor , e_log , e_log10 , e_log2 , e_log1p , e_neg , e_pos , e_round , e_sin , e_sinc , e_sinh , e_sqrt , e_tan , e_tanh , e_cot , e_sec , e_csc , e_r2d , e_d2r , e_d2g , e_g2d , e_notl , e_sgn , e_erf , e_erfc , e_ncdf , e_frac , e_trunc , e_uvouv , e_vov , e_cov , e_voc , e_vob , e_bov , e_cob , e_boc , e_vovov , e_vovoc , e_vocov , e_covov , e_covoc , e_vovovov , e_vovovoc , e_vovocov , e_vocovov , e_covovov , e_covocov , e_vocovoc , e_covovoc , e_vococov , e_sf3ext , e_sf4ext , e_nulleq , e_strass , e_vector , e_vecelem , e_vecdefass , e_vecvalass , e_vecvecass , e_vecopvalass , e_vecopvecass , e_vecfunc , e_vecvecswap , e_vecvecineq , e_vecvalineq , e_valvecineq , e_vecvecarith , e_vecvalarith , e_valvecarith , e_vecunaryop , e_break , e_continue , e_swap }; typedef T value_type; typedef expression_node* expression_ptr; 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; } }; 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 expression_node* node) { return std::not_equal_to()(T(0),node->value()); } template inline bool is_false(const expression_node* node) { return std::equal_to()(T(0),node->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() ); } template inline bool is_vector_elem_node(const expression_node* node) { return node && (details::expression_node::e_vecelem == 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 : 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 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 !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 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& node_allocator, expression_node*& node, const bool force_delete = false) { if (0 != node) { if ( (is_variable_node(node) || is_string_node(node)) || force_delete ) return; node_allocator.free(node); node = 0; } } 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(); } 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 operator=(const array_vector_impl&); 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 operator=(const sequence_vector_impl&); sequence_t& sequence_; }; public: vector_holder(Type* vec, const std::size_t& vec_size) : vector_holder_base_(new(buffer)array_vector_impl(vec,vec_size)) {} template vector_holder(std::vector& vec) : vector_holder_base_(new(buffer)sequence_vector_impl(vec)) {} template vector_holder(std::deque& deq) : vector_holder_base_(new(buffer)sequence_vector_impl(deq)) {} 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(); } private: mutable vector_holder_base* vector_holder_base_; unsigned char buffer[64]; }; template class null_node : public expression_node { public: inline T value() const { return std::numeric_limits::quiet_NaN(); } inline typename expression_node::node_type type() const { return expression_node::e_null; } }; template class null_eq_node : public expression_node { public: typedef expression_node* expression_ptr; null_eq_node(expression_ptr brnch, const bool equality = true) : branch_(brnch), branch_deletable_(branch_deletable(branch_)), equality_(equality) {} ~null_eq_node() { if (branch_ && branch_deletable_) { delete branch_; branch_ = 0; } } inline T value() const { const T v = branch_->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 { return expression_node::e_nulleq; } inline operator_type operation() const { return details::e_eq; } inline expression_node* branch(const std::size_t&) const { return branch_; } private: expression_ptr branch_; bool branch_deletable_; bool equality_; }; template class literal_node : public expression_node { public: explicit literal_node(const T& v) : value_(v) {} inline T value() const { return value_; } inline typename expression_node::node_type type() const { return expression_node::e_constant; } inline expression_node* branch(const std::size_t&) const { return reinterpret_cast*>(0); } private: literal_node(literal_node&) {} literal_node& operator=(literal_node&) { return *this; } const T value_; }; template struct range_pack; template struct range_data_type; template class range_interface { public: typedef range_pack range_t; virtual range_t& range_ref() = 0; virtual const range_t& range_ref() const = 0; }; template class string_base_node { public: typedef range_data_type range_data_type_t; virtual std::string str () const = 0; virtual const char* base() const = 0; virtual std::size_t size() const = 0; }; template class string_literal_node : 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 { return std::numeric_limits::quiet_NaN(); } inline typename expression_node::node_type type() const { return expression_node::e_stringconst; } inline expression_node* branch(const std::size_t&) const { return reinterpret_cast*>(0); } std::string str() const { return value_; } const char* base() const { return value_.data(); } std::size_t size() const { return value_.size(); } range_t& range_ref() { return rp_; } const range_t& range_ref() const { return rp_; } private: string_literal_node(const string_literal_node&); string_literal_node& operator=(const string_literal_node&); const std::string value_; range_t rp_; }; template class unary_node : public expression_node { public: typedef expression_node* expression_ptr; unary_node(const operator_type& opr, expression_ptr brnch) : operation_(opr), branch_(brnch), branch_deletable_(branch_deletable(branch_)) {} ~unary_node() { if (branch_ && branch_deletable_) { delete branch_; branch_ = 0; } } inline T value() const { const T arg = branch_->value(); return numeric::process(operation_,arg); } inline typename expression_node::node_type type() const { return expression_node::e_unary; } inline operator_type operation() const { return operation_; } inline expression_node* branch(const std::size_t&) const { return branch_; } inline void release() { branch_deletable_ = false; } protected: operator_type operation_; expression_ptr branch_; bool branch_deletable_; }; template struct construct_branch_pair { template static inline void process(std::pair*,bool> (&)[N], expression_node*) {} }; template struct construct_branch_pair { template static inline void process(std::pair*,bool> (&branch)[N], expression_node* b) { if (b) { branch[D] = std::make_pair(b,branch_deletable(b)); } } }; template inline void init_branches(std::pair*,bool> (&branch)[N], expression_node* b0, expression_node* b1 = reinterpret_cast*>(0), expression_node* b2 = reinterpret_cast*>(0), expression_node* b3 = reinterpret_cast*>(0), expression_node* b4 = reinterpret_cast*>(0), expression_node* b5 = reinterpret_cast*>(0), expression_node* b6 = reinterpret_cast*>(0), expression_node* b7 = reinterpret_cast*>(0), expression_node* b8 = reinterpret_cast*>(0), expression_node* b9 = reinterpret_cast*>(0)) { construct_branch_pair 0)>::process(branch,b0); construct_branch_pair 1)>::process(branch,b1); construct_branch_pair 2)>::process(branch,b2); construct_branch_pair 3)>::process(branch,b3); construct_branch_pair 4)>::process(branch,b4); construct_branch_pair 5)>::process(branch,b5); construct_branch_pair 6)>::process(branch,b6); construct_branch_pair 7)>::process(branch,b7); construct_branch_pair 8)>::process(branch,b8); construct_branch_pair 9)>::process(branch,b9); } struct cleanup_branches { template static inline void execute(std::pair*,bool> (&branch)[N]) { for (std::size_t i = 0; i < N; ++i) { if (branch[i].first && branch[i].second) { delete branch[i].first; branch[i].first = 0; } } } template class Sequence> static inline void execute(Sequence*,bool>,Allocator>& branch) { for (std::size_t i = 0; i < branch.size(); ++i) { if (branch[i].first && branch[i].second) { delete branch[i].first; branch[i].first = 0; } } } }; template class binary_node : public expression_node { public: typedef expression_node* expression_ptr; typedef std::pair branch_t; binary_node(const operator_type& opr, expression_ptr branch0, expression_ptr branch1) : operation_(opr) { init_branches<2>(branch_,branch0,branch1); } ~binary_node() { cleanup_branches::execute(branch_); } inline T value() const { 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 { return expression_node::e_binary; } inline operator_type operation() { return operation_; } inline expression_node* branch(const std::size_t& index = 0) const { if (0 == index) return branch_[0].first; else if (1 == index) return branch_[1].first; else return reinterpret_cast(0); } protected: operator_type operation_; branch_t branch_[2]; }; template class binary_ext_node : 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); } ~binary_ext_node() { cleanup_branches::execute(branch_); } inline T value() const { 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 { return expression_node::e_binary_ext; } inline operator_type operation() { return Operation::operation(); } inline expression_node* branch(const std::size_t& index = 0) const { if (0 == index) return branch_[0].first; else if (1 == index) return branch_[1].first; else return reinterpret_cast(0); } 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); } ~trinary_node() { cleanup_branches::execute(branch_); } inline T value() const { const T arg0 = branch_[0].first->value(); const T arg1 = branch_[1].first->value(); const T arg2 = branch_[2].first->value(); switch (operation_) { case e_inrange : return (arg1 < arg0) ? T(0) : ((arg1 > arg2) ? T(0) : T(1)); case e_min : return std::min(std::min(arg0,arg1),arg2); case e_max : return std::max(std::max(arg0,arg1),arg2); case e_clamp : return (arg1 < arg0) ? arg0 : (arg1 > arg2 ? arg2 : arg1); case e_iclamp : if ((arg1 <= arg0) || (arg1 >= arg2)) return arg1; else return ((T(2) * arg1 <= (arg2 + arg0)) ? arg0 : arg2); default : return std::numeric_limits::quiet_NaN(); } } inline typename expression_node::node_type type() const { return expression_node::e_trinary; } 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); } ~quaternary_node() { cleanup_branches::execute(branch_); } inline T value() const { const T arg0 = branch_[0].first->value(); const T arg1 = branch_[1].first->value(); const T arg2 = branch_[2].first->value(); const T arg3 = branch_[3].first->value(); switch (operation_) { case e_min : return std::min(std::min(arg0,arg1),std::min(arg2,arg3)); case e_max : return std::max(std::max(arg0,arg1),std::max(arg2,arg3)); default : return std::numeric_limits::quiet_NaN(); } } inline typename expression_node::node_type type() const { return expression_node::e_quaternary; } protected: operator_type operation_; branch_t branch_[4]; }; template class quinary_node : public expression_node { public: typedef expression_node* expression_ptr; typedef std::pair branch_t; quinary_node(const operator_type& opr, expression_ptr branch0, expression_ptr branch1, expression_ptr branch2, expression_ptr branch3, expression_ptr branch4) : operation_(opr) { init_branches<5>(branch_,branch0,branch1,branch2,branch3,branch4); } ~quinary_node() { cleanup_branches::execute(branch_); } inline T value() const { const T arg0 = branch_[0].first->value(); const T arg1 = branch_[1].first->value(); const T arg2 = branch_[2].first->value(); const T arg3 = branch_[3].first->value(); const T arg4 = branch_[4].first->value(); switch (operation_) { case e_min : return std::min(std::min(std::min(arg0,arg1),std::min(arg2,arg3)),arg4); case e_max : return std::max(std::max(std::max(arg0,arg1),std::max(arg2,arg3)),arg4); default : return std::numeric_limits::quiet_NaN(); } } inline typename expression_node::node_type type() const { return expression_node::e_quinary; } private: operator_type operation_; branch_t branch_[5]; }; template class senary_node : public expression_node { public: typedef expression_node* expression_ptr; typedef std::pair branch_t; senary_node(const operator_type& opr, expression_ptr branch0, expression_ptr branch1, expression_ptr branch2, expression_ptr branch3, expression_ptr branch4, expression_ptr branch5) : operation_(opr) { init_branches<6>(branch_,branch0,branch1,branch2,branch3,branch4,branch5); } ~senary_node() { cleanup_branches::execute(branch_); } inline T value() const { const T arg0 = branch_[0].first->value(); const T arg1 = branch_[1].first->value(); const T arg2 = branch_[2].first->value(); const T arg3 = branch_[3].first->value(); const T arg4 = branch_[4].first->value(); const T arg5 = branch_[5].first->value(); switch (operation_) { case e_min : return std::min(std::min(std::min(arg0,arg1),std::min(arg2,arg3)),std::min(arg4,arg5)); case e_max : return std::max(std::max(std::max(arg0,arg1),std::max(arg2,arg3)),std::max(arg4,arg5)); case e_default : default : return std::numeric_limits::quiet_NaN(); } } inline typename expression_node::node_type type() const { return expression_node::e_senary; } private: operator_type operation_; branch_t branch_[6]; }; template class conditional_node : public expression_node { public: typedef expression_node* expression_ptr; conditional_node(expression_ptr test, expression_ptr consequent, expression_ptr alternative) : test_(test), consequent_(consequent), alternative_(alternative), test_deletable_(branch_deletable(test_)), consequent_deletable_(branch_deletable(consequent_)), alternative_deletable_(branch_deletable(alternative_)) {} ~conditional_node() { if (test_ && test_deletable_ ) delete test_; if (consequent_ && consequent_deletable_ ) delete consequent_; if (alternative_ && alternative_deletable_) delete alternative_; } inline T value() const { if (is_true(test_)) return consequent_->value(); else return alternative_->value(); } inline typename expression_node::node_type type() const { return expression_node::e_conditional; } private: expression_ptr test_; expression_ptr consequent_; expression_ptr alternative_; bool test_deletable_; bool consequent_deletable_; bool alternative_deletable_; }; template class cons_conditional_node : public expression_node { public: // Consequent only conditional statement node typedef expression_node* expression_ptr; cons_conditional_node(expression_ptr test, expression_ptr consequent) : test_(test), consequent_(consequent), test_deletable_(branch_deletable(test_)), consequent_deletable_(branch_deletable(consequent_)) {} ~cons_conditional_node() { if (test_ && test_deletable_ ) delete test_; if (consequent_ && consequent_deletable_) delete consequent_; } inline T value() const { if (is_true(test_)) return consequent_->value(); else return std::numeric_limits::quiet_NaN(); } inline typename expression_node::node_type type() const { return expression_node::e_conditional; } private: expression_ptr test_; expression_ptr consequent_; bool test_deletable_; bool consequent_deletable_; }; #ifndef exprtk_disable_break_continue template class break_exception : public std::exception { public: break_exception(const T& v) : value(v) {} T value; }; class continue_exception : public std::exception {}; template class break_node : public expression_node { public: typedef expression_node* expression_ptr; break_node(expression_ptr ret = expression_ptr(0)) : return_(ret), return_deletable_(branch_deletable(return_)) {} ~break_node() { if (return_deletable_) { delete return_; } } inline T value() const { throw break_exception(return_ ? return_->value() : std::numeric_limits::quiet_NaN()); #ifndef _MSC_VER return std::numeric_limits::quiet_NaN(); #endif } inline typename expression_node::node_type type() const { return expression_node::e_break; } private: expression_ptr return_; bool return_deletable_; }; template class continue_node : public expression_node { public: inline T value() const { throw continue_exception(); #ifndef _MSC_VER return std::numeric_limits::quiet_NaN(); #endif } inline typename expression_node::node_type type() const { return expression_node::e_break; } }; #endif template class while_loop_node : public expression_node { public: typedef expression_node* expression_ptr; while_loop_node(expression_ptr condition, expression_ptr loop_body) : condition_(condition), loop_body_(loop_body), condition_deletable_(branch_deletable(condition_)), loop_body_deletable_(branch_deletable(loop_body_)) {} ~while_loop_node() { if (condition_ && condition_deletable_) { delete condition_; } if (loop_body_ && loop_body_deletable_) { delete loop_body_; } } inline T value() const { T result = T(0); while (is_true(condition_)) { result = loop_body_->value(); } return result; } inline typename expression_node::node_type type() const { return expression_node::e_while; } private: expression_ptr condition_; expression_ptr loop_body_; bool condition_deletable_; bool loop_body_deletable_; }; template class repeat_until_loop_node : public expression_node { public: typedef expression_node* expression_ptr; repeat_until_loop_node(expression_ptr condition, expression_ptr loop_body) : condition_(condition), loop_body_(loop_body), condition_deletable_(branch_deletable(condition_)), loop_body_deletable_(branch_deletable(loop_body_)) {} ~repeat_until_loop_node() { if (condition_ && condition_deletable_) { delete condition_; } if (loop_body_ && loop_body_deletable_) { delete loop_body_; } } inline T value() const { T result = T(0); do { result = loop_body_->value(); } while (is_false(condition_)); return result; } inline typename expression_node::node_type type() const { return expression_node::e_repeat; } private: expression_ptr condition_; expression_ptr loop_body_; bool condition_deletable_; bool loop_body_deletable_; }; template class for_loop_node : public expression_node { public: typedef expression_node* expression_ptr; for_loop_node(expression_ptr initialiser, expression_ptr condition, expression_ptr incrementor, expression_ptr loop_body) : initialiser_(initialiser), condition_ (condition), incrementor_(incrementor), loop_body_ (loop_body), initialiser_deletable_(branch_deletable(initialiser_)), condition_deletable_ (branch_deletable(condition_ )), incrementor_deletable_(branch_deletable(incrementor_)), loop_body_deletable_ (branch_deletable(loop_body_ )) {} ~for_loop_node() { if (initialiser_ && initialiser_deletable_) { delete initialiser_; } if (condition_ && condition_deletable_) { delete condition_; } if (incrementor_ && incrementor_deletable_) { delete incrementor_; } if (loop_body_ && loop_body_deletable_) { delete loop_body_; } } inline T value() const { T result = T(0); if (initialiser_) initialiser_->value(); if (incrementor_) { while (is_true(condition_)) { result = loop_body_->value(); incrementor_->value(); } } else { while (is_true(condition_)) { result = loop_body_->value(); } } return result; } inline typename expression_node::node_type type() const { return expression_node::e_for; } private: expression_ptr initialiser_; expression_ptr condition_ ; expression_ptr incrementor_; expression_ptr loop_body_ ; bool initialiser_deletable_; bool condition_deletable_ ; bool incrementor_deletable_; bool loop_body_deletable_ ; }; #ifndef exprtk_disable_break_continue template class while_loop_bc_node : public expression_node { public: typedef expression_node* expression_ptr; while_loop_bc_node(expression_ptr condition, expression_ptr loop_body) : condition_(condition), loop_body_(loop_body), condition_deletable_(branch_deletable(condition_)), loop_body_deletable_(branch_deletable(loop_body_)) {} ~while_loop_bc_node() { if (condition_ && condition_deletable_) { delete condition_; } if (loop_body_ && loop_body_deletable_) { delete loop_body_; } } inline T value() const { T result = T(0); while (is_true(condition_)) { try { result = loop_body_->value(); } catch(const break_exception& e) { return e.value; } catch(const continue_exception&) {} } return result; } inline typename expression_node::node_type type() const { return expression_node::e_while; } private: expression_ptr condition_; expression_ptr loop_body_; bool condition_deletable_; bool loop_body_deletable_; }; template class repeat_until_loop_bc_node : public expression_node { public: typedef expression_node* expression_ptr; repeat_until_loop_bc_node(expression_ptr condition, expression_ptr loop_body) : condition_(condition), loop_body_(loop_body), condition_deletable_(branch_deletable(condition_)), loop_body_deletable_(branch_deletable(loop_body_)) {} ~repeat_until_loop_bc_node() { if (condition_ && condition_deletable_) { delete condition_; } if (loop_body_ && loop_body_deletable_) { delete loop_body_; } } inline T value() const { T result = T(0); do { try { result = loop_body_->value(); } catch(const break_exception& e) { return e.value; } catch(const continue_exception&) {} } while (is_false(condition_)); return result; } inline typename expression_node::node_type type() const { return expression_node::e_repeat; } private: expression_ptr condition_; expression_ptr loop_body_; bool condition_deletable_; bool loop_body_deletable_; }; template class for_loop_bc_node : public expression_node { public: typedef expression_node* expression_ptr; for_loop_bc_node(expression_ptr initialiser, expression_ptr condition, expression_ptr incrementor, expression_ptr loop_body) : initialiser_(initialiser), condition_ (condition ), incrementor_(incrementor), loop_body_ (loop_body ), initialiser_deletable_(branch_deletable(initialiser_)), condition_deletable_ (branch_deletable(condition_ )), incrementor_deletable_(branch_deletable(incrementor_)), loop_body_deletable_ (branch_deletable(loop_body_ )) {} ~for_loop_bc_node() { if (initialiser_ && initialiser_deletable_) { delete initialiser_; } if (condition_ && condition_deletable_) { delete condition_; } if (incrementor_ && incrementor_deletable_) { delete incrementor_; } if (loop_body_ && loop_body_deletable_) { delete loop_body_; } } inline T value() const { T result = T(0); if (initialiser_) initialiser_->value(); if (incrementor_) { while (is_true(condition_)) { try { result = loop_body_->value(); } catch(const break_exception& e) { return e.value; } catch(const continue_exception&) {} incrementor_->value(); } } else { while (is_true(condition_)) { try { result = loop_body_->value(); } catch(const break_exception& e) { return e.value; } catch(const continue_exception&) {} } } return result; } inline typename expression_node::node_type type() const { return expression_node::e_for; } private: expression_ptr initialiser_; expression_ptr condition_ ; expression_ptr incrementor_; expression_ptr loop_body_ ; bool initialiser_deletable_; bool condition_deletable_ ; bool incrementor_deletable_; bool loop_body_deletable_ ; }; #endif template class switch_node : public expression_node { public: typedef expression_node* expression_ptr; template class Sequence> switch_node(const Sequence& arg_list) { if (1 != (arg_list.size() & 1)) return; arg_list_.resize(arg_list.size()); delete_branch_.resize(arg_list.size()); for (std::size_t i = 0; i < arg_list.size(); ++i) { if (arg_list[i]) { arg_list_[i] = arg_list[i]; delete_branch_[i] = static_cast(branch_deletable(arg_list_[i]) ? 1 : 0); } else { arg_list_.clear(); delete_branch_.clear(); return; } } } ~switch_node() { for (std::size_t i = 0; i < arg_list_.size(); ++i) { if (arg_list_[i] && delete_branch_[i]) { delete arg_list_[i]; arg_list_[i] = 0; } } } inline T value() const { if (!arg_list_.empty()) { 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 ]; expression_ptr consequent = arg_list_[i + 1]; if (is_true(condition)) { return consequent->value(); } } return arg_list_[upper_bound]->value(); } else return std::numeric_limits::quiet_NaN(); } inline typename expression_node::node_type type() const { return expression_node::e_switch; } private: std::vector arg_list_; std::vector delete_branch_; }; template class multi_switch_node : public expression_node { public: typedef expression_node* expression_ptr; template class Sequence> multi_switch_node(const Sequence& arg_list) { if (0 != (arg_list.size() & 1)) return; arg_list_.resize(arg_list.size()); delete_branch_.resize(arg_list.size()); for (std::size_t i = 0; i < arg_list.size(); ++i) { if (arg_list[i]) { arg_list_[i] = arg_list[i]; delete_branch_[i] = static_cast(branch_deletable(arg_list_[i]) ? 1 : 0); } else { arg_list_.clear(); delete_branch_.clear(); return; } } } ~multi_switch_node() { for (std::size_t i = 0; i < arg_list_.size(); ++i) { if (arg_list_[i] && delete_branch_[i]) { delete arg_list_[i]; arg_list_[i] = 0; } } } inline T value() const { T result = T(0); 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 ]; expression_ptr consequent = arg_list_[i + 1]; if (is_true(condition)) { result = consequent->value(); } } return result; } inline typename expression_node::node_type type() const { return expression_node::e_mswitch; } private: std::vector arg_list_; std::vector delete_branch_; }; template class ivariable { public: virtual T& ref() = 0; virtual const T& ref() const = 0; }; template class variable_node : public expression_node, public ivariable { public: static T null_value; explicit variable_node() : value_(&null_value), delete_value_(false) {} variable_node(T& v) : value_(&v), delete_value_(false) {} ~variable_node() { if (delete_value_) { delete value_; } } inline bool operator <(const variable_node& v) const { return this < (&v); } inline T value() const { return (*value_); } inline T& ref() { return (*value_); } inline const T& ref() const { return (*value_); } inline typename expression_node::node_type type() const { return expression_node::e_variable; } inline bool& delete_value() { return delete_value_; } private: T* value_; bool delete_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) ) { delete n0_e.second; n0_e.second = expression_node_ptr(0); } } if (n1_e.first && n1_e.second) { n1_e.first = false; if ( !is_variable_node(n1_e.second) && !is_string_node (n1_e.second) ) { delete n1_e.second; n1_e.second = expression_node_ptr(0); } } } bool const_range() { return ( n0_c.first && n1_c.first) && (!n0_e.first && !n1_e.first); } bool var_range() { 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) { T r0_value = n0_e.second->value(); if (r0_value < 0) return false; else r0 = static_cast(details::numeric::to_int64(r0_value)); } else return false; if (n1_c.first) r1 = n1_c.second; else if (n1_e.first) { T r1_value = n1_e.second->value(); if (r1_value < 0) return false; else r1 = static_cast(details::numeric::to_int64(r1_value)); } else return false; if ( (std::numeric_limits::max() != size) && (std::numeric_limits::max() == r1 ) ) { r1 = size - 1; } cache.first = r0; cache.second = r1; return (r0 <= r1); } 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; }; 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; virtual ~vector_interface() {} virtual vector_node_ptr vec() const = 0; virtual vector_node_ptr vec() = 0; virtual std::size_t size() const = 0; }; template class vector_node : public expression_node, public vector_interface { public: typedef expression_node* expression_ptr; typedef vector_holder vector_holder_t; typedef vector_node* vector_node_ptr; vector_node(vector_holder_t* vh) : vector_holder_(vh) {} inline T value() const { return *(ref()[0]); } inline const vector_holder_t& ref() const { return (*vector_holder_); } inline vector_holder_t& ref() { return (*vector_holder_); } vector_node_ptr vec() const { return const_cast(this); } vector_node_ptr vec() { return this; } inline typename expression_node::node_type type() const { return expression_node::e_vector; } std::size_t size() const { return ref().size(); } private: vector_holder_t* vector_holder_; }; template class vector_elem_node : public expression_node, public ivariable { public: typedef expression_node* expression_ptr; vector_elem_node(expression_ptr index, T* vector_base) : index_(index), vector_base_(vector_base), index_deletable_(branch_deletable(index_)) {} ~vector_elem_node() { if (index_ && index_deletable_) { delete index_; } } inline T value() const { return *(vector_base_ + static_cast(details::numeric::to_int64(index_->value()))); } inline T& ref() { return *(vector_base_ + static_cast(details::numeric::to_int64(index_->value()))); } inline const T& ref() const { return *(vector_base_ + static_cast(details::numeric::to_int64(index_->value()))); } inline typename expression_node::node_type type() const { return expression_node::e_vecelem; } private: expression_ptr index_; T* vector_base_; bool index_deletable_; }; template class vector_assignment_node : public expression_node { public: typedef expression_node* expression_ptr; vector_assignment_node(T* vector_base, const std::size_t& size, const std::vector& initialiser_list, const bool single_value_initialse) : vector_base_(vector_base), initialiser_list_(initialiser_list), size_(size), single_value_initialse_(single_value_initialse) {} ~vector_assignment_node() { for (std::size_t i = 0; i < initialiser_list_.size(); ++i) { if (branch_deletable(initialiser_list_[i])) { delete initialiser_list_[i]; } } } inline T value() const { if (single_value_initialse_) { for (std::size_t i = 0; i < size_; ++i) { *(vector_base_ + i) = initialiser_list_[0]->value(); } } else { std::size_t il_size = initialiser_list_.size(); for (std::size_t i = 0; i < il_size; ++i) { *(vector_base_ + i) = initialiser_list_[i]->value(); } if (il_size < size_) { for (std::size_t i = il_size; i < size_; ++i) { *(vector_base_ + i) = T(0); } } } return *(vector_base_); } inline typename expression_node::node_type type() const { return expression_node::e_vecdefass; } private: vector_assignment_node& operator=(const vector_assignment_node&); mutable T* vector_base_; std::vector initialiser_list_; const std::size_t size_; const bool single_value_initialse_; }; template class swap_node : 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 { std::swap(var0_->ref(),var1_->ref()); return var1_->ref(); } inline typename expression_node::node_type type() const { return expression_node::e_swap; } private: variable_node_ptr var0_; variable_node_ptr var1_; }; template class swap_generic_node : 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 { std::swap(var0_->ref(),var1_->ref()); return var1_->ref(); } inline typename expression_node::node_type type() const { return expression_node::e_swap; } private: ivariable_ptr var0_; ivariable_ptr var1_; }; template class swap_vecvec_node : public binary_node, public vector_interface { public: typedef expression_node* expression_ptr; typedef vector_node* vector_node_ptr; 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) { if (is_ivector_node(binary_node::branch_[0].first)) { vector_interface* vi = reinterpret_cast*>(0); if ((vi = dynamic_cast*>(binary_node::branch_[0].first))) { vec0_node_ptr_ = vi->vec(); } } if (is_ivector_node(binary_node::branch_[1].first)) { vector_interface* vi = reinterpret_cast*>(0); if ((vi = dynamic_cast*>(binary_node::branch_[1].first))) { vec1_node_ptr_ = vi->vec(); } } if (vec0_node_ptr_ && vec1_node_ptr_) { vec_size_ = std::min(vec0_node_ptr_->ref().size(), vec1_node_ptr_->ref().size()); } } inline T value() const { if (vec0_node_ptr_ && vec1_node_ptr_) { binary_node::branch_[0].first->value(); binary_node::branch_[1].first->value(); vector_holder& vec0 = vec0_node_ptr_->ref(); vector_holder& vec1 = vec1_node_ptr_->ref(); 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 { return vec0_node_ptr_; } vector_node_ptr vec() { return vec0_node_ptr_; } inline typename expression_node::node_type type() const { return expression_node::e_vecvecswap; } std::size_t size() const { return vec_size_; } private: vector_node* vec0_node_ptr_; vector_node* vec1_node_ptr_; std::size_t vec_size_; }; #ifndef exprtk_disable_string_capabilities template class stringvar_node : public expression_node , public string_base_node, public range_interface { public: typedef range_pack 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 { rp_.n1_c.second = (*value_).size() - 1; rp_.cache.second = rp_.n1_c.second; return std::numeric_limits::quiet_NaN(); } std::string str() const { return ref(); } const char* base() const { return (*value_).data(); } std::size_t size() const { return ref().size(); } std::string& ref() { return (*value_); } const std::string& ref() const { return (*value_); } range_t& range_ref() { return rp_; } const range_t& range_ref() const { return rp_; } inline typename expression_node::node_type type() const { return expression_node::e_stringvar; } private: std::string* value_; mutable range_t rp_; }; template std::string stringvar_node::null_value = std::string(""); template class string_range_node : public expression_node , public string_base_node, public range_interface { public: typedef range_pack range_t; static std::string null_value; explicit string_range_node(std::string& v, range_t rp) : value_(&v), rp_(rp) {} ~string_range_node() { rp_.free(); } inline bool operator <(const string_range_node& v) const { return this < (&v); } inline T value() const { return std::numeric_limits::quiet_NaN(); } inline std::string str() const { return (*value_); } const char* base() const { return (*value_).data(); } std::size_t size() const { 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() { return rp_; } inline const range_t& range_ref() const { return rp_; } inline typename expression_node::node_type type() const { 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 : public expression_node , public string_base_node, public range_interface { public: typedef range_pack range_t; explicit const_string_range_node(const std::string& v, range_t rp) : value_(v), rp_(rp) {} ~const_string_range_node() { rp_.free(); } inline T value() const { return std::numeric_limits::quiet_NaN(); } std::string str() const { return value_; } const char* base() const { return value_.data(); } std::size_t size() const { return value_.size(); } range_t range() const { return rp_; } range_t& range_ref() { return rp_; } const range_t& range_ref() const { return rp_; } inline typename expression_node::node_type type() const { return expression_node::e_cstringvarrng; } private: const_string_range_node& operator=(const const_string_range_node&); const std::string value_; range_t rp_; }; template class generic_string_range_node : 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 range_pack range_t; typedef range_t* range_ptr; typedef range_interface irange_t; typedef irange_t* irange_ptr; typedef typename range_t::cached_range_t cached_range_t; generic_string_range_node(expression_ptr str_branch, range_t brange) : initialised_(false), branch_(str_branch), branch_deletable_(branch_deletable(branch_)), 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; if (is_generally_string_node(branch_)) { str_base_ptr_ = dynamic_cast(branch_); if (0 == str_base_ptr_) return; str_range_ptr_ = dynamic_cast(branch_); if (0 == str_range_ptr_) return; } initialised_ = (str_base_ptr_ && str_range_ptr_); } ~generic_string_range_node() { base_range_.free(); if (branch_ && branch_deletable_) { delete branch_; branch_ = 0; } } inline T value() const { if (initialised_) { branch_->value(); std::size_t str_r0 = 0; std::size_t str_r1 = 0; std::size_t r0 = 0; std::size_t r1 = 0; 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) ) { 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 { return value_; } const char* base() const { return value_.data(); } std::size_t size() const { return value_.size(); } range_t& range_ref() { return range_; } const range_t& range_ref() const { return range_; } inline typename expression_node::node_type type() const { return expression_node::e_strgenrange; } private: bool initialised_; expression_ptr branch_; bool branch_deletable_; str_base_ptr str_base_ptr_; irange_ptr str_range_ptr_; mutable range_t base_range_; mutable range_t range_; mutable std::string value_; }; template class string_concat_node : public binary_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 range_pack range_t; typedef range_t* range_ptr; typedef range_interface irange_t; typedef irange_t* irange_ptr; typedef typename range_t::cached_range_t cached_range_t; string_concat_node(const operator_type& opr, expression_ptr branch0, expression_ptr branch1) : binary_node(opr,branch0,branch1), 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_ ; } inline T value() const { if (initialised_) { 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; range_t& range0 = str0_range_ptr_->range_ref(); 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 { return value_; } const char* base() const { return value_.data(); } std::size_t size() const { return value_.size(); } range_t& range_ref() { return range_; } const range_t& range_ref() const { return range_; } inline typename expression_node::node_type type() const { return expression_node::e_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 : public binary_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 range_pack range_t; typedef range_t* range_ptr; typedef range_interface irange_t; typedef irange_t* irange_ptr; typedef typename range_t::cached_range_t cached_range_t; 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_); } inline T value() const { if (initialised_) { 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 { return str0_node_ptr_->str(); } const char* base() const { return str0_node_ptr_->base(); } std::size_t size() const { return str0_node_ptr_->size(); } range_t& range_ref() { return str0_node_ptr_->range_ref(); } const range_t& range_ref() const { return str0_node_ptr_->range_ref(); } inline typename expression_node::node_type type() const { return expression_node::e_strswap; } private: bool initialised_; strvar_node_ptr str0_node_ptr_; strvar_node_ptr str1_node_ptr_; }; template class stringvar_size_node : 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 { return T((*value_).size()); } inline typename expression_node::node_type type() const { return expression_node::e_stringvarsize; } private: std::string* value_; }; template std::string stringvar_size_node::null_value = std::string(""); template class string_size_node : public expression_node { public: typedef expression_node * expression_ptr; typedef string_base_node* str_base_ptr; string_size_node(expression_ptr brnch) : branch_(brnch), branch_deletable_(branch_deletable(branch_)), str_base_ptr_(0) { if (is_generally_string_node(branch_)) { str_base_ptr_ = dynamic_cast(branch_); if (0 == str_base_ptr_) return; } } ~string_size_node() { if (branch_ && branch_deletable_) { delete branch_; branch_ = 0; } } inline T value() const { T result = std::numeric_limits::quiet_NaN(); if (str_base_ptr_) { branch_->value(); result = T(str_base_ptr_->size()); } return result; } inline typename expression_node::node_type type() const { return expression_node::e_stringsize; } private: expression_ptr branch_; bool branch_deletable_; str_base_ptr str_base_ptr_; }; struct asn_assignment { static inline void execute(std::string& s, const char* data, const std::size_t size) { s.assign(data,size); } }; struct asn_addassignment { static inline void execute(std::string& s, const char* data, const std::size_t size) { s.append(data,size); } }; template class assignment_string_node : public binary_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 range_pack range_t; typedef range_t* range_ptr; typedef range_interface irange_t; typedef irange_t* irange_ptr; typedef typename range_t::cached_range_t cached_range_t; 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_ptr = dynamic_cast(binary_node::branch_[1].first); if (0 == range_ptr) return; str1_range_ptr_ = &(range_ptr->range_ref()); } initialised_ = str0_base_ptr_ && str1_base_ptr_ && str0_node_ptr_ && str1_range_ptr_ ; } inline T value() const { if (initialised_) { binary_node::branch_[1].first->value(); std::size_t r0 = 0; std::size_t r1 = 0; 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 { return str0_node_ptr_->str(); } const char* base() const { return str0_node_ptr_->base(); } std::size_t size() const { return str0_node_ptr_->size(); } range_t& range_ref() { return str0_node_ptr_->range_ref(); } const range_t& range_ref() const { return str0_node_ptr_->range_ref(); } inline typename expression_node::node_type type() const { 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 : public binary_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 range_pack range_t; typedef range_t* range_ptr; typedef range_interface irange_t; typedef irange_t* irange_ptr; typedef typename range_t::cached_range_t cached_range_t; assignment_string_range_node(const operator_type& opr, expression_ptr branch0, expression_ptr branch1) : binary_node(opr,branch0,branch1), initialised_(false), str0_base_ptr_ (0), str1_base_ptr_ (0), str0_node_ptr_ (0), str0_range_ptr_(0), str1_range_ptr_(0) { if (is_string_range_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); irange_ptr range_ptr = dynamic_cast(binary_node::branch_[0].first); if (0 == range_ptr) return; str0_range_ptr_ = &(range_ptr->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_ptr = dynamic_cast(binary_node::branch_[1].first); if (0 == range_ptr) return; str1_range_ptr_ = &(range_ptr->range_ref()); } initialised_ = str0_base_ptr_ && str1_base_ptr_ && str0_node_ptr_ && str0_range_ptr_ && str1_range_ptr_ ; } inline T value() const { if (initialised_) { 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; range_t& range0 = (*str0_range_ptr_); range_t& range1 = (*str1_range_ptr_); if ( range0(s0_r0,s0_r1,str0_base_ptr_->size()) && range1(s1_r0,s1_r1,str1_base_ptr_->size()) ) { std::size_t size = std::min((s0_r1 - s0_r0),(s1_r1 - s1_r0)) + 1; 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 { return str0_node_ptr_->str(); } const char* base() const { return str0_node_ptr_->base(); } std::size_t size() const { return str0_node_ptr_->size(); } range_t& range_ref() { return str0_node_ptr_->range_ref(); } const range_t& range_ref() const { return str0_node_ptr_->range_ref(); } inline typename expression_node::node_type type() const { 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 str0_range_ptr_; range_ptr str1_range_ptr_; }; #endif template inline T axn(T a, T x) { // a*x^n return a * exprtk::details::numeric::fast_exp::result(x); } template inline T axnb(T a, T x, T b) { // a*x^n+b return a * exprtk::details::numeric::fast_exp::result(x) + b; } template 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 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 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)") #undef define_sfop3 #undef define_sfop4 template class sf3_node : 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 { 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 : 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 { 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 : public expression_node { public: typedef expression_node* expression_ptr; sf3_var_node(const T& v0, const T& v1, const T& v2) : v0_(v0), v1_(v1), v2_(v2) {} inline T value() const { return SpecialFunction::process(v0_,v1_,v2_); } inline typename expression_node::node_type type() const { return expression_node::e_trinary; } private: sf3_var_node(sf3_var_node&); sf3_var_node& operator=(sf3_var_node&); const T& v0_; const T& v1_; const T& v2_; }; template class sf4_var_node : public expression_node { public: typedef expression_node* expression_ptr; sf4_var_node(const T& v0, const T& v1, const T& v2, const T& v3) : v0_(v0), v1_(v1), v2_(v2), v3_(v3) {} inline T value() const { return SpecialFunction::process(v0_,v1_,v2_,v3_); } inline typename expression_node::node_type type() const { return expression_node::e_trinary; } private: sf4_var_node(sf4_var_node&); sf4_var_node& operator=(sf4_var_node&); const T& v0_; const T& v1_; const T& v2_; const T& v3_; }; template class vararg_node : public expression_node { public: typedef expression_node* expression_ptr; template class Sequence> vararg_node(const Sequence& arg_list) { arg_list_.resize(arg_list.size()); delete_branch_.resize(arg_list.size()); for (std::size_t i = 0; i < arg_list.size(); ++i) { if (arg_list[i]) { arg_list_[i] = arg_list[i]; delete_branch_[i] = static_cast(branch_deletable(arg_list_[i]) ? 1 : 0); } else { arg_list_.clear(); delete_branch_.clear(); return; } } } ~vararg_node() { for (std::size_t i = 0; i < arg_list_.size(); ++i) { if (arg_list_[i] && delete_branch_[i]) { delete arg_list_[i]; arg_list_[i] = 0; } } } inline T value() const { if (!arg_list_.empty()) return VarArgFunction::process(arg_list_); else return std::numeric_limits::quiet_NaN(); } inline typename expression_node::node_type type() const { return expression_node::e_vararg; } private: std::vector arg_list_; std::vector delete_branch_; }; template class vararg_varnode : public expression_node { public: typedef expression_node* expression_ptr; template class Sequence> 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 { if (!arg_list_.empty()) return VarArgFunction::process(arg_list_); else return std::numeric_limits::quiet_NaN(); } inline typename expression_node::node_type type() const { return expression_node::e_vararg; } private: std::vector arg_list_; }; template class vectorize_node : public expression_node { public: typedef expression_node* expression_ptr; vectorize_node(const expression_ptr v) : ivec_ptr_(0), v_(v), v_deletable_(branch_deletable(v_)) { if (is_ivector_node(v)) { ivec_ptr_ = dynamic_cast*>(v); } else ivec_ptr_ = 0; } ~vectorize_node() { if (v_ && v_deletable_) { delete v_; } } inline T value() const { if (ivec_ptr_) { v_->value(); return VecFunction::process(ivec_ptr_); } else return std::numeric_limits::quiet_NaN(); } inline typename expression_node::node_type type() const { return expression_node::e_vecfunc; } private: vector_interface* ivec_ptr_; expression_ptr v_; bool v_deletable_; }; template class assignment_node : 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 { if (var_node_ptr_) { 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 : 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 { if (vec_node_ptr_) { T& result = vec_node_ptr_->ref(); result = binary_node::branch_[1].first->value(); return result; } else return std::numeric_limits::quiet_NaN(); } private: vector_elem_node* vec_node_ptr_; }; template class assignment_vec_node : public binary_node, public vector_interface { public: typedef expression_node* expression_ptr; typedef vector_node* vector_node_ptr; assignment_vec_node(const operator_type& opr, expression_ptr branch0, expression_ptr branch1) : binary_node(opr,branch0,branch1), vec_node_ptr_(0), vec_size_ (0) { if (is_vector_node(binary_node::branch_[0].first)) { vec_node_ptr_ = static_cast*>(binary_node::branch_[0].first); vec_size_ = vec_node_ptr_->ref().size(); } } inline T value() const { if (vec_node_ptr_) { vector_holder& vec_hldr = vec_node_ptr_->ref(); const T v = binary_node::branch_[1].first->value(); for (std::size_t i = 0; i < vec_size_; ++i) { (*vec_hldr[i]) = v; } return vec_node_ptr_->value(); } else return std::numeric_limits::quiet_NaN(); } vector_node_ptr vec() const { return vec_node_ptr_; } vector_node_ptr vec() { return vec_node_ptr_; } inline typename expression_node::node_type type() const { return expression_node::e_vecvalass; } std::size_t size() const { return vec_size_; } private: vector_node* vec_node_ptr_; std::size_t vec_size_; }; template class assignment_vecvec_node : public binary_node, public vector_interface { public: typedef expression_node* expression_ptr; typedef vector_node* vector_node_ptr; assignment_vecvec_node(const operator_type& opr, expression_ptr branch0, expression_ptr branch1) : binary_node(opr,branch0,branch1), vec0_node_ptr_(0), vec1_node_ptr_(0), vec_size_ (0) { if (is_vector_node(binary_node::branch_[0].first)) { vec0_node_ptr_ = static_cast*>(binary_node::branch_[0].first); } if (is_vector_node(binary_node::branch_[1].first)) { vec1_node_ptr_ = static_cast*>(binary_node::branch_[1].first); } else if (is_ivector_node(binary_node::branch_[1].first)) { vector_interface* vi = reinterpret_cast*>(0); if ((vi = dynamic_cast*>(binary_node::branch_[1].first))) { vec1_node_ptr_ = vi->vec(); } } if (vec0_node_ptr_ && vec1_node_ptr_) { vec_size_ = std::min(vec0_node_ptr_->ref().size(), vec1_node_ptr_->ref().size()); } } inline T value() const { binary_node::branch_[1].first->value(); if (vec0_node_ptr_ && vec1_node_ptr_) { vector_holder& vec0 = vec0_node_ptr_->ref(); vector_holder& vec1 = vec1_node_ptr_->ref(); for (std::size_t i = 0; i < vec_size_; ++i) { (*vec0[i]) = (*vec1[i]); } return vec0_node_ptr_->value(); } else return std::numeric_limits::quiet_NaN(); } vector_node_ptr vec() const { return vec0_node_ptr_; } vector_node_ptr vec() { return vec0_node_ptr_; } inline typename expression_node::node_type type() const { return expression_node::e_vecvecass; } std::size_t size() const { return vec_size_; } private: vector_node* vec0_node_ptr_; vector_node* vec1_node_ptr_; std::size_t vec_size_; }; template class assignment_op_node : public binary_node { public: typedef expression_node* expression_ptr; assignment_op_node(const operator_type& opr, expression_ptr branch0, expression_ptr branch1) : binary_node(opr,branch0,branch1), 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 { if (var_node_ptr_) { 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 : 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 { if (vec_node_ptr_) { 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_vec_op_node : public binary_node, public vector_interface { public: typedef expression_node* expression_ptr; typedef vector_node* vector_node_ptr; assignment_vec_op_node(const operator_type& opr, expression_ptr branch0, expression_ptr branch1) : binary_node(opr,branch0,branch1), vec_node_ptr_(0), vec_size_ (0) { if (is_vector_node(binary_node::branch_[0].first)) { vec_node_ptr_ = static_cast*>(binary_node::branch_[0].first); vec_size_ = vec_node_ptr_->ref().size(); } } inline T value() const { if (vec_node_ptr_) { vector_holder& vec_hldr = vec_node_ptr_->ref(); const T v = binary_node::branch_[1].first->value(); for (std::size_t i = 0; i < vec_size_; ++i) { T& vec_i = *vec_hldr[i]; vec_i = Operation::process(vec_i,v); } return vec_node_ptr_->value(); } else return std::numeric_limits::quiet_NaN(); } vector_node_ptr vec() const { return vec_node_ptr_; } vector_node_ptr vec() { return vec_node_ptr_; } inline typename expression_node::node_type type() const { return expression_node::e_vecopvalass; } std::size_t size() const { return vec_size_; } private: vector_node* vec_node_ptr_; std::size_t vec_size_; }; template class assignment_vecvec_op_node : public binary_node, public vector_interface { public: typedef expression_node* expression_ptr; typedef vector_node* vector_node_ptr; assignment_vecvec_op_node(const operator_type& opr, expression_ptr branch0, expression_ptr branch1) : binary_node(opr,branch0,branch1), vec0_node_ptr_(0), vec1_node_ptr_(0), vec_size_ (0) { if (is_vector_node(binary_node::branch_[0].first)) { vec0_node_ptr_ = static_cast*>(binary_node::branch_[0].first); } if (is_vector_node(binary_node::branch_[1].first)) { vec1_node_ptr_ = static_cast*>(binary_node::branch_[1].first); } else if (is_ivector_node(binary_node::branch_[1].first)) { vector_interface* vi = reinterpret_cast*>(0); if ((vi = dynamic_cast*>(binary_node::branch_[1].first))) { vec1_node_ptr_ = vi->vec(); } } if (vec0_node_ptr_ && vec1_node_ptr_) { vec_size_ = std::min(vec0_node_ptr_->ref().size(), vec1_node_ptr_->ref().size()); } } inline T value() const { if (vec0_node_ptr_ && vec1_node_ptr_) { binary_node::branch_[0].first->value(); binary_node::branch_[1].first->value(); vector_holder& vec0 = vec0_node_ptr_->ref(); vector_holder& vec1 = vec1_node_ptr_->ref(); for (std::size_t i = 0; i < vec_size_; ++i) { T& vec0_i = *vec0[i]; T& vec1_i = *vec1[i]; vec0_i = Operation::process(vec0_i,vec1_i); } return vec0_node_ptr_->value(); } else return std::numeric_limits::quiet_NaN(); } vector_node_ptr vec() const { return vec0_node_ptr_; } vector_node_ptr vec() { return vec0_node_ptr_; } inline typename expression_node::node_type type() const { return expression_node::e_vecopvecass; } std::size_t size() const { return vec_size_; } private: vector_node* vec0_node_ptr_; vector_node* vec1_node_ptr_; std::size_t vec_size_; }; template class eqineq_vecvec_node : public binary_node, public vector_interface { public: typedef expression_node* expression_ptr; typedef vector_node* vector_node_ptr; eqineq_vecvec_node(const operator_type& opr, expression_ptr branch0, expression_ptr branch1) : binary_node(opr,branch0,branch1), vec0_node_ptr_(0), vec1_node_ptr_(0), vec_size_ (0) { if (is_vector_node(binary_node::branch_[0].first)) { vec0_node_ptr_ = static_cast*>(binary_node::branch_[0].first); } else if (is_ivector_node(binary_node::branch_[0].first)) { vector_interface* vi = reinterpret_cast*>(0); if ((vi = dynamic_cast*>(binary_node::branch_[0].first))) { vec0_node_ptr_ = vi->vec(); } } if (is_vector_node(binary_node::branch_[1].first)) { vec1_node_ptr_ = static_cast*>(binary_node::branch_[1].first); } else if (is_ivector_node(binary_node::branch_[1].first)) { vector_interface* vi = reinterpret_cast*>(0); if ((vi = dynamic_cast*>(binary_node::branch_[1].first))) { vec1_node_ptr_ = vi->vec(); } } if (vec0_node_ptr_ && vec1_node_ptr_) { vec_size_ = std::min(vec0_node_ptr_->ref().size(), vec1_node_ptr_->ref().size()); } } inline T value() const { if (vec0_node_ptr_ && vec1_node_ptr_) { binary_node::branch_[0].first->value(); binary_node::branch_[1].first->value(); vector_holder& vec0 = vec0_node_ptr_->ref(); vector_holder& vec1 = vec1_node_ptr_->ref(); for (std::size_t i = 0; i < vec_size_; ++i) { if (std::equal_to()(T(0),Operation::process(*vec0[i],*vec1[i]))) { return T(0); } } return T(1); } else return std::numeric_limits::quiet_NaN(); } vector_node_ptr vec() const { return vec0_node_ptr_; } vector_node_ptr vec() { return vec0_node_ptr_; } inline typename expression_node::node_type type() const { return expression_node::e_vecvecineq; } std::size_t size() const { return vec_size_; } private: vector_node* vec0_node_ptr_; vector_node* vec1_node_ptr_; std::size_t vec_size_; }; template class eqineq_vecval_node : public binary_node, public vector_interface { public: typedef expression_node* expression_ptr; typedef vector_node* vector_node_ptr; eqineq_vecval_node(const operator_type& opr, expression_ptr branch0, expression_ptr branch1) : binary_node(opr,branch0,branch1), vec_node_ptr_(0), vec_size_ (0) { if (is_vector_node(binary_node::branch_[0].first)) { vec_node_ptr_ = static_cast(binary_node::branch_[0].first); } else if (is_ivector_node(binary_node::branch_[0].first)) { vector_interface* vi = reinterpret_cast*>(0); if ((vi = dynamic_cast*>(binary_node::branch_[0].first))) { vec_node_ptr_ = vi->vec(); } } if (vec_node_ptr_) { vec_size_ = vec_node_ptr_->ref().size(); } } inline T value() const { if (vec_node_ptr_) { binary_node::branch_[0].first->value(); T v = binary_node::branch_[1].first->value(); vector_holder& vec_hldr = vec_node_ptr_->ref(); for (std::size_t i = 0; i < vec_size_; ++i) { if (std::equal_to()(T(0),Operation::process(*vec_hldr[i],v))) { return T(0); } } return T(1); } else return std::numeric_limits::quiet_NaN(); } vector_node_ptr vec() const { return vec_node_ptr_; } vector_node_ptr vec() { return vec_node_ptr_; } inline typename expression_node::node_type type() const { return expression_node::e_vecvalineq; } std::size_t size() const { return vec_size_; } private: vector_node* vec_node_ptr_; std::size_t vec_size_; }; template class eqineq_valvec_node : public binary_node, public vector_interface { public: typedef expression_node* expression_ptr; typedef vector_node* vector_node_ptr; eqineq_valvec_node(const operator_type& opr, expression_ptr branch0, expression_ptr branch1) : binary_node(opr,branch0,branch1), vec_node_ptr_(0), vec_size_ (0) { if (is_vector_node(binary_node::branch_[1].first)) { vec_node_ptr_ = static_cast(binary_node::branch_[1].first); } else if (is_ivector_node(binary_node::branch_[1].first)) { vector_interface* vi = reinterpret_cast*>(0); if ((vi = dynamic_cast*>(binary_node::branch_[1].first))) { vec_node_ptr_ = vi->vec(); } } if (vec_node_ptr_) { vec_size_ = vec_node_ptr_->ref().size(); } } inline T value() const { if (vec_node_ptr_) { T v = binary_node::branch_[0].first->value(); binary_node::branch_[1].first->value(); vector_holder& vec_hldr = vec_node_ptr_->ref(); for (std::size_t i = 0; i < vec_size_; ++i) { if (std::equal_to()(T(0),Operation::process(v,*vec_hldr[i]))) { return T(0); } } return T(1); } else return std::numeric_limits::quiet_NaN(); } vector_node_ptr vec() const { return vec_node_ptr_; } vector_node_ptr vec() { return vec_node_ptr_; } inline typename expression_node::node_type type() const { return expression_node::e_valvecineq; } std::size_t size() const { return vec_size_; } private: vector_node* vec_node_ptr_; std::size_t vec_size_; }; template class vecarith_vecvec_node : public binary_node, public vector_interface { public: typedef expression_node* expression_ptr; typedef vector_node* vector_node_ptr; typedef vector_holder* vector_holder_ptr; vecarith_vecvec_node(const operator_type& opr, expression_ptr branch0, expression_ptr branch1) : binary_node(opr,branch0,branch1), vec0_node_ptr_(0), vec1_node_ptr_(0), vec_size_ (0), data_ (0), temp_ (0), temp_vec_node_(0) { if (is_vector_node(binary_node::branch_[0].first)) { vec0_node_ptr_ = static_cast(binary_node::branch_[0].first); } else if (is_ivector_node(binary_node::branch_[0].first)) { vector_interface* vi = reinterpret_cast*>(0); if ((vi = dynamic_cast*>(binary_node::branch_[0].first))) { vec0_node_ptr_ = vi->vec(); } } if (is_vector_node(binary_node::branch_[1].first)) { vec1_node_ptr_ = static_cast(binary_node::branch_[1].first); } else if (is_ivector_node(binary_node::branch_[1].first)) { vector_interface* vi = reinterpret_cast*>(0); if ((vi = dynamic_cast*>(binary_node::branch_[1].first))) { vec1_node_ptr_ = vi->vec(); } } if (vec0_node_ptr_ && vec1_node_ptr_) { vector_holder& vec0 = vec0_node_ptr_->ref(); vector_holder& vec1 = vec1_node_ptr_->ref(); vec_size_ = std::min(vec0.size(),vec1.size()); data_ = new T[vec_size_]; temp_ = new vector_holder(data_,vec_size_); temp_vec_node_ = new vector_node (temp_); } } ~vecarith_vecvec_node() { delete[] data_; delete temp_; delete temp_vec_node_; } inline T value() const { if (vec0_node_ptr_ && vec1_node_ptr_) { binary_node::branch_[0].first->value(); binary_node::branch_[1].first->value(); vector_holder& vec0 = vec0_node_ptr_->ref(); vector_holder& vec1 = vec1_node_ptr_->ref(); vector_holder& vec2 = *temp_; for (std::size_t i = 0; i < vec_size_; ++i) { T& vec0_i = *vec0[i]; T& vec1_i = *vec1[i]; T& vec2_i = *vec2[i]; vec2_i = Operation::process(vec0_i,vec1_i); } return *vec2[0]; } else return std::numeric_limits::quiet_NaN(); } vector_node_ptr vec() const { return temp_vec_node_; } vector_node_ptr vec() { return temp_vec_node_; } inline typename expression_node::node_type type() const { return expression_node::e_vecvecarith; } std::size_t size() const { return vec_size_; } private: vector_node_ptr vec0_node_ptr_; vector_node_ptr vec1_node_ptr_; std::size_t vec_size_; T* data_; vector_holder_ptr temp_; vector_node_ptr temp_vec_node_; }; template class vecarith_vecval_node : public binary_node, public vector_interface { public: typedef expression_node* expression_ptr; typedef vector_node* vector_node_ptr; typedef vector_holder* vector_holder_ptr; vecarith_vecval_node(const operator_type& opr, expression_ptr branch0, expression_ptr branch1) : binary_node(opr,branch0,branch1), vec0_node_ptr_(0), vec_size_ (0), data_ (0), temp_ (0), temp_vec_node_(0) { if (is_vector_node(binary_node::branch_[0].first)) { vec0_node_ptr_ = static_cast(binary_node::branch_[0].first); } else if (is_ivector_node(binary_node::branch_[0].first)) { vector_interface* vi = reinterpret_cast*>(0); if ((vi = dynamic_cast*>(binary_node::branch_[0].first))) { vec0_node_ptr_ = vi->vec(); } } if (vec0_node_ptr_) { vector_holder& vec0 = vec0_node_ptr_->ref(); vec_size_ = vec0.size(); data_ = new T[vec_size_]; temp_ = new vector_holder(data_,vec_size_); temp_vec_node_ = new vector_node (temp_); } } ~vecarith_vecval_node() { delete[] data_; delete temp_; delete temp_vec_node_; } inline T value() const { if (vec0_node_ptr_) { binary_node::branch_[0].first->value(); const T v = binary_node::branch_[1].first->value(); vector_holder& vec0 = vec0_node_ptr_->ref(); vector_holder& vec1 = *temp_; for (std::size_t i = 0; i < vec_size_; ++i) { T& vec0_i = *vec0[i]; T& vec1_i = *vec1[i]; vec1_i = Operation::process(vec0_i,v); } return *vec1[0]; } else return std::numeric_limits::quiet_NaN(); } vector_node_ptr vec() const { return temp_vec_node_; } vector_node_ptr vec() { return temp_vec_node_; } inline typename expression_node::node_type type() const { return expression_node::e_vecvalarith; } std::size_t size() const { return vec_size_; } private: vector_node_ptr vec0_node_ptr_; std::size_t vec_size_; T* data_; vector_holder_ptr temp_; vector_node_ptr temp_vec_node_; }; template class vecarith_valvec_node : public binary_node, public vector_interface { public: typedef expression_node* expression_ptr; typedef vector_node* vector_node_ptr; typedef vector_holder* vector_holder_ptr; vecarith_valvec_node(const operator_type& opr, expression_ptr branch0, expression_ptr branch1) : binary_node(opr,branch0,branch1), vec1_node_ptr_(0), vec_size_ (0), data_ (0), temp_ (0), temp_vec_node_(0) { if (is_vector_node(binary_node::branch_[1].first)) { vec1_node_ptr_ = static_cast(binary_node::branch_[1].first); } else if (is_ivector_node(binary_node::branch_[1].first)) { vector_interface* vi = reinterpret_cast*>(0); if ((vi = dynamic_cast*>(binary_node::branch_[1].first))) { vec1_node_ptr_ = vi->vec(); } } if (vec1_node_ptr_) { vector_holder& vec0 = vec1_node_ptr_->ref(); vec_size_ = vec0.size(); data_ = new T[vec_size_]; temp_ = new vector_holder(data_,vec_size_); temp_vec_node_ = new vector_node (temp_); } } ~vecarith_valvec_node() { delete[] data_; delete temp_; delete temp_vec_node_; } inline T value() const { if (vec1_node_ptr_) { const T v = binary_node::branch_[0].first->value(); binary_node::branch_[1].first->value(); vector_holder& vec1 = vec1_node_ptr_->ref(); vector_holder& vec2 = *temp_; for (std::size_t i = 0; i < vec_size_; ++i) { T& vec1_i = *vec1[i]; T& vec2_i = *vec2[i]; vec2_i = Operation::process(v,vec1_i); } return *vec2[0]; } else return std::numeric_limits::quiet_NaN(); } vector_node_ptr vec() const { return temp_vec_node_; } vector_node_ptr vec() { return temp_vec_node_; } inline typename expression_node::node_type type() const { return expression_node::e_vecvalarith; } std::size_t size() const { return vec_size_; } private: vector_node_ptr vec1_node_ptr_; std::size_t vec_size_; T* data_; vector_holder_ptr temp_; vector_node_ptr temp_vec_node_; }; template class unary_vector_node : public unary_node, public vector_interface { public: typedef expression_node* expression_ptr; typedef vector_node* vector_node_ptr; typedef vector_holder* vector_holder_ptr; unary_vector_node(const operator_type& opr, expression_ptr branch0) : unary_node(opr,branch0), vec0_node_ptr_(0), vec_size_ (0), data_ (0), temp_ (0), temp_vec_node_(0) { if (is_vector_node(unary_node::branch_)) { vec0_node_ptr_ = static_cast(unary_node::branch_); } else if (is_ivector_node(unary_node::branch_)) { vector_interface* vi = reinterpret_cast*>(0); if ((vi = dynamic_cast*>(unary_node::branch_))) { vec0_node_ptr_ = vi->vec(); } } if (vec0_node_ptr_) { vector_holder& vec0 = vec0_node_ptr_->ref(); vec_size_ = vec0.size(); data_ = new T[vec_size_]; temp_ = new vector_holder(data_,vec_size_); temp_vec_node_ = new vector_node (temp_); } } ~unary_vector_node() { delete[] data_; delete temp_; delete temp_vec_node_; } inline T value() const { unary_node::branch_->value(); if (vec0_node_ptr_) { vector_holder& vec0 = vec0_node_ptr_->ref(); vector_holder& vec1 = *temp_; for (std::size_t i = 0; i < vec_size_; ++i) { T& vec0_i = *vec0[i]; T& vec1_i = *vec1[i]; vec1_i = Operation::process(vec0_i); } return *vec1[0]; } else return std::numeric_limits::quiet_NaN(); } vector_node_ptr vec() const { return temp_vec_node_; } vector_node_ptr vec() { return temp_vec_node_; } inline typename expression_node::node_type type() const { return expression_node::e_vecunaryop; } std::size_t size() const { return vec_size_; } private: vector_node_ptr vec0_node_ptr_; std::size_t vec_size_; T* data_; vector_holder_ptr temp_; vector_node_ptr temp_vec_node_; }; template class scand_node : 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 { 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 : 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 { 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 : public expression_node { public: // Function of N paramters. typedef expression_node* expression_ptr; typedef std::pair branch_t; typedef IFunction ifunction; function_N_node(ifunction* func) : function_((N == func->param_count) ? func : reinterpret_cast(0)), parameter_count_(func->param_count) {} ~function_N_node() { cleanup_branches::execute(branch_); } template bool init_branches(expression_ptr (&b)[NumBranches]) { // 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 { // 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 } 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]); } }; inline typename expression_node::node_type type() const { return expression_node::e_function; } private: ifunction* function_; std::size_t parameter_count_; branch_t branch_[N]; }; template class function_N_node : public expression_node { public: typedef expression_node* expression_ptr; typedef IFunction ifunction; 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 { if (function_) return (*function_)(); else return std::numeric_limits::quiet_NaN(); } inline typename expression_node::node_type type() const { return expression_node::e_function; } private: ifunction* function_; }; template class vararg_function_node : 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()); } ~vararg_function_node() { for (std::size_t i = 0; i < arg_list_.size(); ++i) { if (arg_list_[i] && !details::is_variable_node(arg_list_[i])) { delete arg_list_[i]; arg_list_[i] = 0; } } } inline bool operator <(const vararg_function_node& fn) const { return this < (&fn); } inline T value() const { if (function_) { populate_value_list(); return (*function_)(value_list_); } else return std::numeric_limits::quiet_NaN(); } inline typename expression_node::node_type type() const { return expression_node::e_vafunction; } 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_elem_node vector_elem_node_t; typedef vector_node vector_node_t; typedef variable_node_t* variable_node_ptr_t; typedef vector_elem_node_t* vector_elem_node_ptr_t; typedef vector_node_t* vector_node_ptr_t; typedef range_interface range_interface_t; typedef range_data_type range_data_type_t; typedef range_pack range_t; typedef std::pair branch_t; typedef std::pair void_t; typedef std::vector tmp_vs_t; typedef std::vector typestore_list_t; typedef std::vector range_list_t; generic_function_node(GenericFunction* func, const std::vector& arg_list) : function_(func), arg_list_(arg_list) {} ~generic_function_node() { cleanup_branches::execute(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((expression_ptr)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->vec()->ref()[0]; ts.type = type_store_t::e_vector; } 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; if (is_generally_string_node(arg_list_[i])) { range_interface_t* ri = reinterpret_cast(0); if (0 == (ri = dynamic_cast(arg_list_[i]))) return false; 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()); } } 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 if (is_vector_elem_node(arg_list_[i])) { vector_elem_node_ptr_t var = vector_elem_node_ptr_t(0); if (0 == (var = dynamic_cast(arg_list_[i]))) return false; ts.size = 1; ts.data = reinterpret_cast(&var->ref()); ts.type = type_store_t::e_scalar; } else { ts.size = 1; 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 { 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 { 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) { 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(); if (ts.type == type_store_t::e_string) ts.data = const_cast(rdt.str_node->base()) + rp.cache.first; else 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_; }; 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 range_pack range_t; string_function_node(StringFunction* func, const std::vector& arg_list) : gen_function_t(func,arg_list) { 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 { T result = std::numeric_limits::quiet_NaN(); if (gen_function_t::function_) { if (gen_function_t::populate_value_list()) { typedef typename StringFunction::parameter_list_t parameter_list_t; result = (*gen_function_t::function_)(ret_string_, parameter_list_t(gen_function_t::typestore_list_)); range_.n1_c.second = ret_string_.size() - 1; range_.cache.second = range_.n1_c.second; return result; } } return result; } inline typename expression_node::node_type type() const { return expression_node::e_strfunction; } std::string str() const { return ret_string_; } const char* base() const { return ret_string_.data(); } std::size_t size() const { return ret_string_.size(); } range_t& range_ref() { return range_; } const range_t& range_ref() const { return range_; } protected: mutable range_t range_; mutable std::string ret_string_; }; template class multimode_genfunction_node : public generic_function_node { public: typedef generic_function_node gen_function_t; typedef range_pack range_t; multimode_genfunction_node(GenericFunction* func, const std::size_t& param_seq_index, const std::vector& arg_list) : gen_function_t(func,arg_list), param_seq_index_(param_seq_index) {} inline T value() const { T result = std::numeric_limits::quiet_NaN(); if (gen_function_t::function_) { if (gen_function_t::populate_value_list()) { typedef typename GenericFunction::parameter_list_t parameter_list_t; return (*gen_function_t::function_)(param_seq_index_, parameter_list_t(gen_function_t::typestore_list_)); } } return result; } inline typename expression_node::node_type type() const { return expression_node::e_genfunction; } private: std::size_t param_seq_index_; }; template class multimode_strfunction_node : public string_function_node { public: typedef string_function_node str_function_t; typedef range_pack 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 { T result = std::numeric_limits::quiet_NaN(); if (str_function_t::function_) { if (str_function_t::populate_value_list()) { typedef typename StringFunction::parameter_list_t parameter_list_t; result = (*str_function_t::function_)(param_seq_index_, str_function_t::ret_string_, parameter_list_t(str_function_t::typestore_list_)); 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 result; } inline typename expression_node::node_type type() const { return expression_node::e_strfunction; } private: std::size_t param_seq_index_; }; #define exprtk_define_unary_op(OpName) \ template \ struct OpName##_op \ { \ typedef typename functor_t::Type Type; \ \ static inline T process(Type v) \ { \ return numeric:: OpName (v); \ } \ \ static inline typename expression_node::node_type type() \ { \ return expression_node::e_##OpName; \ } \ \ static inline details::operator_type operation() \ { \ return details::e_##OpName; \ } \ }; \ 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 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; 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 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; 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 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; 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 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; 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 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; static inline T process(Type t1, Type t2) { return 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; static inline T process(Type t1, Type t2) { return 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 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(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) { vector_holder& vec = v->vec()->ref(); T result = T(0); for (std::size_t i = 0; i < vec.size(); ++i) { result += (*vec[i]); } return result; } }; template struct vec_mul_op { typedef vector_interface* ivector_ptr; static inline T process(const ivector_ptr v) { vector_holder& vec = v->vec()->ref(); T result = (*vec[0]); for (std::size_t i = 1; i < vec.size(); ++i) { result *= (*vec[i]); } return result; } }; template struct vec_avg_op { typedef vector_interface* ivector_ptr; static inline T process(const ivector_ptr v) { vector_holder& vec = v->vec()->ref(); T result = T(0); for (std::size_t i = 0; i < vec.size(); ++i) { result += (*vec[i]); } return result / vec.size(); } }; template struct vec_min_op { typedef vector_interface* ivector_ptr; static inline T process(const ivector_ptr v) { vector_holder& vec = v->vec()->ref(); T result = (*vec[0]); for (std::size_t i = 1; i < vec.size(); ++i) { 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) { vector_holder& vec = v->vec()->ref(); T result = (*vec[0]); for (std::size_t i = 1; i < vec.size(); ++i) { T v_i = (*vec[i]); if (v_i > result) result = v_i; } return result; } }; template class vov_base_node : public expression_node { public: 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: 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: 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 const T& v() const = 0; }; template class bov_base_node : public expression_node { public: virtual const T& v() const = 0; }; template class cob_base_node : public expression_node { public: 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: 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: 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: inline virtual operator_type operation() const { return details::e_default; } }; template class sosos_base_node : public expression_node { public: inline virtual operator_type operation() const { return details::e_default; } }; template class T0oT1oT2_base_node : public expression_node { public: virtual std::string type_id() const = 0; }; template class T0oT1oT2oT3_base_node : public expression_node { public: virtual std::string type_id() const = 0; }; template class unary_variable_node : 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 { return Operation::process(v_); } inline typename expression_node::node_type type() const { return Operation::type(); } inline operator_type operation() const { return Operation::operation(); } inline const T& v() const { return v_; } private: unary_variable_node(unary_variable_node&); unary_variable_node& operator=(unary_variable_node&); const T& v_; }; template class uvouv_node : public expression_node { public: // UOpr1(v0) Op UOpr2(v1) typedef expression_node* expression_ptr; typedef typename details::functor_t functor_t; typedef typename functor_t::bfunc_t bfunc_t; typedef typename functor_t::ufunc_t ufunc_t; 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 { return f_(u0_(v0_),u1_(v1_)); } inline typename expression_node::node_type type() const { return expression_node::e_uvouv; } inline operator_type operation() const { return details::e_default; } 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(uvouv_node&); uvouv_node& operator=(uvouv_node&); const T& v0_; const T& v1_; const ufunc_t u0_; const ufunc_t u1_; const bfunc_t f_; }; template class unary_branch_node : public expression_node { public: typedef expression_node* expression_ptr; typedef Operation operation_t; explicit unary_branch_node(expression_ptr brnch) : branch_(brnch), branch_deletable_(branch_deletable(branch_)) {} ~unary_branch_node() { if (branch_ && branch_deletable_) { delete branch_; branch_ = 0; } } inline T value() const { return Operation::process(branch_->value()); } inline typename expression_node::node_type type() const { return Operation::type(); } inline operator_type operation() const { return Operation::operation(); } inline expression_node* branch(const std::size_t&) const { return branch_; } inline void release() { branch_deletable_ = false; } private: unary_branch_node(unary_branch_node&); unary_branch_node& operator=(unary_branch_node&); expression_ptr branch_; bool branch_deletable_; }; 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 : 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 { static const typename expression_node::node_type result = nodetype_T0oT1::result; return result; } inline operator_type operation() const { return e_default; } inline T value() const { 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(T0oT1&) {} T0oT1& operator=(T0oT1&) { return *this; } T0 t0_; T1 t1_; const bfunc_t f_; }; template class T0oT1oT2 : 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 { static const typename expression_node::node_type result = nodetype_T0oT1oT2::result; return result; } inline operator_type operation() const { return e_default; } inline T value() const { 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 { 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(node_type&) {} node_type& operator=(node_type&) { return *this; } T0 t0_; T1 t1_; T2 t2_; const bfunc_t f0_; const bfunc_t f1_; }; template class T0oT1oT2oT3 : 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 { 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 { 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(node_type&) {} node_type& operator=(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 : 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 { static const typename expression_node::node_type result = nodetype_T0oT1oT2::result; return result; } inline operator_type operation() const { return e_default; } inline T value() const { 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(node_type&) {} node_type& operator=(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 T0 t0() const = 0; virtual T1 t1() const = 0; virtual T2 t2() const = 0; }; template class T0oT1oT2_sf3ext : 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 { static const typename expression_node::node_type result = nodetype_T0oT1oT2::result; return result; } inline operator_type operation() const { return e_default; } inline T value() const { return SF3Operation::process(t0_,t1_,t2_); } T0 t0() const { return t0_; } T1 t1() const { return t1_; } T2 t2() const { return t2_; } std::string type_id() const { 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(node_type&) {} node_type& operator=(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 : 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 { static const typename expression_node::node_type result = nodetype_T0oT1oT2oT3::result; return result; } inline operator_type operation() const { return e_default; } inline T value() const { 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(node_type&) {} node_type& operator=(node_type&) { return *this; } T0 t0_; T1 t1_; T2 t2_; T3 t3_; const qfunc_t f_; }; template class T0oT1oT2oT3_sf4ext : 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 { static const typename expression_node::node_type result = nodetype_T0oT1oT2oT3::result; return result; } inline operator_type operation() const { return e_default; } inline T value() const { 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 t2_; } std::string type_id() const { 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(node_type&) {} node_type& operator=(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 : 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 { return Operation::process(v0_,v1_); } inline typename expression_node::node_type type() const { return Operation::type(); } inline operator_type operation() const { return Operation::operation(); } inline const T& v0() const { return v0_; } inline const T& v1() const { return v1_; } protected: const T& v0_; const T& v1_; private: vov_node(vov_node&); vov_node& operator=(vov_node&); }; template class cov_node : 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 { return Operation::process(c_,v_); } inline typename expression_node::node_type type() const { return Operation::type(); } inline operator_type operation() const { return Operation::operation(); } inline const T c() const { return c_; } inline const T& v() const { return v_; } protected: const T c_; const T& v_; private: cov_node(const cov_node&); cov_node& operator=(const cov_node&); }; template class voc_node : 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 { return Operation::process(v_,c_); } inline operator_type operation() const { return Operation::operation(); } inline const T c() const { return c_; } inline const T& v() const { return v_; } protected: const T& v_; const T c_; private: voc_node(const voc_node&); voc_node& operator=(const voc_node&); }; template class vob_node : 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 brnch) : v_(var) { init_branches<1>(branch_,brnch); } ~vob_node() { cleanup_branches::execute(branch_); } inline T value() const { return Operation::process(v_,branch_[0].first->value()); } inline operator_type operation() const { return Operation::operation(); } inline const T& v() const { return v_; } inline expression_node* branch(const std::size_t&) const { return branch_[0].first; } private: vob_node(const vob_node&); vob_node& operator=(const vob_node&); const T& v_; branch_t branch_[1]; }; template class bov_node : 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 brnch, const T& var) : v_(var) { init_branches<1>(branch_,brnch); } ~bov_node() { cleanup_branches::execute(branch_); } inline T value() const { return Operation::process(branch_[0].first->value(),v_); } inline operator_type operation() const { return Operation::operation(); } inline const T& v() const { return v_; } inline expression_node* branch(const std::size_t&) const { return branch_[0].first; } private: bov_node(const bov_node&); bov_node& operator=(const bov_node&); const T& v_; branch_t branch_[1]; }; template class cob_node : 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 brnch) : c_(const_var) { init_branches<1>(branch_,brnch); } ~cob_node() { cleanup_branches::execute(branch_); } inline T value() const { return Operation::process(c_,branch_[0].first->value()); } inline operator_type operation() const { return Operation::operation(); } inline const T c() const { return c_; } inline void set_c(const T new_c) { (*const_cast(&c_)) = new_c; } inline expression_node* branch(const std::size_t&) const { return branch_[0].first; } inline expression_node* move_branch(const std::size_t&) { branch_[0].second = false; return branch_[0].first; } private: cob_node(const cob_node&); cob_node& operator=(const cob_node&); const T c_; branch_t branch_[1]; }; template class boc_node : 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 brnch, const T const_var) : c_(const_var) { init_branches<1>(branch_,brnch); } ~boc_node() { cleanup_branches::execute(branch_); } inline T value() const { return Operation::process(branch_[0].first->value(),c_); } inline operator_type operation() const { return Operation::operation(); } inline const T c() const { return c_; } inline void set_c(const T new_c) { (*const_cast(&c_)) = new_c; } inline expression_node* branch(const std::size_t&) const { return branch_[0].first; } inline expression_node* move_branch(const std::size_t&) { branch_[0].second = false; return branch_[0].first; } private: boc_node(const boc_node&); boc_node& operator=(const boc_node&); const T c_; branch_t branch_[1]; }; #ifndef exprtk_disable_string_capabilities template class sos_node : 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 { return Operation::process(s0_,s1_); } inline typename expression_node::node_type type() const { return Operation::type(); } inline operator_type operation() const { return Operation::operation(); } inline std::string& s0() { return s0_; } inline std::string& s1() { return s1_; } protected: SType0 s0_; SType1 s1_; private: sos_node(sos_node&); sos_node& operator=(sos_node&); }; template class str_xrox_node : public sos_base_node { public: typedef expression_node* expression_ptr; typedef Operation operation_t; // 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 { 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 { return Operation::type(); } inline operator_type operation() const { 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(str_xrox_node&); str_xrox_node& operator=(str_xrox_node&); }; template class str_xoxr_node : public sos_base_node { public: typedef expression_node* expression_ptr; typedef Operation operation_t; // 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 { 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 { return Operation::type(); } inline operator_type operation() const { 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(str_xoxr_node&); str_xoxr_node& operator=(str_xoxr_node&); }; template class str_xroxr_node : public sos_base_node { public: typedef expression_node* expression_ptr; typedef Operation operation_t; // 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 { 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 { return Operation::type(); } inline operator_type operation() const { 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(str_xroxr_node&); str_xroxr_node& operator=(str_xroxr_node&); }; template class str_sogens_node : public binary_node { public: typedef expression_node * expression_ptr; typedef string_base_node* str_base_ptr; typedef range_pack range_t; typedef range_t* range_ptr; typedef range_interface irange_t; typedef irange_t* irange_ptr; 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_ptr = dynamic_cast(binary_node::branch_[0].first); if (0 == range_ptr) return; str0_range_ptr_ = &(range_ptr->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_ptr = dynamic_cast(binary_node::branch_[1].first); if (0 == range_ptr) return; str1_range_ptr_ = &(range_ptr->range_ref()); } } inline T value() const { 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; range_t& range0 = (*str0_range_ptr_); 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 { return Operation::type(); } inline operator_type operation() const { return Operation::operation(); } private: str_sogens_node(str_sogens_node&); str_sogens_node& operator=(str_sogens_node&); 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 : public sosos_base_node { public: typedef expression_node* expression_ptr; typedef Operation operation_t; // variable op variable node explicit sosos_node(SType0 p0, SType1 p1, SType2 p2) : s0_(p0), s1_(p1), s2_(p2) {} inline T value() const { return Operation::process(s0_,s1_,s2_); } inline typename expression_node::node_type type() const { return Operation::type(); } inline operator_type operation() const { 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(sosos_node&); sosos_node& operator=(sosos_node&); }; #endif template class ipow_node : 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 { return PowOp::result(v_); } inline typename expression_node::node_type type() const { return expression_node::e_ipow; } private: ipow_node(const ipow_node&); ipow_node& operator=(const ipow_node&); const T& v_; }; template class ipowinv_node : 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 { return (T(1) / PowOp::result(v_)); } inline typename expression_node::node_type type() const { return expression_node::e_ipowinv; } private: ipowinv_node(const ipowinv_node&); ipowinv_node& operator=(const ipowinv_node&); const T& v_; }; 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_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 : return true; default : return false; } } return false; } class node_allocator { public: template inline expression_node* allocate(OpType& operation, ExprNode (&branch)[1]) { return allocate(operation,branch[0]); } template inline expression_node* allocate(OpType& operation, ExprNode (&branch)[2]) { return allocate(operation,branch[0],branch[1]); } template inline expression_node* allocate(OpType& operation, ExprNode (&branch)[3]) { return allocate(operation,branch[0],branch[1],branch[2]); } template inline expression_node* allocate(OpType& operation, ExprNode (&branch)[4]) { return allocate(operation,branch[0],branch[1],branch[2],branch[3]); } template inline expression_node* allocate(OpType& operation, ExprNode (&branch)[5]) { return allocate(operation,branch[0],branch[1],branch[2],branch[3],branch[4]); } template inline expression_node* allocate(OpType& operation, ExprNode (&branch)[6]) { return allocate(operation,branch[0],branch[1],branch[2],branch[3],branch[4],branch[5]); } template inline expression_node* allocate() const { return new node_type(); } template class Sequence> inline expression_node* allocate(const Sequence& seq) const { return new node_type(seq); } template inline expression_node* allocate(T1& t1) const { return new node_type(t1); } template inline expression_node* allocate_c(const T1& t1) const { return new node_type(t1); } template inline expression_node* allocate(const T1& t1, const T2& t2) const { return new node_type(t1,t2); } template inline expression_node* allocate_cr(const T1& t1, T2& t2) const { return new node_type(t1,t2); } template inline expression_node* allocate_rc(T1& t1, const T2& t2) const { return new node_type(t1,t2); } template inline expression_node* allocate_rr(T1& t1, T2& t2) const { return new node_type(t1,t2); } template inline expression_node* allocate_tt(T1 t1, T2 t2) const { return new node_type(t1,t2); } template inline expression_node* allocate_ttt(T1 t1, T2 t2, T3 t3) const { return new node_type(t1,t2,t3); } template inline expression_node* allocate_tttt(T1 t1, T2 t2, T3 t3, T4 t4) const { return new node_type(t1,t2,t3,t4); } template inline expression_node* allocate_rrr(T1& t1, T2& t2, T3& t3) const { return new node_type(t1,t2,t3); } template inline expression_node* allocate_rrrr(T1& t1, T2& t2, T3& t3, T4& t4) const { return new node_type(t1,t2,t3,t4); } template inline expression_node* allocate_rrrrr(T1& t1, T2& t2, T3& t3, T4& t4, T5& t5) const { return new node_type(t1,t2,t3,t4,t5); } template inline expression_node* allocate(const T1& t1, const T2& t2, const T3& t3) const { return new node_type(t1,t2,t3); } template inline expression_node* allocate(const T1& t1, const T2& t2, const T3& t3, const T4& t4) const { return new node_type(t1,t2,t3,t4); } template inline expression_node* allocate(const T1& t1, const T2& t2, const T3& t3, const T4& t4, const T5& t5) const { return new node_type(t1,t2,t3,t4,t5); } template inline expression_node* allocate(const T1& t1, const T2& t2, const T3& t3, const T4& t4, const T5& t5, const T6& t6) const { return new node_type(t1,t2,t3,t4,t5,t6); } 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 { return new node_type(t1,t2,t3,t4,t5,t6,t7); } 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 { return new node_type(t1,t2,t3,t4,t5,t6,t7,t8); } 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 { return new node_type(t1,t2,t3,t4,t5,t6,t7,t8,t9); } 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 { return new node_type(t1,t2,t3,t4,t5,t6,t7,t8,t9,t10); } template inline expression_node* allocate_type(T1 t1, T2 t2, T3 t3) const { return new node_type(t1,t2,t3); } template inline expression_node* allocate_type(T1 t1, T2 t2, T3 t3, T4 t4) const { return new node_type(t1,t2,t3,t4); } template inline expression_node* allocate_type(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5) const { return new node_type(t1,t2,t3,t4,t5); } template inline expression_node* allocate_type(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7) const { return new node_type(t1,t2,t3,t4,t5,t6,t7); } template void inline free(expression_node*& e) const { 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 template class ifunction { public: explicit ifunction(const std::size_t& pc, const bool hse = true) : param_count(pc), has_side_effects(hse) {} virtual ~ifunction() {} inline virtual T operator()() { return std::numeric_limits::quiet_NaN(); } inline virtual T operator()(const T&) { return std::numeric_limits::quiet_NaN(); } inline virtual T operator()(const T&,const T&) { return std::numeric_limits::quiet_NaN(); } inline virtual T operator()(const T&, const T&, const T&) { return std::numeric_limits::quiet_NaN(); } inline virtual T operator()(const T&, const T&, const T&, const T&) { return std::numeric_limits::quiet_NaN(); } inline virtual T operator()(const T&, const T&, const T&, const T&, const T&) { return std::numeric_limits::quiet_NaN(); } inline virtual T operator()(const T&, const T&, const T&, const T&, const T&, const T&) { return std::numeric_limits::quiet_NaN(); } inline virtual T operator()(const T&, const T&, const T&, const T&, const T&, const T&, const T&) { return std::numeric_limits::quiet_NaN(); } inline virtual T operator()(const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&) { return std::numeric_limits::quiet_NaN(); } inline virtual T operator()(const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&) { return std::numeric_limits::quiet_NaN(); } inline virtual T operator()(const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&) { return std::numeric_limits::quiet_NaN(); } inline virtual T operator()(const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&) { return std::numeric_limits::quiet_NaN(); } inline virtual T operator()(const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&) { return std::numeric_limits::quiet_NaN(); } inline virtual T operator()(const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&) { return std::numeric_limits::quiet_NaN(); } inline virtual T operator()(const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&) { return std::numeric_limits::quiet_NaN(); } inline virtual T operator()(const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&) { return std::numeric_limits::quiet_NaN(); } inline virtual T operator()(const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&) { return std::numeric_limits::quiet_NaN(); } inline virtual T operator()(const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&) { return std::numeric_limits::quiet_NaN(); } inline virtual T operator()(const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&) { return std::numeric_limits::quiet_NaN(); } inline virtual T operator()(const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&) { return std::numeric_limits::quiet_NaN(); } inline virtual T operator()(const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&) { return std::numeric_limits::quiet_NaN(); } std::size_t param_count; bool has_side_effects; }; template class ivararg_function { public: ivararg_function(const bool hse = true) : has_side_effects(hse) {} virtual ~ivararg_function() {} inline virtual T operator()(const std::vector&) { exprtk_debug(("ivararg_function::operator() - Operator has not been overriden.\n")); return std::numeric_limits::quiet_NaN(); } bool has_side_effects; }; template class igeneric_function { public: typedef T type; typedef type_store generic_type; typedef typename generic_type::parameter_list parameter_list_t; igeneric_function(const std::string& param_seq = "", const bool hse = true) : has_side_effects(hse), parameter_sequence(param_seq) {} virtual ~igeneric_function() {} // f(i_0,i_1,....,i_N) --> Number inline virtual T operator()(parameter_list_t) { exprtk_debug(("igeneric_function::operator() - Operator has not been overriden. [1]\n")); return std::numeric_limits::quiet_NaN(); } // f(i_0,i_1,....,i_N) --> String inline virtual T operator()(std::string&, parameter_list_t) { exprtk_debug(("igeneric_function::operator() - Operator has not been overriden. [2]\n")); return std::numeric_limits::quiet_NaN(); } // f(psi,i_0,i_1,....,i_N) --> Number inline virtual T operator()(const std::size_t&, parameter_list_t) { exprtk_debug(("igeneric_function::operator() - Operator has not been overriden. [3]\n")); return std::numeric_limits::quiet_NaN(); } // f(psi,i_0,i_1,....,i_N) --> String inline virtual T operator()(const std::size_t&, std::string&, parameter_list_t) { exprtk_debug(("igeneric_function::operator() - Operator has not been overriden. [4]\n")); return std::numeric_limits::quiet_NaN(); } bool has_side_effects; std::string parameter_sequence; }; template class parser; template class expression_helper; template class symbol_table { protected: template class parser; protected: 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) {} 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 { 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; } } } 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_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); } 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_const = false) { return std::make_pair(is_const,new variable_node_t(t)); } #ifndef exprtk_disable_string_capabilities static inline std::pair make(std::string& t,const bool is_const = false) { return std::make_pair(is_const,new stringvar_node_t(t)); } #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_const = false) { return std::make_pair(is_const,&t); } static inline std::pair make(generic_function_t& t, const bool is_constant = false) { return std::make_pair(is_constant,&t); } }; if (symbol_name.size() > 1) { for (std::size_t i = 0; i < details::reserved_symbols_size; ++i) { if (details::imatch(symbol_name,details::reserved_symbols[i])) { return false; } } } tm_itr_t itr = map.find(symbol_name); 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 { 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) { tm_itr_t itr = map.find(symbol_name); if (map.end() != itr) { struct deleter { static inline void process(std::pair& n) { delete n.second; } static inline void process(std::pair& n) { delete n.second; } #ifndef exprtk_disable_string_capabilities static inline void process(std::pair& n) { delete n.second; } #endif static inline void process(std::pair&) { } }; if (delete_node) { deleter::process((*itr).second); } 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()); 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) { struct deleter { static inline void process(std::pair& n) { delete n.second; } static inline void process(std::pair& n) { delete n.second; } static inline void process(std::pair&) { } #ifndef exprtk_disable_string_capabilities static inline void process(std::pair& n) { delete n.second; } #endif }; if (!map.empty()) { if (delete_node) { tm_itr_t itr = map.begin(); tm_itr_t end = map.end(); 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 st_holder { struct st_data { type_store,T> variable_store; #ifndef exprtk_disable_string_capabilities type_store,std::string> stringvar_store; #endif type_store,ifunction > function_store; type_store,ivararg_function > vararg_function_store; type_store,igeneric_function > generic_function_store; type_store,igeneric_function > string_function_store; type_store vector_store; st_data() { 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]); } } inline bool is_reserved_symbol(const std::string& symbol) const { return (reserved_symbol_table_.end() != reserved_symbol_table_.find(symbol)); } std::list local_symbol_list_; std::list local_stringvar_list_; std::set reserved_symbol_table_; }; st_holder() : ref_count(1), data_(new st_data) {} st_holder(st_data* data) : ref_count(1), data_(data) {} ~st_holder() { if (data_ && (0 == ref_count)) { delete data_; data_ = 0; } } std::size_t ref_count; st_data* data_; }; public: symbol_table() : holder_(new st_holder) { clear(); } ~symbol_table() { if (holder_) { if (0 == --holder_->ref_count) { clear(); delete holder_; } } } symbol_table(const symbol_table& st) { holder_ = st.holder_; holder_->ref_count++; } inline symbol_table& operator=(const symbol_table& st) { if (holder_) { if (0 == --holder_->ref_count) { delete holder_; } holder_ = 0; } holder_ = st.holder_; holder_->ref_count++; return *this; } inline bool operator==(const symbol_table& st) { return (this == &st) || (holder_ == st.holder_); } 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() { if (!valid()) return; clear_variables(); clear_functions(); clear_strings (); clear_vectors (); } 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); } #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); } 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); } enum func_type { e_ft_unknown = 0, e_ft_basicfunc = 1, e_ft_strfunc = 2 }; inline bool add_function(const std::string& function_name, generic_function_t& function, const func_type ft = e_ft_basicfunc) { if (!valid()) return false; else if (!valid_symbol(function_name)) return false; else if (symbol_exists(function_name)) return false; else if (std::string::npos != function.parameter_sequence.find_first_not_of("STV*?|")) return false; else if (e_ft_basicfunc == ft) return local_data().generic_function_store.add(function_name,function); else if (e_ft_strfunc == ft) return local_data().string_function_store.add(function_name, function); else return 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 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 return local_data().vector_store.add(vector_name,v); } template inline bool add_vector(const std::string& vector_name, std::deque& v) { 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 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() { static const T local_pi = T(details::numeric::constant::pi); 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 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 { /* Will return true if symbol_name exists as either a reserved symbol, variable, stringvar 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().function_store.symbol_exists(symbol_name)) return true; else if (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 holder_ && holder_->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,e_ft_strfunc); } } } } private: inline bool valid_symbol(const std::string& symbol) const { if (symbol.empty()) return false; if (!details::is_letter(symbol[0])) return false; else if (symbol.size() > 1) { for (std::size_t i = 1; i < symbol.size(); ++i) { if ( (!details::is_letter(symbol[i])) && (!details:: is_digit(symbol[i])) && ('_' != symbol[i]) ) { return false; } } } return (!local_data().is_reserved_symbol(symbol)); } inline typename st_holder::st_data& local_data() { return *(holder_->data_); } inline const typename st_holder::st_data& local_data() const { return *(holder_->data_); } st_holder* holder_; }; template class function_compositor; template class expression { private: typedef details::expression_node* expression_ptr; typedef details::vector_holder* vector_holder_ptr; struct expression_holder { 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, data_type dt, 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; expression_holder() : ref_count(0), expr(0) {} expression_holder(expression_ptr e) : ref_count(1), expr(e) {} ~expression_holder() { if (expr && details::branch_deletable(expr)) { delete 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 (T*)(local_data_list[i].pointer); break; case e_vecdata : delete [] (T*)(local_data_list[i].pointer); break; case e_string : delete (std::string*)(local_data_list[i].pointer); break; default : break; } } } } std::size_t ref_count; expression_ptr expr; local_data_list_t local_data_list; friend class function_compositor; }; public: expression() : expression_holder_(0) { set_expression(new details::null_node()); } expression(const expression& e) : expression_holder_(e.expression_holder_), symbol_table_(e.symbol_table_) { expression_holder_->ref_count++; } inline expression& operator=(const expression& e) { if (this != &e) { if (expression_holder_) { if (0 == --expression_holder_->ref_count) { delete expression_holder_; } expression_holder_ = 0; } expression_holder_ = e.expression_holder_; expression_holder_->ref_count++; symbol_table_ = e.symbol_table_; } return *this; } inline bool operator==(const expression& e) { return (this == &e); } inline bool operator!() const { return ( (0 == expression_holder_ ) || (0 == expression_holder_->expr) ); } inline expression& release() { if (expression_holder_) { if (0 == --expression_holder_->ref_count) { delete expression_holder_; } expression_holder_ = 0; } return *this; } ~expression() { if (expression_holder_) { if (0 == --expression_holder_->ref_count) { delete expression_holder_; } } } inline T value() const { return expression_holder_->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_ = st; } inline const symbol_table& get_symbol_table() const { return symbol_table_; } inline symbol_table& get_symbol_table() { return symbol_table_; } private: inline void set_expression(const expression_ptr expr) { if (expr) { if (expression_holder_) { if (0 == --expression_holder_->ref_count) { delete expression_holder_; } } expression_holder_ = new expression_holder(expr); } } inline void register_local_var(expression_ptr expr) { if (expr) { if (expression_holder_) { expression_holder_-> local_data_list.push_back( typename expression::expression_holder:: data_pack(reinterpret_cast(expr), expression_holder::e_expr)); } } } inline void register_local_var(vector_holder_ptr vec_holder) { if (vec_holder) { if (expression_holder_) { expression_holder_-> local_data_list.push_back( typename expression::expression_holder:: data_pack(reinterpret_cast(vec_holder), expression_holder::e_vecholder)); } } } inline void register_local_data(void* data, const std::size_t& size = 0, const bool vectype = false) { if (data) { if (expression_holder_) { expression_holder_-> local_data_list.push_back( typename expression::expression_holder:: data_pack(reinterpret_cast(data), vectype ? expression_holder::e_vecdata : expression_holder::e_data, size)); } } } inline const typename expression_holder::local_data_list_t& local_data_list() { if (expression_holder_) { return expression_holder_->local_data_list; } else { static typename expression_holder::local_data_list_t null_local_data_list; return null_local_data_list; } } expression_holder* expression_holder_; symbol_table symbol_table_; friend class parser; friend class expression_helper; friend class function_compositor; }; template class expression_helper { public: static inline bool is_constant(const expression& expr) { return details::is_constant_node(expr.expression_holder_->expr); } static inline bool is_variable(const expression& expr) { return details::is_variable_node(expr.expression_holder_->expr); } static inline bool is_unary(const expression& expr) { return details::is_unary_node(expr.expression_holder_->expr); } static inline bool is_binary(const expression& expr) { return details::is_binary_node(expr.expression_holder_->expr); } static inline bool is_function(const expression& expr) { return details::is_function(expr.expression_holder_->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 }; 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 error_line; std::size_t line_no; std::size_t column_no; }; inline type make_error(error_mode mode, const std::string& diagnostic = "") { type t; t.mode = mode; t.token.type = lexer::token::e_error; t.diagnostic = diagnostic; exprtk_debug(((diagnostic + "\n").c_str())); return t; } inline type make_error(error_mode mode, const lexer::token& tk, const std::string& diagnostic = "") { type t; t.mode = mode; t.token = tk; t.diagnostic = diagnostic; exprtk_debug(((diagnostic + "\n").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" ); 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 char 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()); } } template class parser { 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::quinary_node quinary_node_t; typedef details::senary_node senary_node_t; typedef details::conditional_node conditional_node_t; typedef details::cons_conditional_node cons_conditional_node_t; typedef details::while_loop_node while_loop_node_t; typedef details::repeat_until_loop_node repeat_until_loop_node_t; typedef details::for_loop_node for_loop_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; #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::vector_node vector_node_t; #ifndef exprtk_disable_string_capabilities typedef details::range_pack range_t; typedef details::stringvar_node stringvar_node_t; typedef details::string_literal_node string_literal_node_t; typedef details::string_range_node string_range_node_t; 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; #endif typedef details::assignment_node assignment_node_t; typedef details::assignment_vec_elem_node assignment_vec_elem_node_t; typedef details::assignment_vec_node assignment_vec_node_t; typedef details::assignment_vecvec_node assignment_vecvec_node_t; typedef details::scand_node scand_node_t; typedef details::scor_node scor_node_t; typedef lexer::token token_t; typedef expression_node_t* expression_node_ptr; typedef symbol_table symbol_table_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 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; struct scope_element { enum element_type { e_none , e_variable, e_vector , e_vecelem , e_string }; typedef variable_node_t* variable_node_ptr; typedef details::vector_holder vector_holder_t; typedef vector_holder_t* vector_holder_ptr; 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) {} 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); } 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; variable_node_ptr var_node; vector_holder_ptr vec_node; }; class scope_element_manager { public: typedef variable_node_t* variable_node_ptr; typedef parser parser_t; 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()) { for (std::size_t i = 0; i < element_.size(); ++i) { scope_element& se = element_[i]; if (se.depth > parser_.scope_depth_) return null_element_; else if ( (se.name == var_name) && (se.index == index) ) return se; } return null_element_; } inline bool add_element(const scope_element& se) { for (std::size_t j = 0; j < element_.size(); ++j) { if ( (element_[j].name == se.name ) && (element_[j].depth <= se.depth) && (element_[j].index == se.index) && (element_[j].size == se.size ) ) return false; } element_.push_back(se); std::sort(element_.begin(),element_.end()); return true; } inline void deactivate(const std::size_t& scope_depth) { for (std::size_t j = 0; j < element_.size(); ++j) { if (element_[j].depth >= scope_depth) { element_[j].active = false; } } } void cleanup() { for (std::size_t i = 0; i < element_.size(); ++i) { if (element_[i].var_node) { delete element_[i].var_node; } if (element_[i].vec_node) { delete element_[i].vec_node; } T* data = (T*)(element_[i].data); switch (element_[i].type) { case scope_element::e_variable : delete data; break; case scope_element::e_vector : delete [] data; break; default : break; } } element_.clear(); input_param_cnt_ = 0; } inline std::size_t next_ip_index() { return ++input_param_cnt_; } inline variable_node_ptr get_variable(const T& v) { for (std::size_t i = 0; i < element_.size(); ++i) { scope_element& se = element_[i]; if (se.active && se.var_node) { if (&se.var_node->ref() == (&v)) { return se.var_node; } } } return variable_node_ptr(0); } private: scope_element_manager& operator=(const scope_element_manager&); parser_t& parser_; std::vector element_; scope_element null_element_; std::size_t input_param_cnt_; }; class scope_handler { public: typedef parser parser_t; scope_handler(parser& p) : parser_(p) { parser_.scope_depth_++; #ifdef exprtk_enable_debugging std::string depth(2 * parser_.scope_depth_,'-'); exprtk_debug(("%s> Scope Depth: %02d\n",depth.c_str(),static_cast(parser_.scope_depth_))); #endif } ~scope_handler() { parser_.scope_depth_--; parser_.sem_.deactivate(parser_.scope_depth_); #ifdef exprtk_enable_debugging std::string depth(2 * parser_.scope_depth_,'-'); exprtk_debug(("<%s Scope Depth: %02d\n",depth.c_str(),static_cast(parser_.scope_depth_))); #endif } private: scope_handler& operator=(const scope_handler&); parser_t& parser_; }; public: enum 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 }; struct unknown_symbol_resolver { enum usr_symbol_type { e_usr_variable_type = 0, e_usr_constant_type = 1 }; virtual ~unknown_symbol_resolver() {} virtual bool process(const std::string& /*unknown_symbol*/, usr_symbol_type& st, T& default_value, std::string& error_message) { st = e_usr_variable_type; default_value = T(0); error_message = ""; return true; } }; 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_string = 3, e_st_function = 4, e_st_local_variable = 5, e_st_local_vector = 6, e_st_local_string = 7 }; 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) {} 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) { std::string& s = symbol_name_list_[i].first; std::transform(s.begin(),s.end(),s.begin(),static_cast(std::tolower)); } 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) { std::string& s = assignment_name_list_[i].first; std::transform(s.begin(),s.end(),s.begin(),static_cast(std::tolower)); } 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(); } bool& collect_variables() { return collect_variables_; } bool& collect_functions() { return collect_functions_; } bool& collect_assignments() { return collect_assignments_; } 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 : case e_st_function : if (collect_variables_ || 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_; symbol_list_t symbol_name_list_; symbol_list_t assignment_name_list_; friend class parser; }; 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; parser(const std::size_t compile_options = compile_all_opts) : compile_options_(compile_options), resolve_unknown_symbol_(false), vardef_disabled_((compile_options & e_disable_vardef) == e_disable_vardef), scope_depth_(0), unknown_symbol_resolver_(reinterpret_cast(0)), #ifdef _MSC_VER #pragma warning(push) #pragma warning (disable:4355) #endif sem_(*this), #ifdef _MSC_VER #pragma warning(pop) #endif operator_joiner_2_(2), operator_joiner_3_(3) { init_precompilation(); 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(strength_reduction_enabled()); } ~parser() {} inline void init_precompilation() { if (collect_variables_enabled()) dec_.collect_variables() = true; if (collect_functions_enabled()) dec_.collect_functions() = true; if (collect_assignments_enabled()) dec_.collect_assignments() = true; if (replacer_enabled()) { symbol_replacer_.clear(); symbol_replacer_.add_replace("true" ,"1",lexer::token::e_number); symbol_replacer_.add_replace("false","0",lexer::token::e_number); helper_assembly_.token_modifier_list.clear(); helper_assembly_.register_modifier(&symbol_replacer_); } if (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 (joiner_enabled()) { helper_assembly_.token_joiner_list.clear(); helper_assembly_.register_joiner(&operator_joiner_2_); helper_assembly_.register_joiner(&operator_joiner_3_); } if ( numeric_check_enabled () || bracket_check_enabled () || sequence_check_enabled() ) { helper_assembly_.token_scanner_list.clear(); if (numeric_check_enabled()) { helper_assembly_.register_scanner(&numeric_checker_); } if (bracket_check_enabled()) { helper_assembly_.register_scanner(&bracket_checker_); } if (sequence_check_enabled()) { helper_assembly_.register_scanner(&sequence_validator_); } } } inline bool compile(const std::string& expression_string, expression& expr) { error_list_ .clear(); brkcnt_list_ .clear(); synthesis_error_.clear(); sem_ .cleanup(); expression_generator_.set_allocator(node_allocator_); scope_depth_ = 0; if (expression_string.empty()) { set_error( make_error(parser_error::e_syntax, "ERR00 - Empty expression!")); return false; } if (!lexer_.process(expression_string)) { process_lexer_errors(); return false; } if (lexer_.empty()) { set_error( make_error(parser_error::e_syntax, "ERR01 - Empty expression!")); return false; } if (!run_assemblies()) { return false; } symbol_table_ = expr.get_symbol_table(); dec_.clear(); lexer_.begin(); next_token(); expression_node_ptr e = parse_corpus(); if ((0 != e) && (token_t::e_eof == current_token_.type)) { expr.set_expression(e); register_local_vars(expr); return !(!expr); } else { if (error_list_.empty()) { set_error( make_error(parser_error::e_syntax, current_token_, "ERR02 - Invalid expression encountered")); } dec_.clear (); sem_.cleanup(); if (0 != e) { delete e; } return false; } } void process_lexer_errors() { for (std::size_t i = 0; i < lexer_.size(); ++i) { if (lexer_[i].is_error()) { std::string diagnostic = "ERR03 - "; 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)); } } } inline bool replacer_enabled() const { return ((compile_options_ & e_replacer) == e_replacer); } inline bool commutative_check_enabled() const { return ((compile_options_ & e_commutative_check) == e_commutative_check); } inline bool joiner_enabled() const { return ((compile_options_ & e_joiner) == e_joiner); } inline bool numeric_check_enabled() const { return ((compile_options_ & e_numeric_check) == e_numeric_check); } inline bool bracket_check_enabled() const { return ((compile_options_ & e_bracket_check) == e_bracket_check); } inline bool sequence_check_enabled() const { return ((compile_options_ & e_sequence_check) == e_sequence_check); } inline bool strength_reduction_enabled() const { return ((compile_options_ & e_strength_reduction) == e_strength_reduction); } inline bool collect_variables_enabled() const { return ((compile_options_ & e_collect_vars) == e_collect_vars); } inline bool collect_functions_enabled() const { return ((compile_options_ & e_collect_funcs) == e_collect_funcs); } inline bool collect_assignments_enabled() const { return ((compile_options_ & e_collect_assings) == e_collect_assings); } inline bool run_assemblies() { if (commutative_check_enabled()) { helper_assembly_.run_inserters(lexer_); } if (joiner_enabled()) { helper_assembly_.run_joiners(lexer_); } if (replacer_enabled()) { helper_assembly_.run_modifiers(lexer_); } if ( numeric_check_enabled () || bracket_check_enabled () || 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; if (0 != (bracket_checker_ptr = dynamic_cast(helper_assembly_.error_token_scanner))) { set_error( make_error(parser_error::e_token, bracket_checker_ptr->error_token(), "ERR04 - Mismatched brackets: '" + bracket_checker_ptr->error_token().value + "'")); } else if (0 != (numeric_checker_ptr = dynamic_cast(helper_assembly_.error_token_scanner))) { for (std::size_t i = 0; i < numeric_checker_ptr->error_count(); ++i) { lexer::token error_token = lexer_[numeric_checker_ptr->error_index(i)]; set_error( make_error(parser_error::e_token, error_token, "ERR05 - Invalid numeric token: '" + error_token.value + "'")); } 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, "ERR06 - Invalid token sequence: '" + error_token.first.value + "' and '" + error_token.second.value + "'")); } if (sequence_validator_ptr->error_count()) { sequence_validator_ptr->clear_errors(); } } } return false; } } return true; } inline parser_error::type get_error(const std::size_t& index) { if (index < error_list_.size()) return error_list_[index]; else throw std::invalid_argument("parser::get_error() - Invalid error index specificed"); } 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 (!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 (!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 disable_unknown_symbol_resolver() { resolve_unknown_symbol_ = false; unknown_symbol_resolver_ = &default_usr_; } private: inline bool valid_base_operation(const std::string& symbol) { const std::size_t length = symbol.size(); if ( (length < 3) || // Shortest base op symbol length (length > 9) // Longest base op symbol length ) return false; else return (base_ops_map_.end() != base_ops_map_.find(symbol)); } inline bool valid_vararg_operation(const std::string& symbol) { static const std::string s_sum = "sum" ; static const std::string s_mul = "mul" ; static const std::string s_avg = "avg" ; static const std::string s_min = "min" ; static const std::string s_max = "max" ; static const std::string s_mand = "mand"; static const std::string s_mor = "mor" ; static const std::string s_multi = "~" ; static const std::string s_mswitch = "[*]" ; return ( details::imatch(symbol,s_sum ) || details::imatch(symbol,s_mul ) || details::imatch(symbol,s_avg ) || details::imatch(symbol,s_min ) || details::imatch(symbol,s_max ) || details::imatch(symbol,s_mand ) || details::imatch(symbol,s_mor ) || details::imatch(symbol,s_multi ) || details::imatch(symbol,s_mswitch) ); } inline void store_token() { lexer_.store(); store_current_token_ = current_token_; } inline void restore_token() { lexer_.restore(); current_token_ = store_current_token_; } #ifndef exprtk_enable_debugging inline void next_token() { current_token_ = lexer_.next_token(); } #else inline void next_token() { std::string ct_str = current_token_.value; current_token_ = lexer_.next_token(); std::string depth(2 * scope_depth_,' '); exprtk_debug(("%s" "prev[%s] --> curr[%s]\n", depth.c_str(), ct_str.c_str(), current_token_.value.c_str())); } #endif inline const lexer::token& current_token() const { return current_token_; } inline expression_node_ptr parse_corpus() { std::vector arg_list; expression_node_ptr result = error_node(); scoped_vec_delete sdd(*this,arg_list); for (;;) { expression_node_ptr arg = parse_expression(); if (0 == arg) { if (error_list_.empty()) { set_error( make_error(parser_error::e_syntax, current_token_, "ERR07 - Invalid expression encountered")); } return error_node(); } else arg_list.push_back(arg); if (lexer_.finished()) break; else if (token_is(token_t::e_eof,false)) { if (lexer_.finished()) break; else next_token(); } } result = simplify(arg_list); sdd.delete_ptr = (0 == result); 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; } precedence_level left; precedence_level right; details::operator_type operation; }; inline expression_node_ptr parse_expression(precedence_level precedence = e_level00) { 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 = "|"; if (details::imatch(current_token_.value,s_and)) { current_state.set(e_level01,e_level02,details::e_and); break; } else if (details::imatch(current_token_.value,s_and1)) { #ifndef exprtk_disable_sc_andor current_state.set(e_level01,e_level02,details::e_scand); #else current_state.set(e_level01,e_level02,details::e_and); #endif break; } else if (details::imatch(current_token_.value,s_nand)) { current_state.set(e_level01,e_level02,details::e_nand); break; } else if (details::imatch(current_token_.value,s_or)) { current_state.set(e_level03,e_level04,details::e_or); break; } else if (details::imatch(current_token_.value,s_or1)) { #ifndef exprtk_disable_sc_andor current_state.set(e_level03,e_level04,details::e_scor); #else current_state.set(e_level03,e_level04,details::e_or); #endif break; } else if (details::imatch(current_token_.value,s_nor)) { current_state.set(e_level03,e_level04,details::e_nor); break; } else if (details::imatch(current_token_.value,s_xor)) { current_state.set(e_level03,e_level04,details::e_xor); break; } else if (details::imatch(current_token_.value,s_xnor)) { current_state.set(e_level03,e_level04,details::e_xnor); break; } else if (details::imatch(current_token_.value,s_in)) { current_state.set(e_level03,e_level04,details::e_in); break; } else if (details::imatch(current_token_.value,s_like)) { current_state.set(e_level03,e_level04,details::e_like); break; } else if (details::imatch(current_token_.value,s_ilike)) { current_state.set(e_level03,e_level04,details::e_ilike); break; } } break_loop = true; } if (break_loop) { parse_pending_string_rangesize(expression); break; } else if (current_state.left < precedence) break; lexer::token prev_token = current_token_; next_token(); expression_node_ptr right_branch = error_node(); expression_node_ptr new_expression = error_node(); if ((right_branch = parse_expression(current_state.right))) { 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_ : "ERR08 - General parsing error at token: '" + prev_token.value + "'")); } free_node(node_allocator_,expression); return error_node(); } else { expression = new_expression; if (token_is(token_t::e_ternary,false) && (precedence == e_level00)) { expression = parse_ternary_conditional_statement(expression); } parse_pending_string_rangesize(expression); } } return 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 > ubn_t; ubn_t* n = dynamic_cast(node); if (n) { const T& v = n->v(); expression_node_ptr return_node = error_node(); if ( (return_node = symbol_table_.get_variable(v)) || (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_, "ERR09 - Failed to find variable node in symbol table")); free_node(node_allocator_,node); return false; } } } return false; } static inline expression_node_ptr error_node() { return reinterpret_cast(0); } 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& operator=(const scoped_delete&); }; template struct scoped_deq_delete { typedef Type* ptr_t; scoped_deq_delete(parser& pr, std::deque& deq) : delete_ptr(true), parser_(pr), deq_(deq) {} ~scoped_deq_delete() { 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& operator=(const scoped_deq_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& operator=(const scoped_vec_delete&); }; 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_, "ERR10 - Invalid number of parameters for function: '" + function_name + "'")); return error_node(); } } if (func_node) return func_node; else { set_error( make_error(parser_error::e_syntax, current_token_, "ERR11 - Failed to generate call to function: '" + function_name + "'")); return error_node(); } } template inline expression_node_ptr parse_function_call(ifunction* function, const std::string& function_name) { if (0 == NumberofParameters) { set_error( make_error(parser_error::e_syntax, current_token_, "ERR12 - Expecting ifunction '" + function_name + "' to have non-zero parameter count")); return error_node(); } 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_, "ERR13 - Expecting argument list for function: '" + function_name + "'")); 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_, "ERR14 - Failed to parse argument " + details::to_str(i) + " for function: '" + function_name + "'")); 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_, "ERR15 - Invalid number of arguments for function: '" + function_name + "'")); return error_node(); } } } if (!token_is(token_t::e_rbracket)) { set_error( make_error(parser_error::e_syntax, current_token_, "ERR16 - Invalid number of arguments for function: '" + function_name + "'")); return error_node(); } else result = expression_generator_.function(function,branch); sd.delete_ptr = false; 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); next_token(); if ( token_is(token_t::e_lbracket) && !token_is(token_t::e_rbracket) ) { set_error( make_error(parser_error::e_syntax, current_token_, "ERR17 - Expecting '()' to proceed call to function: '" + function_name + "'")); free_node(node_allocator_,result); return error_node(); } else return result; } template inline int parse_base_function_call(expression_node_ptr (¶m_list)[MaxNumberofParameters]) { 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_, "ERR18 - Expected a '(' at start of function call, instead got: '" + current_token_.value + "'")); return 0; } int param_index = 0; for (; param_index < static_cast(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)) break; else if (token_is(token_t::e_comma)) continue; else { set_error( make_error(parser_error::e_syntax, current_token_, "ERR19 - Expected a ',' between function input parameters, instead got: '" + current_token_.value + "'")); return 0; } } sd.delete_ptr = false; return (param_index + 1); } inline expression_node_ptr parse_base_operation() { typedef std::pair map_range_t; const std::string operation_name = current_token_.value; map_range_t itr_range = base_ops_map_.equal_range(operation_name); if (0 == std::distance(itr_range.first,itr_range.second)) { set_error( make_error(parser_error::e_syntax, current_token_, "ERR20 - No entry found for base operation: " + operation_name)); return error_node(); } const std::size_t MaxNumberofParameters = 6; expression_node_ptr param_list[MaxNumberofParameters] = {0}; std::size_t parameter_count = parse_base_function_call(param_list); if (0 == parameter_count) { return error_node(); } else if (parameter_count <= 6) { for (base_ops_map_t::iterator itr = itr_range.first; itr != itr_range.second; ++itr) { 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) base_opr_case(5) base_opr_case(6) #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, current_token_, "ERR21 - Invalid number of parameters for call to function: '" + operation_name + "'")); return error_node(); } inline expression_node_ptr parse_conditional_statement_01(expression_node_ptr condition) { // 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_, "ERR22 - Expected ',' between if-statement condition and consequent")); result = false; } else if (0 == (consequent = parse_expression())) { set_error( make_error(parser_error::e_syntax, current_token_, "ERR23 - Failed to parse consequent for if-statement")); result = false; } else if (!token_is(token_t::e_comma)) { set_error( make_error(parser_error::e_syntax, current_token_, "ERR24 - Expected ',' between if-statement consequent and alternative")); result = false; } else if (0 == (alternative = parse_expression())) { set_error( make_error(parser_error::e_syntax, current_token_, "ERR25 - Failed to parse alternative for if-statement")); result = false; } else if (!token_is(token_t::e_rbracket)) { set_error( make_error(parser_error::e_syntax, current_token_, "ERR26 - Expected ')' at the end of if-statement")); 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,false)) { if (0 == (consequent = parse_multi_sequence("if-statement-01"))) { set_error( make_error(parser_error::e_syntax, current_token_, "ERR27 - Failed to parse body of consequent for if-statement")); result = false; } } else { if ( commutative_check_enabled() && token_is(token_t::e_mul,false) ) { next_token(); } if (0 != (consequent = parse_expression())) { if (!token_is(token_t::e_eof)) { set_error( make_error(parser_error::e_syntax, current_token_, "ERR28 - Expected ';' at the end of the consequent for if-statement")); result = false; } } else { set_error( make_error(parser_error::e_syntax, current_token_, "ERR29 - Failed to parse body of consequent for if-statement")); result = false; } } if (result) { if (details::imatch(current_token_.value,"else")) { next_token(); if (token_is(token_t::e_lcrlbracket,false)) { if (0 == (alternative = parse_multi_sequence("else-statement-01"))) { set_error( make_error(parser_error::e_syntax, current_token_, "ERR30 - Failed to parse body of the 'else' for if-statement")); result = false; } } else if (details::imatch(current_token_.value,"if")) { if (0 == (alternative = parse_conditional_statement())) { set_error( make_error(parser_error::e_syntax, current_token_, "ERR31 - Failed to parse body of if-else statement")); result = false; } } else if (0 != (alternative = parse_expression())) { if (!token_is(token_t::e_eof)) { set_error( make_error(parser_error::e_syntax, current_token_, "ERR32 - Expected ';' at the end of the 'else-if' for the if-statement")); result = false; } } else { set_error( make_error(parser_error::e_syntax, current_token_, "ERR33 - Failed to parse body of the 'else' for if-statement")); result = false; } } } 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_, "ERR34 - Expected '(' at start of if-statement, instead got: '" + current_token_.value + "'")); return error_node(); } else if (0 == (condition = parse_expression())) { set_error( make_error(parser_error::e_syntax, current_token_, "ERR35 - Failed to parse condition for if-statement")); return error_node(); } else if (token_is(token_t::e_comma,false)) { // if (x,y,z) return parse_conditional_statement_01(condition); } else if (token_is(token_t::e_rbracket)) { // 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_, "ERR36 - Invalid if-statement")); 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_, "ERR37 - Encountered invalid condition branch for ternary if-statement")); return error_node(); } else if (!token_is(token_t::e_ternary)) { set_error( make_error(parser_error::e_syntax, current_token_, "ERR38 - Expected '?' after condition of ternary if-statement")); result = false; } else if (0 == (consequent = parse_expression())) { set_error( make_error(parser_error::e_syntax, current_token_, "ERR39 - Failed to parse consequent for if-statement")); result = false; } else if (!token_is(token_t::e_colon)) { set_error( make_error(parser_error::e_syntax, current_token_, "ERR40 - Expected ':' between ternary if-statement consequent and alternative")); result = false; } else if (0 == (alternative = parse_expression())) { set_error( make_error(parser_error::e_syntax, current_token_, "ERR41 - Failed to parse alternative for if-statement")); 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_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_, "ERR42 - Expected '(' at start of while-loop condition statement")); return error_node(); } else if (0 == (condition = parse_expression())) { set_error( make_error(parser_error::e_syntax, current_token_, "ERR43 - Failed to parse condition for while-loop")); return error_node(); } else if (!token_is(token_t::e_rbracket)) { set_error( make_error(parser_error::e_syntax, current_token_, "ERR44 - Expected ')' at end of while-loop condition statement")); result = false; } brkcnt_list_.push_front(false); if (result) { if (0 == (branch = parse_multi_sequence("while-loop"))) { set_error( make_error(parser_error::e_syntax, current_token_, "ERR45 - Failed to parse body of while-loop")); result = false; } else if (0 == (result_node = expression_generator_.while_loop(condition, branch, brkcnt_list_.front()))) { set_error( make_error(parser_error::e_syntax, current_token_, "ERR46 - Failed to synthesize while-loop")); result = false; } } if (!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; 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 { token_t::token_type seperator = token_t::e_eof; scope_handler sh(*this); for (;;) { expression_node_ptr arg = parse_expression(); if (0 == arg) return error_node(); else arg_list.push_back(arg); if (details::imatch(current_token_.value,"until")) { next_token(); break; } 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_, "ERR47 - Expected '" + token_t::to_str(seperator) + "' for body of repeat until loop")); return error_node(); } if (details::imatch(current_token_.value,"until")) { next_token(); break; } } branch = simplify(arg_list); if ((sdd.delete_ptr = (0 == branch))) { brkcnt_list_.pop_front(); set_error( make_error(parser_error::e_syntax, current_token_, "ERR48 - Failed to parse body of repeat until loop")); return error_node(); } } if (!token_is(token_t::e_lbracket)) { brkcnt_list_.pop_front(); set_error( make_error(parser_error::e_syntax, current_token_, "ERR49 - Expected '(' before condition statement of repeat until loop")); 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_, "ERR50 - Failed to parse condition for repeat until loop")); free_node(node_allocator_,branch); return error_node(); } else if (!token_is(token_t::e_rbracket)) { set_error( make_error(parser_error::e_syntax, current_token_, "ERR51 - Expected ')' after condition of repeat until loop")); free_node(node_allocator_, branch); free_node(node_allocator_, condition); brkcnt_list_.pop_front(); return error_node(); } expression_node_ptr result; result = expression_generator_ .repeat_until_loop(condition,branch,brkcnt_list_.front()); if (0 == result) { set_error( make_error(parser_error::e_syntax, current_token_, "ERR52 - Failed to synthesize repeat until loop")); 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; std::string loop_counter_symbol; next_token(); scope_handler sh(*this); if (!token_is(token_t::e_lbracket)) { set_error( make_error(parser_error::e_syntax, current_token_, "ERR53 - Expected '(' at start of for-loop")); return error_node(); } if (!token_is(token_t::e_eof)) { if ( !token_is(token_t::e_symbol,false) && details::imatch(current_token_.value,"var") ) { next_token(); if (!token_is(token_t::e_symbol,false)) { set_error( make_error(parser_error::e_syntax, current_token_, "ERR54 - Expected a variable at the start of initialiser section of for-loop")); return error_node(); } else if (!peek_token_is(token_t::e_assign)) { set_error( make_error(parser_error::e_syntax, current_token_, "ERR55 - Expected variable assignment of initialiser section of for-loop")); return error_node(); } 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_, "ERR56 - For-loop variable '" + loop_counter_symbol+ "' is being shadowed by a previous declaration")); return error_node(); } else if (!symbol_table_.is_variable(loop_counter_symbol)) { if ( !se->active && (se->name == loop_counter_symbol) && (se->type == scope_element::e_variable) ) { se->active = true; se->ref_count++; } else { scope_element nse; nse.name = loop_counter_symbol; nse.type = scope_element::e_variable; nse.depth = scope_depth_; nse.data = new T(T(0)); nse.var_node = new variable_node_t(*(T*)(nse.data)); if (!sem_.add_element(nse)) { set_error( make_error(parser_error::e_syntax, current_token_, "ERR57 - Failed to add new local variable '" + loop_counter_symbol + "' to SEM")); result = false; } else exprtk_debug(("parse_for_loop() - INFO - Added new local variable: %s\n",nse.name.c_str())); } } } if (0 == (initialiser = parse_expression())) { set_error( make_error(parser_error::e_syntax, current_token_, "ERR58 - Failed to parse initialiser of for-loop")); result = false; } if (!token_is(token_t::e_eof)) { set_error( make_error(parser_error::e_syntax, current_token_, "ERR59 - Expected ';' after initialiser of for-loop")); result = false; } } if (!token_is(token_t::e_eof)) { if (0 == (condition = parse_expression())) { set_error( make_error(parser_error::e_syntax, current_token_, "ERR60 - Failed to parse condition of for-loop")); result = false; } else if (!token_is(token_t::e_eof)) { set_error( make_error(parser_error::e_syntax, current_token_, "ERR61 - Expected ';' after condition section of for-loop")); result = false; } } if (!token_is(token_t::e_rbracket)) { if (0 == (incrementor = parse_expression())) { set_error( make_error(parser_error::e_syntax, current_token_, "ERR62 - Failed to parse incrementor of for-loop")); result = false; } else if (!token_is(token_t::e_rbracket)) { set_error( make_error(parser_error::e_syntax, current_token_, "ERR63 - Expected ')' after incrementor section of for-loop")); result = false; } } if (result) { brkcnt_list_.push_front(false); if (0 == (loop_body = parse_multi_sequence("for-loop"))) { set_error( make_error(parser_error::e_syntax, current_token_, "ERR64 - Failed to parse body of for-loop")); result = false; } } if (!result) { if (se) { se->ref_count--; } sem_.cleanup(); 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_, "ERR65 - Expected keyword 'switch'")); 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_, "ERR66 - Expected '{' for call to switch statement")); return error_node(); } for ( ; ; ) { if (!details::imatch("case",current_token_.value)) { set_error( make_error(parser_error::e_syntax, current_token_, "ERR67 - Expected either a 'case' or 'default' statement")); return error_node(); } 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_, "ERR68 - Expected ':' for case of switch statement")); return error_node(); } expression_node_ptr consequent = parse_expression(); if (0 == consequent) return error_node(); else if (!token_is(token_t::e_eof)) { set_error( make_error(parser_error::e_syntax, current_token_, "ERR69 - Expected ';' at end of case for switch statement")); return error_node(); } // Can we optimize away the case statement? if (is_constant_node(condition) && is_false(condition)) { free_node(node_allocator_, condition); free_node(node_allocator_,consequent); condition = 0; consequent = 0; } else { arg_list.push_back(condition); arg_list.push_back(consequent); } if (details::imatch("default",current_token_.value)) { next_token(); if (!token_is(token_t::e_colon)) { set_error( make_error(parser_error::e_syntax, current_token_, "ERR70 - Expected ':' for default of switch statement")); return error_node(); } expression_node_ptr 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_, "ERR71 - Expected ';' at end of default for switch statement")); return error_node(); } arg_list.push_back(default_statement); break; } } if (!token_is(token_t::e_rcrlbracket)) { set_error( make_error(parser_error::e_syntax, current_token_, "ERR72 - Expected '}' at end of switch statement")); return error_node(); } result = expression_generator_.switch_statement(arg_list); svd.delete_ptr = (0 == result); return result; } inline expression_node_ptr parse_multi_switch_statement() { std::vector arg_list; expression_node_ptr result = error_node(); if (!details::imatch(current_token_.value,"[*]")) { set_error( make_error(parser_error::e_syntax, current_token_, "ERR73 - Expected token '[*]'")); 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_, "ERR74 - Expected '{' for call to [*] statement")); return error_node(); } for ( ; ; ) { if (!details::imatch("case",current_token_.value)) { set_error( make_error(parser_error::e_syntax, current_token_, "ERR75 - Expected a 'case' statement for multi-switch")); 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_, "ERR76 - Expected ':' for case of [*] statement")); 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_, "ERR77 - Expected ';' at end of case for [*] statement")); return error_node(); } // Can we optimize away the case statement? if (is_constant_node(condition) && is_false(condition)) { free_node(node_allocator_, condition); free_node(node_allocator_,consequent); condition = 0; consequent = 0; } else { arg_list.push_back(condition); arg_list.push_back(consequent); } if (token_is(token_t::e_rcrlbracket,false)) { break; } } if (!token_is(token_t::e_rcrlbracket)) { set_error( make_error(parser_error::e_syntax, current_token_, "ERR78 - Expected '}' at end of [*] statement")); return error_node(); } 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; expression_node_ptr result = error_node(); 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_, "ERR79 - Unsupported vararg function: " + symbol)); return error_node(); } scoped_vec_delete sdd(*this,arg_list); next_token(); if (!token_is(token_t::e_lbracket)) { set_error( make_error(parser_error::e_syntax, current_token_, "ERR80 - Expected '(' for call to vararg function: " + symbol)); 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_, "ERR81 - Expected ',' for call to vararg function: " + symbol)); return error_node(); } } result = expression_generator_.vararg_function(opt_type,arg_list); sdd.delete_ptr = (0 == result); return result; } 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_, "ERR82 - Expected '[' as start of string range definition")); 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_, "ERR83 - Failed to generate string range node")); free_node(node_allocator_,expression); } rp.clear(); return result; } inline void parse_pending_string_rangesize(expression_node_ptr& expression) { const std::size_t max_rangesize_parses = 100; std::size_t i = 0; while ( (0 != expression) && (i++ < max_rangesize_parses) && error_list_.empty() && token_is(token_t::e_lsqrbracket,false) && is_generally_string_node(expression) ) { expression = parse_string_range_statement(expression); } } template class Sequence> inline expression_node_ptr simplify(Sequence& expression_list) { if (expression_list.empty()) return error_node(); else if (1 == expression_list.size()) return expression_list[0]; Sequence tmp_expression_list; for (std::size_t i = 0; i < (expression_list.size() - 1); ++i) { if (is_variable_node(expression_list[i])) continue; else if ( is_constant_node(expression_list[i]) || is_null_node (expression_list[i]) ) { free_node(node_allocator_,expression_list[i]); continue; } else tmp_expression_list.push_back(expression_list[i]); } tmp_expression_list.push_back(expression_list.back()); expression_list.swap(tmp_expression_list); if (1 == expression_list.size()) return expression_list[0]; 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_, "ERR84 - Expected '" + token_t::to_str(close_bracket) + "' for call to multi-sequence" + ((!source.empty()) ? std::string(" section of " + source): ""))); return error_node(); } } else if (token_is(token_t::e_rcrlbracket)) { return node_allocator_.allocate >(); } std::vector arg_list; expression_node_ptr result = error_node(); scoped_vec_delete sdd(*this,arg_list); scope_handler sh(*this); for (;;) { expression_node_ptr arg = parse_expression(); if (0 == arg) return error_node(); else arg_list.push_back(arg); if (token_is(close_bracket)) break; 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_, "ERR85 - Expected '" + details::to_str(seperator) + "' for call to multi-sequence section of " + source)); return error_node(); } if (token_is(close_bracket)) break; } result = simplify(arg_list); 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_, "ERR86 - Expected '[' for start of range")); 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_, "ERR87 - Failed parse begin section of range")); return false; } else if (is_constant_node(r0)) { 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_, "ERR88 - Range lower bound less than zero! Constraint: r0 >= 0")); 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_, "ERR89 - Expected ':' for break in range")); 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_, "ERR90 - Failed parse end section of range")); rp.free(); return false; } else if (is_constant_node(r1)) { 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_, "ERR91 - Range upper bound less than zero! Constraint: r1 >= 0")); 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_, "ERR92 - Expected ']' for start of range")); rp.free(); return false; } } if (rp.const_range()) { std::size_t r0 = 0; std::size_t r1 = 0; bool rp_result = rp(r0,r1); if (!rp_result || (r0 > r1)) { set_error( make_error(parser_error::e_syntax, current_token_, "ERR93 - Invalid range, Constraint: r0 <= r1")); return false; } } return true; } inline void lodge_symbol(const std::string& symbol, const symbol_type st) { dec_.add_symbol(symbol,st); } inline expression_node_ptr parse_string() { const std::string symbol = current_token_.value; if (!symbol_table_.is_conststr_stringvar(symbol)) { set_error( make_error(parser_error::e_syntax, current_token_, "ERR94 - Unknown string symbol")); return error_node(); } expression_node_ptr result = symbol_table_.get_stringvar(symbol); typedef details::stringvar_node* strvar_node_t; strvar_node_t const_str_node = static_cast(0); const bool is_const_string = symbol_table_.is_constant_string(symbol); if (is_const_string) { 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; } 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); 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_, "ERR95 - Overflow in range for string: '" + const_str + "'[" + (rp.n0_c.first ? details::to_str(rp.n0_c.second) : "?") + ":" + (rp.n1_c.first ? details::to_str(rp.n1_c.second) : "?") + "]")); return error_node(); } result = expression_generator_(const_str,rp); if (result) rp.clear(); } else next_token(); return result; } 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_element(symbol); if ( (se.name != symbol) || (se.depth > scope_depth_) || (scope_element::e_vector != se.type) ) { if (0 == (vec = symbol_table_.get_vector(symbol))) { set_error( make_error(parser_error::e_syntax, current_token_, "ERR96 - Symbol '" + symbol+ " not a vector")); 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_, "ERR97 - Failed to parse index for vector: '" + symbol + "'")); return error_node(); } else if (!token_is(token_t::e_rsqrbracket)) { set_error( make_error(parser_error::e_syntax, current_token_, "ERR98 - Expected ']' for index of vector: '" + symbol + "'")); 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)) { for ( ; ; ) { expression_node_ptr arg = parse_expression(); if (0 == arg) return error_node(); else arg_list.push_back(arg); if (token_is(token_t::e_rbracket)) break; else if (!token_is(token_t::e_comma)) { set_error( make_error(parser_error::e_syntax, current_token_, "ERR99 - Expected ',' for call to vararg function: " + vararg_function_name)); return error_node(); } } } } result = expression_generator_.vararg_function_call(vararg_function,arg_list); sdd.delete_ptr = (0 == result); return result; } class type_checker { public: typedef parser parser_t; typedef std::vector param_seq_list_t; type_checker(parser_t& p, const std::string& func_name, const std::string& param_seq) : invalid_state_(true), parser_(p), function_name_(func_name) { split(param_seq); } bool verify(const std::string& param_seq, std::size_t& pseq_index) { if (param_seq_list_.empty()) return true; std::vector > error_list; for (std::size_t i = 0; i < param_seq_list_.size(); ++i) { std::size_t diff_index = 0; char diff_value = 0; bool result = details::sequence_match(param_seq_list_[i], 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(), "ERR100 - Failed parameter type check for function '" + function_name_ + "', " "Expected '" + param_seq_list_[0] + "' call set: '" + param_seq +"'")); } 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(), "ERR101 - Failed parameter type check for function '" + function_name_ + "', " "Best match: '" + param_seq_list_[max_diff_index] + "' call set: '" + param_seq +"'")); } return false; } std::size_t paramseq_count() const { return param_seq_list_.size(); } std::string paramseq(const std::size_t& index) const { return param_seq_list_[index]; } bool invalid() const { return !invalid_state_; } private: void split(const std::string& s) { if (s.empty()) return; std::size_t start = 0; std::size_t end = 0; param_seq_list_t param_seq_list; struct token_validator { static inline bool process(const std::string& str, std::size_t s, std::size_t e, param_seq_list_t& psl) { if ( (e - s) && (std::string::npos == str.find("?*")) && (std::string::npos == str.find("**")) ) { const std::string curr_str = str.substr(s,e - s); if (std::string::npos == curr_str.find_first_not_of("STV*?|")) { psl.push_back(curr_str); return true; } } return false; } }; while (std::string::npos != (end = s.find('|',start))) { if (!token_validator::process(s,start,end,param_seq_list)) { invalid_state_ = false; const std::string err_param_seq = s.substr(start,end - start); parser_. set_error( make_error(parser_error::e_syntax, parser_.current_token(), "ERR102 - Invalid parameter sequence of '" + err_param_seq + "' for function: " + function_name_)); return; } else start = end + 1; } if (start < s.size()) { if (token_validator::process(s,start,s.size(),param_seq_list)) param_seq_list_ = param_seq_list; else { const std::string err_param_seq = s.substr(start,s.size() - start); parser_. set_error( make_error(parser_error::e_syntax, parser_.current_token(), "ERR103 - Invalid parameter sequence of '" + err_param_seq + "' for function: " + function_name_)); return; } } } type_checker(const type_checker&); type_checker& operator=(const type_checker&); bool invalid_state_; parser_t& parser_; std::string function_name_; param_seq_list_t param_seq_list_; }; inline expression_node_ptr parse_generic_function_call(igeneric_function* function, const std::string& function_name) { std::vector arg_list; scoped_vec_delete sdd(*this,arg_list); next_token(); std::string param_type_list; type_checker tc(*this,function_name,function->parameter_sequence); if (tc.invalid()) { set_error( make_error(parser_error::e_syntax, current_token_, "ERR104 - Type checker instantiation failure for generic function: " + function_name)); return error_node(); } if (token_is(token_t::e_lbracket)) { if (!token_is(token_t::e_rbracket)) { for ( ; ; ) { expression_node_ptr arg = parse_expression(); if (0 == arg) return error_node(); if (is_ivector_node(arg)) param_type_list += 'V'; else if (is_generally_string_node(arg)) param_type_list += 'S'; else // Everything else is assumed to be scalar returning expression param_type_list += 'T'; 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_, "ERR105 - Expected ',' for call to generic function: " + function_name)); 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_, "ERR106 - Expected ',' for call to generic function: " + function_name)); 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 expression_node_ptr parse_string_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); if ( (!function->parameter_sequence.empty()) && (0 == tc.paramseq_count()) ) { return error_node(); } if (token_is(token_t::e_lbracket)) { if (!token_is(token_t::e_rbracket)) { 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 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_, "ERR107 - Expected ',' for call to string function: " + function_name)); 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_, "ERR108 - Expected ',' for call to string function: " + function_name)); 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; } template struct parse_special_function_impl { static inline expression_node_ptr process(parser& p,const details::operator_type opt_type) { 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(), "ERR109 - Expected '(' for special function")); 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(), "ERR110 - Expected ',' before next parameter of special function")); return p.error_node(); } } } if (!p.token_is(token_t::e_rbracket)) return p.error_node(); else result = p.expression_generator_.special_function(opt_type,branch); sd.delete_ptr = (0 == result); return result; } }; inline expression_node_ptr parse_special_function() { // Expect: $fDD(expr0,expr1,expr2) or $fDD(expr0,expr1,expr2,expr3) if ( !details::is_digit(current_token_.value[2]) || !details::is_digit(current_token_.value[3]) ) { set_error( make_error(parser_error::e_token, current_token_, "ERR111 - Invalid special function[1]: " + current_token_.value)); return error_node(); } const unsigned int id = (current_token_.value[2] - '0') * 10 + (current_token_.value[3] - '0'); if (id >= details::e_sffinal) { set_error( make_error(parser_error::e_token, current_token_, "ERR112 - Invalid special function[2]: " + current_token_.value)); return error_node(); } const std::size_t sf_3_to_4 = details::e_sf48; const details::operator_type opt_type = details::operator_type(id + 1000); const std::size_t NumberOfParameters = (id < (sf_3_to_4 - 1000)) ? 3 : 4; switch (NumberOfParameters) { case 3 : return parse_special_function_impl::process(*this,opt_type); case 4 : return parse_special_function_impl::process(*this,opt_type); default : return error_node(); } } 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 (!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_, "ERR113 - Failed to parse return expression for 'break' statement")); return error_node(); } else if (!token_is(token_t::e_rsqrbracket)) { set_error( make_error(parser_error::e_syntax, current_token_, "ERR114 - Expected ']' at the completion of break's return expression")); free_node(node_allocator_,return_expr); return error_node(); } } return node_allocator_.allocate >(return_expr); } else { set_error( make_error(parser_error::e_syntax, current_token_, "ERR115 - Invalid use of 'break', allowed only in the scope of a loop")); } return error_node(); } inline expression_node_ptr parse_continue_statement() { if (!brkcnt_list_.empty()) { next_token(); brkcnt_list_.front() = true; return node_allocator_.allocate >(); } else { set_error( make_error(parser_error::e_syntax, current_token_, "ERR116 - Invalid use of 'continue', allowed only in the scope of a loop")); return error_node(); } } #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_, "ERR117 - Expected '[' as part of vector size definition")); return error_node(); } else if (0 == (size_expr = parse_expression())) { set_error( make_error(parser_error::e_syntax, current_token_, "ERR118 - Failed to determine size of vector '" + vec_name + "'")); return error_node(); } else if (!is_constant_node(size_expr)) { free_node(node_allocator_,size_expr); set_error( make_error(parser_error::e_syntax, current_token_, "ERR119 - Expected a literal number as size of vector '" + vec_name + "'")); return error_node(); } T vector_size = size_expr->value(); free_node(node_allocator_,size_expr); if ( (vector_size <= T(0)) || std::not_equal_to() (T(0),vector_size - details::numeric::trunc(vector_size)) ) { set_error( make_error(parser_error::e_syntax, current_token_, "ERR120 - Invalid vector size. Must be an integer greater than zero, size: " + details::to_str(details::numeric::to_int32(vector_size)))); return error_node(); } std::vector vec_initilizer_list; scoped_vec_delete svd(*this,vec_initilizer_list); bool single_value_initialiser = false; if (!token_is(token_t::e_rsqrbracket)) { set_error( make_error(parser_error::e_syntax, current_token_, "ERR121 - Expected ']' as part of vector size definition")); 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_, "ERR122 - Expected ':=' as part of vector definition")); return error_node(); } else if (token_is(token_t::e_lsqrbracket)) { expression_node_ptr initialiser = parse_expression(); if (0 == initialiser) { set_error( make_error(parser_error::e_syntax, current_token_, "ERR123 - Failed to parse single vector initialiser")); return error_node(); } vec_initilizer_list.push_back(initialiser); if (!token_is(token_t::e_rsqrbracket)) { set_error( make_error(parser_error::e_syntax, current_token_, "ERR124 - Expected ']' to close single value vector initialiser")); return error_node(); } single_value_initialiser = true; } else if (!token_is(token_t::e_lcrlbracket)) { set_error( make_error(parser_error::e_syntax, current_token_, "ERR125 - Expected '{' as part of vector initialiser list")); return error_node(); } else if (!token_is(token_t::e_rcrlbracket)) { for (;;) { expression_node_ptr initialiser = parse_expression(); if (0 == initialiser) { set_error( make_error(parser_error::e_syntax, current_token_, "ERR126 - Expected '{' as part of vector initialiser list")); return error_node(); } else vec_initilizer_list.push_back(initialiser); if (token_is(token_t::e_rcrlbracket)) break; bool is_next_close = peek_token_is(token_t::e_rcrlbracket); if (!token_is(token_t::e_comma) && is_next_close) { set_error( make_error(parser_error::e_syntax, current_token_, "ERR127 - Expected ',' between vector initialisers")); return error_node(); } if (token_is(token_t::e_rcrlbracket)) break; } } if ( !token_is(token_t::e_rbracket ,false) && !token_is(token_t::e_rcrlbracket,false) && !token_is(token_t::e_rsqrbracket,false) ) { if (!token_is(token_t::e_eof)) { set_error( make_error(parser_error::e_syntax, current_token_, "ERR128 - Expected ';' at end of vector definition")); return error_node(); } } if (vec_initilizer_list.size() > vector_size) { set_error( make_error(parser_error::e_syntax, current_token_, "ERR129 - Initialiser list larger than the number of elements in the vector: '" + vec_name + "'")); return error_node(); } } typename symbol_table_t::vector_holder_ptr vec_holder = typename symbol_table_t::vector_holder_ptr(0); std::size_t vec_size = static_cast(details::numeric::to_int32(vector_size)); scope_element& se = sem_.get_element(vec_name); if (se.name == vec_name) { if (se.active) { set_error( make_error(parser_error::e_syntax, current_token_, "ERR130 - Illegal redefinition of local vector: '" + vec_name + "'")); return error_node(); } else if ( (se.size == vec_size) && (scope_element::e_vector == se.type) ) { vec_holder = se.vec_node; se.active = true; se.ref_count++; } } if (0 == vec_holder) { scope_element nse; nse.name = vec_name; nse.type = scope_element::e_vector; nse.depth = scope_depth_; nse.size = vec_size; nse.data = new T[vec_size]; nse.vec_node = new typename scope_element::vector_holder_t((T*)(nse.data),nse.size); if (!sem_.add_element(nse)) { set_error( make_error(parser_error::e_syntax, current_token_, "ERR131 - Failed to add new local vector '" + vec_name + "' to SEM")); 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))); } lodge_symbol(vec_name,e_st_local_vector); expression_node_ptr result = node_allocator_ .allocate >( (*vec_holder)[0], vec_size, vec_initilizer_list, single_value_initialiser); svd.delete_ptr = (0 == result); return result; } 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 (vardef_disabled_) { set_error( make_error(parser_error::e_syntax, current_token_, "ERR132 - Illegal variable definition")); 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_, "ERR133 - Expected a symbol for variable definition")); return error_node(); } else if (details::is_reserved_symbol(var_name)) { set_error( make_error(parser_error::e_syntax, current_token_, "ERR134 - Illegal redefinition of reserved keyword: '" + var_name + "'")); return error_node(); } else if (symbol_table_.symbol_exists(var_name)) { set_error( make_error(parser_error::e_syntax, current_token_, "ERR135 - Illegal redefinition of variable '" + var_name + "'")); return error_node(); } else if (local_variable_is_shadowed(var_name)) { set_error( make_error(parser_error::e_syntax, current_token_, "ERR136 - Illegal redefinition of local variable: '" + var_name + "'")); return error_node(); } else if (token_is(token_t::e_lsqrbracket,false)) { return parse_define_vector_statement(var_name); } else if (token_is(token_t::e_lcrlbracket,false)) { 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_, "ERR137 - Failed to parse initialisation expression")); return error_node(); } } if ( !token_is(token_t::e_rbracket ,false) && !token_is(token_t::e_rcrlbracket,false) && !token_is(token_t::e_rsqrbracket,false) ) { if (!token_is(token_t::e_eof,false)) { set_error( make_error(parser_error::e_syntax, current_token_, "ERR138 - Expected ';' after variable definition")); free_node(node_allocator_,initialisation_expression); return error_node(); } } variable_node_t* 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_, "ERR139 - Illegal redefinition of local variable: '" + var_name + "'")); 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.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 = scope_depth_; nse.data = new T(T(0)); nse.var_node = new variable_node_t(*(T*)(nse.data)); if (!sem_.add_element(nse)) { set_error( make_error(parser_error::e_syntax, current_token_, "ERR140 - Failed to add new local variable '" + var_name + "' to SEM")); free_node(node_allocator_,initialisation_expression); return error_node(); } var_node = nse.var_node; exprtk_debug(("parse_define_var_statement() - INFO - Added new local variable: %s\n",nse.name.c_str())); } 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_, "ERR141 - Expected a '{}' for uninitialised var definition")); return error_node(); } else if (!token_is(token_t::e_eof,false)) { set_error( make_error(parser_error::e_syntax, current_token_, "ERR142 - Expected ';' after uninitialised variable definition")); return error_node(); } variable_node_t* 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_, "ERR143 - Illegal redefinition of local variable: '" + var_name + "'")); 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 = scope_depth_; nse.ip_index = sem_.next_ip_index(); nse.data = new T(T(0)); nse.var_node = new variable_node_t(*(T*)(nse.data)); if (!sem_.add_element(nse)) { set_error( make_error(parser_error::e_syntax, current_token_, "ERR144 - Failed to add new local variable '" + var_name + "' to SEM")); 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); 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_, "ERR145 - Expected '(' at start of swap statement")); 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,false)) { set_error( make_error(parser_error::e_syntax, current_token_, "ERR146 - Expected a symbol for variable or vector element definition")); 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_, "ERR147 - First parameter to swap is an invalid vector element: '" + var0_name + "'")); return error_node(); } variable0_generated = true; } else { if (symbol_table_.is_variable(var0_name)) { variable0 = symbol_table_.get_variable(var0_name); } 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_, "ERR148 - First parameter to swap is an invalid variable: '" + var0_name + "'")); return error_node(); } else next_token(); } if (!token_is(token_t::e_comma)) { set_error( make_error(parser_error::e_syntax, current_token(), "ERR149 - Expected ',' between parameters to swap")); 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,false)) { set_error( make_error(parser_error::e_syntax, current_token_, "ERR150 - Expected a symbol for variable or vector element definition")); if (variable0_generated) { free_node(node_allocator_,variable0); } return error_node(); } else if (peek_token_is(token_t::e_lsqrbracket)) { if (0 == (variable1 = parse_vector())) { set_error( make_error(parser_error::e_syntax, current_token_, "ERR151 - Second parameter to swap is an invalid vector element: '" + var1_name + "'")); if (variable0_generated) { free_node(node_allocator_,variable0); } return error_node(); } variable1_generated = true; } else { if (symbol_table_.is_variable(var1_name)) { variable1 = symbol_table_.get_variable(var1_name); } 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_, "ERR152 - Second parameter to swap is an invalid variable: '" + var1_name + "'")); 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_, "ERR153 - Expected ')' at end of swap statement")); 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); if ( (0 != (v0 = dynamic_cast(variable0))) && (0 != (v1 = dynamic_cast(variable1))) ) { expression_node_ptr result = node_allocator_.allocate >(v0,v1); if (variable0_generated) { free_node(node_allocator_,variable0); } if (variable1_generated) { free_node(node_allocator_,variable1); } return result; } else return node_allocator_.allocate >(variable0,variable1); } inline bool post_variable_process(const std::string& symbol) { if ( peek_token_is(token_t::e_lbracket ) || peek_token_is(token_t::e_lcrlbracket) || peek_token_is(token_t::e_lsqrbracket) ) { if (!commutative_check_enabled()) { set_error( make_error(parser_error::e_syntax, current_token_, "ERR154 - Invalid sequence of variable '"+ symbol + "' and bracket")); 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 (is_generally_string_node(branch)) return true; switch (token) { case token_t::e_lcrlbracket : implied_mul = token_is(token_t::e_lbracket ,false) || token_is(token_t::e_lcrlbracket,false) || token_is(token_t::e_lsqrbracket,false) ; break; case token_t::e_lbracket : implied_mul = token_is(token_t::e_lbracket ,false) || token_is(token_t::e_lcrlbracket,false) || token_is(token_t::e_lsqrbracket,false) ; break; case token_t::e_lsqrbracket : implied_mul = token_is(token_t::e_lbracket ,false) || token_is(token_t::e_lcrlbracket,false) || token_is(token_t::e_lsqrbracket,false) ; break; default : return true; } if (implied_mul) { if (!commutative_check_enabled()) { set_error( make_error(parser_error::e_syntax, current_token_, "ERR155 - Invalid sequence of brackets")); 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 = symbol_table_.get_variable(symbol); if (variable) { if (symbol_table_.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 or vector? if (!sem_.empty()) { scope_element& se = sem_.get_element(symbol); if (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 // Are we dealing with a string variable? if (symbol_table_.is_stringvar(symbol)) { return parse_string(); } #endif { // Are we dealing with a function? ifunction* function = symbol_table_.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_, "ERR156 - Failed to generate node for function: '" + symbol + "'")); return error_node(); } } } { // Are we dealing with a vararg function? ivararg_function* vararg_function = symbol_table_.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_, "ERR157 - Failed to generate node for vararg function: '" + symbol + "'")); return error_node(); } } } { // Are we dealing with a vararg generic function? igeneric_function* generic_function = symbol_table_.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_, "ERR158 - Failed to generate node for generic function: '" + symbol + "'")); return error_node(); } } } { // Are we dealing with a vararg string returing function? igeneric_function* string_function = symbol_table_.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_, "ERR159 - Failed to generate node for string function: '" + symbol + "'")); return error_node(); } } } // Are we dealing with a vector element? if (symbol_table_.is_vector(symbol)) { lodge_symbol(symbol,e_st_vector); return parse_vector(); } if (details::is_reserved_symbol(symbol)) { set_error( make_error(parser_error::e_syntax, current_token_, "ERR160 - Invalid use of reserved symbol '" + symbol + "'")); return error_node(); } // Should we handle unknown symbols? if (resolve_unknown_symbol_ && unknown_symbol_resolver_) { T default_value = T(0); std::string error_message; typename unknown_symbol_resolver::usr_symbol_type usr_symbol_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 = symbol_table_.create_variable(symbol,default_value); break; case unknown_symbol_resolver::e_usr_constant_type : create_result = symbol_table_.add_constant(symbol,default_value); break; default : create_result = false; } if (create_result) { expression_node_ptr var = symbol_table_.get_variable(symbol); if (var) { if (symbol_table_.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_, "ERR161 - Failed to create variable: '" + symbol + "'")); return error_node(); } } set_error( make_error(parser_error::e_syntax, current_token_, "ERR162 - Undefined symbol: '" + symbol + "'")); return error_node(); } inline expression_node_ptr parse_symbol() { static const std::string symbol_if = "if" ; static const std::string symbol_while = "while" ; static const std::string symbol_repeat = "repeat" ; static const std::string symbol_for = "for" ; static const std::string symbol_switch = "switch" ; static const std::string symbol_null = "null" ; static const std::string symbol_break = "break" ; static const std::string symbol_continue = "continue"; static const std::string symbol_var = "var" ; static const std::string symbol_swap = "swap" ; if (valid_vararg_operation(current_token_.value)) { return parse_vararg_function(); } else if (valid_base_operation(current_token_.value)) { return parse_base_operation(); } else if (details::imatch(current_token_.value,symbol_if)) { return parse_conditional_statement(); } else if (details::imatch(current_token_.value,symbol_while)) { return parse_while_loop(); } else if (details::imatch(current_token_.value,symbol_repeat)) { return parse_repeat_until_loop(); } else if (details::imatch(current_token_.value,symbol_for)) { return parse_for_loop(); } else if (details::imatch(current_token_.value,symbol_switch)) { return parse_switch_statement(); } else if (details::is_valid_sf_symbol(current_token_.value)) { return parse_special_function(); } else if (details::imatch(current_token_.value,symbol_null)) { return parse_null_statement(); } #ifndef exprtk_disable_break_continue else if (details::imatch(current_token_.value,symbol_break)) { return parse_break_statement(); } else if (details::imatch(current_token_.value,symbol_continue)) { return parse_continue_statement(); } #endif else if (details::imatch(current_token_.value,symbol_var)) { return parse_define_var_statement(); } else if (details::imatch(current_token_.value,symbol_swap)) { return parse_swap_statement(); } else if (symbol_table_.valid() || !sem_.empty()) { return parse_symtab_symbol(); } else { set_error( make_error(parser_error::e_symtab, current_token_, "ERR163 - Variable or function detected, yet symbol-table is invalid, Symbol: " + current_token_.value)); return error_node(); } } inline expression_node_ptr parse_branch(precedence_level precedence = e_level00) { 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); next_token(); branch = literal_exp; } else { set_error( make_error(parser_error::e_numeric, current_token_, "ERR164 - Failed to convert '" + current_token_.value + "' to a number")); 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_, "ERR165 - Expected ')' instead of: '" + current_token_.value + "'")); free_node(node_allocator_,branch); return error_node(); } else if (!post_bracket_process(token_t::e_lbracket,branch)) { 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_, "ERR166 - Expected ']' instead of: '" + current_token_.value + "'")); free_node(node_allocator_,branch); return error_node(); } else if (!post_bracket_process(token_t::e_lsqrbracket,branch)) { 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_, "ERR167 - Expected '}' instead of: '" + current_token_.value + "'")); free_node(node_allocator_,branch); return error_node(); } else if (!post_bracket_process(token_t::e_lcrlbracket,branch)) { 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) ) ) { branch = expression_generator_(details::e_neg,branch); } } else if (token_t::e_add == current_token_.type) { next_token(); branch = parse_expression(e_level13); } else if (token_t::e_eof == current_token_.type) { set_error( make_error(parser_error::e_syntax, current_token_, "ERR168 - Premature end of expression[1]")); return error_node(); } else { set_error( make_error(parser_error::e_syntax, current_token_, "ERR169 - Premature end of expression[2]")); return error_node(); } if ( branch && (e_level00 == precedence) && token_is(token_t::e_ternary,false) ) { branch = parse_ternary_conditional_statement(branch); } parse_pending_string_rangesize(branch); return branch; } inline bool token_is(const typename token_t::token_type& ttype, const bool advance_token = true) { if (current_token_.type != ttype) { return false; } if (advance_token) { next_token(); } return true; } inline bool peek_token_is(const typename token_t::token_type& ttype) { return (lexer_.peek_next_token().type == ttype); } inline bool peek_token_is(const std::string& s) { return (details::imatch(lexer_.peek_next_token().value,s)); } 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) { return (*inv_binary_op_map_).find(bop)->second; } inline expression_node_ptr operator()(const Type& v) const { return node_allocator_->allocate(v); } 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(); } inline bool unary_optimizable(const details::operator_type& operation) const { return (details::e_abs == operation) || (details::e_acos == operation) || (details::e_acosh == operation) || (details::e_asin == operation) || (details::e_asinh == operation) || (details::e_atan == operation) || (details::e_atanh == operation) || (details::e_ceil == operation) || (details::e_cos == operation) || (details::e_cosh == operation) || (details::e_exp == operation) || (details::e_expm1 == operation) || (details::e_floor == operation) || (details::e_log == operation) || (details::e_log10 == operation) || (details::e_log2 == operation) || (details::e_log1p == operation) || (details::e_neg == operation) || (details::e_pos == operation) || (details::e_round == operation) || (details::e_sin == operation) || (details::e_sinc == operation) || (details::e_sinh == operation) || (details::e_sqrt == operation) || (details::e_tan == operation) || (details::e_tanh == operation) || (details::e_cot == operation) || (details::e_sec == operation) || (details::e_csc == operation) || (details::e_r2d == operation) || (details::e_d2r == operation) || (details::e_d2g == operation) || (details::e_g2d == operation) || (details::e_notl == operation) || (details::e_sgn == operation) || (details::e_erf == operation) || (details::e_erfc == operation) || (details::e_ncdf == operation) || (details::e_frac == operation) || (details::e_trunc == operation); } inline bool sf3_optimizable(const std::string& sf3id, trinary_functor_t& tfunc) { typename sf3_map_t::iterator itr = sf3_map_->find(sf3id); if (sf3_map_->end() == itr) return false; else tfunc = itr->second.first; return true; } inline bool sf4_optimizable(const std::string& sf4id, quaternary_functor_t& qfunc) { typename sf4_map_t::iterator itr = sf4_map_->find(sf4id); if (sf4_map_->end() == itr) return false; else qfunc = itr->second.first; return true; } inline bool sf3_optimizable(const std::string& sf3id, details::operator_type& operation) { typename sf3_map_t::iterator itr = sf3_map_->find(sf3id); if (sf3_map_->end() == itr) return false; else operation = itr->second.second; return true; } inline bool sf4_optimizable(const std::string& sf4id, details::operator_type& operation) { typename sf4_map_t::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_optimizable(operation) && details::is_variable_node(branch[0])) return synthesize_uv_expression(operation,branch); else if (unary_optimizable(operation) && details::is_ivector_node(branch[0])) return synthesize_uvec_expression(operation,branch); else return synthesize_unary_expression(operation,branch); } 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) ; } #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_optimizable(const details::operator_type& operation) const { return (details::e_add == operation) || (details::e_sub == operation) || (details::e_mul == operation) || (details::e_div == operation) || (details::e_mod == operation) || (details::e_pow == operation) || (details::e_lt == operation) || (details::e_lte == operation) || (details::e_gt == operation) || (details::e_gte == operation) || (details::e_eq == operation) || (details::e_ne == operation) || (details::e_and == operation) || (details::e_nand == operation) || (details::e_or == operation) || (details::e_nor == operation) || (details::e_xor == operation) || (details::e_xnor == operation) ; } inline std::string branch_to_id(expression_node_ptr branch) { static const std::string null_str ("(null)" ); static const std::string const_str ("(c)" ); static const std::string var_str ("(v)" ); static const std::string vov_str ("(vov)" ); static const std::string cov_str ("(cov)" ); static const std::string voc_str ("(voc)" ); static const std::string str_str ("(s)" ); static const std::string strrng_str ("(rngs)" ); static const std::string cs_str ("(cs)" ); static const std::string cstrrng_str("(crngs)"); 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]) { return branch_to_id(branch[0]) + std::string("o") + branch_to_id(branch[1]); } inline bool cov_optimizable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const { if (!operation_optimizable(operation)) return false; else return (details::is_constant_node(branch[0]) && details::is_variable_node(branch[1])); } inline bool voc_optimizable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const { if (!operation_optimizable(operation)) return false; else return (details::is_variable_node(branch[0]) && details::is_constant_node(branch[1])); } inline bool vov_optimizable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const { if (!operation_optimizable(operation)) return false; else return (details::is_variable_node(branch[0]) && details::is_variable_node(branch[1])); } inline bool cob_optimizable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const { if (!operation_optimizable(operation)) return false; else return (details::is_constant_node(branch[0]) && !details::is_constant_node(branch[1])); } inline bool boc_optimizable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const { if (!operation_optimizable(operation)) return false; else return (!details::is_constant_node(branch[0]) && details::is_constant_node(branch[1])); } inline bool cocob_optimizable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const { if ( (details::e_add == operation) || (details::e_sub == operation) || (details::e_mul == operation) || (details::e_div == operation) ) { 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_optimizable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const { if ( (details::e_add == operation) || (details::e_sub == operation) || (details::e_mul == operation) || (details::e_div == operation) ) { 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_optimizable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const { if (!operation_optimizable(operation)) return false; else return (details::is_uv_node(branch[0]) && details::is_uv_node(branch[1])); } inline bool vob_optimizable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const { if (!operation_optimizable(operation)) return false; else return (details::is_variable_node(branch[0]) && !details::is_variable_node(branch[1])); } inline bool bov_optimizable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const { if (!operation_optimizable(operation)) return false; else return (!details::is_variable_node(branch[0]) && details::is_variable_node(branch[1])); } inline bool binext_optimizable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const { if (!operation_optimizable(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]) { 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_vector_node (branch[0]) ) || b1_is_genstring; } else return false; } inline bool is_invalid_break_continue_op(expression_node_ptr (&branch)[2]) { 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 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 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 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 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) { return ( (details::e_scand == operation) || (details::e_scor == operation) ); } #else inline bool is_shortcircuit_expression(const details::operator_type&) { return false; } #endif inline bool is_null_present(expression_node_ptr (&branch)[2]) { return ( details::is_null_node(branch[0]) || details::is_null_node(branch[1]) ); } inline bool is_vector_eqineq_operation(const details::operator_type& operation, expression_node_ptr (&branch)[2]) { if (!is_ivector_node(branch[0]) && !is_ivector_node(branch[1])) return false; else return ( (details::e_lt == operation) || (details::e_lte == operation) || (details::e_gt == operation) || (details::e_gte == operation) || (details::e_eq == operation) || (details::e_ne == operation) ); } inline bool is_vector_arithmetic_operation(const details::operator_type& operation, expression_node_ptr (&branch)[2]) { if (!is_ivector_node(branch[0]) && !is_ivector_node(branch[1])) return false; else return ( (details::e_add == operation) || (details::e_sub == operation) || (details::e_mul == operation) || (details::e_div == operation) || (details::e_pow == operation) ); } inline expression_node_ptr operator()(const details::operator_type& operation, expression_node_ptr (&branch)[2]) { if ((0 == branch[0]) || (0 == branch[1])) return error_node(); else if (is_invalid_string_op(operation,branch)) return error_node(); else if (is_invalid_assignment_op(operation,branch)) return error_node(); else if (is_invalid_break_continue_op(branch)) return error_node(); else if (details::e_assign == operation) return synthesize_assignment_expression(operation,branch); else if (details::e_swap == operation) return synthesize_swap_expression(branch); else if (is_assignment_operation(operation)) return synthesize_assignment_operation_expression(operation,branch); else if (is_vector_eqineq_operation(operation,branch)) return synthesize_veceqineq_operation_expression(operation,branch); else if (is_vector_arithmetic_operation(operation,branch)) return synthesize_vecarithmetic_operation_expression(operation,branch); else if (is_shortcircuit_expression(operation)) return synthesize_shortcircuit_expression(operation,branch); else if (is_string_operation(operation,branch)) return synthesize_string_expression(operation,branch); else if (is_null_present(branch)) return synthesize_null_expression(operation,branch); expression_node_ptr result = error_node(); #ifndef exprtk_disable_enhanced_features if (synthesize_expression(operation,branch,result)) return result; else #endif { /* 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_optimizable(operation,branch)) result = synthesize_cocob_expression::process(*this,operation,branch); else if (coboc_optimizable(operation,branch) && (0 == result)) result = synthesize_coboc_expression::process(*this,operation,branch); if (result) return result; } if (uvouv_optimizable(operation,branch)) return synthesize_uvouv_expression(operation,branch); else if (vob_optimizable(operation,branch)) return synthesize_vob_expression::process(*this,operation,branch); else if (bov_optimizable(operation,branch)) return synthesize_bov_expression::process(*this,operation,branch); else if (cob_optimizable(operation,branch)) return synthesize_cob_expression::process(*this,operation,branch); else if (boc_optimizable(operation,branch)) return synthesize_boc_expression::process(*this,operation,branch); #ifndef exprtk_disable_enhanced_features else if (cov_optimizable(operation,branch)) return synthesize_cov_expression::process(*this,operation,branch); #endif else if (binext_optimizable(operation,branch)) return synthesize_binary_ext_expression::process(*this,operation,branch); else return synthesize_expression(operation,branch); } 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 (&branch)[5]) { return synthesize_expression(operation,branch); } inline expression_node_ptr operator()(const details::operator_type& operation, expression_node_ptr (&branch)[6]) { 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) { if ((0 == b0) || (0 == b1)) return error_node(); else { expression_node_ptr branch[2] = { b0, b1 }; return expression_generator::operator()(operation,branch); } } inline expression_node_ptr conditional(expression_node_ptr condition, expression_node_ptr consequent, expression_node_ptr alternative) const { if ((0 == condition) || (0 == consequent)) { free_node(*node_allocator_,condition ); free_node(*node_allocator_,consequent ); free_node(*node_allocator_,alternative); return error_node(); } // Can the condition be immediately evaluated? if so optimize. else if (details::is_constant_node(condition)) { // True branch if (details::is_true(condition)) { free_node(*node_allocator_,condition ); free_node(*node_allocator_,alternative); return consequent; } // False branch else { free_node(*node_allocator_,condition); 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); } inline expression_node_ptr while_loop(expression_node_ptr& condition, expression_node_ptr& branch, const bool brkcont = false) const { if (!brkcont && details::is_constant_node(condition)) { expression_node_ptr result = error_node(); if (details::is_true(condition)) // Infinite loops are not allowed. result = error_node(); else result = node_allocator_->allocate >(); free_node(*node_allocator_, condition); free_node(*node_allocator_, branch ); return result; } else if (details::is_null_node(condition)) { free_node(*node_allocator_,condition); return branch; } else if (!brkcont) return node_allocator_->allocate(condition,branch); #ifndef exprtk_disable_break_continue else return node_allocator_->allocate(condition,branch); #else return error_node(); #endif } inline expression_node_ptr repeat_until_loop(expression_node_ptr& condition, expression_node_ptr& branch, const bool brkcont = false) const { if (!brkcont && details::is_constant_node(condition)) { if (details::is_true(condition) && details::is_constant_node(branch)) { free_node(*node_allocator_,condition); return branch; } free_node(*node_allocator_, condition); free_node(*node_allocator_, branch ); return error_node(); } else if (details::is_null_node(condition)) { free_node(*node_allocator_,condition); return branch; } else if (!brkcont) return node_allocator_->allocate(condition,branch); #ifndef exprtk_disable_break_continue else return node_allocator_->allocate(condition,branch); #else return error_node(); #endif } inline expression_node_ptr for_loop(expression_node_ptr& initialiser, expression_node_ptr& condition, expression_node_ptr& incrementor, expression_node_ptr& loop_body, bool brkcont = false) const { if (!brkcont && details::is_constant_node(condition)) { expression_node_ptr result = error_node(); if (details::is_true(condition)) // Infinite loops are not allowed. result = error_node(); else result = node_allocator_->allocate >(); free_node(*node_allocator_,initialiser); free_node(*node_allocator_,condition ); free_node(*node_allocator_,incrementor); free_node(*node_allocator_,loop_body ); return result; } else if (details::is_null_node(condition)) { free_node(*node_allocator_,initialiser); free_node(*node_allocator_,condition ); free_node(*node_allocator_,incrementor); return loop_body; } else if (!brkcont) return node_allocator_->allocate(initialiser, condition, incrementor, loop_body); #ifndef exprtk_disable_break_continue else return node_allocator_->allocate(initialiser, condition, incrementor, loop_body); #else return error_node(); #endif } template class Sequence> inline expression_node_ptr const_optimize_switch(Sequence& arg_list) { 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_optimize_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)) { free_node(*node_allocator_,current_expr); } } return result; } template class Sequence> inline expression_node_ptr 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_optimize_switch(arg_list); else 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_optimize_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_optimize_sf3(const details::operator_type& operation, expression_node_ptr (&branch)[3]) { expression_node_ptr temp_node = error_node(); switch (operation) { #define case_stmt(op0,op1) \ case op0 : temp_node = node_allocator_-> \ allocate > > \ (operation,branch); \ break; \ case_stmt(details::e_sf00,details::sf00_op) case_stmt(details::e_sf01,details::sf01_op) case_stmt(details::e_sf02,details::sf02_op) case_stmt(details::e_sf03,details::sf03_op) case_stmt(details::e_sf04,details::sf04_op) case_stmt(details::e_sf05,details::sf05_op) case_stmt(details::e_sf06,details::sf06_op) case_stmt(details::e_sf07,details::sf07_op) case_stmt(details::e_sf08,details::sf08_op) case_stmt(details::e_sf09,details::sf09_op) case_stmt(details::e_sf10,details::sf10_op) case_stmt(details::e_sf11,details::sf11_op) case_stmt(details::e_sf12,details::sf12_op) case_stmt(details::e_sf13,details::sf13_op) case_stmt(details::e_sf14,details::sf14_op) case_stmt(details::e_sf15,details::sf15_op) case_stmt(details::e_sf16,details::sf16_op) case_stmt(details::e_sf17,details::sf17_op) case_stmt(details::e_sf18,details::sf18_op) case_stmt(details::e_sf19,details::sf19_op) case_stmt(details::e_sf20,details::sf20_op) case_stmt(details::e_sf21,details::sf21_op) case_stmt(details::e_sf22,details::sf22_op) case_stmt(details::e_sf23,details::sf23_op) case_stmt(details::e_sf24,details::sf24_op) case_stmt(details::e_sf25,details::sf25_op) case_stmt(details::e_sf26,details::sf26_op) case_stmt(details::e_sf27,details::sf27_op) case_stmt(details::e_sf28,details::sf28_op) case_stmt(details::e_sf29,details::sf29_op) case_stmt(details::e_sf30,details::sf30_op) case_stmt(details::e_sf31,details::sf31_op) case_stmt(details::e_sf32,details::sf32_op) case_stmt(details::e_sf33,details::sf33_op) case_stmt(details::e_sf34,details::sf34_op) case_stmt(details::e_sf35,details::sf35_op) case_stmt(details::e_sf36,details::sf36_op) case_stmt(details::e_sf37,details::sf37_op) case_stmt(details::e_sf38,details::sf38_op) case_stmt(details::e_sf39,details::sf39_op) case_stmt(details::e_sf40,details::sf40_op) case_stmt(details::e_sf41,details::sf41_op) case_stmt(details::e_sf42,details::sf42_op) case_stmt(details::e_sf43,details::sf43_op) case_stmt(details::e_sf44,details::sf44_op) case_stmt(details::e_sf45,details::sf45_op) case_stmt(details::e_sf46,details::sf46_op) case_stmt(details::e_sf47,details::sf47_op) #undef case_stmt default : return error_node(); } T v = temp_node->value(); node_allocator_->free(temp_node); details::free_node(*node_allocator_,temp_node); return node_allocator_->allocate(v); } inline expression_node_ptr varnode_optimize_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(op0,op1) \ case op0 : return node_allocator_-> \ allocate_rrr > > \ (v0,v1,v2); \ case_stmt(details::e_sf00,details::sf00_op) case_stmt(details::e_sf01,details::sf01_op) case_stmt(details::e_sf02,details::sf02_op) case_stmt(details::e_sf03,details::sf03_op) case_stmt(details::e_sf04,details::sf04_op) case_stmt(details::e_sf05,details::sf05_op) case_stmt(details::e_sf06,details::sf06_op) case_stmt(details::e_sf07,details::sf07_op) case_stmt(details::e_sf08,details::sf08_op) case_stmt(details::e_sf09,details::sf09_op) case_stmt(details::e_sf10,details::sf10_op) case_stmt(details::e_sf11,details::sf11_op) case_stmt(details::e_sf12,details::sf12_op) case_stmt(details::e_sf13,details::sf13_op) case_stmt(details::e_sf14,details::sf14_op) case_stmt(details::e_sf15,details::sf15_op) case_stmt(details::e_sf16,details::sf16_op) case_stmt(details::e_sf17,details::sf17_op) case_stmt(details::e_sf18,details::sf18_op) case_stmt(details::e_sf19,details::sf19_op) case_stmt(details::e_sf20,details::sf20_op) case_stmt(details::e_sf21,details::sf21_op) case_stmt(details::e_sf22,details::sf22_op) case_stmt(details::e_sf23,details::sf23_op) case_stmt(details::e_sf24,details::sf24_op) case_stmt(details::e_sf25,details::sf25_op) case_stmt(details::e_sf26,details::sf26_op) case_stmt(details::e_sf27,details::sf27_op) case_stmt(details::e_sf28,details::sf28_op) case_stmt(details::e_sf29,details::sf29_op) case_stmt(details::e_sf30,details::sf30_op) case_stmt(details::e_sf31,details::sf31_op) case_stmt(details::e_sf32,details::sf32_op) case_stmt(details::e_sf33,details::sf33_op) case_stmt(details::e_sf34,details::sf34_op) case_stmt(details::e_sf35,details::sf35_op) case_stmt(details::e_sf36,details::sf36_op) case_stmt(details::e_sf37,details::sf37_op) case_stmt(details::e_sf38,details::sf38_op) case_stmt(details::e_sf39,details::sf39_op) case_stmt(details::e_sf40,details::sf40_op) case_stmt(details::e_sf41,details::sf41_op) case_stmt(details::e_sf42,details::sf42_op) case_stmt(details::e_sf43,details::sf43_op) case_stmt(details::e_sf44,details::sf44_op) case_stmt(details::e_sf45,details::sf45_op) case_stmt(details::e_sf46,details::sf46_op) case_stmt(details::e_sf47,details::sf47_op) #undef case_stmt default : return error_node(); } } 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_optimize_sf3(operation,branch); else if (all_nodes_variables(branch)) return varnode_optimize_sf3(operation,branch); else { switch (operation) { #define case_stmt(op0,op1) \ case op0 : return node_allocator_-> \ allocate > >(operation,branch); \ case_stmt(details::e_sf00,details::sf00_op) case_stmt(details::e_sf01,details::sf01_op) case_stmt(details::e_sf02,details::sf02_op) case_stmt(details::e_sf03,details::sf03_op) case_stmt(details::e_sf04,details::sf04_op) case_stmt(details::e_sf05,details::sf05_op) case_stmt(details::e_sf06,details::sf06_op) case_stmt(details::e_sf07,details::sf07_op) case_stmt(details::e_sf08,details::sf08_op) case_stmt(details::e_sf09,details::sf09_op) case_stmt(details::e_sf10,details::sf10_op) case_stmt(details::e_sf11,details::sf11_op) case_stmt(details::e_sf12,details::sf12_op) case_stmt(details::e_sf13,details::sf13_op) case_stmt(details::e_sf14,details::sf14_op) case_stmt(details::e_sf15,details::sf15_op) case_stmt(details::e_sf16,details::sf16_op) case_stmt(details::e_sf17,details::sf17_op) case_stmt(details::e_sf18,details::sf18_op) case_stmt(details::e_sf19,details::sf19_op) case_stmt(details::e_sf20,details::sf20_op) case_stmt(details::e_sf21,details::sf21_op) case_stmt(details::e_sf22,details::sf22_op) case_stmt(details::e_sf23,details::sf23_op) case_stmt(details::e_sf24,details::sf24_op) case_stmt(details::e_sf25,details::sf25_op) case_stmt(details::e_sf26,details::sf26_op) case_stmt(details::e_sf27,details::sf27_op) case_stmt(details::e_sf28,details::sf28_op) case_stmt(details::e_sf29,details::sf29_op) case_stmt(details::e_sf30,details::sf30_op) case_stmt(details::e_sf31,details::sf31_op) case_stmt(details::e_sf32,details::sf32_op) case_stmt(details::e_sf33,details::sf33_op) case_stmt(details::e_sf34,details::sf34_op) case_stmt(details::e_sf35,details::sf35_op) case_stmt(details::e_sf36,details::sf36_op) case_stmt(details::e_sf37,details::sf37_op) case_stmt(details::e_sf38,details::sf38_op) case_stmt(details::e_sf39,details::sf39_op) case_stmt(details::e_sf40,details::sf40_op) case_stmt(details::e_sf41,details::sf41_op) case_stmt(details::e_sf42,details::sf42_op) case_stmt(details::e_sf43,details::sf43_op) case_stmt(details::e_sf44,details::sf44_op) case_stmt(details::e_sf45,details::sf45_op) case_stmt(details::e_sf46,details::sf46_op) case_stmt(details::e_sf47,details::sf47_op) #undef case_stmt default : return error_node(); } } } inline expression_node_ptr const_optimize_sf4(const details::operator_type& operation, expression_node_ptr (&branch)[4]) { expression_node_ptr temp_node = error_node(); switch (operation) { #define case_stmt(op0,op1) \ case op0 : temp_node = node_allocator_-> \ allocate > >(operation,branch); \ break; \ case_stmt(details::e_sf48,details::sf48_op) case_stmt(details::e_sf49,details::sf49_op) case_stmt(details::e_sf50,details::sf50_op) case_stmt(details::e_sf51,details::sf51_op) case_stmt(details::e_sf52,details::sf52_op) case_stmt(details::e_sf53,details::sf53_op) case_stmt(details::e_sf54,details::sf54_op) case_stmt(details::e_sf55,details::sf55_op) case_stmt(details::e_sf56,details::sf56_op) case_stmt(details::e_sf57,details::sf57_op) case_stmt(details::e_sf58,details::sf58_op) case_stmt(details::e_sf59,details::sf59_op) case_stmt(details::e_sf60,details::sf60_op) case_stmt(details::e_sf61,details::sf61_op) case_stmt(details::e_sf62,details::sf62_op) case_stmt(details::e_sf63,details::sf63_op) case_stmt(details::e_sf64,details::sf64_op) case_stmt(details::e_sf65,details::sf65_op) case_stmt(details::e_sf66,details::sf66_op) case_stmt(details::e_sf67,details::sf67_op) case_stmt(details::e_sf68,details::sf68_op) case_stmt(details::e_sf69,details::sf69_op) case_stmt(details::e_sf70,details::sf70_op) case_stmt(details::e_sf71,details::sf71_op) case_stmt(details::e_sf72,details::sf72_op) case_stmt(details::e_sf73,details::sf73_op) case_stmt(details::e_sf74,details::sf74_op) case_stmt(details::e_sf75,details::sf75_op) case_stmt(details::e_sf76,details::sf76_op) case_stmt(details::e_sf77,details::sf77_op) case_stmt(details::e_sf78,details::sf78_op) case_stmt(details::e_sf79,details::sf79_op) case_stmt(details::e_sf80,details::sf80_op) case_stmt(details::e_sf81,details::sf81_op) case_stmt(details::e_sf82,details::sf82_op) case_stmt(details::e_sf83,details::sf83_op) case_stmt(details::e_sf84,details::sf84_op) case_stmt(details::e_sf85,details::sf85_op) case_stmt(details::e_sf86,details::sf86_op) case_stmt(details::e_sf87,details::sf87_op) case_stmt(details::e_sf88,details::sf88_op) case_stmt(details::e_sf89,details::sf89_op) case_stmt(details::e_sf90,details::sf90_op) case_stmt(details::e_sf91,details::sf91_op) case_stmt(details::e_sf92,details::sf92_op) case_stmt(details::e_sf93,details::sf93_op) case_stmt(details::e_sf94,details::sf94_op) case_stmt(details::e_sf95,details::sf95_op) case_stmt(details::e_sf96,details::sf96_op) case_stmt(details::e_sf97,details::sf97_op) case_stmt(details::e_sf98,details::sf98_op) case_stmt(details::e_sf99,details::sf99_op) #undef case_stmt default : return error_node(); } T v = temp_node->value(); details::free_node(*node_allocator_,temp_node); return node_allocator_->allocate(v); } inline expression_node_ptr varnode_optimize_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(op0,op1) \ case op0 : return node_allocator_-> \ allocate_rrrr > >(v0,v1,v2,v3); \ case_stmt(details::e_sf48,details::sf48_op) case_stmt(details::e_sf49,details::sf49_op) case_stmt(details::e_sf50,details::sf50_op) case_stmt(details::e_sf51,details::sf51_op) case_stmt(details::e_sf52,details::sf52_op) case_stmt(details::e_sf53,details::sf53_op) case_stmt(details::e_sf54,details::sf54_op) case_stmt(details::e_sf55,details::sf55_op) case_stmt(details::e_sf56,details::sf56_op) case_stmt(details::e_sf57,details::sf57_op) case_stmt(details::e_sf58,details::sf58_op) case_stmt(details::e_sf59,details::sf59_op) case_stmt(details::e_sf60,details::sf60_op) case_stmt(details::e_sf61,details::sf61_op) case_stmt(details::e_sf62,details::sf62_op) case_stmt(details::e_sf63,details::sf63_op) case_stmt(details::e_sf64,details::sf64_op) case_stmt(details::e_sf65,details::sf65_op) case_stmt(details::e_sf66,details::sf66_op) case_stmt(details::e_sf67,details::sf67_op) case_stmt(details::e_sf68,details::sf68_op) case_stmt(details::e_sf69,details::sf69_op) case_stmt(details::e_sf70,details::sf70_op) case_stmt(details::e_sf71,details::sf71_op) case_stmt(details::e_sf72,details::sf72_op) case_stmt(details::e_sf73,details::sf73_op) case_stmt(details::e_sf74,details::sf74_op) case_stmt(details::e_sf75,details::sf75_op) case_stmt(details::e_sf76,details::sf76_op) case_stmt(details::e_sf77,details::sf77_op) case_stmt(details::e_sf78,details::sf78_op) case_stmt(details::e_sf79,details::sf79_op) case_stmt(details::e_sf80,details::sf80_op) case_stmt(details::e_sf81,details::sf81_op) case_stmt(details::e_sf82,details::sf82_op) case_stmt(details::e_sf83,details::sf83_op) case_stmt(details::e_sf84,details::sf84_op) case_stmt(details::e_sf85,details::sf85_op) case_stmt(details::e_sf86,details::sf86_op) case_stmt(details::e_sf87,details::sf87_op) case_stmt(details::e_sf88,details::sf88_op) case_stmt(details::e_sf89,details::sf89_op) case_stmt(details::e_sf90,details::sf90_op) case_stmt(details::e_sf91,details::sf91_op) case_stmt(details::e_sf92,details::sf92_op) case_stmt(details::e_sf93,details::sf93_op) case_stmt(details::e_sf94,details::sf94_op) case_stmt(details::e_sf95,details::sf95_op) case_stmt(details::e_sf96,details::sf96_op) case_stmt(details::e_sf97,details::sf97_op) case_stmt(details::e_sf98,details::sf98_op) case_stmt(details::e_sf99,details::sf99_op) #undef case_stmt default : return error_node(); } } inline expression_node_ptr special_function(const details::operator_type& operation, expression_node_ptr (&branch)[4]) { if (!all_nodes_valid(branch)) return error_node(); else if (is_constant_foldable(branch)) return const_optimize_sf4(operation,branch); else if (all_nodes_variables(branch)) return varnode_optimize_sf4(operation,branch); switch (operation) { #define case_stmt(op0,op1) \ case op0 : return node_allocator_-> \ allocate > >(operation,branch); \ case_stmt(details::e_sf48,details::sf48_op) case_stmt(details::e_sf49,details::sf49_op) case_stmt(details::e_sf50,details::sf50_op) case_stmt(details::e_sf51,details::sf51_op) case_stmt(details::e_sf52,details::sf52_op) case_stmt(details::e_sf53,details::sf53_op) case_stmt(details::e_sf54,details::sf54_op) case_stmt(details::e_sf55,details::sf55_op) case_stmt(details::e_sf56,details::sf56_op) case_stmt(details::e_sf57,details::sf57_op) case_stmt(details::e_sf58,details::sf58_op) case_stmt(details::e_sf59,details::sf59_op) case_stmt(details::e_sf60,details::sf60_op) case_stmt(details::e_sf61,details::sf61_op) case_stmt(details::e_sf62,details::sf62_op) case_stmt(details::e_sf63,details::sf63_op) case_stmt(details::e_sf64,details::sf64_op) case_stmt(details::e_sf65,details::sf65_op) case_stmt(details::e_sf66,details::sf66_op) case_stmt(details::e_sf67,details::sf67_op) case_stmt(details::e_sf68,details::sf68_op) case_stmt(details::e_sf69,details::sf69_op) case_stmt(details::e_sf70,details::sf70_op) case_stmt(details::e_sf71,details::sf71_op) case_stmt(details::e_sf72,details::sf72_op) case_stmt(details::e_sf73,details::sf73_op) case_stmt(details::e_sf74,details::sf74_op) case_stmt(details::e_sf75,details::sf75_op) case_stmt(details::e_sf76,details::sf76_op) case_stmt(details::e_sf77,details::sf77_op) case_stmt(details::e_sf78,details::sf78_op) case_stmt(details::e_sf79,details::sf79_op) case_stmt(details::e_sf80,details::sf80_op) case_stmt(details::e_sf81,details::sf81_op) case_stmt(details::e_sf82,details::sf82_op) case_stmt(details::e_sf83,details::sf83_op) case_stmt(details::e_sf84,details::sf84_op) case_stmt(details::e_sf85,details::sf85_op) case_stmt(details::e_sf86,details::sf86_op) case_stmt(details::e_sf87,details::sf87_op) case_stmt(details::e_sf88,details::sf88_op) case_stmt(details::e_sf89,details::sf89_op) case_stmt(details::e_sf90,details::sf90_op) case_stmt(details::e_sf91,details::sf91_op) case_stmt(details::e_sf92,details::sf92_op) case_stmt(details::e_sf93,details::sf93_op) case_stmt(details::e_sf94,details::sf94_op) case_stmt(details::e_sf95,details::sf95_op) case_stmt(details::e_sf96,details::sf96_op) case_stmt(details::e_sf97,details::sf97_op) case_stmt(details::e_sf98,details::sf98_op) case_stmt(details::e_sf99,details::sf99_op) #undef case_stmt default : return error_node(); } } template class Sequence> inline expression_node_ptr const_optimize_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(); } 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) { 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_optimize_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_optimize_varargfunc(operation,arg_list); else if ((arg_list.size() == 1) && details::is_ivector_node(arg_list[0])) return vectorize_func(operation,arg_list); else if ((arg_list.size() == 1) && special_one_parameter_vararg(operation)) return arg_list[0]; else if (all_nodes_variables(arg_list)) return varnode_optimize_varargfunc(operation,arg_list); switch (operation) { #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 optimized? if (details::is_constant_node(result)) return result; else if (!all_nodes_valid(b)) return error_node(); else if (N != f->param_count) { details::free_all_nodes(*node_allocator_,b); return error_node(); } function_N_node_t* func_node_ptr = static_cast(result); if (func_node_ptr->init_branches(b)) return result; else { details::free_all_nodes(*node_allocator_,b); return error_node(); } } } 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) ) { Type v = result->value(); details::free_node(*node_allocator_,result); result = node_allocator_->allocate(v); } 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(gf,arg_list); 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 && is_constant_foldable(arg_list) ) { genfunc_node_ptr->init_branches(); Type v = result->value(); details::free_node(*node_allocator_,result); return node_allocator_->allocate(v); } else if (genfunc_node_ptr->init_branches()) return result; else { details::free_node(*node_allocator_,result); details::free_all_nodes(*node_allocator_,arg_list); return error_node(); } } inline expression_node_ptr string_function_call(igeneric_function_t* gf, std::vector& arg_list, const std::size_t& param_seq_index = std::numeric_limits::max()) { 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(); Type v = result->value(); details::free_node(*node_allocator_,result); return node_allocator_->allocate(v); } else if (strfunc_node_ptr->init_branches()) return result; else { details::free_node(*node_allocator_,result); details::free_all_nodes(*node_allocator_,arg_list); return error_node(); } } 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); Type* v = (*vector_base)[i]; 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.type = scope_element::e_vecelem; nse.index = i; nse.depth = parser_->scope_depth_; nse.data = 0; nse.var_node = new variable_node_t((*v)); if (!parser_->sem_.add_element(nse)) { parser_->set_synthesis_error("Failed to add new local vector element to SEM [1]"); result = error_node(); } else exprtk_debug(("vector_element() - INFO - Added new local vector element: %s\n",nse.name.c_str())); result = nse.var_node; } } else result = node_allocator_->allocate >(index,(*vector_base)[0]); 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) { if (!parser_->dec_.collect_assignments()) return; std::string symbol_name; switch (cst) { case e_st_variable : symbol_name = parser_->symbol_table_ .get_variable_name(node); break; case e_st_string : symbol_name = parser_->symbol_table_ .get_stringvar_name(node); break; case e_st_vector : { typedef details::vector_holder vector_holder_t; vector_holder_t& vh = static_cast(node)->ref(); symbol_name = parser_->symbol_table_.get_vector_name(&vh); } break; default : return; } 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])) return synthesize_expression(operation,branch); 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); } 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])) { 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(); } } } 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); } else { parser_->set_synthesis_error("Invalid assignment operation[2]"); return error_node(); } } inline expression_node_ptr synthesize_veceqineq_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]); 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]); \ case_stmt(details:: e_lt,details:: lt_op) case_stmt(details:: e_lte,details:: lte_op) case_stmt(details:: e_gt,details:: gt_op) case_stmt(details:: e_gte,details:: gte_op) case_stmt(details:: e_eq,details:: eq_op) case_stmt(details:: e_ne,details:: ne_op) #undef case_stmt default : return error_node(); } } 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]); \ case_stmt(details:: e_lt,details:: lt_op) case_stmt(details:: e_lte,details:: lte_op) case_stmt(details:: e_gt,details:: gt_op) case_stmt(details:: e_gte,details:: gte_op) case_stmt(details:: e_eq,details:: eq_op) case_stmt(details:: e_ne,details:: ne_op) #undef case_stmt default : return error_node(); } } 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]); \ case_stmt(details:: e_lt,details:: lt_op) case_stmt(details:: e_lte,details:: lte_op) case_stmt(details:: e_gt,details:: gt_op) case_stmt(details:: e_gte,details:: gte_op) case_stmt(details:: e_eq,details:: eq_op) case_stmt(details:: e_ne,details:: ne_op) #undef case_stmt default : return error_node(); } } else return error_node(); } 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]); const bool v0_is_str = details::is_generally_string_node(branch[0]); const bool v1_is_str = details::is_generally_string_node(branch[1]); 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]))) ) { return node_allocator_->allocate >(v0,v1); } else return node_allocator_->allocate >(branch[0],branch[1]); } else if (v0_is_ivec && v1_is_ivec) { return node_allocator_->allocate >(branch[0],branch[1]); } else if (v0_is_str && v1_is_str) { return node_allocator_->allocate >(branch[0],branch[1]); } else { parser_->set_synthesis_error("Only variables, strings, vectors or vector elements can be swapped"); return error_node(); } } #ifndef exprtk_disable_sc_andor inline expression_node_ptr synthesize_shortcircuit_expression(const details::operator_type& operation, expression_node_ptr (&branch)[2]) { expression_node_ptr result = error_node(); 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) { free_node(*node_allocator_,branch[0]); 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