From 2cdda140b8ff390bc2e1cef642666828d55ac6ec Mon Sep 17 00:00:00 2001 From: ArashPartow Date: Mon, 10 Apr 2017 19:01:40 +1000 Subject: [PATCH 1/2] Minor updates to ExprTk Updated multi-sub expression operator to return final sub-expression type. Updates to exprtk_disable_return_statement macro for disabling return statements and associated exceptions at the source code level. --- resources/3rdparty/exprtk/exprtk.hpp | 72466 +++++++++++++------------ 1 file changed, 36459 insertions(+), 36007 deletions(-) diff --git a/resources/3rdparty/exprtk/exprtk.hpp b/resources/3rdparty/exprtk/exprtk.hpp index a86c45509..4cb3a776a 100755 --- a/resources/3rdparty/exprtk/exprtk.hpp +++ b/resources/3rdparty/exprtk/exprtk.hpp @@ -2,14 +2,14 @@ ****************************************************************** * C++ Mathematical Expression Toolkit Library * * * - * Author: Arash Partow (1999-2016) * + * Author: Arash Partow (1999-2017) * * URL: http://www.partow.net/programming/exprtk/index.html * * * * Copyright notice: * * Free use of the C++ Mathematical Expression Toolkit Library is * * permitted under the guidelines and in accordance with the most * - * current version of the Common Public License. * - * http://www.opensource.org/licenses/cpl1.0.php * + * current version of the MIT License. * + * http://www.opensource.org/licenses/MIT * * * * Example expressions: * * (00) (y + x / y) * (x - y / x) * @@ -27,7 +27,7 @@ * (12) (x ilike 's*ri?g') and [y < (3 z^7 + w)] * * * ****************************************************************** - */ +*/ #ifndef INCLUDE_EXPRTK_HPP @@ -60,36824 +60,37276 @@ namespace exprtk { -#ifdef exprtk_enable_debugging -#define exprtk_debug(params) printf params -#else -#define exprtk_debug(params) (void)0 -#endif - - namespace details - { - typedef unsigned char uchar_t; - typedef char char_t; - - inline bool is_whitespace(const char_t c) - { - return (' ' == c) || ('\n' == c) || - ('\r' == c) || ('\t' == c) || - ('\b' == c) || ('\v' == c) || - ('\f' == c) ; - } - - inline bool is_operator_char(const char_t c) - { - return ('+' == c) || ('-' == c) || - ('*' == c) || ('/' == c) || - ('^' == c) || ('<' == c) || - ('>' == c) || ('=' == c) || - (',' == c) || ('!' == c) || - ('(' == c) || (')' == c) || - ('[' == c) || (']' == c) || - ('{' == c) || ('}' == c) || - ('%' == c) || (':' == c) || - ('?' == c) || ('&' == c) || - ('|' == c) || (';' == c) ; - } - - inline bool is_letter(const char_t c) - { - return (('a' <= c) && (c <= 'z')) || - (('A' <= c) && (c <= 'Z')) -#ifdef MODIFICATION - || ('_' == c) -#endif - ; - } - - inline bool is_digit(const char_t c) - { - return ('0' <= c) && (c <= '9'); - } - - inline bool is_letter_or_digit(const char_t c) - { - return is_letter(c) || is_digit(c); - } - - inline bool is_left_bracket(const char_t c) - { - return ('(' == c) || ('[' == c) || ('{' == c); - } - - inline bool is_right_bracket(const char_t c) - { - return (')' == c) || (']' == c) || ('}' == c); - } - - inline bool is_bracket(const char_t c) - { - return is_left_bracket(c) || is_right_bracket(c); - } - - inline bool is_sign(const char_t c) - { - return ('+' == c) || ('-' == c); - } - - inline bool is_invalid(const char_t c) - { - return !is_whitespace (c) && - !is_operator_char(c) && - !is_letter (c) && - !is_digit (c) && -#ifndef MODIFICATION - ('.' != c) && - ('_' != c) && -#endif - ('$' != c) && - ('~' != c) && - ('\'' != c); - } - - inline bool imatch(const char_t c1, const char_t c2) - { -#ifdef MODIFICATION - return c1 == c2; -#else - return std::tolower(c1) == std::tolower(c2); -#endif - } - - 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) - { -#ifdef MODIFICATION - if (s1[i] != s2[i]) -#else - if (std::tolower(s1[i]) != std::tolower(s2[i])) -#endif - { - 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 const char& front(const std::string& s) - { - return s[0]; - } - - inline const char& back(const std::string& s) - { - return s[s.size() - 1]; - } - - inline std::string to_str(int i) - { - if (0 == i) - return std::string("0"); - - std::string result; - - if (i < 0) - { - for ( ; i; i /= 10) - { - result += '0' + char(-(i % 10)); - } - - result += '-'; + #ifdef exprtk_enable_debugging + #define exprtk_debug(params) printf params + #else + #define exprtk_debug(params) (void)0 + #endif + + namespace details + { + typedef unsigned char uchar_t; + typedef char char_t; + + inline bool is_whitespace(const char_t c) + { + return (' ' == c) || ('\n' == c) || + ('\r' == c) || ('\t' == c) || + ('\b' == c) || ('\v' == c) || + ('\f' == c) ; + } + + inline bool is_operator_char(const char_t c) + { + return ('+' == c) || ('-' == c) || + ('*' == c) || ('/' == c) || + ('^' == c) || ('<' == c) || + ('>' == c) || ('=' == c) || + (',' == c) || ('!' == c) || + ('(' == c) || (')' == c) || + ('[' == c) || (']' == c) || + ('{' == c) || ('}' == c) || + ('%' == c) || (':' == c) || + ('?' == c) || ('&' == c) || + ('|' == c) || (';' == c) ; + } + + inline bool is_letter(const char_t c) + { + return (('a' <= c) && (c <= 'z')) || + (('A' <= c) && (c <= 'Z')) ; + } + + inline bool is_digit(const char_t c) + { + return ('0' <= c) && (c <= '9'); + } + + inline bool is_letter_or_digit(const char_t c) + { + return is_letter(c) || is_digit(c); + } + + inline bool is_left_bracket(const char_t c) + { + return ('(' == c) || ('[' == c) || ('{' == c); + } + + inline bool is_right_bracket(const char_t c) + { + return (')' == c) || (']' == c) || ('}' == c); + } + + inline bool is_bracket(const char_t c) + { + return is_left_bracket(c) || is_right_bracket(c); + } + + inline bool is_sign(const char_t c) + { + return ('+' == c) || ('-' == c); + } + + inline bool is_invalid(const char_t c) + { + return !is_whitespace (c) && + !is_operator_char(c) && + !is_letter (c) && + !is_digit (c) && + ('.' != c) && + ('_' != c) && + ('$' != c) && + ('~' != c) && + ('\'' != c); + } + + inline bool imatch(const char_t c1, const char_t c2) + { + #ifdef MODIFICATION + return c1 == c2; + #else + return std::tolower(c1) == std::tolower(c2); + #endif + } + + 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) + { + #ifdef MODIFICATION + if (s1[i] != s2[i]) + #else + if (std::tolower(s1[i]) != std::tolower(s2[i])) + #endif + { + return false; + } } - else + + 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 const char& front(const std::string& s) + { + return s[0]; + } + + inline const char& back(const std::string& s) + { + return s[s.size() - 1]; + } + + inline std::string to_str(int i) + { + if (0 == i) + return std::string("0"); + + std::string result; + + if (i < 0) + { + for ( ; i; i /= 10) { - for ( ; i; i /= 10) - { - result += '0' + char(i % 10); - } + result += '0' + char(-(i % 10)); } - - std::reverse(result.begin(), result.end()); - - 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 uchar_t hex_to_bin(uchar_t h) - { - if (('0' <= h) && (h <= '9')) - return (h - '0'); - else - return static_cast(std::toupper(h) - 'A'); - } - - template - inline 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 += '-'; + } + else + { + for ( ; i; i /= 10) { - result = hex_to_bin(*(itr + 2)) << 4 | hex_to_bin(*(itr + 3)); - itr += 3; + result += '0' + char(i % 10); } - else - result = '\0'; - } - - inline void cleanup_escapes(std::string& s) - { - typedef std::string::iterator str_itr_t; - - str_itr_t itr1 = s.begin(); - str_itr_t itr2 = s.begin(); - str_itr_t end = s.end (); - - std::size_t removal_count = 0; - - while (end != itr1) - { - if ('\\' == (*itr1)) - { - ++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)); + } + + std::reverse(result.begin(), result.end()); + + 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 uchar_t hex_to_bin(uchar_t h) + { + if (('0' <= h) && (h <= '9')) + return (h - '0'); + else + return static_cast(std::toupper(h) - 'A'); + } + + template + inline 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) + { + typedef std::string::iterator str_itr_t; + + str_itr_t itr1 = s.begin(); + str_itr_t itr2 = s.begin(); + str_itr_t end = s.end (); + + std::size_t removal_count = 0; + + while (end != itr1) + { + if ('\\' == (*itr1)) + { + ++removal_count; + + if (end == ++itr1) + break; + else if ('\\' != (*itr1)) + { + switch (*itr1) + { + case 'n' : (*itr1) = '\n'; break; + case 'r' : (*itr1) = '\r'; break; + case 't' : (*itr1) = '\t'; break; + case '0' : parse_hex(itr1, end, (*itr1)); removal_count += 3; break; - } - - continue; - } - } - - 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) - { -#ifdef MODIFICATION - const char_t c1 = static_cast(s1[i]); - const char_t c2 = static_cast(s2[i]); -#else - const char_t c1 = static_cast(std::tolower(s1[i])); - const char_t c2 = static_cast(std::tolower(s2[i])); -#endif - - if (c1 > c2) - return false; - else if (c1 < c2) - return true; - } - - return s1.size() < s2.size(); + } + + continue; + } } - }; - - static const std::string reserved_words[] = - { - "break", "case", "continue", "default", "false", "for", - "if", "else", "ilike", "in", "like", "and", "nand", "nor", - "not", "null", "or", "repeat", "return", "shl", "shr", - "swap", "switch", "true", "until", "var", "while", "xnor", - "xor", "&", "|" - }; - - static const std::size_t reserved_words_size = sizeof(reserved_words) / sizeof(std::string); - - static const std::string reserved_symbols[] = - { - "abs", "acos", "acosh", "and", "asin", "asinh", "atan", - "atanh", "atan2", "avg", "break", "case", "ceil", "clamp", - "continue", "cos", "cosh", "cot", "csc", "default", - "deg2grad", "deg2rad", "equal", "erf", "erfc", "exp", - "expm1", "false", "floor", "for", "frac", "grad2deg", - "hypot", "iclamp", "if", "else", "ilike", "in", "inrange", - "like", "log", "log10", "log2", "logn", "log1p", "mand", - "max", "min", "mod", "mor", "mul", "ncdf", "nand", "nor", - "not", "not_equal", "null", "or", "pow", "rad2deg", - "repeat", "return", "root", "round", "roundn", "sec", "sgn", - "shl", "shr", "sin", "sinc", "sinh", "sqrt", "sum", "swap", - "switch", "tan", "tanh", "true", "trunc", "until", "var", - "while", "xnor", "xor", "&", "|" - }; - - static const std::size_t reserved_symbols_size = sizeof(reserved_symbols) / sizeof(std::string); - - static const std::string base_function_list[] = - { - "abs", "acos", "acosh", "asin", "asinh", "atan", "atanh", - "atan2", "avg", "ceil", "clamp", "cos", "cosh", "cot", - "csc", "equal", "erf", "erfc", "exp", "expm1", "floor", - "frac", "hypot", "iclamp", "like", "log", "log10", "log2", - "logn", "log1p", "mand", "max", "min", "mod", "mor", "mul", - "ncdf", "pow", "root", "round", "roundn", "sec", "sgn", - "sin", "sinc", "sinh", "sqrt", "sum", "swap", "tan", "tanh", - "trunc", "not_equal", "inrange", "deg2grad", "deg2rad", - "rad2deg", "grad2deg" - }; - - static const std::size_t base_function_list_size = sizeof(base_function_list) / sizeof(std::string); - - static const std::string logic_ops_list[] = - { - "and", "nand", "nor", "not", "or", "xnor", "xor", "&", "|" - }; - - static const std::size_t logic_ops_list_size = sizeof(logic_ops_list) / sizeof(std::string); - - static const std::string cntrl_struct_list[] = - { - "if", "switch", "for", "while", "repeat" - }; - - static const std::size_t cntrl_struct_list_size = sizeof(cntrl_struct_list) / sizeof(std::string); - - static const std::string arithmetic_ops_list[] = - { - "+", "-", "*", "/", "%", "^" - }; - - static const std::size_t arithmetic_ops_list_size = sizeof(arithmetic_ops_list) / sizeof(std::string); - - static const std::string assignment_ops_list[] = - { - ":=", "+=", "-=", - "*=", "/=", "%=" - }; - - static const std::size_t assignment_ops_list_size = sizeof(assignment_ops_list) / sizeof(std::string); - - static const std::string inequality_ops_list[] = - { - "<", "<=", "==", - "=", "!=", "<>", - ">=", ">" - }; - - static const std::size_t inequality_ops_list_size = sizeof(inequality_ops_list) / sizeof(std::string); - - inline bool is_reserved_word(const std::string& symbol) - { - for (std::size_t i = 0; i < reserved_words_size; ++i) - { - if (imatch(symbol,reserved_words[i])) - { - return true; - } - } - - return false; - } - - inline bool is_reserved_symbol(const std::string& symbol) - { - for (std::size_t i = 0; i < reserved_symbols_size; ++i) - { - if (imatch(symbol,reserved_symbols[i])) - { - return true; - } - } - - return false; - } - - inline bool is_base_function(const std::string& function_name) - { - for (std::size_t i = 0; i < base_function_list_size; ++i) - { - if (imatch(function_name,base_function_list[i])) - { - return true; - } - } - - return false; - } - - inline bool is_control_struct(const std::string& cntrl_strct) - { - for (std::size_t i = 0; i < cntrl_struct_list_size; ++i) - { - if (imatch(cntrl_strct,cntrl_struct_list[i])) - { - return true; - } - } - + + 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) + { + #ifdef MODIFICATION + const char_t c1 = static_cast(s1[i]); + const char_t c2 = static_cast(s2[i]); + #else + const char_t c1 = static_cast(std::tolower(s1[i])); + const char_t c2 = static_cast(std::tolower(s2[i])); + #endif + + 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", "return", "shl", "shr", + "swap", "switch", "true", "until", "var", "while", "xnor", + "xor", "&", "|" + }; + + static const std::size_t reserved_words_size = sizeof(reserved_words) / sizeof(std::string); + + static const std::string reserved_symbols[] = + { + "abs", "acos", "acosh", "and", "asin", "asinh", "atan", + "atanh", "atan2", "avg", "break", "case", "ceil", "clamp", + "continue", "cos", "cosh", "cot", "csc", "default", + "deg2grad", "deg2rad", "equal", "erf", "erfc", "exp", + "expm1", "false", "floor", "for", "frac", "grad2deg", + "hypot", "iclamp", "if", "else", "ilike", "in", "inrange", + "like", "log", "log10", "log2", "logn", "log1p", "mand", + "max", "min", "mod", "mor", "mul", "ncdf", "nand", "nor", + "not", "not_equal", "null", "or", "pow", "rad2deg", + "repeat", "return", "root", "round", "roundn", "sec", "sgn", + "shl", "shr", "sin", "sinc", "sinh", "sqrt", "sum", "swap", + "switch", "tan", "tanh", "true", "trunc", "until", "var", + "while", "xnor", "xor", "&", "|" + }; + + static const std::size_t reserved_symbols_size = sizeof(reserved_symbols) / sizeof(std::string); + + static const std::string base_function_list[] = + { + "abs", "acos", "acosh", "asin", "asinh", "atan", "atanh", + "atan2", "avg", "ceil", "clamp", "cos", "cosh", "cot", + "csc", "equal", "erf", "erfc", "exp", "expm1", "floor", + "frac", "hypot", "iclamp", "like", "log", "log10", "log2", + "logn", "log1p", "mand", "max", "min", "mod", "mor", "mul", + "ncdf", "pow", "root", "round", "roundn", "sec", "sgn", + "sin", "sinc", "sinh", "sqrt", "sum", "swap", "tan", "tanh", + "trunc", "not_equal", "inrange", "deg2grad", "deg2rad", + "rad2deg", "grad2deg" + }; + + static const std::size_t base_function_list_size = sizeof(base_function_list) / sizeof(std::string); + + static const std::string logic_ops_list[] = + { + "and", "nand", "nor", "not", "or", "xnor", "xor", "&", "|" + }; + + static const std::size_t logic_ops_list_size = sizeof(logic_ops_list) / sizeof(std::string); + + static const std::string cntrl_struct_list[] = + { + "if", "switch", "for", "while", "repeat", "return" + }; + + static const std::size_t cntrl_struct_list_size = sizeof(cntrl_struct_list) / sizeof(std::string); + + static const std::string arithmetic_ops_list[] = + { + "+", "-", "*", "/", "%", "^" + }; + + static const std::size_t arithmetic_ops_list_size = sizeof(arithmetic_ops_list) / sizeof(std::string); + + static const std::string assignment_ops_list[] = + { + ":=", "+=", "-=", + "*=", "/=", "%=" + }; + + static const std::size_t assignment_ops_list_size = sizeof(assignment_ops_list) / sizeof(std::string); + + static const std::string inequality_ops_list[] = + { + "<", "<=", "==", + "=", "!=", "<>", + ">=", ">" + }; + + static const std::size_t inequality_ops_list_size = sizeof(inequality_ops_list) / sizeof(std::string); + + inline bool is_reserved_word(const std::string& symbol) + { + for (std::size_t i = 0; i < reserved_words_size; ++i) + { + if (imatch(symbol,reserved_words[i])) + { + return true; + } + } + + return false; + } + + inline bool is_reserved_symbol(const std::string& symbol) + { + for (std::size_t i = 0; i < reserved_symbols_size; ++i) + { + if (imatch(symbol,reserved_symbols[i])) + { + return true; + } + } + + return false; + } + + inline bool is_base_function(const std::string& function_name) + { + for (std::size_t i = 0; i < base_function_list_size; ++i) + { + if (imatch(function_name,base_function_list[i])) + { + return true; + } + } + + return false; + } + + inline bool is_control_struct(const std::string& cntrl_strct) + { + for (std::size_t i = 0; i < cntrl_struct_list_size; ++i) + { + if (imatch(cntrl_strct,cntrl_struct_list[i])) + { + return true; + } + } + + return false; + } + + inline bool is_logic_opr(const std::string& lgc_opr) + { + for (std::size_t i = 0; i < logic_ops_list_size; ++i) + { + if (imatch(lgc_opr,logic_ops_list[i])) + { + return true; + } + } + + return false; + } + + struct cs_match + { + static inline bool cmp(const char_t c0, const char_t c1) + { + #ifdef MODIFICATION + return (c0 == c1); + #else + return (std::tolower(c0) == std::tolower(c1)); + #endif + } + }; + + struct cis_match + { + static inline bool cmp(const char_t c0, const char_t c1) + { + return (std::tolower(c0) == std::tolower(c1)); + } + }; + + template + inline bool match_impl(const Iterator pattern_begin, + const Iterator pattern_end, + const Iterator data_begin, + const Iterator data_end, + const typename std::iterator_traits::value_type& zero_or_more, + const typename std::iterator_traits::value_type& zero_or_one) + { + if (0 == std::distance(data_begin,data_end)) + { return false; - } - - inline bool is_logic_opr(const std::string& lgc_opr) - { - for (std::size_t i = 0; i < logic_ops_list_size; ++i) - { - if (imatch(lgc_opr,logic_ops_list[i])) - { - return true; - } - } - + } + + 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()) + { + return ("Z" == pattern); + } + else if ('*' == pattern[0]) return false; - } - - struct cs_match - { - static inline bool cmp(const char_t c0, const char_t c1) + + 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)) { - return (c0 == c1); + const char_t target = static_cast(std::toupper(*(p_itr - 1))); + + if ('*' == target) + { + diff_index = std::distance(str.begin(),s_itr); + diff_value = static_cast(std::toupper(*p_itr)); + + return false; + } + else + ++p_itr; + + while (s_itr != s_end) + { + if (target != std::toupper(*s_itr)) + break; + else + ++s_itr; + } + + continue; } - }; - - struct cis_match - { - static inline bool cmp(const char_t c0, const char_t c1) + else if ( + ('?' != *p_itr) && + std::toupper(*p_itr) != std::toupper(*s_itr) + ) { -#ifdef MODIFICATION - return (c0 == c1); -#else - return (std::tolower(c0) == std::tolower(c1)); -#endif + diff_index = std::distance(str.begin(),s_itr); + diff_value = static_cast(std::toupper(*p_itr)); + + return false; } - }; - - 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()) - { - return ("Z" == pattern); - } - else if ('*' == pattern[0]) - return false; - - typedef std::string::const_iterator itr_t; - - itr_t p_itr = pattern.begin(); - itr_t s_itr = str .begin(); - - 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_t target = static_cast(std::toupper(*(p_itr - 1))); - - if ('*' == target) - { - diff_index = std::distance(str.begin(),s_itr); - diff_value = static_cast(std::toupper(*p_itr)); - - return false; - } - else - ++p_itr; - - while (s_itr != s_end) - { - if (target != std::toupper(*s_itr)) - break; - else - ++s_itr; - } - - continue; - } - else if ( - ('?' != *p_itr) && - std::toupper(*p_itr) != std::toupper(*s_itr) - ) - { - diff_index = std::distance(str.begin(),s_itr); - diff_value = static_cast(std::toupper(*p_itr)); - - return false; - } - - ++p_itr; - ++s_itr; - } - - return ( - (s_end == s_itr) && - ( - (p_end == p_itr) || - ('*' == *p_itr) - ) - ); - } - - static const double pow10[] = { - 1.0, - 1.0E+001, 1.0E+002, 1.0E+003, 1.0E+004, - 1.0E+005, 1.0E+006, 1.0E+007, 1.0E+008, - 1.0E+009, 1.0E+010, 1.0E+011, 1.0E+012, - 1.0E+013, 1.0E+014, 1.0E+015, 1.0E+016 - }; - - static const std::size_t pow10_size = sizeof(pow10) / sizeof(double); - - namespace numeric - { - namespace constant - { - static const double e = 2.71828182845904523536028747135266249775724709369996; - static const double pi = 3.14159265358979323846264338327950288419716939937510; - static const double pi_2 = 1.57079632679489661923132169163975144209858469968755; - static const double pi_4 = 0.78539816339744830961566084581987572104929234984378; - static const double pi_180 = 0.01745329251994329576923690768488612713442871888542; - static const double _1_pi = 0.31830988618379067153776752674502872406891929148091; - static const double _2_pi = 0.63661977236758134307553505349005744813783858296183; - static const double _180_pi = 57.29577951308232087679815481410517033240547246656443; - static const double log2 = 0.69314718055994530941723212145817656807550013436026; - static const double sqrt2 = 1.41421356237309504880168872420969807856967187537695; - } - - namespace details - { - struct unknown_type_tag {}; - struct real_type_tag {}; - struct complex_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_complex_type_tag(T) \ -template<> struct number_type > \ -{ typedef complex_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_complex_type_tag(double ) - exprtk_register_complex_type_tag(long double) - exprtk_register_complex_type_tag(float ) - - exprtk_register_int_type_tag(short ) - exprtk_register_int_type_tag(int ) - exprtk_register_int_type_tag(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) - { - typedef real_type_tag rtg; - const T epsilon = epsilon_type::value(); - return (abs_impl(v0 - v1,rtg()) > (std::max(T(1),std::max(abs_impl(v0,rtg()),abs_impl(v1,rtg()))) * epsilon)) ? T(1) : T(0); - } - - inline float nequal_impl(const float v0, const float v1, real_type_tag) - { - typedef real_type_tag rtg; - const float epsilon = epsilon_type::value(); - return (abs_impl(v0 - v1,rtg()) > (std::max(1.0f,std::max(abs_impl(v0,rtg()),abs_impl(v1,rtg()))) * epsilon)) ? 1.0f : 0.0f; - } - - template - inline T nequal_impl(const T v0, const T v1, int_type_tag) - { - return (v0 != v1) ? 1 : 0; - } - - template - inline T modulus_impl(const T v0, const T v1, real_type_tag) - { - return std::fmod(v0,v1); - } - - template - inline T modulus_impl(const T v0, const T v1, int_type_tag) - { - return v0 % v1; - } - - template - inline T pow_impl(const T v0, const T v1, real_type_tag) - { - return std::pow(v0,v1); - } - - template - inline T pow_impl(const T v0, const T v1, int_type_tag) - { - return std::pow(static_cast(v0),static_cast(v1)); - } - - template - inline T logn_impl(const T v0, const T v1, real_type_tag) - { - return std::log(v0) / std::log(v1); - } - - template - inline T logn_impl(const T v0, const T v1, int_type_tag) - { - return static_cast(logn_impl(static_cast(v0),static_cast(v1),real_type_tag())); - } - - template - inline T log1p_impl(const T v, real_type_tag) - { - if (v > T(-1)) - { - if (abs_impl(v,real_type_tag()) > T(0.0001)) - { - return std::log(T(1) + v); - } - else - return (T(-0.5) * v + T(1)) * v; - } - else - return std::numeric_limits::quiet_NaN(); - } - - template - inline T log1p_impl(const T v, int_type_tag) - { - if (v > T(-1)) - { - return std::log(T(1) + v); - } - else - return std::numeric_limits::quiet_NaN(); - } - - template - inline T root_impl(const T v0, const T v1, real_type_tag) - { - 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); - } - -#if (defined(_MSC_VER) && (_MSC_VER >= 1900)) || !defined(_MSC_VER) -#define exprtk_define_erf(TT,impl) \ -inline TT erf_impl(TT v) { return impl(v); } \ - - exprtk_define_erf( float,::erff) - exprtk_define_erf( double,::erf ) - exprtk_define_erf(long double,::erfl) -#undef exprtk_define_erf -#endif - - template - inline T erf_impl(T v, real_type_tag) - { -#if defined(_MSC_VER) && (_MSC_VER < 1900) - // Credits: Abramowitz & Stegun Equations 7.1.25-28 - static const T c[] = { - T( 1.26551223), T(1.00002368), - T( 0.37409196), T(0.09678418), - T(-0.18628806), T(0.27886807), - T(-1.13520398), T(1.48851587), - T(-0.82215223), T(0.17087277) - }; - - const T t = T(1) / (T(1) + T(0.5) * abs_impl(v,real_type_tag())); - - T result = T(1) - t * std::exp((-v * v) - - c[0] + t * (c[1] + t * - (c[2] + t * (c[3] + t * - (c[4] + t * (c[5] + t * - (c[6] + t * (c[7] + t * - (c[8] + t * (c[9])))))))))); - - return (v >= T(0)) ? result : -result; -#else - return erf_impl(v); -#endif - } - - template - inline T erf_impl(T v, int_type_tag) - { - return erf_impl(static_cast(v),real_type_tag()); - } - -#if (defined(_MSC_VER) && (_MSC_VER >= 1900)) || !defined(_MSC_VER) -#define exprtk_define_erfc(TT,impl) \ -inline TT erfc_impl(TT v) { return impl(v); } \ - - exprtk_define_erfc( float,::erfcf) - exprtk_define_erfc( double,::erfc ) - exprtk_define_erfc(long double,::erfcl) -#undef exprtk_define_erfc -#endif - - template - inline T erfc_impl(T v, real_type_tag) - { -#if defined(_MSC_VER) && (_MSC_VER < 1900) - return T(1) - erf_impl(v,real_type_tag()); -#else - return erfc_impl(v); -#endif - } - - template - inline T erfc_impl(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) - std::log(T(1) - v)) / T(2); } - template inline T ceil_impl(const T v, real_type_tag) { return std::ceil (v); } - template inline T cos_impl(const T v, real_type_tag) { return std::cos (v); } - template inline T cosh_impl(const T v, real_type_tag) { return std::cosh (v); } - template inline T exp_impl(const T v, real_type_tag) { return std::exp (v); } - template inline T floor_impl(const T v, real_type_tag) { return std::floor(v); } - template inline T log_impl(const T v, real_type_tag) { return std::log (v); } - template inline T log10_impl(const T v, real_type_tag) { return std::log10(v); } - template inline T log2_impl(const T v, real_type_tag) { return std::log(v)/T(numeric::constant::log2); } - template inline T neg_impl(const T v, real_type_tag) { return -v; } - template inline T pos_impl(const T v, real_type_tag) { return +v; } - template inline T sin_impl(const T v, real_type_tag) { return std::sin (v); } - template inline T sinh_impl(const T v, real_type_tag) { return std::sinh (v); } - template inline T sqrt_impl(const T v, real_type_tag) { return std::sqrt (v); } - template inline T tan_impl(const T v, real_type_tag) { return std::tan (v); } - template inline T tanh_impl(const T v, real_type_tag) { return std::tanh (v); } - template inline T cot_impl(const T v, real_type_tag) { return T(1) / std::tan(v); } - template inline T sec_impl(const T v, real_type_tag) { return T(1) / std::cos(v); } - template inline T csc_impl(const T v, real_type_tag) { return T(1) / std::sin(v); } - template inline T r2d_impl(const T v, real_type_tag) { return (v * T(numeric::constant::_180_pi)); } - template inline T d2r_impl(const T v, real_type_tag) { return (v * T(numeric::constant::pi_180)); } - template inline T d2g_impl(const T v, real_type_tag) { return (v * T(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}; }; - + + ++p_itr; + ++s_itr; + } + + return ( + (s_end == s_itr) && + ( + (p_end == p_itr) || + ('*' == *p_itr) + ) + ); + } + + static const double pow10[] = { + 1.0, + 1.0E+001, 1.0E+002, 1.0E+003, 1.0E+004, + 1.0E+005, 1.0E+006, 1.0E+007, 1.0E+008, + 1.0E+009, 1.0E+010, 1.0E+011, 1.0E+012, + 1.0E+013, 1.0E+014, 1.0E+015, 1.0E+016 + }; + + static const std::size_t pow10_size = sizeof(pow10) / sizeof(double); + + namespace numeric + { + namespace constant + { + static const double e = 2.71828182845904523536028747135266249775724709369996; + static const double pi = 3.14159265358979323846264338327950288419716939937510; + static const double pi_2 = 1.57079632679489661923132169163975144209858469968755; + static const double pi_4 = 0.78539816339744830961566084581987572104929234984378; + static const double pi_180 = 0.01745329251994329576923690768488612713442871888542; + static const double _1_pi = 0.31830988618379067153776752674502872406891929148091; + static const double _2_pi = 0.63661977236758134307553505349005744813783858296183; + static const double _180_pi = 57.29577951308232087679815481410517033240547246656443; + static const double log2 = 0.69314718055994530941723212145817656807550013436026; + static const double sqrt2 = 1.41421356237309504880168872420969807856967187537695; + } + + namespace details + { + struct unknown_type_tag {}; + struct real_type_tag {}; + struct complex_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_complex_type_tag(T) \ + template<> struct number_type > \ + { typedef complex_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_complex_type_tag(double ) + exprtk_register_complex_type_tag(long double) + exprtk_register_complex_type_tag(float ) + + exprtk_register_int_type_tag(short ) + exprtk_register_int_type_tag(int ) + exprtk_register_int_type_tag(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 - inline int to_int32(const T v) + struct epsilon_type { - typename details::number_type::type num_type; - return to_int32_impl(v,num_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 long long int to_int64(const T v) + inline bool is_nan_impl(const T v, real_type_tag) { - typename details::number_type::type num_type; - return to_int64_impl(v,num_type); + return std::not_equal_to()(v,v); } - + template - inline bool is_nan(const T v) + inline int to_int32_impl(const T v, real_type_tag) { - typename details::number_type::type num_type; - return is_nan_impl(v,num_type); + return static_cast(v); } - + template - inline T min(const T v0, const T v1) + inline long long int to_int64_impl(const T v, real_type_tag) { - typename details::number_type::type num_type; - return min_impl(v0,v1,num_type); + return static_cast(v); } - + template - inline T max(const T v0, const T v1) + inline bool is_true_impl(const T v) { - typename details::number_type::type num_type; - return max_impl(v0,v1,num_type); + return std::not_equal_to()(T(0),v); } - + template - inline T equal(const T v0, const T v1) + inline bool is_false_impl(const T v) { - typename details::number_type::type num_type; - return equal_impl(v0,v1,num_type); + return std::equal_to()(T(0),v); } - + template - inline T nequal(const T v0, const T v1) + inline T abs_impl(const T v, real_type_tag) { - typename details::number_type::type num_type; - return nequal_impl(v0,v1,num_type); + return ((v < T(0)) ? -v : v); } - + template - inline T modulus(const T v0, const T v1) + inline T min_impl(const T v0, const T v1, real_type_tag) { - typename details::number_type::type num_type; - return modulus_impl(v0,v1,num_type); + return std::min(v0,v1); } - + template - inline T pow(const T v0, const T v1) + inline T max_impl(const T v0, const T v1, real_type_tag) { - typename details::number_type::type num_type; - return pow_impl(v0,v1,num_type); + return std::max(v0,v1); } - + template - inline T logn(const T v0, const T v1) + inline T equal_impl(const T v0, const T v1, real_type_tag) { - typename details::number_type::type num_type; - return logn_impl(v0,v1,num_type); + 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); } - - template - inline T root(const T v0, const T v1) + + inline float equal_impl(const float v0, const float v1, real_type_tag) { - typename details::number_type::type num_type; - return root_impl(v0,v1,num_type); + 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 roundn(const T v0, const T v1) + inline T equal_impl(const T v0, const T v1, int_type_tag) { - typename details::number_type::type num_type; - return roundn_impl(v0,v1,num_type); + return (v0 == v1) ? 1 : 0; } - + template - inline T hypot(const T v0, const T v1) + inline T expm1_impl(const T v, real_type_tag) { - typename details::number_type::type num_type; - return hypot_impl(v0,v1,num_type); + // 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 atan2(const T v0, const T v1) + inline T expm1_impl(const T v, int_type_tag) { - typename details::number_type::type num_type; - return atan2_impl(v0,v1,num_type); + return T(std::exp(v)) - T(1); } - + template - inline T shr(const T v0, const T v1) + inline T nequal_impl(const T v0, const T v1, real_type_tag) + { + typedef real_type_tag rtg; + const T epsilon = epsilon_type::value(); + return (abs_impl(v0 - v1,rtg()) > (std::max(T(1),std::max(abs_impl(v0,rtg()),abs_impl(v1,rtg()))) * epsilon)) ? T(1) : T(0); + } + + inline float nequal_impl(const float v0, const float v1, real_type_tag) { - typename details::number_type::type num_type; - return shr_impl(v0,v1,num_type); + typedef real_type_tag rtg; + const float epsilon = epsilon_type::value(); + return (abs_impl(v0 - v1,rtg()) > (std::max(1.0f,std::max(abs_impl(v0,rtg()),abs_impl(v1,rtg()))) * epsilon)) ? 1.0f : 0.0f; } - + template - inline T shl(const T v0, const T v1) + inline T nequal_impl(const T v0, const T v1, int_type_tag) { - typename details::number_type::type num_type; - return shl_impl(v0,v1,num_type); + return (v0 != v1) ? 1 : 0; } - + template - inline T and_opr(const T v0, const T v1) + inline T modulus_impl(const T v0, const T v1, real_type_tag) { - typename details::number_type::type num_type; - return and_impl(v0,v1,num_type); + return std::fmod(v0,v1); } - + template - inline T nand_opr(const T v0, const T v1) + inline T modulus_impl(const T v0, const T v1, int_type_tag) { - typename details::number_type::type num_type; - return nand_impl(v0,v1,num_type); + return v0 % v1; } - + template - inline T or_opr(const T v0, const T v1) + inline T pow_impl(const T v0, const T v1, real_type_tag) { - typename details::number_type::type num_type; - return or_impl(v0,v1,num_type); + return std::pow(v0,v1); } - + template - inline T nor_opr(const T v0, const T v1) + inline T pow_impl(const T v0, const T v1, int_type_tag) { - typename details::number_type::type num_type; - return nor_impl(v0,v1,num_type); + return std::pow(static_cast(v0),static_cast(v1)); } - + template - inline T xor_opr(const T v0, const T v1) + inline T logn_impl(const T v0, const T v1, real_type_tag) { - typename details::number_type::type num_type; - return xor_impl(v0,v1,num_type); + return std::log(v0) / std::log(v1); } - + template - inline T xnor_opr(const T v0, const T v1) + inline T logn_impl(const T v0, const T v1, int_type_tag) { - typename details::number_type::type num_type; - return xnor_impl(v0,v1,num_type); + return static_cast(logn_impl(static_cast(v0),static_cast(v1),real_type_tag())); } - + 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)); + 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(); } - else + + template + inline T log1p_impl(const T v, int_type_tag) { - 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 - } + if (v > T(-1)) + { + return std::log(T(1) + v); + } + else + return std::numeric_limits::quiet_NaN(); } - 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; - } + + template + inline T root_impl(const T v0, const T v1, real_type_tag) + { + return std::pow(v0,T(1) / v1); } - else if ( - (static_cast('A') != *(itr + 1)) || - (static_cast('N') != *(itr + 2)) - ) + + template + inline T root_impl(const T v0, const T v1, int_type_tag) { - return false; + return root_impl(static_cast(v0),static_cast(v1),real_type_tag()); } - - 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_t inf_uc[] = "INFINITY"; - static const char_t inf_lc[] = "infinity"; - static const std::size_t inf_length = 8; - - const std::size_t length = std::distance(itr,end); - - if ((3 != length) && (inf_length != length)) - return false; - - const char* inf_itr = ('i' == (*itr)) ? inf_lc : inf_uc; - - while (end != itr) + + template + inline T round_impl(const T v, real_type_tag) { - 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,static_cast(-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& RefType; - typedef T (*qfunc_t)(Type t0, Type t1, Type t2, Type t3); - typedef T (*tfunc_t)(Type t0, Type t1, Type t2); - typedef T (*bfunc_t)(Type t0, Type t1); - typedef T (*ufunc_t)(Type t0); - }; - - } // namespace details - - 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; - typedef details::char_t char_t; - - generator() - : base_itr_(0), - s_itr_ (0), - s_end_ (0) - { - clear(); - } - - inline void clear() - { - base_itr_ = 0; - s_itr_ = 0; - s_end_ = 0; - token_list_.clear(); - token_itr_ = token_list_.end(); - store_token_itr_ = token_list_.end(); - } - - inline bool process(const std::string& str) - { - base_itr_ = str.data(); - s_itr_ = str.data(); - s_end_ = str.data() + str.size(); - - eof_token_.set_operator(token_t::e_eof,s_end_,s_end_,base_itr_); - token_list_.clear(); - - while (!is_end(s_itr_)) - { - scan_token(); - - if (token_list_.empty()) - return true; - else if (token_list_.back().is_error()) - return false; - } - - return true; + return ((v < T(0)) ? std::ceil(v - T(0.5)) : std::floor(v + T(0.5))); } - - inline bool empty() const + + template + inline T roundn_impl(const T v0, const T v1, real_type_tag) { - return token_list_.empty(); + 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); } - - inline std::size_t size() const + + template + inline T roundn_impl(const T v0, const T, int_type_tag) { - return token_list_.size(); + return v0; } - - inline void begin() + + template + inline T hypot_impl(const T v0, const T v1, real_type_tag) { - token_itr_ = token_list_.begin(); - store_token_itr_ = token_list_.begin(); + return std::sqrt((v0 * v0) + (v1 * v1)); } - - inline void store() + + template + inline T hypot_impl(const T v0, const T v1, int_type_tag) { - store_token_itr_ = token_itr_; + return static_cast(std::sqrt(static_cast((v0 * v0) + (v1 * v1)))); } - - inline void restore() + + template + inline T atan2_impl(const T v0, const T v1, real_type_tag) { - token_itr_ = store_token_itr_; + return std::atan2(v0,v1); } - - inline token_t& next_token() + + template + inline T atan2_impl(const T, const T, int_type_tag) { - if (token_list_.end() != token_itr_) - { - return *token_itr_++; - } - else - return eof_token_; + return 0; } - - inline token_t& peek_next_token() + + template + inline T shr_impl(const T v0, const T v1, real_type_tag) { - if (token_list_.end() != token_itr_) - { - return *token_itr_; - } - else - return eof_token_; + return v0 * (T(1) / std::pow(T(2),static_cast(static_cast(v1)))); } - - inline token_t& operator[](const std::size_t& index) + + template + inline T shr_impl(const T v0, const T v1, int_type_tag) { - if (index < token_list_.size()) - return token_list_[index]; - else - return eof_token_; + return v0 >> v1; } - - inline token_t operator[](const std::size_t& index) const + + template + inline T shl_impl(const T v0, const T v1, real_type_tag) { - if (index < token_list_.size()) - return token_list_[index]; - else - return eof_token_; + return v0 * std::pow(T(2),static_cast(static_cast(v1))); } - - inline bool finished() const + + template + inline T shl_impl(const T v0, const T v1, int_type_tag) { - return (token_list_.end() == token_itr_); + return v0 << v1; } - - inline void insert_front(token_t::token_type tk_type) + + template + inline T sgn_impl(const T v, real_type_tag) { - if ( - !token_list_.empty() && - (token_list_.end() != token_itr_) - ) - { - token_t t = *token_itr_; - - t.type = tk_type; - token_itr_ = token_list_.insert(token_itr_,t); - } - } - - inline std::string substr(const std::size_t& begin, const std::size_t& end) - { - const char* begin_itr = ((base_itr_ + begin) < s_end_) ? (base_itr_ + begin) : s_end_; - const char* end_itr = ((base_itr_ + end) < s_end_) ? (base_itr_ + end) : s_end_; - - return std::string(begin_itr,end_itr); - } - - inline std::string remaining() const - { - if (finished()) - return ""; - else if (token_list_.begin() != token_itr_) - return std::string(base_itr_ + (token_itr_ - 1)->position,s_end_); - else - return std::string(base_itr_ + token_itr_->position,s_end_); - } - - private: - - inline bool is_end(const char* itr) - { - 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_t c0, const char_t c1, int& mode, int& incr) - { - mode = 0; - if ('#' == c0) { mode = 1; incr = 1; } - else if ('/' == c0) - { - if ('/' == c1) { mode = 1; incr = 2; } - else if ('*' == c1) { mode = 2; incr = 2; } - } - return (0 != mode); - } - - static inline bool comment_end(const char_t c0, const char_t c1, 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_t c0 = s_itr_[0]; - - if (!is_end(s_itr_ + 1)) - { - const char_t c1 = s_itr_[1]; - - if (!is_end(s_itr_ + 2)) - { - const char_t c2 = s_itr_[2]; - - if ((c0 == '<') && (c1 == '=') && (c2 == '>')) - { - t.set_operator(token_t::e_swap,s_itr_,s_itr_ + 3,base_itr_); - token_list_.push_back(t); - s_itr_ += 3; - return; - } - } - - token_t::token_type ttype = token_t::e_none; - - if ((c0 == '<') && (c1 == '=')) ttype = token_t::e_lte; - else if ((c0 == '>') && (c1 == '=')) ttype = token_t::e_gte; - else if ((c0 == '<') && (c1 == '>')) ttype = token_t::e_ne; - else if ((c0 == '!') && (c1 == '=')) ttype = token_t::e_ne; - else if ((c0 == '=') && (c1 == '=')) ttype = token_t::e_eq; - else if ((c0 == ':') && (c1 == '=')) ttype = token_t::e_assign; - else if ((c0 == '<') && (c1 == '<')) ttype = token_t::e_shl; - else if ((c0 == '>') && (c1 == '>')) ttype = token_t::e_shr; - else if ((c0 == '+') && (c1 == '=')) ttype = token_t::e_addass; - else if ((c0 == '-') && (c1 == '=')) ttype = token_t::e_subass; - else if ((c0 == '*') && (c1 == '=')) ttype = token_t::e_mulass; - else if ((c0 == '/') && (c1 == '=')) ttype = token_t::e_divass; - else if ((c0 == '%') && (c1 == '=')) ttype = token_t::e_modass; - - if (token_t::e_none != ttype) - { - t.set_operator(ttype,s_itr_,s_itr_ + 2,base_itr_); - token_list_.push_back(t); - s_itr_ += 2; - return; - } - } - - if ('<' == c0) - t.set_operator(token_t::e_lt ,s_itr_,s_itr_ + 1,base_itr_); - else if ('>' == c0) - t.set_operator(token_t::e_gt ,s_itr_,s_itr_ + 1,base_itr_); - else if (';' == c0) - t.set_operator(token_t::e_eof,s_itr_,s_itr_ + 1,base_itr_); - else if ('&' == c0) - t.set_symbol(s_itr_,s_itr_ + 1,base_itr_); - else if ('|' == c0) - t.set_symbol(s_itr_,s_itr_ + 1,base_itr_); - else - t.set_operator(token_t::token_type(c0),s_itr_,s_itr_ + 1,base_itr_); - - token_list_.push_back(t); - ++s_itr_; - } - - inline void scan_symbol() - { - const char* initial_itr = s_itr_; - - while (!is_end(s_itr_)) - { - if (!details::is_letter_or_digit(*s_itr_) && ('_' != (*s_itr_))) - { - if ('.' != (*s_itr_)) - break; - /* - Permit symbols that contain a 'dot' - Allowed : abc.xyz, a123.xyz, abc.123, abc_.xyz a123_.xyz abc._123 - Disallowed: .abc, abc., abc., abc. - */ - if ( - (s_itr_ != initial_itr) && - !is_end(s_itr_ + 1) && - details::is_letter_or_digit(*s_itr_ + 1) && - ('_' != (*s_itr_ + 1)) - ) - break; - } - - ++s_itr_; - } - - token_t t; - t.set_symbol(initial_itr,s_itr_,base_itr_); - token_list_.push_back(t); - } - - inline void scan_number() - { - /* - Attempt to match a valid numeric value in one of the following formats: - 01. 123456 - 02. 123.456 - 03. 123.456e3 - 04. 123.456E3 - 05. 123.456e+3 - 06. 123.456E+3 - 07. 123.456e-3 - 08. 123.456E-3 - 09. .1234 - 10. .1234e3 - 11. .1234E+3 - 12. .1234e+3 - 13. .1234E-3 - 14. .1234e-3 - */ - const char* initial_itr = s_itr_; - bool dot_found = false; - bool e_found = false; - bool post_e_sign_found = false; - bool post_e_digit_found = false; - token_t t; - - while (!is_end(s_itr_)) - { - if ('.' == (*s_itr_)) - { - if (dot_found) - { - t.set_error(token::e_err_number,initial_itr,s_itr_,base_itr_); - token_list_.push_back(t); - return; - } - - dot_found = true; - ++s_itr_; - - continue; - } - else if (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_) && !post_e_digit_found) - { - if (post_e_sign_found) - { - t.set_error(token::e_err_number,initial_itr,s_itr_,base_itr_); - token_list_.push_back(t); - - return; - } - - post_e_sign_found = true; - ++s_itr_; - - continue; - } - else if (e_found && details::is_digit(*s_itr_)) - { - post_e_digit_found = true; - ++s_itr_; - - continue; - } - else if (('.' != (*s_itr_)) && !details::is_digit(*s_itr_)) - break; - else - ++s_itr_; - } - - t.set_numeric(initial_itr,s_itr_,base_itr_); - token_list_.push_back(t); - - return; - } - - inline void scan_special_function() - { - 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 (!escaped && ('\\' == *s_itr_)) - { - escaped_found = true; - escaped = true; - ++s_itr_; - - continue; - } - else if (!escaped) - { - if ('\'' == *s_itr_) - break; - } - else if (escaped) - { - if (!is_end(s_itr_) && ('0' == *(s_itr_))) - { - /* - Note: The following 'awkward' conditional is - due to various broken msvc compilers. - */ -#if _MSC_VER == 1600 - const bool within_range = !is_end(s_itr_ + 2) && - !is_end(s_itr_ + 3) ; -#else - const bool within_range = !is_end(s_itr_ + 1) && - !is_end(s_itr_ + 2) && - !is_end(s_itr_ + 3) ; -#endif - - const bool x_seperator = ('x' == *(s_itr_ + 1)) || - ('X' == *(s_itr_ + 1)) ; - - const bool both_digits = details::is_hex_digit(*(s_itr_ + 2)) && - details::is_hex_digit(*(s_itr_ + 3)) ; - - if (!within_range || !x_seperator || !both_digits) - { - t.set_error(token::e_err_string,initial_itr,s_itr_,base_itr_); - token_list_.push_back(t); - - return; - } - else - s_itr_ += 3; - } - - escaped = false; - } - - ++s_itr_; - } - - if (is_end(s_itr_)) - { - t.set_error(token::e_err_string,initial_itr,s_itr_,base_itr_); - token_list_.push_back(t); - - return; - } - - if (!escaped_found) - t.set_string(initial_itr,s_itr_,base_itr_); - else - { - std::string parsed_string(initial_itr,s_itr_); - 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); + if (v > T(0)) return T(+1); + else if (v < T(0)) return T(-1); + else return T( 0); } - - virtual bool operator()(const token&) + + template + inline T sgn_impl(const T v, int_type_tag) { - return false; + if (v > T(0)) return T(+1); + else if (v < T(0)) return T(-1); + else return T( 0); } - - virtual bool operator()(const token&, const token&) + + template + inline T and_impl(const T v0, const T v1, real_type_tag) { - return false; + return (is_true_impl(v0) && is_true_impl(v1)) ? T(1) : T(0); } - - virtual bool operator()(const token&, const token&, const token&) + + template + inline T and_impl(const T v0, const T v1, int_type_tag) { - return false; + return v0 && v1; } - - virtual bool operator()(const token&, const token&, const token&, const token&) + + template + inline T nand_impl(const T v0, const T v1, real_type_tag) { - return false; + return (is_false_impl(v0) || is_false_impl(v1)) ? T(1) : T(0); } - - 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; - } - -#define token_inserter_empty_body \ -{ \ -return -1; \ -} \ - - inline virtual int insert(const token&, token&) - token_inserter_empty_body - - inline virtual int insert(const token&, const token&, token&) - token_inserter_empty_body - - inline virtual int insert(const token&, const token&, const token&, token&) - token_inserter_empty_body - - inline virtual int insert(const token&, const token&, const token&, const token&, token&) - token_inserter_empty_body - - inline virtual int insert(const token&, const token&, const token&, const token&, const token&, token&) - token_inserter_empty_body - -#undef token_inserter_empty_body - - private: - - 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[i],g[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[i],g[i + 1],g[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: - - using lexer::token_inserter::insert; - - commutative_inserter() - : lexer::token_inserter(2) - {} - - inline void ignore_symbol(const std::string& symbol) - { - ignore_set_.insert(symbol); - } - - inline int insert(const lexer::token& t0, const lexer::token& t1, lexer::token& new_token) - { - bool match = false; - new_token.type = lexer::token::e_mul; - new_token.value = "*"; - new_token.position = t1.position; - - if (t0.type == lexer::token::e_symbol) - { - if (ignore_set_.end() != ignore_set_.find(t0.value)) - { - return -1; - } - else if (!t0.value.empty() && ('$' == t0.value[0])) - { - return -1; - } - } - - if (t1.type == lexer::token::e_symbol) - { - if (ignore_set_.end() != ignore_set_.find(t1.value)) - { - return -1; - } - } - if ((t0.type == lexer::token::e_number ) && (t1.type == lexer::token::e_symbol )) match = true; - else if ((t0.type == lexer::token::e_number ) && (t1.type == lexer::token::e_lbracket )) match = true; - else if ((t0.type == lexer::token::e_number ) && (t1.type == lexer::token::e_lcrlbracket)) match = true; - else if ((t0.type == lexer::token::e_number ) && (t1.type == lexer::token::e_lsqrbracket)) match = true; - else if ((t0.type == lexer::token::e_symbol ) && (t1.type == lexer::token::e_number )) match = true; - else if ((t0.type == lexer::token::e_rbracket ) && (t1.type == lexer::token::e_number )) match = true; - else if ((t0.type == lexer::token::e_rcrlbracket) && (t1.type == lexer::token::e_number )) match = true; - else if ((t0.type == lexer::token::e_rsqrbracket) && (t1.type == lexer::token::e_number )) match = true; - else if ((t0.type == lexer::token::e_rbracket ) && (t1.type == lexer::token::e_symbol )) match = true; - else if ((t0.type == lexer::token::e_rcrlbracket) && (t1.type == lexer::token::e_symbol )) match = true; - else if ((t0.type == lexer::token::e_rsqrbracket) && (t1.type == lexer::token::e_symbol )) match = true; - - 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 if ((t0.type == lexer::token::e_add) && (t1.type == lexer::token::e_sub)) - { - t.type = lexer::token::e_sub; - t.value = "-"; - t.position = t0.position; - - return true; - } - // '- +' --> '-' - else if ((t0.type == lexer::token::e_sub) && (t1.type == lexer::token::e_add)) - { - t.type = lexer::token::e_sub; - t.value = "-"; - t.position = t0.position; - - return true; - } - // '- -' --> '-' - else if ((t0.type == lexer::token::e_sub) && (t1.type == lexer::token::e_sub)) - { - /* - Note: May need to reconsider this when wanting to implement - pre/postfix decrement operator - */ - t.type = lexer::token::e_add; - t.value = "+"; - t.position = t0.position; - - return true; - } - else - return false; - } - - inline bool join(const lexer::token& t0, const lexer::token& t1, const lexer::token& t2, lexer::token& t) - { - // '[ * ]' --> '[*]' - if ( - (t0.type == lexer::token::e_lsqrbracket) && - (t1.type == lexer::token::e_mul ) && - (t2.type == lexer::token::e_rsqrbracket) - ) - { - t.type = lexer::token::e_symbol; - t.value = "[*]"; - t.position = t0.position; - - return true; - } - else - return false; - } - }; - - class bracket_checker : public lexer::token_scanner - { - public: - - using lexer::token_scanner::operator(); - - bracket_checker() - : token_scanner(1), - state_(true) - {} - - bool result() - { - if (!stack_.empty()) - { - lexer::token t; - t.value = stack_.top().first; - t.position = stack_.top().second; - error_token_ = t; - state_ = false; - - return false; - } - else - return state_; - } - - lexer::token error_token() - { - return error_token_; - } - - void reset() - { - // Why? because msvc doesn't support swap properly. - stack_ = std::stack >(); - state_ = true; - error_token_.clear(); - } - - bool operator()(const lexer::token& t) - { - if ( - !t.value.empty() && - (lexer::token::e_string != t.type) && - (lexer::token::e_symbol != t.type) && - exprtk::details::is_bracket(t.value[0]) - ) - { - details::char_t c = t.value[0]; - - if (t.type == lexer::token::e_lbracket) stack_.push(std::make_pair(')',t.position)); - else if (t.type == lexer::token::e_lcrlbracket) stack_.push(std::make_pair('}',t.position)); - else if (t.type == lexer::token::e_lsqrbracket) stack_.push(std::make_pair(']',t.position)); - else if (exprtk::details::is_right_bracket(c)) - { - if (stack_.empty()) - { - state_ = false; - error_token_ = t; - - return false; - } - else if (c != stack_.top().first) - { - state_ = false; - error_token_ = t; - - return false; - } - else - stack_.pop(); - } - } - - return true; - } - - private: - - bool state_; - std::stack > stack_; - lexer::token error_token_; - }; - - class numeric_checker : public lexer::token_scanner - { - public: - - using lexer::token_scanner::operator(); - - numeric_checker() - : token_scanner (1), - current_index_(0) - {} - - bool result() - { - return error_list_.empty(); - } - - void reset() - { - error_list_.clear(); - current_index_ = 0; - } - - bool operator()(const lexer::token& t) - { - if (token::e_number == t.type) - { - double v; - - if (!exprtk::details::string_to_real(t.value,v)) - { - error_list_.push_back(current_index_); - } - } - - ++current_index_; - - return true; - } - - std::size_t error_count() const - { - return error_list_.size(); - } - - std::size_t error_index(const std::size_t& i) - { - if (i < error_list_.size()) - return error_list_[i]; - else - return std::numeric_limits::max(); - } - - void clear_errors() - { - error_list_.clear(); - } - - private: - - std::size_t current_index_; - std::vector error_list_; - }; - - class symbol_replacer : public lexer::token_modifier - { - private: - - typedef std::map,details::ilesscompare> replace_map_t; - - public: - - bool remove(const std::string& target_symbol) - { - 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: - - using lexer::token_scanner::operator(); - - sequence_validator() - : lexer::token_scanner(2) - { - add_invalid(lexer::token::e_number ,lexer::token::e_number ); - add_invalid(lexer::token::e_string ,lexer::token::e_string ); - add_invalid(lexer::token::e_number ,lexer::token::e_string ); - add_invalid(lexer::token::e_string ,lexer::token::e_number ); - add_invalid(lexer::token::e_string ,lexer::token::e_ternary); - 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); - - for (std::size_t i = 0; i < token_modifier_list.size(); ++i) - { - lexer::token_modifier& modifier = (*token_modifier_list[i]); - - modifier.reset(); - modifier.process(g); - - if (!modifier.result()) - { - error_token_modifier = token_modifier_list[i]; - - return false; - } - } - - return true; - } - - inline bool run_joiners(lexer::generator& g) - { - error_token_joiner = reinterpret_cast(0); - - for (std::size_t i = 0; i < token_joiner_list.size(); ++i) - { - lexer::token_joiner& joiner = (*token_joiner_list[i]); - - joiner.reset(); - joiner.process(g); - - if (!joiner.result()) - { - error_token_joiner = token_joiner_list[i]; - - return false; - } - } - - return true; - } - - inline bool run_inserters(lexer::generator& g) - { - error_token_inserter = reinterpret_cast(0); - - for (std::size_t i = 0; i < token_inserter_list.size(); ++i) - { - lexer::token_inserter& inserter = (*token_inserter_list[i]); - - inserter.reset(); - inserter.process(g); - - if (!inserter.result()) - { - error_token_inserter = token_inserter_list[i]; - - return false; - } - } - - return true; - } - - inline bool run_scanners(lexer::generator& g) - { - error_token_scanner = reinterpret_cast(0); - - for (std::size_t i = 0; i < token_scanner_list.size(); ++i) - { - lexer::token_scanner& scanner = (*token_scanner_list[i]); - - scanner.reset(); - scanner.process(g); - - if (!scanner.result()) - { - error_token_scanner = token_scanner_list[i]; - - return false; - } - } - - return true; - } - - std::vector token_scanner_list; - std::vector token_modifier_list; - std::vector token_joiner_list; - std::vector token_inserter_list; - - lexer::token_scanner* error_token_scanner; - lexer::token_modifier* error_token_modifier; - lexer::token_joiner* error_token_joiner; - lexer::token_inserter* error_token_inserter; - }; - } - - class parser_helper - { - public: - - typedef token token_t; - typedef generator generator_t; - - inline bool init(const std::string& str) + + template + inline T nand_impl(const T v0, const T v1, int_type_tag) { - if (!lexer_.process(str)) - { - return false; - } - - lexer_.begin(); - - next_token(); - - return true; + return !(v0 && v1); } - - inline generator_t& lexer() + + template + inline T or_impl(const T v0, const T v1, real_type_tag) { - return lexer_; + return (is_true_impl(v0) || is_true_impl(v1)) ? T(1) : T(0); } - - inline const generator_t& lexer() const + + template + inline T or_impl(const T v0, const T v1, int_type_tag) { - return lexer_; + return (v0 || v1); } - - inline void store_token() + + template + inline T nor_impl(const T v0, const T v1, real_type_tag) { - lexer_.store(); - store_current_token_ = current_token_; + return (is_false_impl(v0) && is_false_impl(v1)) ? T(1) : T(0); } - - inline void restore_token() + + template + inline T nor_impl(const T v0, const T v1, int_type_tag) { - lexer_.restore(); - current_token_ = store_current_token_; + return !(v0 || v1); } - - inline void next_token() + + template + inline T xor_impl(const T v0, const T v1, real_type_tag) { - current_token_ = lexer_.next_token(); + return (is_false_impl(v0) != is_false_impl(v1)) ? T(1) : T(0); } - - inline const token_t& current_token() const + + template + inline T xor_impl(const T v0, const T v1, int_type_tag) { - return current_token_; + return v0 ^ v1; } - - enum token_advance_mode - { - e_hold = 0, - e_advance = 1 - }; - - inline void advance_token(const token_advance_mode mode) - { - if (e_advance == mode) - { - next_token(); - } - } - - inline bool token_is(const token_t::token_type& ttype, const token_advance_mode mode = e_advance) - { - if (current_token().type != ttype) - { - return false; - } - - advance_token(mode); - - return true; - } - - inline bool token_is(const token_t::token_type& ttype, - const std::string& value, - const token_advance_mode mode = e_advance) - { - if ( - (current_token().type != ttype) || - !exprtk::details::imatch(value,current_token().value) - ) - { - return false; - } - - advance_token(mode); - - return true; - } - - inline bool token_is_then_assign(const token_t::token_type& ttype, - std::string& token, - const token_advance_mode mode = e_advance) - { - if (current_token_.type != ttype) - { - return false; - } - - token = current_token_.value; - - advance_token(mode); - - return true; - } - - template class Container> - inline bool token_is_then_assign(const token_t::token_type& ttype, - Container& token_list, - const token_advance_mode mode = e_advance) - { - if (current_token_.type != ttype) - { - return false; - } - - token_list.push_back(current_token_.value); - - advance_token(mode); - - return true; - } - - inline bool peek_token_is(const token_t::token_type& ttype) - { - return (lexer_.peek_next_token().type == ttype); - } - - inline bool peek_token_is(const std::string& s) - { - return (exprtk::details::imatch(lexer_.peek_next_token().value,s)); - } - - private: - - generator_t lexer_; - token_t current_token_; - token_t store_current_token_; - }; - } - - template - class vector_view - { - public: - - typedef T* data_ptr_t; - - vector_view(data_ptr_t data, const std::size_t& size) - : size_(size), - data_(data), - data_ref_(0) - {} - - vector_view(const vector_view& vv) - : size_(vv.size_), - data_(vv.data_), - data_ref_(0) - {} - - inline void rebase(data_ptr_t data) - { - data_ = data; - - if (!data_ref_.empty()) - { - for (std::size_t i = 0; i < data_ref_.size(); ++i) - { - (*data_ref_[i]) = data; - } - } - } - - inline data_ptr_t data() const - { - return data_; - } - - inline std::size_t size() const - { - return size_; - } - - inline const T& operator[](const std::size_t index) const - { - return data_[index]; - } - - inline T& operator[](const std::size_t index) - { - return data_[index]; - } - - void set_ref(data_ptr_t* data_ref) - { - data_ref_.push_back(data_ref); - } - - private: - - std::size_t size_; - data_ptr_t data_; - std::vector data_ref_; - }; - - template - inline vector_view make_vector_view(T* data, - const std::size_t size, const std::size_t offset = 0) - { - return vector_view(data + offset,size); - } - - template - inline vector_view make_vector_view(std::vector& v, - const std::size_t size, const std::size_t offset = 0) - { - return vector_view(v.data() + offset,size); - } - - template class results_context; - - template - struct type_store - { - enum store_type - { - e_unknown, - e_scalar, - e_vector, - e_string - }; - - type_store() - : 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 + + template + inline T xnor_impl(const T v0, const T v1, real_type_tag) { - return parameter_list_.empty(); + 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); } - - inline std::size_t size() const + + template + inline T xnor_impl(const T v0, const T v1, int_type_tag) { - return parameter_list_.size(); + 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); } - - inline type_store& operator[](const std::size_t& index) - { - return parameter_list_[index]; + + #if (defined(_MSC_VER) && (_MSC_VER >= 1900)) || !defined(_MSC_VER) + #define exprtk_define_erf(TT,impl) \ + inline TT erf_impl(TT v) { return impl(v); } \ + + exprtk_define_erf( float,::erff) + exprtk_define_erf( double,::erf ) + exprtk_define_erf(long double,::erfl) + #undef exprtk_define_erf + #endif + + template + inline T erf_impl(T v, real_type_tag) + { + #if defined(_MSC_VER) && (_MSC_VER < 1900) + // Credits: Abramowitz & Stegun Equations 7.1.25-28 + static const T c[] = { + T( 1.26551223), T(1.00002368), + T( 0.37409196), T(0.09678418), + T(-0.18628806), T(0.27886807), + T(-1.13520398), T(1.48851587), + T(-0.82215223), T(0.17087277) + }; + + const T t = T(1) / (T(1) + T(0.5) * abs_impl(v,real_type_tag())); + + T result = T(1) - t * std::exp((-v * v) - + c[0] + t * (c[1] + t * + (c[2] + t * (c[3] + t * + (c[4] + t * (c[5] + t * + (c[6] + t * (c[7] + t * + (c[8] + t * (c[9])))))))))); + + return (v >= T(0)) ? result : -result; + #else + return erf_impl(v); + #endif } - - inline const type_store& operator[](const std::size_t& index) const + + template + inline T erf_impl(T v, int_type_tag) { - return parameter_list_[index]; + return erf_impl(static_cast(v),real_type_tag()); } - - inline type_store& front() + + #if (defined(_MSC_VER) && (_MSC_VER >= 1900)) || !defined(_MSC_VER) + #define exprtk_define_erfc(TT,impl) \ + inline TT erfc_impl(TT v) { return impl(v); } \ + + exprtk_define_erfc( float,::erfcf) + exprtk_define_erfc( double,::erfc ) + exprtk_define_erfc(long double,::erfcl) + #undef exprtk_define_erfc + #endif + + template + inline T erfc_impl(T v, real_type_tag) { - return parameter_list_[0]; + #if defined(_MSC_VER) && (_MSC_VER < 1900) + return T(1) - erf_impl(v,real_type_tag()); + #else + return erfc_impl(v); + #endif } - - inline const type_store& front() const + + template + inline T erfc_impl(T v, int_type_tag) { - return parameter_list_[0]; + return erfc_impl(static_cast(v),real_type_tag()); } - - inline type_store& back() + + template + inline T ncdf_impl(T v, real_type_tag) { - return parameter_list_.back(); + 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; } - - inline const type_store& back() const + + template + inline T ncdf_impl(T v, int_type_tag) { - return parameter_list_.back(); + return ncdf_impl(static_cast(v),real_type_tag()); } - - private: - - std::vector& parameter_list_; - - friend class results_context; - }; - - 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 + + template + inline T sinc_impl(T v, real_type_tag) { - return ts_.size; + if (std::abs(v) >= std::numeric_limits::epsilon()) + return(std::sin(v) / v); + else + return T(1); } - - 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 + + template + inline T sinc_impl(T v, int_type_tag) { - return static_cast(data_ + ts_.size); + return sinc_impl(static_cast(v),real_type_tag()); } - - inline value_t* end() + + template inline T acos_impl(const T v, real_type_tag) { return std::acos (v); } + template inline T acosh_impl(const T v, real_type_tag) { return std::log(v + std::sqrt((v * v) - T(1))); } + template inline T asin_impl(const T v, real_type_tag) { return std::asin (v); } + template inline T asinh_impl(const T v, real_type_tag) { return std::log(v + std::sqrt((v * v) + T(1))); } + template inline T atan_impl(const T v, real_type_tag) { return std::atan (v); } + template inline T atanh_impl(const T v, real_type_tag) { return (std::log(T(1) + v) - std::log(T(1) - v)) / T(2); } + template inline T ceil_impl(const T v, real_type_tag) { return std::ceil (v); } + template inline T cos_impl(const T v, real_type_tag) { return std::cos (v); } + template inline T cosh_impl(const T v, real_type_tag) { return std::cosh (v); } + template inline T exp_impl(const T v, real_type_tag) { return std::exp (v); } + template inline T floor_impl(const T v, real_type_tag) { return std::floor(v); } + template inline T log_impl(const T v, real_type_tag) { return std::log (v); } + template inline T log10_impl(const T v, real_type_tag) { return std::log10(v); } + template inline T log2_impl(const T v, real_type_tag) { return std::log(v)/T(numeric::constant::log2); } + template inline T neg_impl(const T v, real_type_tag) { return -v; } + template inline T pos_impl(const T v, real_type_tag) { return +v; } + template inline T sin_impl(const T v, real_type_tag) { return std::sin (v); } + template inline T sinh_impl(const T v, real_type_tag) { return std::sinh (v); } + template inline T sqrt_impl(const T v, real_type_tag) { return std::sqrt (v); } + template inline T tan_impl(const T v, real_type_tag) { return std::tan (v); } + template inline T tanh_impl(const T v, real_type_tag) { return std::tanh (v); } + template inline T cot_impl(const T v, real_type_tag) { return T(1) / std::tan(v); } + template inline T sec_impl(const T v, real_type_tag) { return T(1) / std::cos(v); } + template inline T csc_impl(const T v, real_type_tag) { return T(1) / std::sin(v); } + template inline T r2d_impl(const T v, real_type_tag) { return (v * T(numeric::constant::_180_pi)); } + template inline T d2r_impl(const T v, real_type_tag) { return (v * T(numeric::constant::pi_180)); } + template inline T d2g_impl(const T v, real_type_tag) { return (v * T(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 static_cast(data_ + ts_.size); + return std::equal_to()(T(0),std::fmod(v,T(1))); } - - 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)) - {} - - scalar_view(const type_store_t& ts) - : v_(*reinterpret_cast(const_cast(ts).data)) - {} - - inline value_t& operator()() - { - return v_; - } - - inline const value_t& operator()() const - { - return v_; - } - - template - inline bool to_int(IntType& i) const - { - if (!exprtk::details::numeric::is_integer(v_)) - return false; - - i = static_cast(v_); - - return true; - } - - template - inline bool to_uint(UIntType& u) const - { - if (v_ < T(0)) - return false; - else if (!exprtk::details::numeric::is_integer(v_)) - return false; - - u = static_cast(v_); - - return true; - } - - T& v_; - }; - }; - - template - inline std::string to_str(const StringView& view) - { - return std::string(view.begin(),view.size()); - } - - namespace details - { - template class return_node; - template class return_envelope_node; - } - - template - class results_context - { - public: - - typedef type_store type_store_t; - - results_context() - : results_available_(false) - {} - - inline std::size_t count() const - { - if (results_available_) - return parameter_list_.size(); - else - return 0; - } - - inline type_store_t& operator[](const std::size_t& index) - { - return parameter_list_[index]; - } - - inline const type_store_t& operator[](const std::size_t& index) const - { - return parameter_list_[index]; - } - - private: - - inline void clear() - { - results_available_ = false; - } - - typedef std::vector ts_list_t; - typedef typename type_store_t::parameter_list parameter_list_t; - - inline void assign(const parameter_list_t& pl) - { - parameter_list_ = pl.parameter_list_; - results_available_ = true; - } - - bool results_available_; - ts_list_t parameter_list_; - - friend class details::return_node; - friend class details::return_envelope_node; - }; - - 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, - e_sf4ext60 = 2060 - }; - - inline std::string to_str(const operator_type opr) - { - switch (opr) - { - case e_add : return "+"; - case e_sub : return "-"; - case e_mul : return "*"; - case e_div : return "/"; - case e_mod : return "%"; - case e_pow : return "^"; - case e_assign : return ":="; - case e_addass : return "+="; - case e_subass : return "-="; - case e_mulass : return "*="; - case e_divass : return "/="; - case e_modass : return "%="; - case e_lt : return "<"; - case e_lte : return "<="; - case e_eq : return "=="; - case e_equal : return "="; - case e_ne : return "!="; - case e_nequal : return "<>"; - case e_gte : return ">="; - case e_gt : return ">"; - default : return"N/A"; - } - } - - struct base_operation_t - { - base_operation_t(const operator_type t, const unsigned int& np) - : type(t), - num_params(np) - {} - - operator_type type; - unsigned int num_params; - }; - - namespace loop_unroll - { -#ifndef exprtk_disable_superscalar_unroll - const unsigned int global_loop_batch_size = 16; -#else - const unsigned int global_loop_batch_size = 4; -#endif - - struct details - { - details(const std::size_t& vsize, - const unsigned int loop_batch_size = global_loop_batch_size) - : batch_size(loop_batch_size), - remainder (vsize % batch_size), - upper_bound(static_cast(vsize) - (remainder ? loop_batch_size : 0)) - {} - - int batch_size; - int remainder; - int upper_bound; - }; - } - -#ifdef exprtk_enable_debugging - inline void dump_ptr(const std::string& s, const void* ptr, const std::size_t size = 0) - { - if (size) - exprtk_debug(("%s - addr: %p\n",s.c_str(),ptr)); - else - exprtk_debug(("%s - addr: %p size: %d\n", - s.c_str(), - ptr, - static_cast(size))); - } -#else - inline void dump_ptr(const std::string&, const void*) {} - inline void dump_ptr(const std::string&, const void*, const std::size_t) {} -#endif - - template - class vec_data_store - { - public: - - typedef vec_data_store type; - typedef T* data_t; - - private: - - struct control_block - { - control_block() - : ref_count(1), - size (0), - data (0), - destruct (true) - {} - - control_block(const std::size_t& dsize) - : ref_count(1), - size (dsize), - data (0), - destruct (true) - { create_data(); } - - control_block(const std::size_t& dsize, data_t dptr, bool dstrct = false) - : ref_count(1), - size (dsize), - data (dptr ), - destruct (dstrct) - {} - - ~control_block() - { - if (data && destruct && (0 == ref_count)) - { - dump_ptr("~control_block() data",data); - delete[] data; - data = 0; - } - } - - static inline control_block* create(const std::size_t& size, data_t data_ptr = data_t(0), bool dstrct = false) - { - if (size) - { - if (0 == data_ptr) - return new control_block(size); - else - return new control_block(size, data_ptr, dstrct); - } - else - return new control_block; - } - - static inline void destroy(control_block*& cntrl_blck) - { - if (cntrl_blck) - { - if ( - (0 != cntrl_blck->ref_count) && - (0 == --cntrl_blck->ref_count) - ) - { - delete cntrl_blck; - } - - cntrl_blck = 0; - } - } - - std::size_t ref_count; - std::size_t size; - data_t data; - bool destruct; - - private: - - control_block(const control_block&); - control_block& operator=(const control_block&); - - inline void create_data() - { - destruct = true; - data = new T[size]; - std::fill_n(data,size,T(0)); - dump_ptr("control_block::create_data() - data",data,size); - } - }; - - public: - - vec_data_store() - : control_block_(control_block::create(0)) - {} - - vec_data_store(const std::size_t& size) - : control_block_(control_block::create(size,(data_t)(0),true)) - {} - - vec_data_store(const std::size_t& size, data_t data, bool dstrct = false) - : control_block_(control_block::create(size, data, dstrct)) - {} - - vec_data_store(const type& vds) + + template + inline bool is_integer_impl(const T&, int_type_tag) { - control_block_ = vds.control_block_; - control_block_->ref_count++; + return true; } - - ~vec_data_store() + } + + 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) { - control_block::destroy(control_block_); + unsigned int k = N; + T l = T(1); + + while (k) + { + if (k & 1) + { + l *= v; + --k; + } + + v *= v; + k >>= 1; + } + + return l; } - - type& operator=(const type& vds) + }; + + 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 (this != &vds) - { - std::size_t final_size = min_size(control_block_, vds.control_block_); - - vds.control_block_->size = final_size; - control_block_->size = final_size; - - if (control_block_->destruct || (0 == control_block_->data)) - { - control_block::destroy(control_block_); - - control_block_ = vds.control_block_; - control_block_->ref_count++; - } - } - - return *this; + if (exponent > 0) + return T(d * fract10[e]); + else + return T(d / fract10[e]); } - - inline data_t data() + 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) { - return control_block_->data; + #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 } - - inline data_t data() const + } + 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 control_block_->data; + return false; } - - inline std::size_t size() + } + 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_t inf_uc[] = "INFINITY"; + static const char_t inf_lc[] = "infinity"; + static const std::size_t inf_length = 8; + + const std::size_t length = std::distance(itr,end); + + 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)) { - return control_block_->size; + ++itr; + ++inf_itr; + continue; } - - inline std::size_t size() const + 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) { - return control_block_->size; - } - - inline data_t& ref() - { - return control_block_->data; - } - - inline void dump() const - { -#ifdef exprtk_enable_debugging - exprtk_debug(("size: %d\taddress:%p\tdestruct:%c\n", - size(), - data(), - (control_block_->destruct ? 'T' : 'F'))); - - for (std::size_t i = 0; i < size(); ++i) - { - if (5 == i) - exprtk_debug(("\n")); - - exprtk_debug(("%15.10f ",data()[i])); - } - exprtk_debug(("\n")); -#endif + // 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) } - - static inline void match_sizes(type& vds0, type& vds1) + + if (curr != itr) instate = true; + } + + int exponent = 0; + + if (end != itr) + { + if ('.' == (*itr)) { - std::size_t size = min_size(vds0.control_block_,vds1.control_block_); - vds0.control_block_->size = size; - vds1.control_block_->size = size; + 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,static_cast(-std::distance(curr,itr))); + } + + #undef parse_digit_1 + #undef parse_digit_2 } - - private: - - static inline std::size_t min_size(control_block* cb0, control_block* cb1) + + if (end != itr) { - std::size_t size0 = cb0->size; - std::size_t size1 = cb1->size; - - if (size0 && size1) - return std::min(size0,size1); - else - return (size0) ? size0 : size1; + 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; + } } - - control_block* control_block_; - }; - - namespace numeric - { - namespace details - { - template - inline T process_impl(const operator_type operation, const T arg) - { - switch (operation) - { - case e_abs : return numeric::abs (arg); - case e_acos : return numeric::acos (arg); - case e_acosh : return numeric::acosh(arg); - case e_asin : return numeric::asin (arg); - case e_asinh : return numeric::asinh(arg); - case e_atan : return numeric::atan (arg); - case e_atanh : return numeric::atanh(arg); - case e_ceil : return numeric::ceil (arg); - case e_cos : return numeric::cos (arg); - case e_cosh : return numeric::cosh (arg); - case e_exp : return numeric::exp (arg); - case e_expm1 : return numeric::expm1(arg); - case e_floor : return numeric::floor(arg); - case e_log : return numeric::log (arg); - case e_log10 : return numeric::log10(arg); - case e_log2 : return numeric::log2 (arg); - case e_log1p : return numeric::log1p(arg); - case e_neg : return numeric::neg (arg); - case e_pos : return numeric::pos (arg); - case e_round : return numeric::round(arg); - case e_sin : return numeric::sin (arg); - case e_sinc : return numeric::sinc (arg); - case e_sinh : return numeric::sinh (arg); - case e_sqrt : return numeric::sqrt (arg); - case e_tan : return numeric::tan (arg); - case e_tanh : return numeric::tanh (arg); - case e_cot : return numeric::cot (arg); - case e_sec : return numeric::sec (arg); - case e_csc : return numeric::csc (arg); - case e_r2d : return numeric::r2d (arg); - case e_d2r : return numeric::d2r (arg); - case e_d2g : return numeric::d2g (arg); - case e_g2d : return numeric::g2d (arg); - case e_notl : return numeric::notl (arg); - case e_sgn : return numeric::sgn (arg); - case e_erf : return numeric::erf (arg); - case e_erfc : return numeric::erfc (arg); - case e_ncdf : return numeric::ncdf (arg); - case e_frac : return numeric::frac (arg); - case e_trunc : return numeric::trunc(arg); - default : 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) + } + + 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& RefType; + typedef T (*qfunc_t)(Type t0, Type t1, Type t2, Type t3); + typedef T (*tfunc_t)(Type t0, Type t1, Type t2); + typedef T (*bfunc_t)(Type t0, Type t1); + typedef T (*ufunc_t)(Type t0); + }; + + } // namespace details + + 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) + ) { - return exprtk::details::numeric::details::process_impl(operation,arg); + type = et; } - - 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_vararg , e_conditional , e_while , e_repeat , - e_for , e_switch , e_mswitch , e_return , - e_retenv , e_variable , e_stringvar , e_stringconst , - e_stringvarrng , e_cstringvarrng, e_strgenrange , e_strconcat , - e_stringvarsize, e_strswap , e_stringsize , e_function , - e_vafunction , e_genfunction , e_strfunction , e_strcondition , - e_strccondition, e_add , e_sub , e_mul , - e_div , e_mod , e_pow , e_lt , - e_lte , e_gt , e_gte , e_eq , - e_ne , e_and , e_nand , e_or , - e_nor , e_xor , e_xnor , e_in , - e_like , e_ilike , e_inranges , e_ipow , - e_ipowinv , e_abs , e_acos , e_acosh , - e_asin , e_asinh , e_atan , e_atanh , - e_ceil , e_cos , e_cosh , e_exp , - e_expm1 , e_floor , e_log , e_log10 , - e_log2 , e_log1p , e_neg , e_pos , - e_round , e_sin , e_sinc , e_sinh , - e_sqrt , e_tan , e_tanh , e_cot , - e_sec , e_csc , e_r2d , e_d2r , - e_d2g , e_g2d , e_notl , e_sgn , - e_erf , e_erfc , e_ncdf , e_frac , - e_trunc , e_uvouv , e_vov , e_cov , - e_voc , e_vob , e_bov , e_cob , - e_boc , e_vovov , e_vovoc , e_vocov , - e_covov , e_covoc , e_vovovov , e_vovovoc , - e_vovocov , e_vocovov , e_covovov , e_covocov , - e_vocovoc , e_covovoc , e_vococov , e_sf3ext , - e_sf4ext , e_nulleq , e_strass , e_vector , - e_vecelem , e_rbvecelem , e_rbveccelem , e_vecdefass , - e_vecvalass , e_vecvecass , e_vecopvalass , e_vecopvecass , - e_vecfunc , e_vecvecswap , e_vecvecineq , e_vecvalineq , - e_valvecineq , e_vecvecarith , e_vecvalarith , e_valvecarith , - e_vecunaryop , e_break , e_continue , e_swap - }; - - typedef T value_type; - typedef expression_node* expression_ptr; - - virtual ~expression_node() - {} - - inline virtual T value() const + 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; + typedef details::char_t char_t; + + generator() + : base_itr_(0), + s_itr_ (0), + s_end_ (0) + { + clear(); + } + + inline void clear() + { + base_itr_ = 0; + s_itr_ = 0; + s_end_ = 0; + token_list_.clear(); + token_itr_ = token_list_.end(); + store_token_itr_ = token_list_.end(); + } + + inline bool process(const std::string& str) + { + base_itr_ = str.data(); + s_itr_ = str.data(); + s_end_ = str.data() + str.size(); + + eof_token_.set_operator(token_t::e_eof,s_end_,s_end_,base_itr_); + token_list_.clear(); + + while (!is_end(s_itr_)) { - return std::numeric_limits::quiet_NaN(); + scan_token(); + + if (token_list_.empty()) + return true; + else if (token_list_.back().is_error()) + return false; } - - inline virtual expression_node* branch(const std::size_t& index = 0) const + + 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 reinterpret_cast(index * 0); + return *token_itr_++; } - - inline virtual node_type type() const + else + return eof_token_; + } + + inline token_t& peek_next_token() + { + if (token_list_.end() != token_itr_) { - 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 std::complex& v) - { - return std::not_equal_to >()(std::complex(0),v); - } - - template - inline bool is_true(const expression_node* node) - { - return std::not_equal_to()(T(0),node->value()); - } - - template - inline bool is_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() || - details::expression_node::e_rbvecelem == node->type() || - details::expression_node::e_rbveccelem == node->type() - ); - } - - template - inline bool is_vector_elem_node(const expression_node* node) - { - return node && (details::expression_node::e_vecelem == node->type()); - } - - template - inline bool is_rebasevector_elem_node(const expression_node* node) - { - return node && (details::expression_node::e_rbvecelem == node->type()); - } - - template - inline bool is_rebasevector_celem_node(const expression_node* node) - { - return node && (details::expression_node::e_rbveccelem == node->type()); - } - - template - inline bool is_vector_node(const expression_node* node) - { - return node && (details::expression_node::e_vector == node->type()); - } - - template - inline bool is_ivector_node(const expression_node* node) - { - if (node) - { - switch (node->type()) - { - case details::expression_node::e_vector : - case details::expression_node::e_vecvalass : - case details::expression_node::e_vecvecass : - case details::expression_node::e_vecopvalass : - case details::expression_node::e_vecopvecass : - case details::expression_node::e_vecvecswap : - case details::expression_node::e_vecvecarith : - case details::expression_node::e_vecvalarith : - case details::expression_node::e_valvecarith : - case details::expression_node::e_vecunaryop : return true; - default : return false; - } + return *token_itr_; } else - return false; - } - - template - inline bool is_constant_node(const expression_node* node) - { - return node && (details::expression_node::e_constant == node->type()); - } - - template - inline bool is_null_node(const expression_node* node) - { - return node && (details::expression_node::e_null == node->type()); - } - - template - inline bool is_break_node(const expression_node* node) - { - return node && (details::expression_node::e_break == node->type()); - } - - template - inline bool is_continue_node(const expression_node* node) - { - return node && (details::expression_node::e_continue == node->type()); - } - - template - inline bool is_swap_node(const expression_node* node) - { - return node && (details::expression_node::e_swap == node->type()); - } - - template - inline bool is_function(const expression_node* node) - { - return node && (details::expression_node::e_function == node->type()); - } - - template - inline bool is_return_node(const expression_node* node) - { - return node && (details::expression_node::e_return == node->type()); - } - - template class unary_node; - - template - inline bool is_negate_node(const expression_node* node) - { - if (node && is_unary_node(node)) - { - return (details::e_neg == static_cast*>(node)->operation()); - } + return eof_token_; + } + + inline token_t& operator[](const std::size_t& index) + { + if (index < token_list_.size()) + return token_list_[index]; 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) + 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_) + ) { - if (0 == b[i]) return false; + token_t t = *token_itr_; + + t.type = tk_type; + token_itr_ = token_list_.insert(token_itr_,t); } - - return true; - } - - template class Sequence> - inline bool all_nodes_valid(const Sequence*,Allocator>& b) - { - for (std::size_t i = 0; i < b.size(); ++i) + } + + inline std::string substr(const std::size_t& begin, const std::size_t& end) + { + const char* begin_itr = ((base_itr_ + begin) < s_end_) ? (base_itr_ + begin) : s_end_; + const char* end_itr = ((base_itr_ + end) < s_end_) ? (base_itr_ + end) : s_end_; + + return std::string(begin_itr,end_itr); + } + + inline std::string remaining() const + { + if (finished()) + return ""; + else if (token_list_.begin() != token_itr_) + return std::string(base_itr_ + (token_itr_ - 1)->position,s_end_); + else + return std::string(base_itr_ + token_itr_->position,s_end_); + } + + private: + + inline bool is_end(const char* itr) + { + return (s_end_ == itr); + } + + inline void skip_whitespace() + { + while (!is_end(s_itr_) && details::is_whitespace(*s_itr_)) { - if (0 == b[i]) return false; + ++s_itr_; } - - return true; - } - - template - inline bool all_nodes_variables(expression_node* (&b)[N]) - { - for (std::size_t i = 0; i < N; ++i) + } + + inline void skip_comments() + { + #ifndef exprtk_disable_comments + // The following comment styles are supported: + // 1. // .... \n + // 2. # .... \n + // 3. /* .... */ + struct test + { + static inline bool comment_start(const char_t c0, const char_t c1, int& mode, int& incr) + { + mode = 0; + if ('#' == c0) { mode = 1; incr = 1; } + else if ('/' == c0) + { + if ('/' == c1) { mode = 1; incr = 2; } + else if ('*' == c1) { mode = 2; incr = 2; } + } + return (0 != mode); + } + + static inline bool comment_end(const char_t c0, const char_t c1, 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)) { - if (0 == b[i]) - return false; - else if (!is_variable_node(b[i])) - return false; + ++s_itr_; } - - return true; - } - - template class Sequence> - inline bool all_nodes_variables(Sequence*,Allocator>& b) - { - for (std::size_t i = 0; i < b.size(); ++i) + + if (!is_end(s_itr_)) { - if (0 == b[i]) - return false; - else if (!is_variable_node(b[i])) - return false; + s_itr_ += mode; + skip_whitespace(); + skip_comments(); } - - return true; - } - - template - inline void free_all_nodes(NodeAllocator& node_allocator, expression_node* (&b)[N]) - { - for (std::size_t i = 0; i < N; ++i) + #endif + } + + inline void scan_token() + { + skip_whitespace(); + + skip_comments(); + + if (is_end(s_itr_)) { - free_node(node_allocator,b[i]); + return; } - } - - template class Sequence> - inline void free_all_nodes(NodeAllocator& node_allocator, Sequence*,Allocator>& b) - { - for (std::size_t i = 0; i < b.size(); ++i) + else if (details::is_operator_char(*s_itr_)) { - free_node(node_allocator,b[i]); + scan_operator(); + return; } - - 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(); - } - - inline value_ptr data() const - { - return value_at(0); - } - - virtual inline bool rebaseable() const - { - return false; - } - - virtual void set_ref(value_ptr*) {} - - protected: - - virtual value_ptr value_at(const std::size_t&) const = 0; - virtual std::size_t vector_size() const = 0; - }; - - class array_vector_impl : public vector_holder_base - { - public: - - array_vector_impl(const Type* vec, const std::size_t& vec_size) - : vec_(vec), - size_(vec_size) - {} - - protected: - - value_ptr value_at(const std::size_t& index) const - { - if (index < size_) - return const_cast(vec_ + index); - else - return const_value_ptr(0); - } - - std::size_t vector_size() const - { - return size_; - } - - private: - - array_vector_impl 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_; - }; - - class vector_view_impl : public vector_holder_base - { - public: - - typedef exprtk::vector_view vector_view_t; - - vector_view_impl(vector_view_t& vec_view) - : vec_view_(vec_view) - {} - - void set_ref(value_ptr* ref) - { - vec_view_.set_ref(ref); - } - - virtual inline bool rebaseable() const - { - return true; - } - - protected: - - value_ptr value_at(const std::size_t& index) const - { - return (index < vec_view_.size()) ? (&vec_view_[index]) : const_value_ptr(0); - } - - std::size_t vector_size() const - { - return vec_view_.size(); - } - - private: - - vector_view_impl operator=(const vector_view_impl&); - - vector_view_t& vec_view_; - }; - - public: - - typedef typename details::vec_data_store vds_t; - - vector_holder(Type* vec, const std::size_t& vec_size) - : vector_holder_base_(new(buffer)array_vector_impl(vec,vec_size)) - {} - - vector_holder(const vds_t& vds) - : vector_holder_base_(new(buffer)array_vector_impl(vds.data(),vds.size())) - {} - - template - vector_holder(std::vector& vec) - : vector_holder_base_(new(buffer)sequence_vector_impl(vec)) - {} - - vector_holder(exprtk::vector_view& vec) - : vector_holder_base_(new(buffer)vector_view_impl(vec)) - {} - - inline value_ptr operator[](const std::size_t& index) const + else if (details::is_letter(*s_itr_)) { - return (*vector_holder_base_)[index]; + scan_symbol(); + return; } - - inline std::size_t size() const + else if (details::is_digit((*s_itr_)) || ('.' == (*s_itr_))) { - return vector_holder_base_->size(); + scan_number(); + return; } - - inline value_ptr data() const + else if ('$' == (*s_itr_)) { - return vector_holder_base_->data(); + scan_special_function(); + return; } - - void set_ref(value_ptr* ref) + #ifndef exprtk_disable_string_capabilities + else if ('\'' == (*s_itr_)) { - return vector_holder_base_->set_ref(ref); + scan_string(); + return; } - - bool rebaseable() const + #endif + else if ('~' == (*s_itr_)) { - return vector_holder_base_->rebaseable(); + token_t t; + t.set_symbol(s_itr_, s_itr_ + 1, base_itr_); + token_list_.push_back(t); + ++s_itr_; + return; } - - private: - - mutable vector_holder_base* vector_holder_base_; - uchar_t buffer[64]; - }; - - template - class null_node : public expression_node - { - public: - - inline T value() const + else { - return std::numeric_limits::quiet_NaN(); + token_t t; + t.set_error(token::e_error, s_itr_, s_itr_ + 2, base_itr_); + token_list_.push_back(t); + ++s_itr_; } - - inline typename expression_node::node_type type() const + } + + inline void scan_operator() + { + token_t t; + + const char_t c0 = s_itr_[0]; + + if (!is_end(s_itr_ + 1)) { - 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; - } + const char_t c1 = s_itr_[1]; + + if (!is_end(s_itr_ + 2)) + { + const char_t c2 = s_itr_[2]; + + if ((c0 == '<') && (c1 == '=') && (c2 == '>')) + { + t.set_operator(token_t::e_swap, s_itr_, s_itr_ + 3, base_itr_); + token_list_.push_back(t); + s_itr_ += 3; + return; + } + } + + token_t::token_type ttype = token_t::e_none; + + if ((c0 == '<') && (c1 == '=')) ttype = token_t::e_lte; + else if ((c0 == '>') && (c1 == '=')) ttype = token_t::e_gte; + else if ((c0 == '<') && (c1 == '>')) ttype = token_t::e_ne; + else if ((c0 == '!') && (c1 == '=')) ttype = token_t::e_ne; + else if ((c0 == '=') && (c1 == '=')) ttype = token_t::e_eq; + else if ((c0 == ':') && (c1 == '=')) ttype = token_t::e_assign; + else if ((c0 == '<') && (c1 == '<')) ttype = token_t::e_shl; + else if ((c0 == '>') && (c1 == '>')) ttype = token_t::e_shr; + else if ((c0 == '+') && (c1 == '=')) ttype = token_t::e_addass; + else if ((c0 == '-') && (c1 == '=')) ttype = token_t::e_subass; + else if ((c0 == '*') && (c1 == '=')) ttype = token_t::e_mulass; + else if ((c0 == '/') && (c1 == '=')) ttype = token_t::e_divass; + else if ((c0 == '%') && (c1 == '=')) ttype = token_t::e_modass; + + if (token_t::e_none != ttype) + { + t.set_operator(ttype, s_itr_, s_itr_ + 2, base_itr_); + token_list_.push_back(t); + s_itr_ += 2; + return; + } } - - 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); + + 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_)) + { + if (!details::is_letter_or_digit(*s_itr_) && ('_' != (*s_itr_))) + { + if ('.' != (*s_itr_)) + break; + /* + Permit symbols that contain a 'dot' + Allowed : abc.xyz, a123.xyz, abc.123, abc_.xyz a123_.xyz abc._123 + Disallowed: .abc, abc., abc., abc. + */ + if ( + (s_itr_ != initial_itr) && + !is_end(s_itr_ + 1) && + !details::is_letter_or_digit(*(s_itr_ + 1)) && + ('_' != (*(s_itr_ + 1))) + ) + break; + } + + ++s_itr_; } - - inline typename expression_node::node_type type() const - { - return expression_node::e_nulleq; + + token_t t; + t.set_symbol(initial_itr,s_itr_,base_itr_); + token_list_.push_back(t); + } + + inline void scan_number() + { + /* + Attempt to match a valid numeric value in one of the following formats: + (01) 123456 + (02) 123456. + (03) 123.456 + (04) 123.456e3 + (05) 123.456E3 + (06) 123.456e+3 + (07) 123.456E+3 + (08) 123.456e-3 + (09) 123.456E-3 + (00) .1234 + (11) .1234e3 + (12) .1234E+3 + (13) .1234e+3 + (14) .1234E-3 + (15) .1234e-3 + */ + + const char* initial_itr = s_itr_; + bool dot_found = false; + bool e_found = false; + bool post_e_sign_found = false; + bool post_e_digit_found = false; + token_t t; + + while (!is_end(s_itr_)) + { + if ('.' == (*s_itr_)) + { + if (dot_found) + { + t.set_error(token::e_err_number, initial_itr, s_itr_, base_itr_); + token_list_.push_back(t); + return; + } + + dot_found = true; + ++s_itr_; + + continue; + } + else if (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_) && !post_e_digit_found) + { + if (post_e_sign_found) + { + t.set_error(token::e_err_number, initial_itr, s_itr_, base_itr_); + token_list_.push_back(t); + + return; + } + + post_e_sign_found = true; + ++s_itr_; + + continue; + } + else if (e_found && details::is_digit(*s_itr_)) + { + post_e_digit_found = true; + ++s_itr_; + + continue; + } + else if (('.' != (*s_itr_)) && !details::is_digit(*s_itr_)) + break; + else + ++s_itr_; } - - inline operator_type operation() const + + 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) { - return details::e_eq; + t.set_error(token::e_err_sfunc, initial_itr, s_itr_, base_itr_); + token_list_.push_back(t); + + return; } - - inline expression_node* branch(const std::size_t&) const - { - return branch_; + + 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; } - - 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 + + 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) { - return value_; + t.set_error(token::e_err_string, s_itr_, s_end_, base_itr_); + token_list_.push_back(t); + return; } - - inline typename expression_node::node_type type() const + + ++s_itr_; + + bool escaped_found = false; + bool escaped = false; + + while (!is_end(s_itr_)) { - return expression_node::e_constant; + if (!escaped && ('\\' == *s_itr_)) + { + escaped_found = true; + escaped = true; + ++s_itr_; + + continue; + } + else if (!escaped) + { + if ('\'' == *s_itr_) + break; + } + else if (escaped) + { + if (!is_end(s_itr_) && ('0' == *(s_itr_))) + { + /* + Note: The following 'awkward' conditional is + due to various broken msvc compilers. + */ + #if _MSC_VER == 1600 + const bool within_range = !is_end(s_itr_ + 2) && + !is_end(s_itr_ + 3) ; + #else + const bool within_range = !is_end(s_itr_ + 1) && + !is_end(s_itr_ + 2) && + !is_end(s_itr_ + 3) ; + #endif + + const bool x_seperator = ('x' == *(s_itr_ + 1)) || + ('X' == *(s_itr_ + 1)) ; + + const bool both_digits = details::is_hex_digit(*(s_itr_ + 2)) && + details::is_hex_digit(*(s_itr_ + 3)) ; + + if (!within_range || !x_seperator || !both_digits) + { + t.set_error(token::e_err_string, initial_itr, s_itr_, base_itr_); + token_list_.push_back(t); + + return; + } + else + s_itr_ += 3; + } + + escaped = false; + } + + ++s_itr_; } - - inline expression_node* branch(const std::size_t&) const + + if (is_end(s_itr_)) { - return reinterpret_cast*>(0); + t.set_error(token::e_err_string, initial_itr, s_itr_, base_itr_); + token_list_.push_back(t); + + return; } - - 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_interface() - {} - - 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 ~string_base_node() - {} - - 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) + + if (!escaped_found) + t.set_string(initial_itr, s_itr_, base_itr_); + else { - 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; + std::string parsed_string(initial_itr,s_itr_); + details::cleanup_escapes(parsed_string); + t.set_string(parsed_string, std::distance(base_itr_,initial_itr)); } - - inline T value() const + + 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) { - return std::numeric_limits::quiet_NaN(); + throw std::invalid_argument("token_scanner() - Invalid stride value"); } - - inline typename expression_node::node_type type() const + } + + inline std::size_t process(generator& g) + { + if (g.token_list_.size() >= stride_) { - return expression_node::e_stringconst; + 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; + } + } } - - inline expression_node* branch(const std::size_t&) const + + 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) { - return reinterpret_cast*>(0); + if (modify(g.token_list_[i])) changes++; } - - std::string str() const + + 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) { - return value_; + throw std::invalid_argument("token_inserter() - Invalid stride value"); } - - const char* base() const + } + + 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) { - return value_.data(); + 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++; + } } - - std::size_t size() const + + return changes; + } + + #define token_inserter_empty_body \ + { \ + return -1; \ + } \ + + inline virtual int insert(const token&, token&) + token_inserter_empty_body + + inline virtual int insert(const token&, const token&, token&) + token_inserter_empty_body + + inline virtual int insert(const token&, const token&, const token&, token&) + token_inserter_empty_body + + inline virtual int insert(const token&, const token&, const token&, const token&, token&) + token_inserter_empty_body + + inline virtual int insert(const token&, const token&, const token&, const token&, const token&, token&) + token_inserter_empty_body + + #undef token_inserter_empty_body + + private: + + 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_) { - return value_.size(); + case 2 : return process_stride_2(g); + case 3 : return process_stride_3(g); + default : return 0; } - - range_t& range_ref() + } + + 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) { - return rp_; + token t; + + while (join(g[i],g[i + 1],t)) + { + g.token_list_[i] = t; + + g.token_list_.erase(g.token_list_.begin() + (i + 1)); + + ++changes; + } } - - const range_t& range_ref() const + + 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) { - return rp_; + token t; + + while (join(g[i],g[i + 1],g[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; + } } - - 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_)) + + 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: + + using lexer::token_inserter::insert; + + commutative_inserter() + : lexer::token_inserter(2) {} - - ~unary_node() + + inline void ignore_symbol(const std::string& symbol) { - if (branch_ && branch_deletable_) - { - delete branch_; - branch_ = 0; - } + ignore_set_.insert(symbol); } - - inline T value() const + + inline int insert(const lexer::token& t0, const lexer::token& t1, lexer::token& new_token) { - const T arg = branch_->value(); - return numeric::process(operation_,arg); + 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; } - - inline typename expression_node::node_type type() const - { - return expression_node::e_unary; + + 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 if ((t0.type == lexer::token::e_add) && (t1.type == lexer::token::e_sub)) + { + t.type = lexer::token::e_sub; + t.value = "-"; + t.position = t0.position; + + return true; + } + // '- +' --> '-' + else if ((t0.type == lexer::token::e_sub) && (t1.type == lexer::token::e_add)) + { + t.type = lexer::token::e_sub; + t.value = "-"; + t.position = t0.position; + + return true; + } + // '- -' --> '-' + else if ((t0.type == lexer::token::e_sub) && (t1.type == lexer::token::e_sub)) + { + /* + Note: May need to reconsider this when wanting to implement + pre/postfix decrement operator + */ + t.type = lexer::token::e_add; + t.value = "+"; + t.position = t0.position; + + return true; + } + else + return false; } - - inline operator_type operation() const - { - return operation_; + + 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; } - - inline expression_node* branch(const std::size_t&) const - { - return branch_; + }; + + class bracket_checker : public lexer::token_scanner + { + public: + + using lexer::token_scanner::operator(); + + bracket_checker() + : token_scanner(1), + state_(true) + {} + + bool result() + { + if (!stack_.empty()) + { + lexer::token t; + t.value = stack_.top().first; + t.position = stack_.top().second; + error_token_ = t; + state_ = false; + + return false; + } + else + return state_; } - - inline void release() + + lexer::token error_token() { - branch_deletable_ = false; + return error_token_; } - - 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)); - } + + void reset() + { + // Why? because msvc doesn't support swap properly. + stack_ = std::stack >(); + state_ = true; + error_token_.clear(); } - }; - - 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; - } - } + + bool operator()(const lexer::token& t) + { + if ( + !t.value.empty() && + (lexer::token::e_string != t.type) && + (lexer::token::e_symbol != t.type) && + exprtk::details::is_bracket(t.value[0]) + ) + { + details::char_t c = t.value[0]; + + if (t.type == lexer::token::e_lbracket) stack_.push(std::make_pair(')',t.position)); + else if (t.type == lexer::token::e_lcrlbracket) stack_.push(std::make_pair('}',t.position)); + else if (t.type == lexer::token::e_lsqrbracket) stack_.push(std::make_pair(']',t.position)); + else if (exprtk::details::is_right_bracket(c)) + { + if (stack_.empty()) + { + state_ = false; + error_token_ = t; + + return false; + } + else if (c != stack_.top().first) + { + state_ = false; + error_token_ = t; + + return false; + } + else + stack_.pop(); + } + } + + return true; } - }; - - 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) + + private: + + bool state_; + std::stack > stack_; + lexer::token error_token_; + }; + + class numeric_checker : public lexer::token_scanner + { + public: + + using lexer::token_scanner::operator(); + + numeric_checker() + : token_scanner (1), + current_index_(0) + {} + + bool result() { - init_branches<2>(branch_,branch0,branch1); + return error_list_.empty(); } - - ~binary_ext_node() + + void reset() { - cleanup_branches::execute(branch_); + error_list_.clear(); + current_index_ = 0; } - - inline T value() const + + bool operator()(const lexer::token& t) { - const T arg0 = branch_[0].first->value(); - const T arg1 = branch_[1].first->value(); - - return Operation::process(arg0,arg1); + 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; } - - inline typename expression_node::node_type type() const + + std::size_t error_count() const { - return expression_node::e_binary_ext; + return error_list_.size(); } - - inline operator_type operation() + + std::size_t error_index(const std::size_t& i) { - return Operation::operation(); + if (i < error_list_.size()) + return error_list_[i]; + else + return std::numeric_limits::max(); } - - inline expression_node* branch(const std::size_t& index = 0) const + + void clear_errors() { - if (0 == index) - return branch_[0].first; - else if (1 == index) - return branch_[1].first; - else - return reinterpret_cast(0); + error_list_.clear(); } - - 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_clamp : return (arg1 < arg0) ? arg0 : (arg1 > arg2 ? arg2 : arg1); - - case e_iclamp : if ((arg1 <= arg0) || (arg1 >= arg2)) - return arg1; - else - return ((T(2) * arg1 <= (arg2 + arg0)) ? arg0 : arg2); - - default : { - exprtk_debug(("trinary_node::value() - Error: Invalid operation\n")); - return std::numeric_limits::quiet_NaN(); - } - } - } - - inline typename expression_node::node_type type() const - { - 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) + + 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) { - init_branches<4>(branch_,branch0,branch1,branch2,branch3); + replace_map_t::iterator itr = replace_map_.find(target_symbol); + + if (replace_map_.end() == itr) + return false; + + replace_map_.erase(itr); + + return true; } - - ~quaternary_node() + + bool add_replace(const std::string& target_symbol, + const std::string& replace_symbol, + const lexer::token::token_type token_type = lexer::token::e_symbol) { - cleanup_branches::execute(branch_); + 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; } - - inline T value() const + + void clear() { - return std::numeric_limits::quiet_NaN(); + replace_map_.clear(); } - - inline typename expression_node::node_type type() const + + private: + + bool modify(lexer::token& t) { - return expression_node::e_quaternary; - } - - protected: - - operator_type operation_; - branch_t branch_[4]; - }; - - 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: - - break_exception(const T& v) - : value(v) - {} - - T value; - }; - - class continue_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; - } - - protected: - - std::vector arg_list_; - std::vector delete_branch_; - }; - - template - class switch_n_node : public switch_node - { - public: - - typedef expression_node* expression_ptr; - - template class Sequence> - switch_n_node(const Sequence& arg_list) - : switch_node(arg_list) - {} - - inline T value() const - { - return Switch_N::process(switch_node::arg_list_); - } - }; - - 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 ~ivariable() - {} - - 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; - typedef vec_data_store vds_t; - - virtual ~vector_interface() - {} - - virtual std::size_t size () const = 0; - - virtual vector_node_ptr vec() const = 0; - - virtual vector_node_ptr vec() = 0; - - virtual vds_t& vds () = 0; - - virtual const vds_t& vds () const = 0; - - virtual bool side_effect () const { return false; } - }; - - template - class vector_node : public expression_node , - public vector_interface - { - public: - - typedef expression_node* expression_ptr; - typedef vector_holder vector_holder_t; - typedef vector_node* vector_node_ptr; - typedef vec_data_store vds_t; - - vector_node(vector_holder_t* vh) - : vector_holder_(vh), - vds_((*vector_holder_).size(),(*vector_holder_)[0]) - { - vector_holder_->set_ref(&vds_.ref()); - } - - vector_node(const vds_t& vds, vector_holder_t* vh) - : vector_holder_(vh), - vds_(vds) - {} - - inline T value() const - { - return vds().data()[0]; - } - - 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 vds().size(); - } - - vds_t& vds() - { - return vds_; - } - - const vds_t& vds() const - { - return vds_; - } - - inline vector_holder_t& vec_holder() - { - return (*vector_holder_); - } - - private: - - vector_holder_t* vector_holder_; - vds_t vds_; - }; - - template - class vector_elem_node : public expression_node, - public ivariable - { - public: - - typedef expression_node* expression_ptr; - typedef vector_holder vector_holder_t; - typedef vector_holder_t* vector_holder_ptr; - - vector_elem_node(expression_ptr index, vector_holder_ptr vec_holder) - : index_(index), - vec_holder_(vec_holder), - vector_base_((*vec_holder)[0]), - index_deletable_(branch_deletable(index_)) - {} - - ~vector_elem_node() - { - 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; - } - - inline vector_holder_t& vec_holder() - { - return (*vec_holder_); + 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; } - - private: - - expression_ptr index_; - vector_holder_ptr vec_holder_; - T* vector_base_; - bool index_deletable_; - }; - - template - class rebasevector_elem_node : public expression_node, - public ivariable - { - public: - - typedef expression_node* expression_ptr; - typedef vector_holder vector_holder_t; - typedef vector_holder_t* vector_holder_ptr; - typedef vec_data_store vds_t; - - rebasevector_elem_node(expression_ptr index, vector_holder_ptr vec_holder) - : index_(index), - index_deletable_(branch_deletable(index_)), - vector_holder_(vec_holder), - vds_((*vector_holder_).size(),(*vector_holder_)[0]) - { - vector_holder_->set_ref(&vds_.ref()); - } - - ~rebasevector_elem_node() - { - if (index_ && index_deletable_) - { - delete index_; - } - } - - inline T value() const - { - return *(vds_.data() + static_cast(details::numeric::to_int64(index_->value()))); - } - - inline T& ref() - { - return *(vds_.data() + static_cast(details::numeric::to_int64(index_->value()))); - } - - inline const T& ref() const - { - return *(vds_.data() + static_cast(details::numeric::to_int64(index_->value()))); - } - - inline typename expression_node::node_type type() const - { - return expression_node::e_rbvecelem; - } - - inline vector_holder_t& vec_holder() - { - return (*vector_holder_); - } - - private: - - expression_ptr index_; - bool index_deletable_; - vector_holder_ptr vector_holder_; - vds_t vds_; - }; - - template - class rebasevector_celem_node : public expression_node, - public ivariable - { - public: - - typedef expression_node* expression_ptr; - typedef vector_holder vector_holder_t; - typedef vector_holder_t* vector_holder_ptr; - typedef vec_data_store vds_t; - - rebasevector_celem_node(const std::size_t index, vector_holder_ptr vec_holder) - : index_(index), - vector_holder_(vec_holder), - vds_((*vector_holder_).size(),(*vector_holder_)[0]) - { - vector_holder_->set_ref(&vds_.ref()); + + replace_map_t replace_map_; + }; + + class sequence_validator : public lexer::token_scanner + { + private: + + typedef std::pair token_pair_t; + typedef std::set set_t; + + public: + + using lexer::token_scanner::operator(); + + sequence_validator() + : lexer::token_scanner(2) + { + add_invalid(lexer::token::e_number ,lexer::token::e_number ); + add_invalid(lexer::token::e_string ,lexer::token::e_string ); + add_invalid(lexer::token::e_number ,lexer::token::e_string ); + add_invalid(lexer::token::e_string ,lexer::token::e_number ); + add_invalid(lexer::token::e_string ,lexer::token::e_ternary); + 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); } - - inline T value() const + + bool result() { - return *(vds_.data() + index_); + return error_list_.empty(); } - - inline T& ref() + + bool operator()(const lexer::token& t0, const lexer::token& t1) { - return *(vds_.data() + index_); + 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; } - - inline const T& ref() const + + std::size_t error_count() { - return *(vds_.data() + index_); + return error_list_.size(); } - - inline typename expression_node::node_type type() const - { - return expression_node::e_rbveccelem; + + 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); + } } - - inline vector_holder_t& vec_holder() + + void clear_errors() { - return (*vector_holder_); + error_list_.clear(); } - - private: - - std::size_t index_; - vector_holder_ptr vector_holder_; - vds_t vds_; - }; - - template - class vector_assignment_node : public expression_node - { - public: - - typedef expression_node* expression_ptr; - - vector_assignment_node(T* vector_base, - const std::size_t& size, - const std::vector& initialiser_list, - const bool single_value_initialse) - : vector_base_(vector_base), - initialiser_list_(initialiser_list), - size_(size), - single_value_initialse_(single_value_initialse) - {} - - ~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 + + private: + + void add_invalid(lexer::token::token_type base, lexer::token::token_type t) { - std::swap(var0_->ref(),var1_->ref()); - return var1_->ref(); + invalid_comb_.insert(std::make_pair(base,t)); } - - inline typename expression_node::node_type type() const - { - return expression_node::e_swap; + + 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 ); } - - 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(); + + 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; } - - inline typename expression_node::node_type type() const - { - return expression_node::e_swap; + + 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; } - - 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; - typedef vec_data_store vds_t; - - swap_vecvec_node(expression_ptr branch0, - expression_ptr branch1) - : binary_node(details::e_swap,branch0,branch1), - vec0_node_ptr_(0), - vec1_node_ptr_(0), - vec_size_ (0), - initialised_ (false) - { - if (is_ivector_node(binary_node::branch_[0].first)) - { - vector_interface* vi = reinterpret_cast*>(0); - - if (0 != (vi = dynamic_cast*>(binary_node::branch_[0].first))) - { - vec0_node_ptr_ = vi->vec(); - vds() = vi->vds(); - } - } - - if (is_ivector_node(binary_node::branch_[1].first)) - { - vector_interface* vi = reinterpret_cast*>(0); - - if (0 != (vi = dynamic_cast*>(binary_node::branch_[1].first))) - { - vec1_node_ptr_ = vi->vec(); - } - } - - if (vec0_node_ptr_ && vec1_node_ptr_) - { - vec_size_ = std::min(vec0_node_ptr_->vds().size(), - vec1_node_ptr_->vds().size()); - - initialised_ = true; - } - } - - inline T value() const - { - if (initialised_) - { - binary_node::branch_[0].first->value(); - binary_node::branch_[1].first->value(); - - T* vec0 = vec0_node_ptr_->vds().data(); - T* vec1 = vec1_node_ptr_->vds().data(); - - for (std::size_t i = 0; i < vec_size_; ++i) - { - std::swap(vec0[i],vec1[i]); - } - - return vec1_node_ptr_->value(); - } - else - return std::numeric_limits::quiet_NaN(); - } - - vector_node_ptr vec() const - { - 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_; - } - - vds_t& vds() - { - return vds_; - } - - const vds_t& vds() const - { - return vds_; - } - - private: - - vector_node* vec0_node_ptr_; - vector_node* vec1_node_ptr_; - std::size_t vec_size_; - bool initialised_; - vds_t vds_; - }; - -#ifndef exprtk_disable_string_capabilities - 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 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 operator <(const stringvar_node& v) const - { - return this < (&v); + + 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 T value() const - { - rp_.n1_c.second = (*value_).size() - 1; - rp_.cache.second = rp_.n1_c.second; - return std::numeric_limits::quiet_NaN(); + + 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; } - - std::string str() const + + inline bool run_modifiers(lexer::generator& g) { - return ref(); + error_token_modifier = reinterpret_cast(0); + + for (std::size_t i = 0; i < token_modifier_list.size(); ++i) + { + lexer::token_modifier& modifier = (*token_modifier_list[i]); + + modifier.reset(); + modifier.process(g); + + if (!modifier.result()) + { + error_token_modifier = token_modifier_list[i]; + + return false; + } + } + + return true; } - - const char* base() const + + inline bool run_joiners(lexer::generator& g) { - return &(*value_)[0]; + error_token_joiner = reinterpret_cast(0); + + for (std::size_t i = 0; i < token_joiner_list.size(); ++i) + { + lexer::token_joiner& joiner = (*token_joiner_list[i]); + + joiner.reset(); + joiner.process(g); + + if (!joiner.result()) + { + error_token_joiner = token_joiner_list[i]; + + return false; + } + } + + return true; } - - std::size_t size() const + + inline bool run_inserters(lexer::generator& g) { - return ref().size(); + error_token_inserter = reinterpret_cast(0); + + for (std::size_t i = 0; i < token_inserter_list.size(); ++i) + { + lexer::token_inserter& inserter = (*token_inserter_list[i]); + + inserter.reset(); + inserter.process(g); + + if (!inserter.result()) + { + error_token_inserter = token_inserter_list[i]; + + return false; + } + } + + return true; } - - std::string& ref() + + inline bool run_scanners(lexer::generator& g) { - return (*value_); + error_token_scanner = reinterpret_cast(0); + + for (std::size_t i = 0; i < token_scanner_list.size(); ++i) + { + lexer::token_scanner& scanner = (*token_scanner_list[i]); + + scanner.reset(); + scanner.process(g); + + if (!scanner.result()) + { + error_token_scanner = token_scanner_list[i]; + + return false; + } + } + + return true; } - - const std::string& ref() const + + std::vector token_scanner_list; + std::vector token_modifier_list; + std::vector token_joiner_list; + std::vector token_inserter_list; + + lexer::token_scanner* error_token_scanner; + lexer::token_modifier* error_token_modifier; + lexer::token_joiner* error_token_joiner; + lexer::token_inserter* error_token_inserter; + }; + } + + class parser_helper + { + public: + + typedef token token_t; + typedef generator generator_t; + + inline bool init(const std::string& str) + { + if (!lexer_.process(str)) { - return (*value_); + return false; } - - range_t& range_ref() + + lexer_.begin(); + + next_token(); + + return true; + } + + inline generator_t& lexer() + { + return lexer_; + } + + inline const generator_t& lexer() const + { + return lexer_; + } + + inline void store_token() + { + lexer_.store(); + store_current_token_ = current_token_; + } + + inline void restore_token() + { + lexer_.restore(); + current_token_ = store_current_token_; + } + + inline void next_token() + { + current_token_ = lexer_.next_token(); + } + + inline const token_t& current_token() const + { + return current_token_; + } + + enum token_advance_mode + { + e_hold = 0, + e_advance = 1 + }; + + inline void advance_token(const token_advance_mode mode) + { + if (e_advance == mode) { - return rp_; + next_token(); } - - const range_t& range_ref() const + } + + inline bool token_is(const token_t::token_type& ttype, const token_advance_mode mode = e_advance) + { + if (current_token().type != ttype) { - return rp_; + return false; } - - inline typename expression_node::node_type type() const + + advance_token(mode); + + return true; + } + + inline bool token_is(const token_t::token_type& ttype, + const std::string& value, + const token_advance_mode mode = e_advance) + { + if ( + (current_token().type != ttype) || + !exprtk::details::imatch(value,current_token().value) + ) { - return expression_node::e_stringvar; + return false; } - - 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, const range_t& rp) - : value_(&v), - rp_(rp) - {} - - virtual ~string_range_node() + + advance_token(mode); + + return true; + } + + inline bool token_is_then_assign(const token_t::token_type& ttype, + std::string& token, + const token_advance_mode mode = e_advance) + { + if (current_token_.type != ttype) { - rp_.free(); + return false; } - - inline bool operator <(const string_range_node& v) const + + token = current_token_.value; + + advance_token(mode); + + return true; + } + + template class Container> + inline bool token_is_then_assign(const token_t::token_type& ttype, + Container& token_list, + const token_advance_mode mode = e_advance) + { + if (current_token_.type != ttype) { - return this < (&v); + return false; } - - inline T value() const + + token_list.push_back(current_token_.value); + + advance_token(mode); + + return true; + } + + inline bool peek_token_is(const token_t::token_type& ttype) + { + return (lexer_.peek_next_token().type == ttype); + } + + inline bool peek_token_is(const std::string& s) + { + return (exprtk::details::imatch(lexer_.peek_next_token().value,s)); + } + + private: + + generator_t lexer_; + token_t current_token_; + token_t store_current_token_; + }; + } + + template + class vector_view + { + public: + + typedef T* data_ptr_t; + + vector_view(data_ptr_t data, const std::size_t& size) + : size_(size), + data_(data), + data_ref_(0) + {} + + vector_view(const vector_view& vv) + : size_(vv.size_), + data_(vv.data_), + data_ref_(0) + {} + + inline void rebase(data_ptr_t data) + { + data_ = data; + + if (!data_ref_.empty()) + { + for (std::size_t i = 0; i < data_ref_.size(); ++i) { - return std::numeric_limits::quiet_NaN(); + (*data_ref_[i]) = data; } - - inline std::string str() const - { - return (*value_); - } - - const char* base() const - { - return &(*value_)[0]; - } - - std::size_t size() const - { - return ref().size(); - } - - inline range_t range() const + } + } + + inline data_ptr_t data() const + { + return data_; + } + + inline std::size_t size() const + { + return size_; + } + + inline const T& operator[](const std::size_t index) const + { + return data_[index]; + } + + inline T& operator[](const std::size_t index) + { + return data_[index]; + } + + void set_ref(data_ptr_t* data_ref) + { + data_ref_.push_back(data_ref); + } + + private: + + std::size_t size_; + data_ptr_t data_; + std::vector data_ref_; + }; + + template + inline vector_view make_vector_view(T* data, + const std::size_t size, const std::size_t offset = 0) + { + return vector_view(data + offset,size); + } + + template + inline vector_view make_vector_view(std::vector& v, + const std::size_t size, const std::size_t offset = 0) + { + return vector_view(v.data() + offset,size); + } + + template class results_context; + + template + struct type_store + { + enum store_type + { + e_unknown, + e_scalar, + e_vector, + e_string + }; + + type_store() + : 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_.back(); + } + + inline const type_store& back() const + { + return parameter_list_.back(); + } + + private: + + std::vector& parameter_list_; + + friend class results_context; + }; + + template + struct type_view + { + typedef type_store type_store_t; + typedef ViewType value_t; + + 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 static_cast(data_ + ts_.size); + } + + inline value_t* end() + { + return static_cast(data_ + ts_.size); + } + + type_store_t& ts_; + value_t* data_; + }; + + typedef type_view vector_view; + typedef type_view string_view; + + struct scalar_view + { + typedef type_store type_store_t; + typedef T value_t; + + scalar_view(type_store_t& ts) + : v_(*reinterpret_cast(ts.data)) + {} + + scalar_view(const type_store_t& ts) + : v_(*reinterpret_cast(const_cast(ts).data)) + {} + + inline value_t& operator()() + { + return v_; + } + + inline const value_t& operator()() const + { + return v_; + } + + template + inline bool to_int(IntType& i) const + { + if (!exprtk::details::numeric::is_integer(v_)) + return false; + + i = static_cast(v_); + + return true; + } + + template + inline bool to_uint(UIntType& u) const + { + if (v_ < T(0)) + return false; + else if (!exprtk::details::numeric::is_integer(v_)) + return false; + + u = static_cast(v_); + + return true; + } + + T& v_; + }; + }; + + template + inline std::string to_str(const StringView& view) + { + return std::string(view.begin(),view.size()); + } + + #ifndef exprtk_disable_return_statement + namespace details + { + template class return_node; + template class return_envelope_node; + } + #endif + + template + class results_context + { + public: + + typedef type_store type_store_t; + + results_context() + : results_available_(false) + {} + + inline std::size_t count() const + { + if (results_available_) + return parameter_list_.size(); + else + return 0; + } + + inline type_store_t& operator[](const std::size_t& index) + { + return parameter_list_[index]; + } + + inline const type_store_t& operator[](const std::size_t& index) const + { + return parameter_list_[index]; + } + + private: + + inline void clear() + { + results_available_ = false; + } + + typedef std::vector ts_list_t; + typedef typename type_store_t::parameter_list parameter_list_t; + + inline void assign(const parameter_list_t& pl) + { + parameter_list_ = pl.parameter_list_; + results_available_ = true; + } + + bool results_available_; + ts_list_t parameter_list_; + + #ifndef exprtk_disable_return_statement + friend class details::return_node; + friend class details::return_envelope_node; + #endif + }; + + namespace details + { + enum operator_type + { + e_default , e_null , e_add , e_sub , + e_mul , e_div , e_mod , e_pow , + e_atan2 , e_min , e_max , e_avg , + e_sum , e_prod , e_lt , e_lte , + e_eq , e_equal , e_ne , e_nequal , + e_gte , e_gt , e_and , e_nand , + e_or , e_nor , e_xor , e_xnor , + e_mand , e_mor , e_scand , e_scor , + e_shr , e_shl , e_abs , e_acos , + e_acosh , e_asin , e_asinh , e_atan , + e_atanh , e_ceil , e_cos , e_cosh , + e_exp , e_expm1 , e_floor , e_log , + e_log10 , e_log2 , e_log1p , e_logn , + e_neg , e_pos , e_round , e_roundn , + e_root , e_sqrt , e_sin , e_sinc , + e_sinh , e_sec , e_csc , e_tan , + e_tanh , e_cot , e_clamp , e_iclamp , + e_inrange , e_sgn , e_r2d , e_d2r , + e_d2g , e_g2d , e_hypot , e_notl , + e_erf , e_erfc , e_ncdf , e_frac , + e_trunc , e_assign , e_addass , e_subass , + e_mulass , e_divass , e_modass , e_in , + e_like , e_ilike , e_multi , e_smulti , + e_swap , + + // Do not add new functions/operators after this point. + e_sf00 = 1000, e_sf01 = 1001, e_sf02 = 1002, e_sf03 = 1003, + e_sf04 = 1004, e_sf05 = 1005, e_sf06 = 1006, e_sf07 = 1007, + e_sf08 = 1008, e_sf09 = 1009, e_sf10 = 1010, e_sf11 = 1011, + e_sf12 = 1012, e_sf13 = 1013, e_sf14 = 1014, e_sf15 = 1015, + e_sf16 = 1016, e_sf17 = 1017, e_sf18 = 1018, e_sf19 = 1019, + e_sf20 = 1020, e_sf21 = 1021, e_sf22 = 1022, e_sf23 = 1023, + e_sf24 = 1024, e_sf25 = 1025, e_sf26 = 1026, e_sf27 = 1027, + e_sf28 = 1028, e_sf29 = 1029, e_sf30 = 1030, e_sf31 = 1031, + e_sf32 = 1032, e_sf33 = 1033, e_sf34 = 1034, e_sf35 = 1035, + e_sf36 = 1036, e_sf37 = 1037, e_sf38 = 1038, e_sf39 = 1039, + e_sf40 = 1040, e_sf41 = 1041, e_sf42 = 1042, e_sf43 = 1043, + e_sf44 = 1044, e_sf45 = 1045, e_sf46 = 1046, e_sf47 = 1047, + e_sf48 = 1048, e_sf49 = 1049, e_sf50 = 1050, e_sf51 = 1051, + e_sf52 = 1052, e_sf53 = 1053, e_sf54 = 1054, e_sf55 = 1055, + e_sf56 = 1056, e_sf57 = 1057, e_sf58 = 1058, e_sf59 = 1059, + e_sf60 = 1060, e_sf61 = 1061, e_sf62 = 1062, e_sf63 = 1063, + e_sf64 = 1064, e_sf65 = 1065, e_sf66 = 1066, e_sf67 = 1067, + e_sf68 = 1068, e_sf69 = 1069, e_sf70 = 1070, e_sf71 = 1071, + e_sf72 = 1072, e_sf73 = 1073, e_sf74 = 1074, e_sf75 = 1075, + e_sf76 = 1076, e_sf77 = 1077, e_sf78 = 1078, e_sf79 = 1079, + e_sf80 = 1080, e_sf81 = 1081, e_sf82 = 1082, e_sf83 = 1083, + e_sf84 = 1084, e_sf85 = 1085, e_sf86 = 1086, e_sf87 = 1087, + e_sf88 = 1088, e_sf89 = 1089, e_sf90 = 1090, e_sf91 = 1091, + e_sf92 = 1092, e_sf93 = 1093, e_sf94 = 1094, e_sf95 = 1095, + e_sf96 = 1096, e_sf97 = 1097, e_sf98 = 1098, e_sf99 = 1099, + e_sffinal = 1100, + e_sf4ext00 = 2000, e_sf4ext01 = 2001, e_sf4ext02 = 2002, e_sf4ext03 = 2003, + e_sf4ext04 = 2004, e_sf4ext05 = 2005, e_sf4ext06 = 2006, e_sf4ext07 = 2007, + e_sf4ext08 = 2008, e_sf4ext09 = 2009, e_sf4ext10 = 2010, e_sf4ext11 = 2011, + e_sf4ext12 = 2012, e_sf4ext13 = 2013, e_sf4ext14 = 2014, e_sf4ext15 = 2015, + e_sf4ext16 = 2016, e_sf4ext17 = 2017, e_sf4ext18 = 2018, e_sf4ext19 = 2019, + e_sf4ext20 = 2020, e_sf4ext21 = 2021, e_sf4ext22 = 2022, e_sf4ext23 = 2023, + e_sf4ext24 = 2024, e_sf4ext25 = 2025, e_sf4ext26 = 2026, e_sf4ext27 = 2027, + e_sf4ext28 = 2028, e_sf4ext29 = 2029, e_sf4ext30 = 2030, e_sf4ext31 = 2031, + e_sf4ext32 = 2032, e_sf4ext33 = 2033, e_sf4ext34 = 2034, e_sf4ext35 = 2035, + e_sf4ext36 = 2036, e_sf4ext37 = 2037, e_sf4ext38 = 2038, e_sf4ext39 = 2039, + e_sf4ext40 = 2040, e_sf4ext41 = 2041, e_sf4ext42 = 2042, e_sf4ext43 = 2043, + e_sf4ext44 = 2044, e_sf4ext45 = 2045, e_sf4ext46 = 2046, e_sf4ext47 = 2047, + e_sf4ext48 = 2048, e_sf4ext49 = 2049, e_sf4ext50 = 2050, e_sf4ext51 = 2051, + e_sf4ext52 = 2052, e_sf4ext53 = 2053, e_sf4ext54 = 2054, e_sf4ext55 = 2055, + e_sf4ext56 = 2056, e_sf4ext57 = 2057, e_sf4ext58 = 2058, e_sf4ext59 = 2059, + e_sf4ext60 = 2060, e_sf4ext61 = 2061 + }; + + inline std::string to_str(const operator_type opr) + { + switch (opr) + { + case e_add : return "+"; + case e_sub : return "-"; + case e_mul : return "*"; + case e_div : return "/"; + case e_mod : return "%"; + case e_pow : return "^"; + case e_assign : return ":="; + case e_addass : return "+="; + case e_subass : return "-="; + case e_mulass : return "*="; + case e_divass : return "/="; + case e_modass : return "%="; + case e_lt : return "<"; + case e_lte : return "<="; + case e_eq : return "=="; + case e_equal : return "="; + case e_ne : return "!="; + case e_nequal : return "<>"; + case e_gte : return ">="; + case e_gt : return ">"; + default : return"N/A"; + } + } + + struct base_operation_t + { + base_operation_t(const operator_type t, const unsigned int& np) + : type(t), + num_params(np) + {} + + operator_type type; + unsigned int num_params; + }; + + namespace loop_unroll + { + #ifndef exprtk_disable_superscalar_unroll + const unsigned int global_loop_batch_size = 16; + #else + const unsigned int global_loop_batch_size = 4; + #endif + + struct details + { + details(const std::size_t& vsize, + const unsigned int loop_batch_size = global_loop_batch_size) + : batch_size(loop_batch_size), + remainder (vsize % batch_size), + upper_bound(static_cast(vsize) - (remainder ? loop_batch_size : 0)) + {} + + int batch_size; + int remainder; + int upper_bound; + }; + } + + #ifdef exprtk_enable_debugging + inline void dump_ptr(const std::string& s, const void* ptr, const std::size_t size = 0) + { + if (size) + exprtk_debug(("%s - addr: %p\n",s.c_str(),ptr)); + else + exprtk_debug(("%s - addr: %p size: %d\n", + s.c_str(), + ptr, + static_cast(size))); + } + #else + inline void dump_ptr(const std::string&, const void*) {} + inline void dump_ptr(const std::string&, const void*, const std::size_t) {} + #endif + + template + class vec_data_store + { + public: + + typedef vec_data_store type; + typedef T* data_t; + + private: + + struct control_block + { + control_block() + : ref_count(1), + size (0), + data (0), + destruct (true) + {} + + control_block(const std::size_t& dsize) + : ref_count(1), + size (dsize), + data (0), + destruct (true) + { create_data(); } + + control_block(const std::size_t& dsize, data_t dptr, bool dstrct = false) + : ref_count(1), + size (dsize), + data (dptr ), + destruct (dstrct) + {} + + ~control_block() { - return rp_; + if (data && destruct && (0 == ref_count)) + { + dump_ptr("~control_block() data",data); + delete[] data; + data = 0; + } } - - inline virtual std::string& ref() - { - return (*value_); + + static inline control_block* create(const std::size_t& size, data_t data_ptr = data_t(0), bool dstrct = false) + { + if (size) + { + if (0 == data_ptr) + return new control_block(size); + else + return new control_block(size, data_ptr, dstrct); + } + else + return new control_block; } - - inline virtual const std::string& ref() const + + static inline void destroy(control_block*& cntrl_blck) { - return (*value_); + if (cntrl_blck) + { + if ( + (0 != cntrl_blck->ref_count) && + (0 == --cntrl_blck->ref_count) + ) + { + delete cntrl_blck; + } + + cntrl_blck = 0; + } } - - inline range_t& range_ref() + + std::size_t ref_count; + std::size_t size; + data_t data; + bool destruct; + + private: + + control_block(const control_block&); + control_block& operator=(const control_block&); + + inline void create_data() { - return rp_; + destruct = true; + data = new T[size]; + std::fill_n(data,size,T(0)); + dump_ptr("control_block::create_data() - data",data,size); } - - inline const range_t& range_ref() const + }; + + public: + + vec_data_store() + : control_block_(control_block::create(0)) + {} + + vec_data_store(const std::size_t& size) + : control_block_(control_block::create(size,(data_t)(0),true)) + {} + + vec_data_store(const std::size_t& size, data_t data, bool dstrct = false) + : control_block_(control_block::create(size, data, dstrct)) + {} + + vec_data_store(const type& vds) + { + control_block_ = vds.control_block_; + control_block_->ref_count++; + } + + ~vec_data_store() + { + control_block::destroy(control_block_); + } + + type& operator=(const type& vds) + { + if (this != &vds) { - return rp_; + std::size_t final_size = min_size(control_block_, vds.control_block_); + + vds.control_block_->size = final_size; + control_block_->size = final_size; + + if (control_block_->destruct || (0 == control_block_->data)) + { + control_block::destroy(control_block_); + + control_block_ = vds.control_block_; + control_block_->ref_count++; + } } - - inline typename expression_node::node_type type() const + + return *this; + } + + inline data_t data() + { + return control_block_->data; + } + + inline data_t data() const + { + return control_block_->data; + } + + inline std::size_t size() + { + return control_block_->size; + } + + inline std::size_t size() const + { + return control_block_->size; + } + + inline data_t& ref() + { + return control_block_->data; + } + + inline void dump() const + { + #ifdef exprtk_enable_debugging + exprtk_debug(("size: %d\taddress:%p\tdestruct:%c\n", + size(), + data(), + (control_block_->destruct ? 'T' : 'F'))); + + for (std::size_t i = 0; i < size(); ++i) { - return expression_node::e_stringvarrng; + if (5 == i) + exprtk_debug(("\n")); + + exprtk_debug(("%15.10f ",data()[i])); } - - 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, const range_t& rp) - : value_(v), - rp_(rp) - {} - - ~const_string_range_node() - { - rp_.free(); + exprtk_debug(("\n")); + #endif + } + + static inline void match_sizes(type& vds0, type& vds1) + { + std::size_t size = min_size(vds0.control_block_,vds1.control_block_); + vds0.control_block_->size = size; + vds1.control_block_->size = size; + } + + private: + + static inline std::size_t min_size(control_block* cb0, control_block* cb1) + { + std::size_t size0 = cb0->size; + std::size_t size1 = cb1->size; + + if (size0 && size1) + return std::min(size0,size1); + else + return (size0) ? size0 : size1; + } + + control_block* control_block_; + }; + + namespace numeric + { + namespace details + { + template + inline T process_impl(const operator_type operation, const T arg) + { + switch (operation) + { + case e_abs : return numeric::abs (arg); + case e_acos : return numeric::acos (arg); + case e_acosh : return numeric::acosh(arg); + case e_asin : return numeric::asin (arg); + case e_asinh : return numeric::asinh(arg); + case e_atan : return numeric::atan (arg); + case e_atanh : return numeric::atanh(arg); + case e_ceil : return numeric::ceil (arg); + case e_cos : return numeric::cos (arg); + case e_cosh : return numeric::cosh (arg); + case e_exp : return numeric::exp (arg); + case e_expm1 : return numeric::expm1(arg); + case e_floor : return numeric::floor(arg); + case e_log : return numeric::log (arg); + case e_log10 : return numeric::log10(arg); + case e_log2 : return numeric::log2 (arg); + case e_log1p : return numeric::log1p(arg); + case e_neg : return numeric::neg (arg); + case e_pos : return numeric::pos (arg); + case e_round : return numeric::round(arg); + case e_sin : return numeric::sin (arg); + case e_sinc : return numeric::sinc (arg); + case e_sinh : return numeric::sinh (arg); + case e_sqrt : return numeric::sqrt (arg); + case e_tan : return numeric::tan (arg); + case e_tanh : return numeric::tanh (arg); + case e_cot : return numeric::cot (arg); + case e_sec : return numeric::sec (arg); + case e_csc : return numeric::csc (arg); + case e_r2d : return numeric::r2d (arg); + case e_d2r : return numeric::d2r (arg); + case e_d2g : return numeric::d2g (arg); + case e_g2d : return numeric::g2d (arg); + case e_notl : return numeric::notl (arg); + case e_sgn : return numeric::sgn (arg); + case e_erf : return numeric::erf (arg); + case e_erfc : return numeric::erfc (arg); + case e_ncdf : return numeric::ncdf (arg); + case e_frac : return numeric::frac (arg); + case e_trunc : return numeric::trunc(arg); + + default : exprtk_debug(("numeric::details::process_impl - Invalid unary operation.\n")); + return std::numeric_limits::quiet_NaN(); + } } - - inline T value() const - { - return std::numeric_limits::quiet_NaN(); + + template + inline T process_impl(const operator_type operation, const T arg0, const T arg1) + { + switch (operation) + { + case e_add : return (arg0 + arg1); + case e_sub : return (arg0 - arg1); + case e_mul : return (arg0 * arg1); + case e_div : return (arg0 / arg1); + case e_mod : return modulus(arg0,arg1); + case e_pow : return pow(arg0,arg1); + case e_atan2 : return atan2(arg0,arg1); + case e_min : return std::min(arg0,arg1); + case e_max : return std::max(arg0,arg1); + case e_logn : return logn(arg0,arg1); + case e_lt : return (arg0 < arg1) ? T(1) : T(0); + case e_lte : return (arg0 <= arg1) ? T(1) : T(0); + case e_eq : return std::equal_to()(arg0,arg1) ? T(1) : T(0); + case e_ne : return std::not_equal_to()(arg0,arg1) ? T(1) : T(0); + case e_gte : return (arg0 >= arg1) ? T(1) : T(0); + case e_gt : return (arg0 > arg1) ? T(1) : T(0); + case e_and : return and_opr (arg0,arg1); + case e_nand : return nand_opr(arg0,arg1); + case e_or : return or_opr (arg0,arg1); + case e_nor : return nor_opr (arg0,arg1); + case e_xor : return xor_opr (arg0,arg1); + case e_xnor : return xnor_opr(arg0,arg1); + case e_root : return root (arg0,arg1); + case e_roundn : return roundn (arg0,arg1); + case e_equal : return equal (arg0,arg1); + case e_nequal : return nequal (arg0,arg1); + case e_hypot : return hypot (arg0,arg1); + case e_shr : return shr (arg0,arg1); + case e_shl : return shl (arg0,arg1); + + default : exprtk_debug(("numeric::details::process_impl - Invalid binary operation.\n")); + return std::numeric_limits::quiet_NaN(); + } } - - std::string str() const - { - return value_; + + template + inline T process_impl(const operator_type operation, const T arg0, const T arg1, int_type_tag) + { + switch (operation) + { + case e_add : return (arg0 + arg1); + case e_sub : return (arg0 - arg1); + case e_mul : return (arg0 * arg1); + case e_div : return (arg0 / arg1); + case e_mod : return arg0 % arg1; + case e_pow : return pow(arg0,arg1); + case e_min : return std::min(arg0,arg1); + case e_max : return std::max(arg0,arg1); + case e_logn : return logn(arg0,arg1); + case e_lt : return (arg0 < arg1) ? T(1) : T(0); + case e_lte : return (arg0 <= arg1) ? T(1) : T(0); + case e_eq : return (arg0 == arg1) ? T(1) : T(0); + case e_ne : return (arg0 != arg1) ? T(1) : T(0); + case e_gte : return (arg0 >= arg1) ? T(1) : T(0); + case e_gt : return (arg0 > arg1) ? T(1) : T(0); + case e_and : return ((arg0 != T(0)) && (arg1 != T(0))) ? T(1) : T(0); + case e_nand : return ((arg0 != T(0)) && (arg1 != T(0))) ? T(0) : T(1); + case e_or : return ((arg0 != T(0)) || (arg1 != T(0))) ? T(1) : T(0); + case e_nor : return ((arg0 != T(0)) || (arg1 != T(0))) ? T(0) : T(1); + case e_xor : return arg0 ^ arg1; + case e_xnor : return !(arg0 ^ arg1); + case e_root : return root(arg0,arg1); + case e_equal : return arg0 == arg1; + case e_nequal : return arg0 != arg1; + case e_hypot : return hypot(arg0,arg1); + case e_shr : return arg0 >> arg1; + case e_shl : return arg0 << arg1; + + default : exprtk_debug(("numeric::details::process_impl - Invalid binary operation.\n")); + return std::numeric_limits::quiet_NaN(); + } } - - const char* base() const + } + + 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_vararg , e_conditional , e_while , e_repeat , + e_for , e_switch , e_mswitch , e_return , + e_retenv , e_variable , e_stringvar , e_stringconst , + e_stringvarrng , e_cstringvarrng, e_strgenrange , e_strconcat , + e_stringvarsize, e_strswap , e_stringsize , e_stringvararg , + e_function , e_vafunction , e_genfunction , e_strfunction , + e_strcondition , e_strccondition, e_add , e_sub , + e_mul , e_div , e_mod , e_pow , + e_lt , e_lte , e_gt , e_gte , + e_eq , e_ne , e_and , e_nand , + e_or , e_nor , e_xor , e_xnor , + e_in , e_like , e_ilike , e_inranges , + e_ipow , e_ipowinv , e_abs , e_acos , + e_acosh , e_asin , e_asinh , e_atan , + e_atanh , e_ceil , e_cos , e_cosh , + e_exp , e_expm1 , e_floor , e_log , + e_log10 , e_log2 , e_log1p , e_neg , + e_pos , e_round , e_sin , e_sinc , + e_sinh , e_sqrt , e_tan , e_tanh , + e_cot , e_sec , e_csc , e_r2d , + e_d2r , e_d2g , e_g2d , e_notl , + e_sgn , e_erf , e_erfc , e_ncdf , + e_frac , e_trunc , e_uvouv , e_vov , + e_cov , e_voc , e_vob , e_bov , + e_cob , e_boc , e_vovov , e_vovoc , + e_vocov , e_covov , e_covoc , e_vovovov , + e_vovovoc , e_vovocov , e_vocovov , e_covovov , + e_covocov , e_vocovoc , e_covovoc , e_vococov , + e_sf3ext , e_sf4ext , e_nulleq , e_strass , + e_vector , e_vecelem , e_rbvecelem , e_rbveccelem , + e_vecdefass , e_vecvalass , e_vecvecass , e_vecopvalass , + e_vecopvecass , e_vecfunc , e_vecvecswap , e_vecvecineq , + e_vecvalineq , e_valvecineq , e_vecvecarith , e_vecvalarith , + e_valvecarith , e_vecunaryop , e_break , e_continue , + e_swap + }; + + typedef T value_type; + typedef expression_node* expression_ptr; + + 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 std::complex& v) + { + return std::not_equal_to >()(std::complex(0),v); + } + + template + inline bool is_true(const expression_node* node) + { + return std::not_equal_to()(T(0),node->value()); + } + + template + inline bool is_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() || + details::expression_node::e_rbvecelem == node->type() || + details::expression_node::e_rbveccelem == node->type() + ); + } + + template + inline bool is_vector_elem_node(const expression_node* node) + { + return node && (details::expression_node::e_vecelem == node->type()); + } + + template + inline bool is_rebasevector_elem_node(const expression_node* node) + { + return node && (details::expression_node::e_rbvecelem == node->type()); + } + + template + inline bool is_rebasevector_celem_node(const expression_node* node) + { + return node && (details::expression_node::e_rbveccelem == node->type()); + } + + template + inline bool is_vector_node(const expression_node* node) + { + return node && (details::expression_node::e_vector == node->type()); + } + + template + inline bool is_ivector_node(const expression_node* node) + { + if (node) + { + switch (node->type()) + { + case details::expression_node::e_vector : + case details::expression_node::e_vecvalass : + case details::expression_node::e_vecvecass : + case details::expression_node::e_vecopvalass : + case details::expression_node::e_vecopvecass : + case details::expression_node::e_vecvecswap : + case details::expression_node::e_vecvecarith : + case details::expression_node::e_vecvalarith : + case details::expression_node::e_valvecarith : + case details::expression_node::e_vecunaryop : return true; + default : return false; + } + } + else + return false; + } + + template + inline bool is_constant_node(const expression_node* node) + { + return node && (details::expression_node::e_constant == node->type()); + } + + template + inline bool is_null_node(const expression_node* node) + { + return node && (details::expression_node::e_null == node->type()); + } + + template + inline bool is_break_node(const expression_node* node) + { + return node && (details::expression_node::e_break == node->type()); + } + + template + inline bool is_continue_node(const expression_node* node) + { + return node && (details::expression_node::e_continue == node->type()); + } + + template + inline bool is_swap_node(const expression_node* node) + { + return node && (details::expression_node::e_swap == node->type()); + } + + template + inline bool is_function(const expression_node* node) + { + return node && (details::expression_node::e_function == node->type()); + } + + template + inline bool is_return_node(const expression_node* node) + { + return node && (details::expression_node::e_return == node->type()); + } + + template class unary_node; + + template + inline bool is_negate_node(const expression_node* node) + { + if (node && is_unary_node(node)) + { + return (details::e_neg == static_cast*>(node)->operation()); + } + else + return false; + } + + template + inline bool branch_deletable(expression_node* node) + { + return !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_.data(); + return value_at(index); } - - std::size_t size() const + + inline std::size_t size() const { - return value_.size(); + return vector_size(); } - - range_t range() const + + inline value_ptr data() const { - return rp_; + return value_at(0); } - - range_t& range_ref() + + virtual inline bool rebaseable() const { - return rp_; + return false; } - - const range_t& range_ref() const + + virtual void set_ref(value_ptr*) {} + + protected: + + virtual value_ptr value_at(const std::size_t&) const = 0; + virtual std::size_t vector_size() const = 0; + }; + + class array_vector_impl : public vector_holder_base + { + public: + + array_vector_impl(const Type* vec, const std::size_t& vec_size) + : vec_(vec), + size_(vec_size) + {} + + protected: + + value_ptr value_at(const std::size_t& index) const { - return rp_; + if (index < size_) + return const_cast(vec_ + index); + else + return const_value_ptr(0); } - - inline typename expression_node::node_type type() const + + std::size_t vector_size() 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; - - generic_string_range_node(expression_ptr str_branch, const range_t& brange) - : initialised_(false), - branch_(str_branch), - branch_deletable_(branch_deletable(branch_)), - str_base_ptr_ (0), - str_range_ptr_(0), - base_range_(brange) - { - 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(); + return size_; } - - std::string str() const + + 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 value_; + return (index < sequence_.size()) ? (&sequence_[index]) : const_value_ptr(0); } - - const char* base() const + + std::size_t vector_size() const { - return &value_[0]; + return sequence_.size(); } - - std::size_t size() const + + private: + + sequence_vector_impl operator=(const sequence_vector_impl&); + + sequence_t& sequence_; + }; + + class vector_view_impl : public vector_holder_base + { + public: + + typedef exprtk::vector_view vector_view_t; + + vector_view_impl(vector_view_t& vec_view) + : vec_view_(vec_view) + {} + + void set_ref(value_ptr* ref) { - return value_.size(); + vec_view_.set_ref(ref); } - - range_t& range_ref() + + virtual inline bool rebaseable() const { - return range_; + return true; } - - const range_t& range_ref() const + + protected: + + value_ptr value_at(const std::size_t& index) const { - return range_; + return (index < vec_view_.size()) ? (&vec_view_[index]) : const_value_ptr(0); } - - inline typename expression_node::node_type type() const + + std::size_t vector_size() const { - return expression_node::e_strgenrange; + return vec_view_.size(); } - - 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 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; - - 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 + + private: + + vector_view_impl operator=(const vector_view_impl&); + + vector_view_t& vec_view_; + }; + + public: + + typedef typename details::vec_data_store vds_t; + + vector_holder(Type* vec, const std::size_t& vec_size) + : vector_holder_base_(new(buffer)array_vector_impl(vec,vec_size)) + {} + + vector_holder(const vds_t& vds) + : vector_holder_base_(new(buffer)array_vector_impl(vds.data(),vds.size())) + {} + + template + vector_holder(std::vector& vec) + : vector_holder_base_(new(buffer)sequence_vector_impl(vec)) + {} + + vector_holder(exprtk::vector_view& vec) + : vector_holder_base_(new(buffer)vector_view_impl(vec)) + {} + + inline value_ptr operator[](const std::size_t& index) const + { + return (*vector_holder_base_)[index]; + } + + inline std::size_t size() const + { + return vector_holder_base_->size(); + } + + inline value_ptr data() const + { + return vector_holder_base_->data(); + } + + void set_ref(value_ptr* ref) + { + return vector_holder_base_->set_ref(ref); + } + + bool rebaseable() const + { + return vector_holder_base_->rebaseable(); + } + + private: + + mutable vector_holder_base* vector_holder_base_; + uchar_t buffer[64]; + }; + + template + class null_node : 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_) { - return value_; + delete branch_; + branch_ = 0; } - - const char* base() const + } + + 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_interface() + {} + + virtual range_t& range_ref() = 0; + + virtual const range_t& range_ref() const = 0; + }; + + #ifndef exprtk_disable_string_capabilities + template + class string_base_node + { + public: + + typedef range_data_type range_data_type_t; + + virtual ~string_base_node() + {} + + virtual std::string str () const = 0; + + virtual 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_; + }; + #endif + + 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_) { - return &value_[0]; + delete branch_; + branch_ = 0; } - - std::size_t size() const + } + + 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) { - return value_.size(); + if (branch[i].first && branch[i].second) + { + delete branch[i].first; + branch[i].first = 0; + } } - - range_t& range_ref() + } + + 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_) { - return range_; + case e_inrange : return (arg1 < arg0) ? T(0) : ((arg1 > arg2) ? T(0) : T(1)); + + case e_clamp : return (arg1 < arg0) ? arg0 : (arg1 > arg2 ? arg2 : arg1); + + case e_iclamp : if ((arg1 <= arg0) || (arg1 >= arg2)) + return arg1; + else + return ((T(2) * arg1 <= (arg2 + arg0)) ? arg0 : arg2); + + default : { + exprtk_debug(("trinary_node::value() - Error: Invalid operation\n")); + return std::numeric_limits::quiet_NaN(); + } } - - const range_t& range_ref() const + } + + 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 + { + 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 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: + + break_exception(const T& v) + : value(v) + {} + + T value; + }; + + class continue_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_) { - return range_; + delete return_; } - - inline typename expression_node::node_type type() const + } + + 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_) { - return expression_node::e_strconcat; + delete condition_; } - - 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; - - 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 swap_genstrings_node : public binary_node - { - public: - - typedef expression_node * expression_ptr; - typedef string_base_node* str_base_ptr; - typedef range_pack range_t; - typedef range_t* range_ptr; - typedef range_interface irange_t; - typedef irange_t* irange_ptr; - - swap_genstrings_node(expression_ptr branch0, - expression_ptr branch1) - : binary_node(details::e_default,branch0,branch1), - str0_base_ptr_ (0), - str1_base_ptr_ (0), - str0_range_ptr_(0), - str1_range_ptr_(0), - initialised_(false) - { - if (is_generally_string_node(binary_node::branch_[0].first)) - { - str0_base_ptr_ = dynamic_cast(binary_node::branch_[0].first); - - if (0 == str0_base_ptr_) - return; - - irange_ptr range_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_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_t& range1 = (*str1_range_ptr_); - - if ( - range0(str0_r0,str0_r1,str0_base_ptr_->size()) && - range1(str1_r0,str1_r1,str1_base_ptr_->size()) - ) - { - const std::size_t size0 = range0.cache_size(); - const std::size_t size1 = range1.cache_size(); - const std::size_t max_size = std::min(size0,size1); - - char* s0 = const_cast(str0_base_ptr_->base() + str0_r0); - char* s1 = const_cast(str1_base_ptr_->base() + str1_r0); - - loop_unroll::details lud(max_size); - const char* upper_bound = s0 + lud.upper_bound; - - while (s0 < upper_bound) - { -#define exprtk_loop(N) \ -std::swap(s0[N], s1[N]); \ - - exprtk_loop( 0) exprtk_loop( 1) - exprtk_loop( 2) exprtk_loop( 3) -#ifndef exprtk_disable_superscalar_unroll - exprtk_loop( 4) exprtk_loop( 5) - exprtk_loop( 6) exprtk_loop( 7) - exprtk_loop( 8) exprtk_loop( 9) - exprtk_loop(10) exprtk_loop(11) - exprtk_loop(12) exprtk_loop(13) - exprtk_loop(14) exprtk_loop(15) -#endif - - s0 += lud.batch_size; - s1 += lud.batch_size; - } - - int i = 0; - - switch (lud.remainder) - { -#define case_stmt(N) \ -case N : { std::swap(s0[i],s1[i]); ++i; } \ - -#ifndef exprtk_disable_superscalar_unroll - case_stmt(15) case_stmt(14) - case_stmt(13) case_stmt(12) - case_stmt(11) case_stmt(10) - case_stmt( 9) case_stmt( 8) - case_stmt( 7) case_stmt( 6) - case_stmt( 5) case_stmt( 4) -#endif - case_stmt( 3) case_stmt( 2) - case_stmt( 1) - } - -#undef exprtk_loop -#undef case_stmt - } - } - - return std::numeric_limits::quiet_NaN(); - } - - inline typename expression_node::node_type type() const - { - return expression_node::e_strswap; - } - - private: - - swap_genstrings_node(swap_genstrings_node&); - swap_genstrings_node& operator=(swap_genstrings_node&); - - str_base_ptr str0_base_ptr_; - str_base_ptr str1_base_ptr_; - range_ptr str0_range_ptr_; - range_ptr str1_range_ptr_; - bool initialised_; - }; - - template - class stringvar_size_node : public expression_node - { - 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 + + if (loop_body_ && loop_body_deletable_) { - return T((*value_).size()); + delete loop_body_; } - - inline typename expression_node::node_type type() const + } + + inline T value() const + { + T result = T(0); + + while (is_true(condition_)) { - 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; - - 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; - - 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(); + result = loop_body_->value(); } - - std::string str() const + + 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_) { - return str0_node_ptr_->str(); + delete condition_; } - - const char* base() const + + if (loop_body_ && loop_body_deletable_) { - return str0_node_ptr_->base(); + delete loop_body_; } - - std::size_t size() const + } + + inline T value() const + { + T result = T(0); + + do { - return str0_node_ptr_->size(); + result = loop_body_->value(); } - - range_t& range_ref() + 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_) { - return str0_node_ptr_->range_ref(); + delete initialiser_; } - - const range_t& range_ref() const + + if (condition_ && condition_deletable_) { - return str0_node_ptr_->range_ref(); + delete condition_; } - - inline typename expression_node::node_type type() const + + if (incrementor_ && incrementor_deletable_) { - 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_; - }; - - template - class conditional_string_node : public trinary_node , - public string_base_node, - public range_interface - { - 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; - - conditional_string_node(expression_ptr test, - expression_ptr consequent, - expression_ptr alternative) - : trinary_node(details::e_default,consequent,alternative,test), - initialised_(false), - str0_base_ptr_ (0), - str1_base_ptr_ (0), - str0_range_ptr_(0), - str1_range_ptr_(0), - test_ (test), - consequent_ (consequent), - alternative_(alternative) - { - range_.n0_c = std::make_pair(true,0); - range_.n1_c = std::make_pair(true,0); - - range_.cache.first = range_.n0_c.second; - range_.cache.second = range_.n1_c.second; - - if (is_generally_string_node(trinary_node::branch_[0].first)) - { - str0_base_ptr_ = dynamic_cast(trinary_node::branch_[0].first); - - if (0 == str0_base_ptr_) - return; - - str0_range_ptr_ = dynamic_cast(trinary_node::branch_[0].first); - - if (0 == str0_range_ptr_) - return; - } - - if (is_generally_string_node(trinary_node::branch_[1].first)) - { - str1_base_ptr_ = dynamic_cast(trinary_node::branch_[1].first); - - if (0 == str1_base_ptr_) - return; - - str1_range_ptr_ = dynamic_cast(trinary_node::branch_[1].first); - - if (0 == str1_range_ptr_) - return; - } - - initialised_ = str0_base_ptr_ && - str1_base_ptr_ && - str0_range_ptr_ && - str1_range_ptr_ ; - - } - - inline T value() const - { - if (initialised_) - { - std::size_t r0 = 0; - std::size_t r1 = 0; - - if (is_true(test_)) - { - consequent_->value(); - - range_t& range = str0_range_ptr_->range_ref(); - - if (range(r0,r1,str0_base_ptr_->size())) - { - const std::size_t size = (r1 - r0) + 1; - - value_.assign(str0_base_ptr_->base() + r0, size); - - range_.n1_c.second = value_.size() - 1; - range_.cache.second = range_.n1_c.second; - - return T(1); - } - } - else - { - alternative_->value(); - - range_t& range = str1_range_ptr_->range_ref(); - - if (range(r0,r1,str1_base_ptr_->size())) - { - const std::size_t size = (r1 - r0) + 1; - - value_.assign(str1_base_ptr_->base() + r0, size); - - range_.n1_c.second = value_.size() - 1; - range_.cache.second = range_.n1_c.second; - - return T(0); - } - } - } - - return std::numeric_limits::quiet_NaN(); + delete incrementor_; } - - std::string str() const + + if (loop_body_ && loop_body_deletable_) { - return value_; + delete loop_body_; } - - const char* base() const - { - return &value_[0]; - } - - std::size_t size() const + } + + inline T value() const + { + T result = T(0); + + if (initialiser_) + initialiser_->value(); + + if (incrementor_) { - return value_.size(); + while (is_true(condition_)) + { + result = loop_body_->value(); + incrementor_->value(); + } } - - range_t& range_ref() + else { - return range_; + while (is_true(condition_)) + { + result = loop_body_->value(); + } } - - const range_t& range_ref() const + + 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_) { - return range_; + delete condition_; } - - inline typename expression_node::node_type type() const + + if (loop_body_ && loop_body_deletable_) { - return expression_node::e_strcondition; + delete loop_body_; } - - private: - - bool initialised_; - str_base_ptr str0_base_ptr_; - str_base_ptr str1_base_ptr_; - irange_ptr str0_range_ptr_; - irange_ptr str1_range_ptr_; - mutable range_t range_; - mutable std::string value_; - - expression_ptr test_; - expression_ptr consequent_; - expression_ptr alternative_; - }; - - template - class cons_conditional_str_node : public binary_node , - public string_base_node, - public range_interface - { - 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; - - cons_conditional_str_node(expression_ptr test, - expression_ptr consequent) - : binary_node(details::e_default,consequent,test), - initialised_(false), - str0_base_ptr_ (0), - str0_range_ptr_(0), - test_ (test), - consequent_(consequent) - { - range_.n0_c = std::make_pair(true,0); - range_.n1_c = std::make_pair(true,0); - - range_.cache.first = range_.n0_c.second; - range_.cache.second = range_.n1_c.second; - - if (is_generally_string_node(binary_node::branch_[0].first)) - { - str0_base_ptr_ = dynamic_cast(binary_node::branch_[0].first); - - if (0 == str0_base_ptr_) - return; - - str0_range_ptr_ = dynamic_cast(binary_node::branch_[0].first); - - if (0 == str0_range_ptr_) - return; - } - - initialised_ = str0_base_ptr_ && str0_range_ptr_ ; - } - - inline T value() const - { - if (initialised_) - { - if (is_true(test_)) - { - consequent_->value(); - - range_t& range = str0_range_ptr_->range_ref(); - - std::size_t r0 = 0; - std::size_t r1 = 0; - - if (range(r0,r1,str0_base_ptr_->size())) - { - const std::size_t size = (r1 - r0) + 1; - - value_.assign(str0_base_ptr_->base() + r0, size); - - range_.n1_c.second = value_.size() - 1; - range_.cache.second = range_.n1_c.second; - - return T(1); - } - } - } - - return std::numeric_limits::quiet_NaN(); + } + + inline T value() const + { + 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&) + {} } - - std::string str() const + + 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_) { - return value_; + delete condition_; } - - const char* base() const + + if (loop_body_ && loop_body_deletable_) { - return &value_[0]; + delete loop_body_; } - - std::size_t size() const + } + + 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_) { - return value_.size(); + delete initialiser_; } - - range_t& range_ref() + + if (condition_ && condition_deletable_) { - return range_; + delete condition_; } - - const range_t& range_ref() const + + if (incrementor_ && incrementor_deletable_) { - return range_; + delete incrementor_; } - - inline typename expression_node::node_type type() const + + if (loop_body_ && loop_body_deletable_) { - return expression_node::e_strccondition; + delete loop_body_; } - - private: - - bool initialised_; - str_base_ptr str0_base_ptr_; - irange_ptr str0_range_ptr_; - mutable range_t range_; - mutable std::string value_; - - expression_ptr test_; - expression_ptr consequent_; - }; -#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)") - define_sfop4(ext60,(((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); + } + + 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(); + } } - }; - - 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 + else { - 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); + while (is_true(condition_)) + { + try + { + result = loop_body_->value(); + } + catch(const break_exception& e) + { + return e.value; + } + catch(const continue_exception&) + {} + } } - }; - - 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 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) { - return SpecialFunction::process(v0_,v1_,v2_); - } - - inline typename expression_node::node_type type() const + 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) { - 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; - } - } + if (arg_list_[i] && delete_branch_[i]) + { + delete arg_list_[i]; + arg_list_[i] = 0; + } } - - inline T value() const + } + + inline T value() const + { + if (!arg_list_.empty()) { - if (!arg_list_.empty()) - return VarArgFunction::process(arg_list_); - else - 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)) + { + return consequent->value(); + } + } + + return arg_list_[upper_bound]->value(); } - - inline typename expression_node::node_type type() const + else + return std::numeric_limits::quiet_NaN(); + } + + inline typename expression_node::node_type type() const + { + return expression_node::e_switch; + } + + protected: + + std::vector arg_list_; + std::vector delete_branch_; + }; + + template + class switch_n_node : public switch_node + { + public: + + typedef expression_node* expression_ptr; + + template class Sequence> + switch_n_node(const Sequence& arg_list) + : switch_node(arg_list) + {} + + inline T value() const + { + return Switch_N::process(switch_node::arg_list_); + } + }; + + 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) { - 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_rebasevec_elem_node : public binary_node - { - public: - - typedef expression_node* expression_ptr; - - assignment_rebasevec_elem_node(const operator_type& opr, - expression_ptr branch0, - expression_ptr branch1) - : binary_node(opr,branch0,branch1), - rbvec_node_ptr_(0) - { - if (is_rebasevector_elem_node(binary_node::branch_[0].first)) - { - rbvec_node_ptr_ = static_cast*>(binary_node::branch_[0].first); - } - } - - inline T value() const - { - if (rbvec_node_ptr_) - { - T& result = rbvec_node_ptr_->ref(); - - result = binary_node::branch_[1].first->value(); - - return result; - } - else - return std::numeric_limits::quiet_NaN(); - } - - private: - - rebasevector_elem_node* rbvec_node_ptr_; - }; - - template - class assignment_rebasevec_celem_node : public binary_node - { - public: - - typedef expression_node* expression_ptr; - - assignment_rebasevec_celem_node(const operator_type& opr, - expression_ptr branch0, - expression_ptr branch1) - : binary_node(opr,branch0,branch1), - rbvec_node_ptr_(0) - { - if (is_rebasevector_celem_node(binary_node::branch_[0].first)) - { - rbvec_node_ptr_ = static_cast*>(binary_node::branch_[0].first); - } - } - - inline T value() const - { - if (rbvec_node_ptr_) - { - T& result = rbvec_node_ptr_->ref(); - - result = binary_node::branch_[1].first->value(); - - return result; - } - else - return std::numeric_limits::quiet_NaN(); - } - - private: - - rebasevector_celem_node* rbvec_node_ptr_; - }; - - template - class assignment_vec_node : public binary_node , - public vector_interface - { - public: - - typedef expression_node* expression_ptr; - typedef vector_node* vector_node_ptr; - typedef vec_data_store vds_t; - - assignment_vec_node(const operator_type& opr, - expression_ptr branch0, - expression_ptr branch1) - : binary_node(opr,branch0,branch1), - vec_node_ptr_(0) - { - if (is_vector_node(binary_node::branch_[0].first)) - { - vec_node_ptr_ = static_cast*>(binary_node::branch_[0].first); - vds() = vec_node_ptr_->vds(); - } - } - - inline T value() const - { - if (vec_node_ptr_) - { - const T v = binary_node::branch_[1].first->value(); - - T* vec = vds().data(); - - loop_unroll::details lud(size()); - const T* upper_bound = vec + lud.upper_bound; - - while (vec < upper_bound) - { -#define exprtk_loop(N) \ -vec[N] = v; \ - - exprtk_loop( 0) exprtk_loop( 1) - exprtk_loop( 2) exprtk_loop( 3) -#ifndef exprtk_disable_superscalar_unroll - exprtk_loop( 4) exprtk_loop( 5) - exprtk_loop( 6) exprtk_loop( 7) - exprtk_loop( 8) exprtk_loop( 9) - exprtk_loop(10) exprtk_loop(11) - exprtk_loop(12) exprtk_loop(13) - exprtk_loop(14) exprtk_loop(15) -#endif - - vec += lud.batch_size; - } - - switch (lud.remainder) - { -#define case_stmt(N) \ -case N : *vec++ = v; \ - -#ifndef exprtk_disable_superscalar_unroll - case_stmt(15) case_stmt(14) - case_stmt(13) case_stmt(12) - case_stmt(11) case_stmt(10) - case_stmt( 9) case_stmt( 8) - case_stmt( 7) case_stmt( 6) - case_stmt( 5) case_stmt( 4) -#endif - case_stmt( 3) case_stmt( 2) - case_stmt( 1) - } - -#undef exprtk_loop -#undef case_stmt - - return vec_node_ptr_->value(); - } - else - return std::numeric_limits::quiet_NaN(); - } - - vector_node_ptr vec() const + 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) { - return vec_node_ptr_; + if (arg_list_[i] && delete_branch_[i]) + { + delete arg_list_[i]; + arg_list_[i] = 0; + } } - - vector_node_ptr vec() + } + + inline T value() const + { + T result = T(0); + + if (arg_list_.empty()) { - return vec_node_ptr_; + return std::numeric_limits::quiet_NaN(); } - - inline typename expression_node::node_type type() const + + const std::size_t upper_bound = (arg_list_.size() - 1); + + for (std::size_t i = 0; i < upper_bound; i += 2) { - return expression_node::e_vecvalass; + expression_ptr condition = arg_list_[i ]; + expression_ptr consequent = arg_list_[i + 1]; + + if (is_true(condition)) + { + result = consequent->value(); + } } - - std::size_t size() const + + 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 ~ivariable() + {} + + 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_) { - return vds().size(); + delete value_; } - - vds_t& vds() + } + + 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) { - return vds_; + 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); + } } - - const vds_t& vds() const + + 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) { - return vds_; + T r0_value = n0_e.second->value(); + + if (r0_value < 0) + return false; + else + r0 = static_cast(details::numeric::to_int64(r0_value)); } - - private: - - vector_node* vec_node_ptr_; - vds_t vds_; - }; - - template - class assignment_vecvec_node : public binary_node , - public vector_interface - { - public: - - typedef expression_node* expression_ptr; - typedef vector_node* vector_node_ptr; - typedef vec_data_store vds_t; - - assignment_vecvec_node(const operator_type& opr, - expression_ptr branch0, - expression_ptr branch1) - : binary_node(opr,branch0,branch1), - vec0_node_ptr_(0), - vec1_node_ptr_(0), - initialised_(false), - src_is_ivec_(false) - { - if (is_vector_node(binary_node::branch_[0].first)) - { - vec0_node_ptr_ = static_cast*>(binary_node::branch_[0].first); - vds() = vec0_node_ptr_->vds(); - } - - if (is_vector_node(binary_node::branch_[1].first)) - { - vec1_node_ptr_ = static_cast*>(binary_node::branch_[1].first); - vds_t::match_sizes(vds(),vec1_node_ptr_->vds()); - } - else if (is_ivector_node(binary_node::branch_[1].first)) - { - vector_interface* vi = reinterpret_cast*>(0); - - if (0 != (vi = dynamic_cast*>(binary_node::branch_[1].first))) - { - vec1_node_ptr_ = vi->vec(); - - if (!vi->side_effect()) - { - vi->vds() = vds(); - src_is_ivec_ = true; - } - else - vds_t::match_sizes(vds(),vi->vds()); - } - } - - initialised_ = (vec0_node_ptr_ && vec1_node_ptr_); - } - - inline T value() const - { - if (initialised_) - { - binary_node::branch_[1].first->value(); - - if (src_is_ivec_) - return vec0_node_ptr_->value(); - - T* vec0 = vec0_node_ptr_->vds().data(); - T* vec1 = vec1_node_ptr_->vds().data(); - - loop_unroll::details lud(size()); - const T* upper_bound = vec0 + lud.upper_bound; - - while (vec0 < upper_bound) - { -#define exprtk_loop(N) \ -vec0[N] = vec1[N]; \ - - exprtk_loop( 0) exprtk_loop( 1) - exprtk_loop( 2) exprtk_loop( 3) -#ifndef exprtk_disable_superscalar_unroll - exprtk_loop( 4) exprtk_loop( 5) - exprtk_loop( 6) exprtk_loop( 7) - exprtk_loop( 8) exprtk_loop( 9) - exprtk_loop(10) exprtk_loop(11) - exprtk_loop(12) exprtk_loop(13) - exprtk_loop(14) exprtk_loop(15) -#endif - - vec0 += lud.batch_size; - vec1 += lud.batch_size; - } - - switch (lud.remainder) - { -#define case_stmt(N) \ -case N : *vec0++ = *vec1++; \ - -#ifndef exprtk_disable_superscalar_unroll - case_stmt(15) case_stmt(14) - case_stmt(13) case_stmt(12) - case_stmt(11) case_stmt(10) - case_stmt( 9) case_stmt( 8) - case_stmt( 7) case_stmt( 6) - case_stmt( 5) case_stmt( 4) -#endif - case_stmt( 3) case_stmt( 2) - case_stmt( 1) - } - -#undef exprtk_loop -#undef case_stmt - - return vec0_node_ptr_->value(); - } - else - return std::numeric_limits::quiet_NaN(); + 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)); } - - vector_node_ptr vec() const + else + return false; + + if ( + (std::numeric_limits::max() != size) && + (std::numeric_limits::max() == r1 ) + ) { - return vec0_node_ptr_; + r1 = size - 1; } - - vector_node_ptr vec() + + 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; + typedef vec_data_store vds_t; + + virtual ~vector_interface() + {} + + virtual std::size_t size () const = 0; + + virtual vector_node_ptr vec() const = 0; + + virtual vector_node_ptr vec() = 0; + + virtual vds_t& vds () = 0; + + virtual const vds_t& vds () const = 0; + + virtual bool side_effect () const { return false; } + }; + + template + class vector_node : public expression_node , + public vector_interface + { + public: + + typedef expression_node* expression_ptr; + typedef vector_holder vector_holder_t; + typedef vector_node* vector_node_ptr; + typedef vec_data_store vds_t; + + vector_node(vector_holder_t* vh) + : vector_holder_(vh), + vds_((*vector_holder_).size(),(*vector_holder_)[0]) + { + vector_holder_->set_ref(&vds_.ref()); + } + + vector_node(const vds_t& vds, vector_holder_t* vh) + : vector_holder_(vh), + vds_(vds) + {} + + inline T value() const + { + return vds().data()[0]; + } + + 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 vds().size(); + } + + vds_t& vds() + { + return vds_; + } + + const vds_t& vds() const + { + return vds_; + } + + inline vector_holder_t& vec_holder() + { + return (*vector_holder_); + } + + private: + + vector_holder_t* vector_holder_; + vds_t vds_; + }; + + template + class vector_elem_node : public expression_node, + public ivariable + { + public: + + typedef expression_node* expression_ptr; + typedef vector_holder vector_holder_t; + typedef vector_holder_t* vector_holder_ptr; + + vector_elem_node(expression_ptr index, vector_holder_ptr vec_holder) + : index_(index), + vec_holder_(vec_holder), + vector_base_((*vec_holder)[0]), + index_deletable_(branch_deletable(index_)) + {} + + ~vector_elem_node() + { + if (index_ && index_deletable_) { - return vec0_node_ptr_; + delete index_; } - - inline typename expression_node::node_type type() const + } + + 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; + } + + inline vector_holder_t& vec_holder() + { + return (*vec_holder_); + } + + private: + + expression_ptr index_; + vector_holder_ptr vec_holder_; + T* vector_base_; + bool index_deletable_; + }; + + template + class rebasevector_elem_node : public expression_node, + public ivariable + { + public: + + typedef expression_node* expression_ptr; + typedef vector_holder vector_holder_t; + typedef vector_holder_t* vector_holder_ptr; + typedef vec_data_store vds_t; + + rebasevector_elem_node(expression_ptr index, vector_holder_ptr vec_holder) + : index_(index), + index_deletable_(branch_deletable(index_)), + vector_holder_(vec_holder), + vds_((*vector_holder_).size(),(*vector_holder_)[0]) + { + vector_holder_->set_ref(&vds_.ref()); + } + + ~rebasevector_elem_node() + { + if (index_ && index_deletable_) { - return expression_node::e_vecvecass; + delete index_; } - - std::size_t size() const + } + + inline T value() const + { + return *(vds_.data() + static_cast(details::numeric::to_int64(index_->value()))); + } + + inline T& ref() + { + return *(vds_.data() + static_cast(details::numeric::to_int64(index_->value()))); + } + + inline const T& ref() const + { + return *(vds_.data() + static_cast(details::numeric::to_int64(index_->value()))); + } + + inline typename expression_node::node_type type() const + { + return expression_node::e_rbvecelem; + } + + inline vector_holder_t& vec_holder() + { + return (*vector_holder_); + } + + private: + + expression_ptr index_; + bool index_deletable_; + vector_holder_ptr vector_holder_; + vds_t vds_; + }; + + template + class rebasevector_celem_node : public expression_node, + public ivariable + { + public: + + typedef expression_node* expression_ptr; + typedef vector_holder vector_holder_t; + typedef vector_holder_t* vector_holder_ptr; + typedef vec_data_store vds_t; + + rebasevector_celem_node(const std::size_t index, vector_holder_ptr vec_holder) + : index_(index), + vector_holder_(vec_holder), + vds_((*vector_holder_).size(),(*vector_holder_)[0]) + { + vector_holder_->set_ref(&vds_.ref()); + } + + inline T value() const + { + return *(vds_.data() + index_); + } + + inline T& ref() + { + return *(vds_.data() + index_); + } + + inline const T& ref() const + { + return *(vds_.data() + index_); + } + + inline typename expression_node::node_type type() const + { + return expression_node::e_rbveccelem; + } + + inline vector_holder_t& vec_holder() + { + return (*vector_holder_); + } + + private: + + std::size_t index_; + vector_holder_ptr vector_holder_; + vds_t vds_; + }; + + template + class vector_assignment_node : public expression_node + { + public: + + typedef expression_node* expression_ptr; + + vector_assignment_node(T* vector_base, + const std::size_t& size, + const std::vector& initialiser_list, + const bool single_value_initialse) + : vector_base_(vector_base), + initialiser_list_(initialiser_list), + size_(size), + single_value_initialse_(single_value_initialse) + {} + + ~vector_assignment_node() + { + for (std::size_t i = 0; i < initialiser_list_.size(); ++i) { - return vds().size(); + if (branch_deletable(initialiser_list_[i])) + { + delete initialiser_list_[i]; + } } - - vds_t& vds() + } + + inline T value() const + { + if (single_value_initialse_) { - return vds_; + for (std::size_t i = 0; i < size_; ++i) + { + *(vector_base_ + i) = initialiser_list_[0]->value(); + } } - - const vds_t& vds() const + else { - return vds_; + 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); + } + } } - - private: - - vector_node* vec0_node_ptr_; - vector_node* vec1_node_ptr_; - bool initialised_; - bool src_is_ivec_; - vds_t vds_; - }; - - template - class assignment_op_node : 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_rebasevec_elem_op_node : public binary_node - { - public: - - typedef expression_node* expression_ptr; - - assignment_rebasevec_elem_op_node(const operator_type& opr, - expression_ptr branch0, - expression_ptr branch1) - : binary_node(opr,branch0,branch1), - rbvec_node_ptr_(0) - { - if (is_rebasevector_elem_node(binary_node::branch_[0].first)) - { - rbvec_node_ptr_ = static_cast*>(binary_node::branch_[0].first); - } - } - - inline T value() const - { - if (rbvec_node_ptr_) - { - T& v = rbvec_node_ptr_->ref(); - v = Operation::process(v,binary_node::branch_[1].first->value()); - - return v; - } - else - return std::numeric_limits::quiet_NaN(); - } - - private: - - rebasevector_elem_node* rbvec_node_ptr_; - }; - - template - class assignment_rebasevec_celem_op_node : public binary_node - { - public: - - typedef expression_node* expression_ptr; - - assignment_rebasevec_celem_op_node(const operator_type& opr, - expression_ptr branch0, - expression_ptr branch1) - : binary_node(opr,branch0,branch1), - rbvec_node_ptr_(0) - { - if (is_rebasevector_celem_node(binary_node::branch_[0].first)) - { - rbvec_node_ptr_ = static_cast*>(binary_node::branch_[0].first); - } - } - - inline T value() const - { - if (rbvec_node_ptr_) - { - T& v = rbvec_node_ptr_->ref(); - v = Operation::process(v,binary_node::branch_[1].first->value()); - - return v; - } - else - return std::numeric_limits::quiet_NaN(); - } - - private: - - rebasevector_celem_node* rbvec_node_ptr_; - }; - - template - class assignment_vec_op_node : public binary_node , - public vector_interface - { - public: - - typedef expression_node* expression_ptr; - typedef vector_node* vector_node_ptr; - typedef vec_data_store vds_t; - - assignment_vec_op_node(const operator_type& opr, - expression_ptr branch0, - expression_ptr branch1) - : binary_node(opr,branch0,branch1), - vec_node_ptr_(0) - { - if (is_vector_node(binary_node::branch_[0].first)) - { - vec_node_ptr_ = static_cast*>(binary_node::branch_[0].first); - vds() = vec_node_ptr_->vds(); - } - } - - inline T value() const - { - if (vec_node_ptr_) - { - const T v = binary_node::branch_[1].first->value(); - - T* vec = vds().data(); - - loop_unroll::details lud(size()); - const T* upper_bound = vec + lud.upper_bound; - - while (vec < upper_bound) - { -#define exprtk_loop(N) \ -Operation::assign(vec[N],v); \ - - exprtk_loop( 0) exprtk_loop( 1) - exprtk_loop( 2) exprtk_loop( 3) -#ifndef exprtk_disable_superscalar_unroll - exprtk_loop( 4) exprtk_loop( 5) - exprtk_loop( 6) exprtk_loop( 7) - exprtk_loop( 8) exprtk_loop( 9) - exprtk_loop(10) exprtk_loop(11) - exprtk_loop(12) exprtk_loop(13) - exprtk_loop(14) exprtk_loop(15) -#endif - - vec += lud.batch_size; - } - - switch (lud.remainder) - { -#define case_stmt(N) \ -case N : Operation::assign(*vec++,v); \ - -#ifndef exprtk_disable_superscalar_unroll - case_stmt(15) case_stmt(14) - case_stmt(13) case_stmt(12) - case_stmt(11) case_stmt(10) - case_stmt( 9) case_stmt( 8) - case_stmt( 7) case_stmt( 6) - case_stmt( 5) case_stmt( 4) -#endif - case_stmt( 3) case_stmt( 2) - case_stmt( 1) - } - -#undef exprtk_loop -#undef case_stmt - - return vec_node_ptr_->value(); - } - else - return std::numeric_limits::quiet_NaN(); + + 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; + typedef vec_data_store vds_t; + + swap_vecvec_node(expression_ptr branch0, + expression_ptr branch1) + : binary_node(details::e_swap,branch0,branch1), + vec0_node_ptr_(0), + vec1_node_ptr_(0), + vec_size_ (0), + initialised_ (false) + { + if (is_ivector_node(binary_node::branch_[0].first)) + { + vector_interface* vi = reinterpret_cast*>(0); + + if (0 != (vi = dynamic_cast*>(binary_node::branch_[0].first))) + { + vec0_node_ptr_ = vi->vec(); + vds() = vi->vds(); + } } - - vector_node_ptr vec() const + + if (is_ivector_node(binary_node::branch_[1].first)) { - return vec_node_ptr_; + vector_interface* vi = reinterpret_cast*>(0); + + if (0 != (vi = dynamic_cast*>(binary_node::branch_[1].first))) + { + vec1_node_ptr_ = vi->vec(); + } } - - vector_node_ptr vec() + + if (vec0_node_ptr_ && vec1_node_ptr_) { - return vec_node_ptr_; + vec_size_ = std::min(vec0_node_ptr_->vds().size(), + vec1_node_ptr_->vds().size()); + + initialised_ = true; } - - inline typename expression_node::node_type type() const + } + + inline T value() const + { + if (initialised_) { - return expression_node::e_vecopvalass; + binary_node::branch_[0].first->value(); + binary_node::branch_[1].first->value(); + + T* vec0 = vec0_node_ptr_->vds().data(); + T* vec1 = vec1_node_ptr_->vds().data(); + + for (std::size_t i = 0; i < vec_size_; ++i) + { + std::swap(vec0[i],vec1[i]); + } + + return vec1_node_ptr_->value(); } - - std::size_t size() const + 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_; + } + + vds_t& vds() + { + return vds_; + } + + const vds_t& vds() const + { + return vds_; + } + + private: + + vector_node* vec0_node_ptr_; + vector_node* vec1_node_ptr_; + std::size_t vec_size_; + bool initialised_; + vds_t vds_; + }; + + #ifndef exprtk_disable_string_capabilities + 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_)[0]; + } + + 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, const range_t& rp) + : value_(&v), + rp_(rp) + {} + + virtual ~string_range_node() + { + rp_.free(); + } + + inline bool operator <(const string_range_node& v) const + { + return this < (&v); + } + + inline T value() const + { + return std::numeric_limits::quiet_NaN(); + } + + inline std::string str() const + { + return (*value_); + } + + const char* base() const + { + return &(*value_)[0]; + } + + 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, const 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; + + generic_string_range_node(expression_ptr str_branch, const range_t& brange) + : initialised_(false), + branch_(str_branch), + branch_deletable_(branch_deletable(branch_)), + str_base_ptr_ (0), + str_range_ptr_(0), + base_range_(brange) + { + 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_)) { - return vds().size(); + str_base_ptr_ = dynamic_cast(branch_); + + if (0 == str_base_ptr_) + return; + + str_range_ptr_ = dynamic_cast(branch_); + + if (0 == str_range_ptr_) + return; } - - vds_t& vds() + + initialised_ = (str_base_ptr_ && str_range_ptr_); + } + + ~generic_string_range_node() + { + base_range_.free(); + + if (branch_ && branch_deletable_) { - return vds_; + delete branch_; + branch_ = 0; } - - const vds_t& vds() const + } + + inline T value() const + { + if (initialised_) { - return vds_; + 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); + } } - - bool side_effect() const + + return std::numeric_limits::quiet_NaN(); + } + + std::string str() const + { + return value_; + } + + const char* base() const + { + return &value_[0]; + } + + std::size_t size() const + { + return value_.size(); + } + + range_t& range_ref() + { + return range_; + } + + const range_t& range_ref() const + { + return range_; + } + + inline typename expression_node::node_type type() const + { + return expression_node::e_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 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; + + 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)) { - return true; - } - - private: - - vector_node* vec_node_ptr_; - vds_t vds_; - }; - - template - class assignment_vecvec_op_node : public binary_node , - public vector_interface - { - public: - - typedef expression_node* expression_ptr; - typedef vector_node* vector_node_ptr; - typedef vec_data_store vds_t; - - assignment_vecvec_op_node(const operator_type& opr, - expression_ptr branch0, - expression_ptr branch1) - : binary_node(opr,branch0,branch1), - vec0_node_ptr_(0), - vec1_node_ptr_(0), - initialised_(false) - { - if (is_vector_node(binary_node::branch_[0].first)) - { - vec0_node_ptr_ = static_cast*>(binary_node::branch_[0].first); - vds() = vec0_node_ptr_->vds(); - } - - if (is_vector_node(binary_node::branch_[1].first)) - { - vec1_node_ptr_ = static_cast*>(binary_node::branch_[1].first); - vec1_node_ptr_->vds() = vds(); - } - else if (is_ivector_node(binary_node::branch_[1].first)) - { - vector_interface* vi = reinterpret_cast*>(0); - - if (0 != (vi = dynamic_cast*>(binary_node::branch_[1].first))) - { - vec1_node_ptr_ = vi->vec(); - vec1_node_ptr_->vds() = vds(); - } - else - vds_t::match_sizes(vds(),vec1_node_ptr_->vds()); - } - - initialised_ = (vec0_node_ptr_ && vec1_node_ptr_); - } - - inline T value() const - { - if (initialised_) - { - binary_node::branch_[0].first->value(); - binary_node::branch_[1].first->value(); - - T* vec0 = vec0_node_ptr_->vds().data(); - T* vec1 = vec1_node_ptr_->vds().data(); - - loop_unroll::details lud(size()); - const T* upper_bound = vec0 + lud.upper_bound; - - while (vec0 < upper_bound) - { -#define exprtk_loop(N) \ -vec0[N] = Operation::process(vec0[N],vec1[N]); \ - - exprtk_loop( 0) exprtk_loop( 1) - exprtk_loop( 2) exprtk_loop( 3) -#ifndef exprtk_disable_superscalar_unroll - exprtk_loop( 4) exprtk_loop( 5) - exprtk_loop( 6) exprtk_loop( 7) - exprtk_loop( 8) exprtk_loop( 9) - exprtk_loop(10) exprtk_loop(11) - exprtk_loop(12) exprtk_loop(13) - exprtk_loop(14) exprtk_loop(15) -#endif - - vec0 += lud.batch_size; - vec1 += lud.batch_size; - } - - int i = 0; - - switch (lud.remainder) - { -#define case_stmt(N) \ -case N : { vec0[i] = Operation::process(vec0[i],vec1[i]); ++i; } \ - -#ifndef exprtk_disable_superscalar_unroll - case_stmt(15) case_stmt(14) - case_stmt(13) case_stmt(12) - case_stmt(11) case_stmt(10) - case_stmt( 9) case_stmt( 8) - case_stmt( 7) case_stmt( 6) - case_stmt( 5) case_stmt( 4) -#endif - case_stmt( 3) case_stmt( 2) - case_stmt( 1) - } - -#undef exprtk_loop -#undef case_stmt - - return vec0_node_ptr_->value(); - } - else - return std::numeric_limits::quiet_NaN(); + 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; } - - vector_node_ptr vec() const + + if (is_generally_string_node(binary_node::branch_[1].first)) { - return vec0_node_ptr_; + 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; } - - vector_node_ptr vec() + + initialised_ = str0_base_ptr_ && + str1_base_ptr_ && + str0_range_ptr_ && + str1_range_ptr_ ; + } + + inline T value() const + { + if (initialised_) { - return vec0_node_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_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; + } } - - inline typename expression_node::node_type type() const + + return std::numeric_limits::quiet_NaN(); + } + + std::string str() const + { + return value_; + } + + const char* base() const + { + return &value_[0]; + } + + std::size_t size() const + { + return value_.size(); + } + + range_t& range_ref() + { + return range_; + } + + const range_t& range_ref() const + { + return range_; + } + + inline typename expression_node::node_type type() const + { + return expression_node::e_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; + + 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)) { - return expression_node::e_vecopvecass; + str0_node_ptr_ = static_cast(binary_node::branch_[0].first); } - - std::size_t size() const + + if (is_string_node(binary_node::branch_[1].first)) { - return vds().size(); + str1_node_ptr_ = static_cast(binary_node::branch_[1].first); } - - vds_t& vds() + + initialised_ = (str0_node_ptr_ && str1_node_ptr_); + } + + inline T value() const + { + if (initialised_) { - return vds_; + 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 swap_genstrings_node : public binary_node + { + public: + + typedef expression_node * expression_ptr; + typedef string_base_node* str_base_ptr; + typedef range_pack range_t; + typedef range_t* range_ptr; + typedef range_interface irange_t; + typedef irange_t* irange_ptr; + + swap_genstrings_node(expression_ptr branch0, + expression_ptr branch1) + : binary_node(details::e_default,branch0,branch1), + str0_base_ptr_ (0), + str1_base_ptr_ (0), + str0_range_ptr_(0), + str1_range_ptr_(0), + initialised_(false) + { + if (is_generally_string_node(binary_node::branch_[0].first)) + { + str0_base_ptr_ = dynamic_cast(binary_node::branch_[0].first); + + if (0 == str0_base_ptr_) + return; + + irange_ptr range_ptr = dynamic_cast(binary_node::branch_[0].first); + + if (0 == range_ptr) + return; + + str0_range_ptr_ = &(range_ptr->range_ref()); } - - const vds_t& vds() const + + if (is_generally_string_node(binary_node::branch_[1].first)) { - return vds_; + 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()); } - - bool side_effect() const + + initialised_ = str0_base_ptr_ && + str1_base_ptr_ && + str0_range_ptr_ && + str1_range_ptr_ ; + } + + inline T value() const + { + if (initialised_) { - return true; + 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()) + ) + { + const std::size_t size0 = range0.cache_size(); + const std::size_t size1 = range1.cache_size(); + const std::size_t max_size = std::min(size0,size1); + + char* s0 = const_cast(str0_base_ptr_->base() + str0_r0); + char* s1 = const_cast(str1_base_ptr_->base() + str1_r0); + + loop_unroll::details lud(max_size); + const char* upper_bound = s0 + lud.upper_bound; + + while (s0 < upper_bound) + { + #define exprtk_loop(N) \ + std::swap(s0[N], s1[N]); \ + + exprtk_loop( 0) exprtk_loop( 1) + exprtk_loop( 2) exprtk_loop( 3) + #ifndef exprtk_disable_superscalar_unroll + exprtk_loop( 4) exprtk_loop( 5) + exprtk_loop( 6) exprtk_loop( 7) + exprtk_loop( 8) exprtk_loop( 9) + exprtk_loop(10) exprtk_loop(11) + exprtk_loop(12) exprtk_loop(13) + exprtk_loop(14) exprtk_loop(15) + #endif + + s0 += lud.batch_size; + s1 += lud.batch_size; + } + + int i = 0; + + switch (lud.remainder) + { + #define case_stmt(N) \ + case N : { std::swap(s0[i],s1[i]); ++i; } \ + + #ifndef exprtk_disable_superscalar_unroll + case_stmt(15) case_stmt(14) + case_stmt(13) case_stmt(12) + case_stmt(11) case_stmt(10) + case_stmt( 9) case_stmt( 8) + case_stmt( 7) case_stmt( 6) + case_stmt( 5) case_stmt( 4) + #endif + case_stmt( 3) case_stmt( 2) + case_stmt( 1) + } + + #undef exprtk_loop + #undef case_stmt + } } - - private: - - vector_node* vec0_node_ptr_; - vector_node* vec1_node_ptr_; - bool initialised_; - vds_t vds_; - }; - - template - class vec_binop_vecvec_node : public binary_node , - public vector_interface - { - public: - - typedef expression_node* expression_ptr; - typedef vector_node* vector_node_ptr; - typedef vector_holder* vector_holder_ptr; - typedef vec_data_store vds_t; - - vec_binop_vecvec_node(const operator_type& opr, - expression_ptr branch0, - expression_ptr branch1) - : binary_node(opr,branch0,branch1), - vec0_node_ptr_(0), - vec1_node_ptr_(0), - temp_ (0), - temp_vec_node_(0), - initialised_(false) - { - bool v0_is_ivec = false; - bool v1_is_ivec = false; - - if (is_vector_node(binary_node::branch_[0].first)) - { - vec0_node_ptr_ = static_cast(binary_node::branch_[0].first); - } - else if (is_ivector_node(binary_node::branch_[0].first)) - { - vector_interface* vi = reinterpret_cast*>(0); - - if (0 != (vi = dynamic_cast*>(binary_node::branch_[0].first))) - { - vec0_node_ptr_ = vi->vec(); - v0_is_ivec = true; - } - } - - if (is_vector_node(binary_node::branch_[1].first)) - { - vec1_node_ptr_ = static_cast(binary_node::branch_[1].first); - } - else if (is_ivector_node(binary_node::branch_[1].first)) - { - vector_interface* vi = reinterpret_cast*>(0); - - if (0 != (vi = dynamic_cast*>(binary_node::branch_[1].first))) - { - vec1_node_ptr_ = vi->vec(); - v1_is_ivec = true; - } - } - - if (vec0_node_ptr_ && vec1_node_ptr_) - { - vector_holder& vec0 = vec0_node_ptr_->vec_holder(); - vector_holder& vec1 = vec1_node_ptr_->vec_holder(); - - if (v0_is_ivec && (vec0.size() <= vec1.size())) - vds_ = vds_t(vec0_node_ptr_->vds()); - else if (v1_is_ivec && (vec1.size() <= vec0.size())) - vds_ = vds_t(vec1_node_ptr_->vds()); - else - vds_ = vds_t(std::min(vec0.size(),vec1.size())); - - temp_ = new vector_holder(vds().data(),vds().size()); - temp_vec_node_ = new vector_node (vds(),temp_); - - initialised_ = true; - } - } - - ~vec_binop_vecvec_node() - { - delete temp_; - delete temp_vec_node_; - } - - inline T value() const - { - if (initialised_) - { - binary_node::branch_[0].first->value(); - binary_node::branch_[1].first->value(); - - T* vec0 = vec0_node_ptr_->vds().data(); - T* vec1 = vec1_node_ptr_->vds().data(); - T* vec2 = vds().data(); - - loop_unroll::details lud(size()); - const T* upper_bound = vec2 + lud.upper_bound; - - while (vec2 < upper_bound) - { -#define exprtk_loop(N) \ -vec2[N] = Operation::process(vec0[N],vec1[N]); \ - - exprtk_loop( 0) exprtk_loop( 1) - exprtk_loop( 2) exprtk_loop( 3) -#ifndef exprtk_disable_superscalar_unroll - exprtk_loop( 4) exprtk_loop( 5) - exprtk_loop( 6) exprtk_loop( 7) - exprtk_loop( 8) exprtk_loop( 9) - exprtk_loop(10) exprtk_loop(11) - exprtk_loop(12) exprtk_loop(13) - exprtk_loop(14) exprtk_loop(15) -#endif - - vec0 += lud.batch_size; - vec1 += lud.batch_size; - vec2 += lud.batch_size; - } - - int i = 0; - - switch (lud.remainder) - { -#define case_stmt(N) \ -case N : { vec2[i] = Operation::process(vec0[i],vec1[i]); ++i; } \ - -#ifndef exprtk_disable_superscalar_unroll - case_stmt(15) case_stmt(14) - case_stmt(13) case_stmt(12) - case_stmt(11) case_stmt(10) - case_stmt( 9) case_stmt( 8) - case_stmt( 7) case_stmt( 6) - case_stmt( 5) case_stmt( 4) -#endif - case_stmt( 3) case_stmt( 2) - case_stmt( 1) - } - -#undef exprtk_loop -#undef case_stmt - - return (vds().data())[0]; - } - else - return std::numeric_limits::quiet_NaN(); + + return std::numeric_limits::quiet_NaN(); + } + + inline typename expression_node::node_type type() const + { + return expression_node::e_strswap; + } + + private: + + swap_genstrings_node(swap_genstrings_node&); + swap_genstrings_node& operator=(swap_genstrings_node&); + + str_base_ptr str0_base_ptr_; + str_base_ptr str1_base_ptr_; + range_ptr str0_range_ptr_; + range_ptr str1_range_ptr_; + bool initialised_; + }; + + template + class stringvar_size_node : public expression_node + { + 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; } - - vector_node_ptr vec() const + } + + ~string_size_node() + { + if (branch_ && branch_deletable_) { - return temp_vec_node_; + delete branch_; + branch_ = 0; } - - vector_node_ptr vec() + } + + inline T value() const + { + T result = std::numeric_limits::quiet_NaN(); + + if (str_base_ptr_) { - return temp_vec_node_; + branch_->value(); + result = T(str_base_ptr_->size()); } - - inline typename expression_node::node_type type() const - { - return expression_node::e_vecvecarith; + + 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; + + 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); } - - std::size_t size() const + + if (is_generally_string_node(binary_node::branch_[1].first)) { - return vds_.size(); - } - - vds_t& vds() - { - return vds_; + 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()); } - - const vds_t& vds() const + + initialised_ = str0_base_ptr_ && + str1_base_ptr_ && + str0_node_ptr_ && + str1_range_ptr_ ; + } + + inline T value() const + { + if (initialised_) { - return vds_; + 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(); + } } - - private: - - vector_node_ptr vec0_node_ptr_; - vector_node_ptr vec1_node_ptr_; - vector_holder_ptr temp_; - vector_node_ptr temp_vec_node_; - bool initialised_; - vds_t vds_; - }; - - template - class vec_binop_vecval_node : public binary_node , - public vector_interface - { - public: - - typedef expression_node* expression_ptr; - typedef vector_node* vector_node_ptr; - typedef vector_holder* vector_holder_ptr; - typedef vec_data_store vds_t; - - vec_binop_vecval_node(const operator_type& opr, - expression_ptr branch0, - expression_ptr branch1) - : binary_node(opr,branch0,branch1), - vec0_node_ptr_(0), - temp_ (0), - temp_vec_node_(0) - { - bool v0_is_ivec = false; - - if (is_vector_node(binary_node::branch_[0].first)) - { - vec0_node_ptr_ = static_cast(binary_node::branch_[0].first); - } - else if (is_ivector_node(binary_node::branch_[0].first)) - { - vector_interface* vi = reinterpret_cast*>(0); - - if (0 != (vi = dynamic_cast*>(binary_node::branch_[0].first))) - { - vec0_node_ptr_ = vi->vec(); - v0_is_ivec = true; - } - } - - if (vec0_node_ptr_) - { - if (v0_is_ivec) - vds() = vec0_node_ptr_->vds(); - else - vds() = vds_t(vec0_node_ptr_->size()); - - temp_ = new vector_holder(vds()); - temp_vec_node_ = new vector_node (vds(),temp_); - } - } - - ~vec_binop_vecval_node() - { - delete temp_; - delete temp_vec_node_; - } - - inline T value() const - { - if (vec0_node_ptr_) - { - binary_node::branch_[0].first->value(); - const T v = binary_node::branch_[1].first->value(); - - T* vec0 = vec0_node_ptr_->vds().data(); - T* vec1 = vds().data(); - - loop_unroll::details lud(size()); - const T* upper_bound = vec0 + lud.upper_bound; - - while (vec0 < upper_bound) - { -#define exprtk_loop(N) \ -vec1[N] = Operation::process(vec0[N],v); \ - - exprtk_loop( 0) exprtk_loop( 1) - exprtk_loop( 2) exprtk_loop( 3) -#ifndef exprtk_disable_superscalar_unroll - exprtk_loop( 4) exprtk_loop( 5) - exprtk_loop( 6) exprtk_loop( 7) - exprtk_loop( 8) exprtk_loop( 9) - exprtk_loop(10) exprtk_loop(11) - exprtk_loop(12) exprtk_loop(13) - exprtk_loop(14) exprtk_loop(15) -#endif - - vec0 += lud.batch_size; - vec1 += lud.batch_size; - } - - int i = 0; - - switch (lud.remainder) - { -#define case_stmt(N) \ -case N : { vec1[i] = Operation::process(vec0[i],v); ++i; } \ - -#ifndef exprtk_disable_superscalar_unroll - case_stmt(15) case_stmt(14) - case_stmt(13) case_stmt(12) - case_stmt(11) case_stmt(10) - case_stmt( 9) case_stmt( 8) - case_stmt( 7) case_stmt( 6) - case_stmt( 5) case_stmt( 4) -#endif - case_stmt( 3) case_stmt( 2) - case_stmt( 1) - } - -#undef exprtk_loop -#undef case_stmt - - return (vds().data())[0]; - } - else - return std::numeric_limits::quiet_NaN(); + + 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; + + 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()); } - - vector_node_ptr vec() const + + if (is_generally_string_node(binary_node::branch_[1].first)) { - return temp_vec_node_; + 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()); } - - vector_node_ptr vec() + + initialised_ = str0_base_ptr_ && + str1_base_ptr_ && + str0_node_ptr_ && + str0_range_ptr_ && + str1_range_ptr_ ; + } + + inline T value() const + { + if (initialised_) { - return temp_vec_node_; + 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)); + } } - - inline typename expression_node::node_type type() const + + 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_; + }; + + template + class conditional_string_node : public trinary_node , + public string_base_node, + public range_interface + { + 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; + + conditional_string_node(expression_ptr test, + expression_ptr consequent, + expression_ptr alternative) + : trinary_node(details::e_default,consequent,alternative,test), + initialised_(false), + str0_base_ptr_ (0), + str1_base_ptr_ (0), + str0_range_ptr_(0), + str1_range_ptr_(0), + test_ (test), + consequent_ (consequent), + alternative_(alternative) + { + range_.n0_c = std::make_pair(true,0); + range_.n1_c = std::make_pair(true,0); + + range_.cache.first = range_.n0_c.second; + range_.cache.second = range_.n1_c.second; + + if (is_generally_string_node(trinary_node::branch_[0].first)) { - return expression_node::e_vecvalarith; + str0_base_ptr_ = dynamic_cast(trinary_node::branch_[0].first); + + if (0 == str0_base_ptr_) + return; + + str0_range_ptr_ = dynamic_cast(trinary_node::branch_[0].first); + + if (0 == str0_range_ptr_) + return; } - - std::size_t size() const + + if (is_generally_string_node(trinary_node::branch_[1].first)) { - return vds().size(); + str1_base_ptr_ = dynamic_cast(trinary_node::branch_[1].first); + + if (0 == str1_base_ptr_) + return; + + str1_range_ptr_ = dynamic_cast(trinary_node::branch_[1].first); + + if (0 == str1_range_ptr_) + return; } - - vds_t& vds() + + initialised_ = str0_base_ptr_ && + str1_base_ptr_ && + str0_range_ptr_ && + str1_range_ptr_ ; + + } + + inline T value() const + { + if (initialised_) { - return vds_; + std::size_t r0 = 0; + std::size_t r1 = 0; + + if (is_true(test_)) + { + consequent_->value(); + + range_t& range = str0_range_ptr_->range_ref(); + + if (range(r0,r1,str0_base_ptr_->size())) + { + const std::size_t size = (r1 - r0) + 1; + + value_.assign(str0_base_ptr_->base() + r0, size); + + range_.n1_c.second = value_.size() - 1; + range_.cache.second = range_.n1_c.second; + + return T(1); + } + } + else + { + alternative_->value(); + + range_t& range = str1_range_ptr_->range_ref(); + + if (range(r0,r1,str1_base_ptr_->size())) + { + const std::size_t size = (r1 - r0) + 1; + + value_.assign(str1_base_ptr_->base() + r0, size); + + range_.n1_c.second = value_.size() - 1; + range_.cache.second = range_.n1_c.second; + + return T(0); + } + } } - - const vds_t& vds() const + + return std::numeric_limits::quiet_NaN(); + } + + std::string str() const + { + return value_; + } + + const char* base() const + { + return &value_[0]; + } + + std::size_t size() const + { + return value_.size(); + } + + range_t& range_ref() + { + return range_; + } + + const range_t& range_ref() const + { + return range_; + } + + inline typename expression_node::node_type type() const + { + return expression_node::e_strcondition; + } + + private: + + bool initialised_; + str_base_ptr str0_base_ptr_; + str_base_ptr str1_base_ptr_; + irange_ptr str0_range_ptr_; + irange_ptr str1_range_ptr_; + mutable range_t range_; + mutable std::string value_; + + expression_ptr test_; + expression_ptr consequent_; + expression_ptr alternative_; + }; + + template + class cons_conditional_str_node : public binary_node , + public string_base_node, + public range_interface + { + 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; + + cons_conditional_str_node(expression_ptr test, + expression_ptr consequent) + : binary_node(details::e_default,consequent,test), + initialised_(false), + str0_base_ptr_ (0), + str0_range_ptr_(0), + test_ (test), + consequent_(consequent) + { + range_.n0_c = std::make_pair(true,0); + range_.n1_c = std::make_pair(true,0); + + range_.cache.first = range_.n0_c.second; + range_.cache.second = range_.n1_c.second; + + if (is_generally_string_node(binary_node::branch_[0].first)) { - return vds_; - } - - private: - - vector_node_ptr vec0_node_ptr_; - vector_holder_ptr temp_; - vector_node_ptr temp_vec_node_; - vds_t vds_; - }; - - template - class vec_binop_valvec_node : public binary_node , - public vector_interface - { - public: - - typedef expression_node* expression_ptr; - typedef vector_node* vector_node_ptr; - typedef vector_holder* vector_holder_ptr; - typedef vec_data_store vds_t; - - vec_binop_valvec_node(const operator_type& opr, - expression_ptr branch0, - expression_ptr branch1) - : binary_node(opr,branch0,branch1), - vec1_node_ptr_(0), - temp_ (0), - temp_vec_node_(0) - { - bool v1_is_ivec = false; - - if (is_vector_node(binary_node::branch_[1].first)) - { - vec1_node_ptr_ = static_cast(binary_node::branch_[1].first); - } - else if (is_ivector_node(binary_node::branch_[1].first)) - { - vector_interface* vi = reinterpret_cast*>(0); - - if (0 != (vi = dynamic_cast*>(binary_node::branch_[1].first))) - { - vec1_node_ptr_ = vi->vec(); - v1_is_ivec = true; - } - } - - if (vec1_node_ptr_) - { - if (v1_is_ivec) - vds() = vec1_node_ptr_->vds(); - else - vds() = vds_t(vec1_node_ptr_->size()); - - temp_ = new vector_holder(vds()); - temp_vec_node_ = new vector_node (vds(),temp_); - } - } - - ~vec_binop_valvec_node() - { - delete temp_; - delete temp_vec_node_; - } - - inline T value() const - { - if (vec1_node_ptr_) - { - const T v = binary_node::branch_[0].first->value(); - binary_node::branch_[1].first->value(); - - T* vec0 = vds().data(); - T* vec1 = vec1_node_ptr_->vds().data(); - - loop_unroll::details lud(size()); - const T* upper_bound = vec0 + lud.upper_bound; - - while (vec0 < upper_bound) - { -#define exprtk_loop(N) \ -vec0[N] = Operation::process(v,vec1[N]); \ - - exprtk_loop( 0) exprtk_loop( 1) - exprtk_loop( 2) exprtk_loop( 3) -#ifndef exprtk_disable_superscalar_unroll - exprtk_loop( 4) exprtk_loop( 5) - exprtk_loop( 6) exprtk_loop( 7) - exprtk_loop( 8) exprtk_loop( 9) - exprtk_loop(10) exprtk_loop(11) - exprtk_loop(12) exprtk_loop(13) - exprtk_loop(14) exprtk_loop(15) -#endif - - vec0 += lud.batch_size; - vec1 += lud.batch_size; - } - - int i = 0; - - switch (lud.remainder) - { -#define case_stmt(N) \ -case N : { vec0[i] = Operation::process(v,vec1[i]); ++i; } \ - -#ifndef exprtk_disable_superscalar_unroll - case_stmt(15) case_stmt(14) - case_stmt(13) case_stmt(12) - case_stmt(11) case_stmt(10) - case_stmt( 9) case_stmt( 8) - case_stmt( 7) case_stmt( 6) - case_stmt( 5) case_stmt( 4) -#endif - case_stmt( 3) case_stmt( 2) - case_stmt( 1) - } - -#undef exprtk_loop -#undef case_stmt - - return (vds().data())[0]; - } - else - return std::numeric_limits::quiet_NaN(); + 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; } - - vector_node_ptr vec() const + + initialised_ = str0_base_ptr_ && str0_range_ptr_ ; + } + + inline T value() const + { + if (initialised_) { - return temp_vec_node_; + if (is_true(test_)) + { + consequent_->value(); + + range_t& range = str0_range_ptr_->range_ref(); + + std::size_t r0 = 0; + std::size_t r1 = 0; + + if (range(r0,r1,str0_base_ptr_->size())) + { + const std::size_t size = (r1 - r0) + 1; + + value_.assign(str0_base_ptr_->base() + r0, size); + + range_.n1_c.second = value_.size() - 1; + range_.cache.second = range_.n1_c.second; + + return T(1); + } + } } - - vector_node_ptr vec() + + return std::numeric_limits::quiet_NaN(); + } + + std::string str() const + { + return value_; + } + + const char* base() const + { + return &value_[0]; + } + + std::size_t size() const + { + return value_.size(); + } + + range_t& range_ref() + { + return range_; + } + + const range_t& range_ref() const + { + return range_; + } + + inline typename expression_node::node_type type() const + { + return expression_node::e_strccondition; + } + + private: + + bool initialised_; + str_base_ptr str0_base_ptr_; + irange_ptr str0_range_ptr_; + mutable range_t range_; + mutable std::string value_; + + expression_ptr test_; + expression_ptr consequent_; + }; + + template + class str_vararg_node : public expression_node , + public string_base_node, + public range_interface + { + 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; + + template class Sequence> + str_vararg_node(const Sequence& arg_list) + : final_node_(arg_list.back()), + final_deletable_(branch_deletable(final_node_)), + initialised_(false), + str_base_ptr_ (0), + str_range_ptr_(0) + { + if (0 == final_node_) + return; + else if (!is_generally_string_node(final_node_)) + return; + + str_base_ptr_ = dynamic_cast(final_node_); + + if (0 == str_base_ptr_) + return; + + str_range_ptr_ = dynamic_cast(final_node_); + + if (0 == str_range_ptr_) + return; + + initialised_ = str_base_ptr_ && str_range_ptr_; + + if (arg_list.size() > 1) { - return temp_vec_node_; - } - - inline typename expression_node::node_type type() const + const std::size_t arg_list_size = arg_list.size() - 1; + + arg_list_.resize(arg_list_size); + delete_branch_.resize(arg_list_size); + + for (std::size_t i = 0; i < arg_list_size; ++i) + { + if (arg_list[i]) + { + arg_list_[i] = arg_list[i]; + delete_branch_[i] = static_cast(branch_deletable(arg_list_[i]) ? 1 : 0); + } + else + { + arg_list_.clear(); + delete_branch_.clear(); + return; + } + } + } + } + + ~str_vararg_node() + { + if (final_node_ && final_deletable_) { - return expression_node::e_vecvalarith; + delete final_node_; + final_node_ = 0; } - - std::size_t size() const + + for (std::size_t i = 0; i < arg_list_.size(); ++i) { - return vds().size(); + if (arg_list_[i] && delete_branch_[i]) + { + delete arg_list_[i]; + arg_list_[i] = 0; + } } - - vds_t& vds() + } + + inline T value() const + { + if (!arg_list_.empty()) { - return vds_; + VarArgFunction::process(arg_list_); } - - const vds_t& vds() const + + final_node_->value(); + + return std::numeric_limits::quiet_NaN(); + } + + std::string str() const + { + return str_base_ptr_->str(); + } + + const char* base() const + { + return str_base_ptr_->base(); + } + + std::size_t size() const + { + return str_base_ptr_->size(); + } + + range_t& range_ref() + { + return str_range_ptr_->range_ref(); + } + + const range_t& range_ref() const + { + return str_range_ptr_->range_ref(); + } + + inline typename expression_node::node_type type() const + { + return expression_node::e_stringvararg; + } + + private: + + expression_ptr final_node_; + bool final_deletable_; + bool initialised_; + str_base_ptr str_base_ptr_; + irange_ptr str_range_ptr_; + std::vector arg_list_; + std::vector delete_branch_; + }; + #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)") + define_sfop4(ext60,((x / y) + (z * w)),"(t/t)+(t*t)") + define_sfop4(ext61,(((x * y) * z) / w),"((t*t)*t)/t") + + #undef define_sfop3 + #undef define_sfop4 + + template + class sf3_node : 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) { - return vds_; - } - - private: - - vector_node_ptr vec1_node_ptr_; - vector_holder_ptr temp_; - vector_node_ptr temp_vec_node_; - vds_t vds_; - }; - - template - class unary_vector_node : public unary_node , - public vector_interface - { - public: - - typedef expression_node* expression_ptr; - typedef vector_node* vector_node_ptr; - typedef vector_holder* vector_holder_ptr; - typedef vec_data_store vds_t; - - unary_vector_node(const operator_type& opr, expression_ptr branch0) - : unary_node(opr,branch0), - vec0_node_ptr_(0), - temp_ (0), - temp_vec_node_(0) - { - bool vec0_is_ivec = false; - - if (is_vector_node(unary_node::branch_)) - { - vec0_node_ptr_ = static_cast(unary_node::branch_); - } - else if (is_ivector_node(unary_node::branch_)) - { - vector_interface* vi = reinterpret_cast*>(0); - - if (0 != (vi = dynamic_cast*>(unary_node::branch_))) - { - vec0_node_ptr_ = vi->vec(); - vec0_is_ivec = true; - } - } - - if (vec0_node_ptr_) - { - if (vec0_is_ivec) - vds_ = vec0_node_ptr_->vds(); - else - vds_ = vds_t(vec0_node_ptr_->size()); - - temp_ = new vector_holder(vds()); - temp_vec_node_ = new vector_node (vds(),temp_); - } - } - - ~unary_vector_node() - { - delete temp_; - delete temp_vec_node_; - } - - inline T value() const - { - unary_node::branch_->value(); - - if (vec0_node_ptr_) - { - T* vec0 = vec0_node_ptr_->vds().data(); - T* vec1 = vds().data(); - - loop_unroll::details lud(size()); - const T* upper_bound = vec0 + lud.upper_bound; - - while (vec0 < upper_bound) - { -#define exprtk_loop(N) \ -vec1[N] = Operation::process(vec0[N]); \ - - exprtk_loop( 0) exprtk_loop( 1) - exprtk_loop( 2) exprtk_loop( 3) -#ifndef exprtk_disable_superscalar_unroll - exprtk_loop( 4) exprtk_loop( 5) - exprtk_loop( 6) exprtk_loop( 7) - exprtk_loop( 8) exprtk_loop( 9) - exprtk_loop(10) exprtk_loop(11) - exprtk_loop(12) exprtk_loop(13) - exprtk_loop(14) exprtk_loop(15) -#endif - - vec0 += lud.batch_size; - vec1 += lud.batch_size; - } - - int i = 0; - - switch (lud.remainder) - { -#define case_stmt(N) \ -case N : { vec1[i] = Operation::process(vec0[i]); ++i; } \ - -#ifndef exprtk_disable_superscalar_unroll - case_stmt(15) case_stmt(14) - case_stmt(13) case_stmt(12) - case_stmt(11) case_stmt(10) - case_stmt( 9) case_stmt( 8) - case_stmt( 7) case_stmt( 6) - case_stmt( 5) case_stmt( 4) -#endif - case_stmt( 3) case_stmt( 2) - case_stmt( 1) - } - -#undef exprtk_loop -#undef case_stmt - - return (vds().data())[0]; - } - else - return std::numeric_limits::quiet_NaN(); - } - - vector_node_ptr vec() const + 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) { - return temp_vec_node_; + if (arg_list_[i] && delete_branch_[i]) + { + delete arg_list_[i]; + arg_list_[i] = 0; + } } - - vector_node_ptr vec() + } + + 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) { - return temp_vec_node_; - } - - inline typename expression_node::node_type type() const + 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)) { - return expression_node::e_vecunaryop; + ivec_ptr_ = dynamic_cast*>(v); } - - std::size_t size() const + else + ivec_ptr_ = 0; + } + + ~vectorize_node() + { + if (v_ && v_deletable_) { - return vds().size(); + delete v_; } - - vds_t& vds() + } + + inline T value() const + { + if (ivec_ptr_) { - return vds_; + v_->value(); + return VecFunction::process(ivec_ptr_); } - - const vds_t& vds() const + 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)) { - return vds_; + var_node_ptr_ = static_cast*>(binary_node::branch_[0].first); } - - private: - - vector_node_ptr vec0_node_ptr_; - vector_holder_ptr temp_; - vector_node_ptr temp_vec_node_; - vds_t vds_; - }; - - 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 + } + + inline T value() const + { + if (var_node_ptr_) { - 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); + T& result = var_node_ptr_->ref(); + + result = binary_node::branch_[1].first->value(); + + return result; } - }; - - 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 + 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)) { - 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); + vec_node_ptr_ = static_cast*>(binary_node::branch_[0].first); } - }; - - 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() + } + + inline T value() const + { + if (vec_node_ptr_) { - cleanup_branches::execute(branch_); + T& result = vec_node_ptr_->ref(); + + result = binary_node::branch_[1].first->value(); + + return result; } - - template - bool init_branches(expression_ptr (&b)[NumBranches]) + else + return std::numeric_limits::quiet_NaN(); + } + + private: + + vector_elem_node* vec_node_ptr_; + }; + + template + class assignment_rebasevec_elem_node : public binary_node + { + public: + + typedef expression_node* expression_ptr; + + assignment_rebasevec_elem_node(const operator_type& opr, + expression_ptr branch0, + expression_ptr branch1) + : binary_node(opr,branch0,branch1), + rbvec_node_ptr_(0) + { + if (is_rebasevector_elem_node(binary_node::branch_[0].first)) { - // 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 + rbvec_node_ptr_ = static_cast*>(binary_node::branch_[0].first); } - - inline bool operator <(const function_N_node& fn) const + } + + inline T value() const + { + if (rbvec_node_ptr_) { - return this < (&fn); + T& result = rbvec_node_ptr_->ref(); + + result = binary_node::branch_[1].first->value(); + + return result; } - - inline T value() const + else + return std::numeric_limits::quiet_NaN(); + } + + private: + + rebasevector_elem_node* rbvec_node_ptr_; + }; + + template + class assignment_rebasevec_celem_node : public binary_node + { + public: + + typedef expression_node* expression_ptr; + + assignment_rebasevec_celem_node(const operator_type& opr, + expression_ptr branch0, + expression_ptr branch1) + : binary_node(opr,branch0,branch1), + rbvec_node_ptr_(0) + { + if (is_rebasevector_celem_node(binary_node::branch_[0].first)) { - // 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 + rbvec_node_ptr_ = static_cast*>(binary_node::branch_[0].first); } - - 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 + } + + inline T value() const + { + if (rbvec_node_ptr_) { - static inline T_ execute(ifunction& f, T_ (&v)[3]) - { return f(v[0],v[1],v[2]); } - }; - - template - struct invoke + T& result = rbvec_node_ptr_->ref(); + + result = binary_node::branch_[1].first->value(); + + return result; + } + else + return std::numeric_limits::quiet_NaN(); + } + + private: + + rebasevector_celem_node* rbvec_node_ptr_; + }; + + template + class assignment_vec_node : public binary_node , + public vector_interface + { + public: + + typedef expression_node* expression_ptr; + typedef vector_node* vector_node_ptr; + typedef vec_data_store vds_t; + + assignment_vec_node(const operator_type& opr, + expression_ptr branch0, + expression_ptr branch1) + : binary_node(opr,branch0,branch1), + vec_node_ptr_(0) + { + if (is_vector_node(binary_node::branch_[0].first)) { - static inline T_ execute(ifunction& f, T_ (&v)[2]) - { return f(v[0],v[1]); } - }; - - template - struct invoke + vec_node_ptr_ = static_cast*>(binary_node::branch_[0].first); + vds() = vec_node_ptr_->vds(); + } + } + + inline T value() const + { + if (vec_node_ptr_) { - static inline T_ execute(ifunction& f, T_ (&v)[1]) - { return f(v[0]); } - }; - - inline typename expression_node::node_type type() const + const T v = binary_node::branch_[1].first->value(); + + T* vec = vds().data(); + + loop_unroll::details lud(size()); + const T* upper_bound = vec + lud.upper_bound; + + while (vec < upper_bound) + { + #define exprtk_loop(N) \ + vec[N] = v; \ + + exprtk_loop( 0) exprtk_loop( 1) + exprtk_loop( 2) exprtk_loop( 3) + #ifndef exprtk_disable_superscalar_unroll + exprtk_loop( 4) exprtk_loop( 5) + exprtk_loop( 6) exprtk_loop( 7) + exprtk_loop( 8) exprtk_loop( 9) + exprtk_loop(10) exprtk_loop(11) + exprtk_loop(12) exprtk_loop(13) + exprtk_loop(14) exprtk_loop(15) + #endif + + vec += lud.batch_size; + } + + switch (lud.remainder) + { + #define case_stmt(N) \ + case N : *vec++ = v; \ + + #ifndef exprtk_disable_superscalar_unroll + case_stmt(15) case_stmt(14) + case_stmt(13) case_stmt(12) + case_stmt(11) case_stmt(10) + case_stmt( 9) case_stmt( 8) + case_stmt( 7) case_stmt( 6) + case_stmt( 5) case_stmt( 4) + #endif + case_stmt( 3) case_stmt( 2) + case_stmt( 1) + } + + #undef exprtk_loop + #undef case_stmt + + 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 vds().size(); + } + + vds_t& vds() + { + return vds_; + } + + const vds_t& vds() const + { + return vds_; + } + + private: + + vector_node* vec_node_ptr_; + vds_t vds_; + }; + + template + class assignment_vecvec_node : public binary_node , + public vector_interface + { + public: + + typedef expression_node* expression_ptr; + typedef vector_node* vector_node_ptr; + typedef vec_data_store vds_t; + + assignment_vecvec_node(const operator_type& opr, + expression_ptr branch0, + expression_ptr branch1) + : binary_node(opr,branch0,branch1), + vec0_node_ptr_(0), + vec1_node_ptr_(0), + initialised_(false), + src_is_ivec_(false) + { + if (is_vector_node(binary_node::branch_[0].first)) { - return expression_node::e_function; + vec0_node_ptr_ = static_cast*>(binary_node::branch_[0].first); + vds() = vec0_node_ptr_->vds(); } - - 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 + + if (is_vector_node(binary_node::branch_[1].first)) { - return this < (&fn); + vec1_node_ptr_ = static_cast*>(binary_node::branch_[1].first); + vds_t::match_sizes(vds(),vec1_node_ptr_->vds()); } - - inline T value() const + else if (is_ivector_node(binary_node::branch_[1].first)) { - if (function_) - return (*function_)(); - else - return std::numeric_limits::quiet_NaN(); + vector_interface* vi = reinterpret_cast*>(0); + + if (0 != (vi = dynamic_cast*>(binary_node::branch_[1].first))) + { + vec1_node_ptr_ = vi->vec(); + + if (!vi->side_effect()) + { + vi->vds() = vds(); + src_is_ivec_ = true; + } + else + vds_t::match_sizes(vds(),vi->vds()); + } } - - inline typename expression_node::node_type type() const + + initialised_ = (vec0_node_ptr_ && vec1_node_ptr_); + } + + inline T value() const + { + if (initialised_) { - return expression_node::e_function; + binary_node::branch_[1].first->value(); + + if (src_is_ivec_) + return vec0_node_ptr_->value(); + + T* vec0 = vec0_node_ptr_->vds().data(); + T* vec1 = vec1_node_ptr_->vds().data(); + + loop_unroll::details lud(size()); + const T* upper_bound = vec0 + lud.upper_bound; + + while (vec0 < upper_bound) + { + #define exprtk_loop(N) \ + vec0[N] = vec1[N]; \ + + exprtk_loop( 0) exprtk_loop( 1) + exprtk_loop( 2) exprtk_loop( 3) + #ifndef exprtk_disable_superscalar_unroll + exprtk_loop( 4) exprtk_loop( 5) + exprtk_loop( 6) exprtk_loop( 7) + exprtk_loop( 8) exprtk_loop( 9) + exprtk_loop(10) exprtk_loop(11) + exprtk_loop(12) exprtk_loop(13) + exprtk_loop(14) exprtk_loop(15) + #endif + + vec0 += lud.batch_size; + vec1 += lud.batch_size; + } + + switch (lud.remainder) + { + #define case_stmt(N) \ + case N : *vec0++ = *vec1++; \ + + #ifndef exprtk_disable_superscalar_unroll + case_stmt(15) case_stmt(14) + case_stmt(13) case_stmt(12) + case_stmt(11) case_stmt(10) + case_stmt( 9) case_stmt( 8) + case_stmt( 7) case_stmt( 6) + case_stmt( 5) case_stmt( 4) + #endif + case_stmt( 3) case_stmt( 2) + case_stmt( 1) + } + + #undef exprtk_loop + #undef case_stmt + + return vec0_node_ptr_->value(); } - - 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_node vector_node_t; - typedef variable_node_t* variable_node_ptr_t; - typedef vector_node_t* vector_node_ptr_t; - typedef range_interface range_interface_t; - typedef range_data_type range_data_type_t; - typedef range_pack range_t; - typedef std::pair branch_t; - typedef std::pair void_t; - typedef std::vector tmp_vs_t; - typedef std::vector typestore_list_t; - typedef std::vector range_list_t; - - generic_function_node(const std::vector& arg_list, - GenericFunction* func = (GenericFunction*)(0)) - : function_(func), - arg_list_(arg_list) - {} - - virtual ~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->vds().data(); - 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; - - 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 - { - 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(arg_list,func) - { - range_.n0_c = std::make_pair(true,0); - range_.n1_c = std::make_pair(true,0); - range_.cache.first = range_.n0_c.second; - range_.cache.second = range_.n1_c.second; - } - - inline bool operator <(const string_function_node& fn) const - { - return this < (&fn); - } - - inline T value() const - { - 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_[0]; - } - - 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(arg_list,func), - param_seq_index_(param_seq_index) - {} - - inline T value() const - { - T result = std::numeric_limits::quiet_NaN(); - - if (gen_function_t::function_) - { - if (gen_function_t::populate_value_list()) - { - typedef typename GenericFunction::parameter_list_t parameter_list_t; - - return (*gen_function_t::function_)(param_seq_index_, - parameter_list_t(gen_function_t::typestore_list_)); - } - } - - return 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_; - }; - - class return_exception - {}; - - template - class null_igenfunc - { - public: - - virtual ~null_igenfunc() - {} - - typedef type_store generic_type; - typedef typename generic_type::parameter_list parameter_list_t; - - inline virtual T operator()(parameter_list_t) + 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 vds().size(); + } + + vds_t& vds() + { + return vds_; + } + + const vds_t& vds() const + { + return vds_; + } + + private: + + vector_node* vec0_node_ptr_; + vector_node* vec1_node_ptr_; + bool initialised_; + bool src_is_ivec_; + vds_t vds_; + }; + + 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)) { - return std::numeric_limits::quiet_NaN(); + var_node_ptr_ = static_cast*>(binary_node::branch_[0].first); } - }; - - template - class return_node : public generic_function_node > - { - public: - - typedef null_igenfunc igeneric_function_t; - typedef igeneric_function_t* igeneric_function_ptr; - typedef generic_function_node gen_function_t; - typedef results_context results_context_t; - - return_node(const std::vector& arg_list, - results_context_t& rc) - : gen_function_t (arg_list), - results_context_(&rc) - {} - - inline T value() const + } + + inline T value() const + { + if (var_node_ptr_) { - if ( - (0 != results_context_) && - gen_function_t::populate_value_list() - ) - { - typedef typename type_store::parameter_list parameter_list_t; - - results_context_-> - assign(parameter_list_t(gen_function_t::typestore_list_)); - - throw return_exception(); - } - - return std::numeric_limits::quiet_NaN(); - } - - inline typename expression_node::node_type type() const - { - return expression_node::e_return; - } - - private: - - results_context_t* results_context_; - }; - - template - class return_envelope_node : public expression_node - { - public: - - typedef expression_node* expression_ptr; - typedef results_context results_context_t; - - return_envelope_node(expression_ptr body, results_context_t& rc) - : results_context_(&rc), - return_invoked_ (false), - body_ (body), - body_deletable_ (branch_deletable(body_)) - {} - - ~return_envelope_node() - { - if (body_ && body_deletable_) - { - delete body_; - } - } - - inline T value() const - { - try - { - return_invoked_ = false; - results_context_->clear(); - - return body_->value(); - } - catch(const return_exception&) - { - return_invoked_ = true; - return std::numeric_limits::quiet_NaN(); - } - } - - inline typename expression_node::node_type type() const - { - return expression_node::e_retenv; - } - - inline bool* retinvk_ptr() - { - return &return_invoked_; - } - - private: - - results_context_t* results_context_; - mutable bool return_invoked_; - expression_ptr body_; - bool body_deletable_; - }; - -#define exprtk_define_unary_op(OpName) \ -template \ -struct OpName##_op \ -{ \ -typedef typename functor_t::Type Type; \ -typedef typename expression_node::node_type node_t; \ -\ -static inline T process(Type v) \ -{ \ -return numeric:: OpName (v); \ -} \ -\ -static inline node_t type() \ -{ \ -return expression_node::e_##OpName; \ -} \ -\ -static inline details::operator_type operation() \ -{ \ -return details::e_##OpName; \ -} \ -}; \ - - exprtk_define_unary_op(abs ) - exprtk_define_unary_op(acos ) - exprtk_define_unary_op(acosh) - exprtk_define_unary_op(asin ) - exprtk_define_unary_op(asinh) - exprtk_define_unary_op(atan ) - exprtk_define_unary_op(atanh) - exprtk_define_unary_op(ceil ) - exprtk_define_unary_op(cos ) - exprtk_define_unary_op(cosh ) - exprtk_define_unary_op(cot ) - exprtk_define_unary_op(csc ) - exprtk_define_unary_op(d2g ) - exprtk_define_unary_op(d2r ) - exprtk_define_unary_op(erf ) - exprtk_define_unary_op(erfc ) - exprtk_define_unary_op(exp ) - exprtk_define_unary_op(expm1) - exprtk_define_unary_op(floor) - exprtk_define_unary_op(frac ) - exprtk_define_unary_op(g2d ) - exprtk_define_unary_op(log ) - exprtk_define_unary_op(log10) - exprtk_define_unary_op(log2 ) - exprtk_define_unary_op(log1p) - exprtk_define_unary_op(ncdf ) - exprtk_define_unary_op(neg ) - exprtk_define_unary_op(notl ) - exprtk_define_unary_op(pos ) - exprtk_define_unary_op(r2d ) - exprtk_define_unary_op(round) - exprtk_define_unary_op(sec ) - exprtk_define_unary_op(sgn ) - exprtk_define_unary_op(sin ) - exprtk_define_unary_op(sinc ) - exprtk_define_unary_op(sinh ) - exprtk_define_unary_op(sqrt ) - exprtk_define_unary_op(tan ) - exprtk_define_unary_op(tanh ) - exprtk_define_unary_op(trunc) -#undef exprtk_define_unary_op - - template - struct opr_base - { - typedef typename details::functor_t::Type Type; - typedef typename details::functor_t::RefType RefType; - typedef typename details::functor_t functor_t; - typedef typename functor_t::qfunc_t quaternary_functor_t; - typedef typename functor_t::tfunc_t trinary_functor_t; - typedef typename functor_t::bfunc_t binary_functor_t; - typedef typename functor_t::ufunc_t unary_functor_t; - }; - - template - struct add_op : public opr_base - { - typedef typename opr_base::Type Type; - typedef typename opr_base::RefType RefType; - static inline T process(Type t1, Type t2) { return t1 + t2; } - static inline T process(Type t1, Type t2, Type t3) { return t1 + t2 + t3; } - static inline void assign(RefType t1, Type t2) { t1 += t2; } - static inline typename expression_node::node_type type() { return expression_node::e_add; } - static inline details::operator_type operation() { return details::e_add; } - }; - - template - struct mul_op : public opr_base - { - typedef typename opr_base::Type Type; - typedef typename opr_base::RefType RefType; - static inline T process(Type t1, Type t2) { return t1 * t2; } - static inline T process(Type t1, Type t2, Type t3) { return t1 * t2 * t3; } - static inline void assign(RefType t1, Type t2) { t1 *= t2; } - static inline typename expression_node::node_type type() { return expression_node::e_mul; } - static inline details::operator_type operation() { return details::e_mul; } - }; - - template - struct sub_op : public opr_base - { - typedef typename opr_base::Type Type; - typedef typename opr_base::RefType RefType; - static inline T process(Type t1, Type t2) { return t1 - t2; } - static inline T process(Type t1, Type t2, Type t3) { return t1 - t2 - t3; } - static inline void assign(RefType t1, Type t2) { t1 -= t2; } - static inline typename expression_node::node_type type() { return expression_node::e_sub; } - static inline details::operator_type operation() { return details::e_sub; } - }; - - template - struct div_op : public opr_base - { - typedef typename opr_base::Type Type; - typedef typename opr_base::RefType RefType; - static inline T process(Type t1, Type t2) { return t1 / t2; } - static inline T process(Type t1, Type t2, Type t3) { return t1 / t2 / t3; } - static inline void assign(RefType t1, Type t2) { t1 /= t2; } - static inline typename expression_node::node_type type() { return expression_node::e_div; } - static inline details::operator_type operation() { return details::e_div; } - }; - - template - struct mod_op : public opr_base - { - typedef typename opr_base::Type Type; - typedef typename opr_base::RefType RefType; - static inline T process(Type t1, Type t2) { return numeric::modulus(t1,t2); } - static inline void assign(RefType t1, Type t2) { t1 = numeric::modulus(t1,t2); } - static inline typename expression_node::node_type type() { return expression_node::e_mod; } - static inline details::operator_type operation() { return details::e_mod; } - }; - - template - struct pow_op : public opr_base - { - typedef typename opr_base::Type Type; - typedef typename opr_base::RefType RefType; - static inline T process(Type t1, Type t2) { return numeric::pow(t1,t2); } - static inline void assign(RefType t1, Type t2) { t1 = numeric::pow(t1,t2); } - static inline typename expression_node::node_type type() { return expression_node::e_pow; } - static inline details::operator_type operation() { return details::e_pow; } - }; - - template - struct lt_op : public opr_base - { - typedef typename opr_base::Type Type; - static inline T process(Type t1, Type t2) { return ((t1 < t2) ? T(1) : T(0)); } - static inline T process(const std::string& t1, const std::string& t2) { return ((t1 < t2) ? T(1) : T(0)); } - static inline typename expression_node::node_type type() { return expression_node::e_lt; } - static inline details::operator_type operation() { return details::e_lt; } - }; - - template - struct lte_op : public opr_base - { - typedef typename opr_base::Type Type; - static inline T process(Type t1, Type t2) { return ((t1 <= t2) ? T(1) : T(0)); } - static inline T process(const std::string& t1, const std::string& t2) { return ((t1 <= t2) ? T(1) : T(0)); } - static inline typename expression_node::node_type type() { return expression_node::e_lte; } - static inline details::operator_type operation() { return details::e_lte; } - }; - - template - struct gt_op : public opr_base - { - typedef typename opr_base::Type Type; - static inline T process(Type t1, Type t2) { return ((t1 > t2) ? T(1) : T(0)); } - static inline T process(const std::string& t1, const std::string& t2) { return ((t1 > t2) ? T(1) : T(0)); } - static inline typename expression_node::node_type type() { return expression_node::e_gt; } - static inline details::operator_type operation() { return details::e_gt; } - }; - - template - struct gte_op : public opr_base - { - typedef typename opr_base::Type Type; - static inline T process(Type t1, Type t2) { return ((t1 >= t2) ? T(1) : T(0)); } - static inline T process(const std::string& t1, const std::string& t2) { return ((t1 >= t2) ? T(1) : T(0)); } - static inline typename expression_node::node_type type() { return expression_node::e_gte; } - static inline details::operator_type operation() { return details::e_gte; } - }; - - template - struct eq_op : public opr_base - { - typedef typename opr_base::Type Type; - static inline T process(Type t1, Type t2) { return (std::equal_to()(t1,t2) ? T(1) : T(0)); } - static inline T process(const std::string& t1, const std::string& t2) { return ((t1 == t2) ? T(1) : T(0)); } - static inline typename expression_node::node_type type() { return expression_node::e_eq; } - static inline details::operator_type operation() { return details::e_eq; } - }; - - template - struct equal_op : public opr_base - { - typedef typename opr_base::Type Type; - static inline T process(Type t1, Type t2) { return (numeric::equal(t1,t2) ? 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_equal; } - }; - - template - struct ne_op : public opr_base - { - typedef typename opr_base::Type Type; - static inline T process(Type t1, Type t2) { return (std::not_equal_to()(t1,t2) ? T(1) : T(0)); } - static inline T process(const std::string& t1, const std::string& t2) { return ((t1 != t2) ? T(1) : T(0)); } - static inline typename expression_node::node_type type() { return expression_node::e_ne; } - static inline details::operator_type operation() { return details::e_ne; } - }; - - template - struct and_op : public opr_base - { - typedef typename opr_base::Type Type; - static inline T process(Type t1, Type t2) { return (details::is_true(t1) && details::is_true(t2)) ? T(1) : T(0); } - static inline typename expression_node::node_type type() { return expression_node::e_and; } - static inline details::operator_type operation() { return details::e_and; } - }; - - template - struct nand_op : public opr_base - { - typedef typename opr_base::Type Type; - static inline T process(Type t1, Type t2) { return (details::is_true(t1) && details::is_true(t2)) ? T(0) : T(1); } - static inline typename expression_node::node_type type() { return expression_node::e_nand; } - static inline details::operator_type operation() { return details::e_nand; } - }; - - template - struct or_op : public opr_base - { - typedef typename opr_base::Type Type; - static inline T process(Type t1, Type t2) { return (details::is_true(t1) || details::is_true(t2)) ? T(1) : T(0); } - static inline typename expression_node::node_type type() { return expression_node::e_or; } - static inline details::operator_type operation() { return details::e_or; } - }; - - template - struct nor_op : public opr_base - { - typedef typename opr_base::Type Type; - static inline T process(Type t1, Type t2) { return (details::is_true(t1) || details::is_true(t2)) ? T(0) : T(1); } - static inline typename expression_node::node_type type() { return expression_node::e_nor; } - static inline details::operator_type operation() { return details::e_nor; } - }; - - template - struct xor_op : public opr_base - { - typedef typename opr_base::Type Type; - static inline T process(Type t1, Type t2) { return numeric::xor_opr(t1,t2); } - static inline typename expression_node::node_type type() { return expression_node::e_nor; } - static inline details::operator_type operation() { return details::e_xor; } - }; - - template - struct xnor_op : public opr_base - { - typedef typename opr_base::Type Type; - static inline T process(Type t1, Type t2) { return numeric::xnor_opr(t1,t2); } - static inline typename expression_node::node_type type() { return expression_node::e_nor; } - static inline details::operator_type operation() { return details::e_xnor; } - }; - - template - struct in_op : public opr_base - { - typedef typename opr_base::Type Type; - static inline T process(const T&, const T&) { return std::numeric_limits::quiet_NaN(); } - static inline T process(const std::string& t1, const std::string& t2) { return ((std::string::npos != t2.find(t1)) ? T(1) : T(0)); } - static inline typename expression_node::node_type type() { return expression_node::e_in; } - static inline details::operator_type operation() { return details::e_in; } - }; - - template - struct like_op : public opr_base - { - typedef typename opr_base::Type Type; - static inline T process(const T&, const T&) { return std::numeric_limits::quiet_NaN(); } - static inline T process(const std::string& t1, const std::string& t2) { return (details::wc_match(t2,t1) ? T(1) : T(0)); } - static inline typename expression_node::node_type type() { return expression_node::e_like; } - static inline details::operator_type operation() { return details::e_like; } - }; - - template - struct ilike_op : public opr_base - { - typedef typename opr_base::Type Type; - static inline T process(const T&, const T&) { return std::numeric_limits::quiet_NaN(); } - static inline T process(const std::string& t1, const std::string& t2) { return (details::wc_imatch(t2,t1) ? T(1) : T(0)); } - static inline typename expression_node::node_type type() { return expression_node::e_ilike; } - static inline details::operator_type operation() { return details::e_ilike; } - }; - - template - struct inrange_op : public opr_base - { - typedef typename opr_base::Type Type; - static inline T process(const T& t0, const T& t1, const T& t2) { return ((t0 <= t1) && (t1 <= t2)) ? T(1) : T(0); } - static inline T process(const std::string& t0, const std::string& t1, const std::string& t2) - { - return ((t0 <= t1) && (t1 <= t2)) ? T(1) : T(0); - } - static inline typename expression_node::node_type type() { return expression_node::e_inranges; } - static inline details::operator_type operation() { return details::e_inrange; } - }; - - template - inline T value(details::expression_node* n) - { - return n->value(); - } - - template - inline T value(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; - } - } + T& v = var_node_ptr_->ref(); + v = Operation::process(v,binary_node::branch_[1].first->value()); + + return v; } - - template - static inline T process_1(const Sequence& arg_list) + 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)) { - return value(arg_list[0]); + vec_node_ptr_ = static_cast*>(binary_node::branch_[0].first); } - - template - static inline T process_2(const Sequence& arg_list) + } + + inline T value() const + { + if (vec_node_ptr_) { - return value(arg_list[0]) + value(arg_list[1]); + T& v = vec_node_ptr_->ref(); + v = Operation::process(v,binary_node::branch_[1].first->value()); + + return v; } - - template - static inline T process_3(const Sequence& arg_list) + else + return std::numeric_limits::quiet_NaN(); + } + + private: + + vector_elem_node* vec_node_ptr_; + }; + + template + class assignment_rebasevec_elem_op_node : public binary_node + { + public: + + typedef expression_node* expression_ptr; + + assignment_rebasevec_elem_op_node(const operator_type& opr, + expression_ptr branch0, + expression_ptr branch1) + : binary_node(opr,branch0,branch1), + rbvec_node_ptr_(0) + { + if (is_rebasevector_elem_node(binary_node::branch_[0].first)) { - return value(arg_list[0]) + value(arg_list[1]) + - value(arg_list[2]); + rbvec_node_ptr_ = static_cast*>(binary_node::branch_[0].first); } - - template - static inline T process_4(const Sequence& arg_list) + } + + inline T value() const + { + if (rbvec_node_ptr_) { - return value(arg_list[0]) + value(arg_list[1]) + - value(arg_list[2]) + value(arg_list[3]); + T& v = rbvec_node_ptr_->ref(); + v = Operation::process(v,binary_node::branch_[1].first->value()); + + return v; } - - template - static inline T process_5(const Sequence& arg_list) + else + return std::numeric_limits::quiet_NaN(); + } + + private: + + rebasevector_elem_node* rbvec_node_ptr_; + }; + + template + class assignment_rebasevec_celem_op_node : public binary_node + { + public: + + typedef expression_node* expression_ptr; + + assignment_rebasevec_celem_op_node(const operator_type& opr, + expression_ptr branch0, + expression_ptr branch1) + : binary_node(opr,branch0,branch1), + rbvec_node_ptr_(0) + { + if (is_rebasevector_celem_node(binary_node::branch_[0].first)) { - return value(arg_list[0]) + value(arg_list[1]) + - value(arg_list[2]) + value(arg_list[3]) + - value(arg_list[4]); + rbvec_node_ptr_ = static_cast*>(binary_node::branch_[0].first); } - }; - - 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; - } - } + } + + inline T value() const + { + if (rbvec_node_ptr_) + { + T& v = rbvec_node_ptr_->ref(); + v = Operation::process(v,binary_node::branch_[1].first->value()); + + return v; } - - template - static inline T process_1(const Sequence& arg_list) + else + return std::numeric_limits::quiet_NaN(); + } + + private: + + rebasevector_celem_node* rbvec_node_ptr_; + }; + + template + class assignment_vec_op_node : public binary_node , + public vector_interface + { + public: + + typedef expression_node* expression_ptr; + typedef vector_node* vector_node_ptr; + typedef vec_data_store vds_t; + + assignment_vec_op_node(const operator_type& opr, + expression_ptr branch0, + expression_ptr branch1) + : binary_node(opr,branch0,branch1), + vec_node_ptr_(0) + { + if (is_vector_node(binary_node::branch_[0].first)) { - return value(arg_list[0]); + vec_node_ptr_ = static_cast*>(binary_node::branch_[0].first); + vds() = vec_node_ptr_->vds(); } - - template - static inline T process_2(const Sequence& arg_list) + } + + inline T value() const + { + if (vec_node_ptr_) { - return value(arg_list[0]) * value(arg_list[1]); + const T v = binary_node::branch_[1].first->value(); + + T* vec = vds().data(); + + loop_unroll::details lud(size()); + const T* upper_bound = vec + lud.upper_bound; + + while (vec < upper_bound) + { + #define exprtk_loop(N) \ + Operation::assign(vec[N],v); \ + + exprtk_loop( 0) exprtk_loop( 1) + exprtk_loop( 2) exprtk_loop( 3) + #ifndef exprtk_disable_superscalar_unroll + exprtk_loop( 4) exprtk_loop( 5) + exprtk_loop( 6) exprtk_loop( 7) + exprtk_loop( 8) exprtk_loop( 9) + exprtk_loop(10) exprtk_loop(11) + exprtk_loop(12) exprtk_loop(13) + exprtk_loop(14) exprtk_loop(15) + #endif + + vec += lud.batch_size; + } + + switch (lud.remainder) + { + #define case_stmt(N) \ + case N : Operation::assign(*vec++,v); \ + + #ifndef exprtk_disable_superscalar_unroll + case_stmt(15) case_stmt(14) + case_stmt(13) case_stmt(12) + case_stmt(11) case_stmt(10) + case_stmt( 9) case_stmt( 8) + case_stmt( 7) case_stmt( 6) + case_stmt( 5) case_stmt( 4) + #endif + case_stmt( 3) case_stmt( 2) + case_stmt( 1) + } + + #undef exprtk_loop + #undef case_stmt + + return vec_node_ptr_->value(); } - - template - static inline T process_3(const Sequence& arg_list) + 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 vds().size(); + } + + vds_t& vds() + { + return vds_; + } + + const vds_t& vds() const + { + return vds_; + } + + bool side_effect() const + { + return true; + } + + private: + + vector_node* vec_node_ptr_; + vds_t vds_; + }; + + template + class assignment_vecvec_op_node : public binary_node , + public vector_interface + { + public: + + typedef expression_node* expression_ptr; + typedef vector_node* vector_node_ptr; + typedef vec_data_store vds_t; + + assignment_vecvec_op_node(const operator_type& opr, + expression_ptr branch0, + expression_ptr branch1) + : binary_node(opr,branch0,branch1), + vec0_node_ptr_(0), + vec1_node_ptr_(0), + initialised_(false) + { + if (is_vector_node(binary_node::branch_[0].first)) { - return value(arg_list[0]) * value(arg_list[1]) * - value(arg_list[2]); + vec0_node_ptr_ = static_cast*>(binary_node::branch_[0].first); + vds() = vec0_node_ptr_->vds(); } - - template - static inline T process_4(const Sequence& arg_list) + + if (is_vector_node(binary_node::branch_[1].first)) { - return value(arg_list[0]) * value(arg_list[1]) * - value(arg_list[2]) * value(arg_list[3]); + vec1_node_ptr_ = static_cast*>(binary_node::branch_[1].first); + vec1_node_ptr_->vds() = vds(); } - - template - static inline T process_5(const Sequence& arg_list) + else if (is_ivector_node(binary_node::branch_[1].first)) { - return value(arg_list[0]) * value(arg_list[1]) * - value(arg_list[2]) * value(arg_list[3]) * - value(arg_list[4]); + vector_interface* vi = reinterpret_cast*>(0); + + if (0 != (vi = dynamic_cast*>(binary_node::branch_[1].first))) + { + vec1_node_ptr_ = vi->vec(); + vec1_node_ptr_->vds() = vds(); + } + else + vds_t::match_sizes(vds(),vec1_node_ptr_->vds()); } - }; - - 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) + + initialised_ = (vec0_node_ptr_ && vec1_node_ptr_); + } + + inline T value() const + { + if (initialised_) { - return value(arg_list[0]); + binary_node::branch_[0].first->value(); + binary_node::branch_[1].first->value(); + + T* vec0 = vec0_node_ptr_->vds().data(); + T* vec1 = vec1_node_ptr_->vds().data(); + + loop_unroll::details lud(size()); + const T* upper_bound = vec0 + lud.upper_bound; + + while (vec0 < upper_bound) + { + #define exprtk_loop(N) \ + vec0[N] = Operation::process(vec0[N],vec1[N]); \ + + exprtk_loop( 0) exprtk_loop( 1) + exprtk_loop( 2) exprtk_loop( 3) + #ifndef exprtk_disable_superscalar_unroll + exprtk_loop( 4) exprtk_loop( 5) + exprtk_loop( 6) exprtk_loop( 7) + exprtk_loop( 8) exprtk_loop( 9) + exprtk_loop(10) exprtk_loop(11) + exprtk_loop(12) exprtk_loop(13) + exprtk_loop(14) exprtk_loop(15) + #endif + + vec0 += lud.batch_size; + vec1 += lud.batch_size; + } + + int i = 0; + + switch (lud.remainder) + { + #define case_stmt(N) \ + case N : { vec0[i] = Operation::process(vec0[i],vec1[i]); ++i; } \ + + #ifndef exprtk_disable_superscalar_unroll + case_stmt(15) case_stmt(14) + case_stmt(13) case_stmt(12) + case_stmt(11) case_stmt(10) + case_stmt( 9) case_stmt( 8) + case_stmt( 7) case_stmt( 6) + case_stmt( 5) case_stmt( 4) + #endif + case_stmt( 3) case_stmt( 2) + case_stmt( 1) + } + + #undef exprtk_loop + #undef case_stmt + + return vec0_node_ptr_->value(); } - - template - static inline T process_2(const Sequence& arg_list) + else + return std::numeric_limits::quiet_NaN(); + } + + vector_node_ptr vec() const + { + return vec0_node_ptr_; + } + + vector_node_ptr vec() + { + return vec0_node_ptr_; + } + + inline typename expression_node::node_type type() const + { + return expression_node::e_vecopvecass; + } + + std::size_t size() const + { + return vds().size(); + } + + vds_t& vds() + { + return vds_; + } + + const vds_t& vds() const + { + return vds_; + } + + bool side_effect() const + { + return true; + } + + private: + + vector_node* vec0_node_ptr_; + vector_node* vec1_node_ptr_; + bool initialised_; + vds_t vds_; + }; + + template + class vec_binop_vecvec_node : public binary_node , + public vector_interface + { + public: + + typedef expression_node* expression_ptr; + typedef vector_node* vector_node_ptr; + typedef vector_holder* vector_holder_ptr; + typedef vec_data_store vds_t; + + vec_binop_vecvec_node(const operator_type& opr, + expression_ptr branch0, + expression_ptr branch1) + : binary_node(opr,branch0,branch1), + vec0_node_ptr_(0), + vec1_node_ptr_(0), + temp_ (0), + temp_vec_node_(0), + initialised_(false) + { + bool v0_is_ivec = false; + bool v1_is_ivec = false; + + if (is_vector_node(binary_node::branch_[0].first)) { - return std::max(value(arg_list[0]),value(arg_list[1])); + vec0_node_ptr_ = static_cast(binary_node::branch_[0].first); } - - template - static inline T process_3(const Sequence& arg_list) + else if (is_ivector_node(binary_node::branch_[0].first)) { - return std::max(std::max(value(arg_list[0]),value(arg_list[1])),value(arg_list[2])); + vector_interface* vi = reinterpret_cast*>(0); + + if (0 != (vi = dynamic_cast*>(binary_node::branch_[0].first))) + { + vec0_node_ptr_ = vi->vec(); + v0_is_ivec = true; + } } - - template - static inline T process_4(const Sequence& arg_list) + + if (is_vector_node(binary_node::branch_[1].first)) { - return std::max( - std::max(value(arg_list[0]),value(arg_list[1])), - std::max(value(arg_list[2]),value(arg_list[3]))); + vec1_node_ptr_ = static_cast(binary_node::branch_[1].first); } - - template - static inline T process_5(const Sequence& arg_list) + else if (is_ivector_node(binary_node::branch_[1].first)) { - return std::max( - std::max(std::max(value(arg_list[0]),value(arg_list[1])), - std::max(value(arg_list[2]),value(arg_list[3]))), - value(arg_list[4])); - } - }; - - template - struct vararg_mand_op : public opr_base - { - typedef typename opr_base::Type Type; - - template class Sequence> - static inline T process(const Sequence& arg_list) - { - switch (arg_list.size()) - { - case 1 : return process_1(arg_list); - case 2 : return process_2(arg_list); - case 3 : return process_3(arg_list); - case 4 : return process_4(arg_list); - case 5 : return process_5(arg_list); - default : - { - for (std::size_t i = 0; i < arg_list.size(); ++i) - { - if (std::equal_to()(T(0),value(arg_list[i]))) - return T(0); - } - - return T(1); - } - } - } - - template - static inline T process_1(const Sequence& arg_list) - { - return std::not_equal_to() - (T(0),value(arg_list[0])) ? T(1) : T(0); - } - - template - static inline T process_2(const Sequence& arg_list) - { - return ( - std::not_equal_to()(T(0),value(arg_list[0])) && - std::not_equal_to()(T(0),value(arg_list[1])) - ) ? T(1) : T(0); - } - - template - static inline T process_3(const Sequence& arg_list) - { - return ( - std::not_equal_to()(T(0),value(arg_list[0])) && - std::not_equal_to()(T(0),value(arg_list[1])) && - std::not_equal_to()(T(0),value(arg_list[2])) - ) ? T(1) : T(0); - } - - template - static inline T process_4(const Sequence& arg_list) - { - return ( - std::not_equal_to()(T(0),value(arg_list[0])) && - std::not_equal_to()(T(0),value(arg_list[1])) && - std::not_equal_to()(T(0),value(arg_list[2])) && - std::not_equal_to()(T(0),value(arg_list[3])) - ) ? T(1) : T(0); - } - - template - static inline T process_5(const Sequence& arg_list) - { - return ( - std::not_equal_to()(T(0),value(arg_list[0])) && - std::not_equal_to()(T(0),value(arg_list[1])) && - std::not_equal_to()(T(0),value(arg_list[2])) && - std::not_equal_to()(T(0),value(arg_list[3])) && - std::not_equal_to()(T(0),value(arg_list[4])) - ) ? T(1) : T(0); - } - }; - - template - struct vararg_mor_op : public opr_base - { - typedef typename opr_base::Type Type; - - template class Sequence> - static inline T process(const Sequence& arg_list) - { - switch (arg_list.size()) - { - case 1 : return process_1(arg_list); - case 2 : return process_2(arg_list); - case 3 : return process_3(arg_list); - case 4 : return process_4(arg_list); - case 5 : return process_5(arg_list); - default : - { - for (std::size_t i = 0; i < arg_list.size(); ++i) - { - if (std::not_equal_to()(T(0),value(arg_list[i]))) - return T(1); - } - - return T(0); - } - } - } - - template - static inline T process_1(const Sequence& arg_list) - { - return std::not_equal_to() - (T(0),value(arg_list[0])) ? T(1) : T(0); - } - - template - static inline T process_2(const Sequence& arg_list) - { - return ( - std::not_equal_to()(T(0),value(arg_list[0])) || - std::not_equal_to()(T(0),value(arg_list[1])) - ) ? T(1) : T(0); - } - - template - static inline T process_3(const Sequence& arg_list) - { - return ( - std::not_equal_to()(T(0),value(arg_list[0])) || - std::not_equal_to()(T(0),value(arg_list[1])) || - std::not_equal_to()(T(0),value(arg_list[2])) - ) ? T(1) : T(0); - } - - template - static inline T process_4(const Sequence& arg_list) - { - return ( - std::not_equal_to()(T(0),value(arg_list[0])) || - std::not_equal_to()(T(0),value(arg_list[1])) || - std::not_equal_to()(T(0),value(arg_list[2])) || - std::not_equal_to()(T(0),value(arg_list[3])) - ) ? T(1) : T(0); - } - - template - static inline T process_5(const Sequence& arg_list) - { - return ( - std::not_equal_to()(T(0),value(arg_list[0])) || - std::not_equal_to()(T(0),value(arg_list[1])) || - std::not_equal_to()(T(0),value(arg_list[2])) || - std::not_equal_to()(T(0),value(arg_list[3])) || - std::not_equal_to()(T(0),value(arg_list[4])) - ) ? T(1) : T(0); - } - }; - - template - struct vararg_multi_op : public opr_base - { - typedef typename opr_base::Type Type; - - template class Sequence> - static inline T process(const Sequence& arg_list) - { - switch (arg_list.size()) - { - case 0 : return std::numeric_limits::quiet_NaN(); - case 1 : return process_1(arg_list); - case 2 : return process_2(arg_list); - case 3 : return process_3(arg_list); - case 4 : return process_4(arg_list); - case 5 : return process_5(arg_list); - case 6 : return process_6(arg_list); - case 7 : return process_7(arg_list); - case 8 : return process_8(arg_list); - default : - { - for (std::size_t i = 0; i < (arg_list.size() - 1); ++i) - { - value(arg_list[i]); - } - - return value(arg_list.back()); - } - } - } - - template - static inline T process_1(const Sequence& arg_list) - { - return value(arg_list[0]); - } - - template - static inline T process_2(const Sequence& arg_list) - { - value(arg_list[0]); - return value(arg_list[1]); - } - - template - static inline T process_3(const Sequence& arg_list) - { - value(arg_list[0]); - value(arg_list[1]); - return value(arg_list[2]); - } - - template - static inline T process_4(const Sequence& arg_list) - { - value(arg_list[0]); - value(arg_list[1]); - value(arg_list[2]); - return value(arg_list[3]); - } - - template - static inline T process_5(const Sequence& arg_list) - { - value(arg_list[0]); - value(arg_list[1]); - value(arg_list[2]); - value(arg_list[3]); - return value(arg_list[4]); - } - - template - static inline T process_6(const Sequence& arg_list) - { - value(arg_list[0]); - value(arg_list[1]); - value(arg_list[2]); - value(arg_list[3]); - value(arg_list[4]); - return value(arg_list[5]); - } - - template - static inline T process_7(const Sequence& arg_list) - { - value(arg_list[0]); - value(arg_list[1]); - value(arg_list[2]); - value(arg_list[3]); - value(arg_list[4]); - value(arg_list[5]); - return value(arg_list[6]); - } - - template - static inline T process_8(const Sequence& arg_list) - { - value(arg_list[0]); - value(arg_list[1]); - value(arg_list[2]); - value(arg_list[3]); - value(arg_list[4]); - value(arg_list[5]); - value(arg_list[6]); - return value(arg_list[7]); - } - }; - - template - struct vec_add_op - { - typedef vector_interface* ivector_ptr; - - static inline T process(const ivector_ptr v) - { - const T* vec = v->vec()->vds().data(); - const std::size_t vec_size = v->vec()->vds().size(); - - loop_unroll::details lud(vec_size); - - if (vec_size <= static_cast(lud.batch_size)) - { - T result = T(0); - int i = 0; - - switch (vec_size) - { -#define case_stmt(N) \ -case N : result += vec[i++]; \ - -#ifndef exprtk_disable_superscalar_unroll - case_stmt(16) case_stmt(15) - case_stmt(14) case_stmt(13) - case_stmt(12) case_stmt(11) - case_stmt(10) case_stmt( 9) - case_stmt( 8) case_stmt( 7) - case_stmt( 6) case_stmt( 5) -#endif - case_stmt( 4) case_stmt( 3) - case_stmt( 2) case_stmt( 1) - } - -#undef case_stmt - - return result; - } - - T r[] = { - T(0), T(0), T(0), T(0), T(0), T(0), T(0), T(0), - T(0), T(0), T(0), T(0), T(0), T(0), T(0), T(0) - }; - - const T* upper_bound = vec + lud.upper_bound; - - while (vec < upper_bound) - { -#define exprtk_loop(N) \ -r[N] += vec[N]; \ - - exprtk_loop( 0) exprtk_loop( 1) - exprtk_loop( 2) exprtk_loop( 3) -#ifndef exprtk_disable_superscalar_unroll - exprtk_loop( 4) exprtk_loop( 5) - exprtk_loop( 6) exprtk_loop( 7) - exprtk_loop( 8) exprtk_loop( 9) - exprtk_loop(10) exprtk_loop(11) - exprtk_loop(12) exprtk_loop(13) - exprtk_loop(14) exprtk_loop(15) -#endif - - vec += lud.batch_size; - } - - int i = 0; - - switch (lud.remainder) - { -#define case_stmt(N) \ -case N : r[0] += vec[i++]; \ - -#ifndef exprtk_disable_superscalar_unroll - case_stmt(15) case_stmt(14) - case_stmt(13) case_stmt(12) - case_stmt(11) case_stmt(10) - case_stmt( 9) case_stmt( 8) - case_stmt( 7) case_stmt( 6) - case_stmt( 5) case_stmt( 4) -#endif - case_stmt( 3) case_stmt( 2) - case_stmt( 1) - } - -#undef exprtk_loop -#undef case_stmt - - return (r[ 0] + r[ 1] + r[ 2] + r[ 3]) -#ifndef exprtk_disable_superscalar_unroll - + (r[ 4] + r[ 5] + r[ 6] + r[ 7]) - + (r[ 8] + r[ 9] + r[10] + r[11]) - + (r[12] + r[13] + r[14] + r[15]) -#endif - ; - } - }; - - template - struct vec_mul_op - { - typedef vector_interface* ivector_ptr; - - static inline T process(const ivector_ptr v) - { - const T* vec = v->vec()->vds().data(); - const std::size_t vec_size = v->vec()->vds().size(); - - loop_unroll::details lud(vec_size); - - if (vec_size <= static_cast(lud.batch_size)) - { - T result = T(1); - int i = 0; - - switch (vec_size) - { -#define case_stmt(N) \ -case N : result *= vec[i++]; \ - -#ifndef exprtk_disable_superscalar_unroll - case_stmt(16) case_stmt(15) - case_stmt(14) case_stmt(13) - case_stmt(12) case_stmt(11) - case_stmt(10) case_stmt( 9) - case_stmt( 8) case_stmt( 7) - case_stmt( 6) case_stmt( 5) -#endif - case_stmt( 4) case_stmt( 3) - case_stmt( 2) case_stmt( 1) - } - -#undef case_stmt - - return result; - } - - T r[] = { - T(1), T(1), T(1), T(1), T(1), T(1), T(1), T(1), - T(1), T(1), T(1), T(1), T(1), T(1), T(1), T(1) - }; - - const T* upper_bound = vec + lud.upper_bound; - - while (vec < upper_bound) - { -#define exprtk_loop(N) \ -r[N] *= vec[N]; \ - - exprtk_loop( 0) exprtk_loop( 1) - exprtk_loop( 2) exprtk_loop( 3) -#ifndef exprtk_disable_superscalar_unroll - exprtk_loop( 4) exprtk_loop( 5) - exprtk_loop( 6) exprtk_loop( 7) - exprtk_loop( 8) exprtk_loop( 9) - exprtk_loop(10) exprtk_loop(11) - exprtk_loop(12) exprtk_loop(13) - exprtk_loop(14) exprtk_loop(15) -#endif - - vec += lud.batch_size; - } - - int i = 0; - - switch (lud.remainder) - { -#define case_stmt(N) \ -case N : r[0] *= vec[i++]; \ - -#ifndef exprtk_disable_superscalar_unroll - case_stmt(15) case_stmt(14) - case_stmt(13) case_stmt(12) - case_stmt(11) case_stmt(10) - case_stmt( 9) case_stmt( 8) - case_stmt( 7) case_stmt( 6) - case_stmt( 5) case_stmt( 4) -#endif - case_stmt( 3) case_stmt( 2) - case_stmt( 1) - } - -#undef exprtk_loop -#undef case_stmt - - return (r[ 0] * r[ 1] * r[ 2] * r[ 3]) -#ifndef exprtk_disable_superscalar_unroll - + (r[ 4] * r[ 5] * r[ 6] * r[ 7]) - + (r[ 8] * r[ 9] * r[10] * r[11]) - + (r[12] * r[13] * r[14] * r[15]) -#endif - ; - } - }; - - template - struct vec_avg_op - { - typedef vector_interface* ivector_ptr; - - static inline T process(const ivector_ptr v) - { - const std::size_t vec_size = v->vec()->vds().size(); - - return vec_add_op::process(v) / vec_size; - } - }; - - template - struct vec_min_op - { - typedef vector_interface* ivector_ptr; - - static inline T process(const ivector_ptr v) - { - const T* vec = v->vec()->vds().data(); - const std::size_t vec_size = v->vec()->vds().size(); - - T result = vec[0]; - - for (std::size_t i = 1; i < vec_size; ++i) - { - T v_i = vec[i]; - - if (v_i < result) - result = v_i; - } - - return result; - } - }; - - template - struct vec_max_op - { - typedef vector_interface* ivector_ptr; - - static inline T process(const ivector_ptr v) - { - const T* vec = v->vec()->vds().data(); - const std::size_t vec_size = v->vec()->vds().size(); - - T result = vec[0]; - - for (std::size_t i = 1; i < vec_size; ++i) - { - T v_i = vec[i]; - - if (v_i > result) - result = v_i; - } - - return result; + vector_interface* vi = reinterpret_cast*>(0); + + if (0 != (vi = dynamic_cast*>(binary_node::branch_[1].first))) + { + vec1_node_ptr_ = vi->vec(); + v1_is_ivec = true; + } } - }; - - template - class vov_base_node : public expression_node - { - public: - - virtual ~vov_base_node() - {} - - inline virtual operator_type operation() const + + if (vec0_node_ptr_ && vec1_node_ptr_) { - return details::e_default; + vector_holder& vec0 = vec0_node_ptr_->vec_holder(); + vector_holder& vec1 = vec1_node_ptr_->vec_holder(); + + if (v0_is_ivec && (vec0.size() <= vec1.size())) + vds_ = vds_t(vec0_node_ptr_->vds()); + else if (v1_is_ivec && (vec1.size() <= vec0.size())) + vds_ = vds_t(vec1_node_ptr_->vds()); + else + vds_ = vds_t(std::min(vec0.size(),vec1.size())); + + temp_ = new vector_holder(vds().data(),vds().size()); + temp_vec_node_ = new vector_node (vds(),temp_); + + initialised_ = true; } - - virtual const T& v0() const = 0; - - virtual const T& v1() const = 0; - }; - - template - class cov_base_node : public expression_node - { - public: - - virtual ~cov_base_node() - {} - - inline virtual operator_type operation() const + } + + ~vec_binop_vecvec_node() + { + delete temp_; + delete temp_vec_node_; + } + + inline T value() const + { + if (initialised_) { - return details::e_default; + binary_node::branch_[0].first->value(); + binary_node::branch_[1].first->value(); + + T* vec0 = vec0_node_ptr_->vds().data(); + T* vec1 = vec1_node_ptr_->vds().data(); + T* vec2 = vds().data(); + + loop_unroll::details lud(size()); + const T* upper_bound = vec2 + lud.upper_bound; + + while (vec2 < upper_bound) + { + #define exprtk_loop(N) \ + vec2[N] = Operation::process(vec0[N],vec1[N]); \ + + exprtk_loop( 0) exprtk_loop( 1) + exprtk_loop( 2) exprtk_loop( 3) + #ifndef exprtk_disable_superscalar_unroll + exprtk_loop( 4) exprtk_loop( 5) + exprtk_loop( 6) exprtk_loop( 7) + exprtk_loop( 8) exprtk_loop( 9) + exprtk_loop(10) exprtk_loop(11) + exprtk_loop(12) exprtk_loop(13) + exprtk_loop(14) exprtk_loop(15) + #endif + + vec0 += lud.batch_size; + vec1 += lud.batch_size; + vec2 += lud.batch_size; + } + + int i = 0; + + switch (lud.remainder) + { + #define case_stmt(N) \ + case N : { vec2[i] = Operation::process(vec0[i],vec1[i]); ++i; } \ + + #ifndef exprtk_disable_superscalar_unroll + case_stmt(15) case_stmt(14) + case_stmt(13) case_stmt(12) + case_stmt(11) case_stmt(10) + case_stmt( 9) case_stmt( 8) + case_stmt( 7) case_stmt( 6) + case_stmt( 5) case_stmt( 4) + #endif + case_stmt( 3) case_stmt( 2) + case_stmt( 1) + } + + #undef exprtk_loop + #undef case_stmt + + return (vds().data())[0]; } - - virtual const T c() const = 0; - - virtual const T& v() const = 0; - }; - - template - class voc_base_node : public expression_node - { - public: - - virtual ~voc_base_node() - {} - - inline virtual operator_type operation() const + 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 vds_.size(); + } + + vds_t& vds() + { + return vds_; + } + + const vds_t& vds() const + { + return vds_; + } + + private: + + vector_node_ptr vec0_node_ptr_; + vector_node_ptr vec1_node_ptr_; + vector_holder_ptr temp_; + vector_node_ptr temp_vec_node_; + bool initialised_; + vds_t vds_; + }; + + template + class vec_binop_vecval_node : public binary_node , + public vector_interface + { + public: + + typedef expression_node* expression_ptr; + typedef vector_node* vector_node_ptr; + typedef vector_holder* vector_holder_ptr; + typedef vec_data_store vds_t; + + vec_binop_vecval_node(const operator_type& opr, + expression_ptr branch0, + expression_ptr branch1) + : binary_node(opr,branch0,branch1), + vec0_node_ptr_(0), + temp_ (0), + temp_vec_node_(0) + { + bool v0_is_ivec = false; + + if (is_vector_node(binary_node::branch_[0].first)) { - return details::e_default; + vec0_node_ptr_ = static_cast(binary_node::branch_[0].first); } - - virtual const T c() const = 0; - - virtual const T& v() const = 0; - }; - - template - class vob_base_node : public expression_node - { - public: - - virtual ~vob_base_node() - {} - - virtual const T& v() const = 0; - }; - - template - class bov_base_node : public expression_node - { - public: - - virtual ~bov_base_node() - {} - - virtual const T& v() const = 0; - }; - - template - class cob_base_node : public expression_node - { - public: - - virtual ~cob_base_node() - {} - - inline virtual operator_type operation() const + else if (is_ivector_node(binary_node::branch_[0].first)) { - return details::e_default; + vector_interface* vi = reinterpret_cast*>(0); + + if (0 != (vi = dynamic_cast*>(binary_node::branch_[0].first))) + { + vec0_node_ptr_ = vi->vec(); + v0_is_ivec = true; + } } - - virtual const T c() const = 0; - - virtual void set_c(const T) = 0; - - virtual expression_node* move_branch(const std::size_t& index) = 0; - }; - - template - class boc_base_node : public expression_node - { - public: - - virtual ~boc_base_node() - {} - - inline virtual operator_type operation() const + + if (vec0_node_ptr_) { - return details::e_default; + if (v0_is_ivec) + vds() = vec0_node_ptr_->vds(); + else + vds() = vds_t(vec0_node_ptr_->size()); + + temp_ = new vector_holder(vds()); + temp_vec_node_ = new vector_node (vds(),temp_); } - - virtual const T c() const = 0; - - virtual void set_c(const T) = 0; - - virtual expression_node* move_branch(const std::size_t& index) = 0; - }; - - template - class uv_base_node : public expression_node - { - public: - - virtual ~uv_base_node() - {} - - inline virtual operator_type operation() const + } + + ~vec_binop_vecval_node() + { + delete temp_; + delete temp_vec_node_; + } + + inline T value() const + { + if (vec0_node_ptr_) { - return details::e_default; + binary_node::branch_[0].first->value(); + const T v = binary_node::branch_[1].first->value(); + + T* vec0 = vec0_node_ptr_->vds().data(); + T* vec1 = vds().data(); + + loop_unroll::details lud(size()); + const T* upper_bound = vec0 + lud.upper_bound; + + while (vec0 < upper_bound) + { + #define exprtk_loop(N) \ + vec1[N] = Operation::process(vec0[N],v); \ + + exprtk_loop( 0) exprtk_loop( 1) + exprtk_loop( 2) exprtk_loop( 3) + #ifndef exprtk_disable_superscalar_unroll + exprtk_loop( 4) exprtk_loop( 5) + exprtk_loop( 6) exprtk_loop( 7) + exprtk_loop( 8) exprtk_loop( 9) + exprtk_loop(10) exprtk_loop(11) + exprtk_loop(12) exprtk_loop(13) + exprtk_loop(14) exprtk_loop(15) + #endif + + vec0 += lud.batch_size; + vec1 += lud.batch_size; + } + + int i = 0; + + switch (lud.remainder) + { + #define case_stmt(N) \ + case N : { vec1[i] = Operation::process(vec0[i],v); ++i; } \ + + #ifndef exprtk_disable_superscalar_unroll + case_stmt(15) case_stmt(14) + case_stmt(13) case_stmt(12) + case_stmt(11) case_stmt(10) + case_stmt( 9) case_stmt( 8) + case_stmt( 7) case_stmt( 6) + case_stmt( 5) case_stmt( 4) + #endif + case_stmt( 3) case_stmt( 2) + case_stmt( 1) + } + + #undef exprtk_loop + #undef case_stmt + + return (vds().data())[0]; } - - virtual const T& v() const = 0; - }; - - template - class sos_base_node : public expression_node - { - public: - - virtual ~sos_base_node() - {} - - inline virtual operator_type operation() const + 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 vds().size(); + } + + vds_t& vds() + { + return vds_; + } + + const vds_t& vds() const + { + return vds_; + } + + private: + + vector_node_ptr vec0_node_ptr_; + vector_holder_ptr temp_; + vector_node_ptr temp_vec_node_; + vds_t vds_; + }; + + template + class vec_binop_valvec_node : public binary_node , + public vector_interface + { + public: + + typedef expression_node* expression_ptr; + typedef vector_node* vector_node_ptr; + typedef vector_holder* vector_holder_ptr; + typedef vec_data_store vds_t; + + vec_binop_valvec_node(const operator_type& opr, + expression_ptr branch0, + expression_ptr branch1) + : binary_node(opr,branch0,branch1), + vec1_node_ptr_(0), + temp_ (0), + temp_vec_node_(0) + { + bool v1_is_ivec = false; + + if (is_vector_node(binary_node::branch_[1].first)) { - return details::e_default; + vec1_node_ptr_ = static_cast(binary_node::branch_[1].first); } - }; - - template - class sosos_base_node : public expression_node - { - public: - - virtual ~sosos_base_node() - {} - - inline virtual operator_type operation() const + else if (is_ivector_node(binary_node::branch_[1].first)) { - return details::e_default; + vector_interface* vi = reinterpret_cast*>(0); + + if (0 != (vi = dynamic_cast*>(binary_node::branch_[1].first))) + { + vec1_node_ptr_ = vi->vec(); + v1_is_ivec = true; + } } - }; - - template - class T0oT1oT2_base_node : public expression_node - { - public: - - virtual ~T0oT1oT2_base_node() - {} - - virtual std::string type_id() const = 0; - }; - - template - class T0oT1oT2oT3_base_node : public expression_node - { - public: - - virtual ~T0oT1oT2oT3_base_node() - {} - - virtual std::string type_id() const = 0; - }; - - template - class unary_variable_node : 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 + + if (vec1_node_ptr_) { - return Operation::process(v_); + if (v1_is_ivec) + vds() = vec1_node_ptr_->vds(); + else + vds() = vds_t(vec1_node_ptr_->size()); + + temp_ = new vector_holder(vds()); + temp_vec_node_ = new vector_node (vds(),temp_); } - - inline typename expression_node::node_type type() const + } + + ~vec_binop_valvec_node() + { + delete temp_; + delete temp_vec_node_; + } + + inline T value() const + { + if (vec1_node_ptr_) { - return Operation::type(); + const T v = binary_node::branch_[0].first->value(); + binary_node::branch_[1].first->value(); + + T* vec0 = vds().data(); + T* vec1 = vec1_node_ptr_->vds().data(); + + loop_unroll::details lud(size()); + const T* upper_bound = vec0 + lud.upper_bound; + + while (vec0 < upper_bound) + { + #define exprtk_loop(N) \ + vec0[N] = Operation::process(v,vec1[N]); \ + + exprtk_loop( 0) exprtk_loop( 1) + exprtk_loop( 2) exprtk_loop( 3) + #ifndef exprtk_disable_superscalar_unroll + exprtk_loop( 4) exprtk_loop( 5) + exprtk_loop( 6) exprtk_loop( 7) + exprtk_loop( 8) exprtk_loop( 9) + exprtk_loop(10) exprtk_loop(11) + exprtk_loop(12) exprtk_loop(13) + exprtk_loop(14) exprtk_loop(15) + #endif + + vec0 += lud.batch_size; + vec1 += lud.batch_size; + } + + int i = 0; + + switch (lud.remainder) + { + #define case_stmt(N) \ + case N : { vec0[i] = Operation::process(v,vec1[i]); ++i; } \ + + #ifndef exprtk_disable_superscalar_unroll + case_stmt(15) case_stmt(14) + case_stmt(13) case_stmt(12) + case_stmt(11) case_stmt(10) + case_stmt( 9) case_stmt( 8) + case_stmt( 7) case_stmt( 6) + case_stmt( 5) case_stmt( 4) + #endif + case_stmt( 3) case_stmt( 2) + case_stmt( 1) + } + + #undef exprtk_loop + #undef case_stmt + + return (vds().data())[0]; } - - inline operator_type operation() const + 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 vds().size(); + } + + vds_t& vds() + { + return vds_; + } + + const vds_t& vds() const + { + return vds_; + } + + private: + + vector_node_ptr vec1_node_ptr_; + vector_holder_ptr temp_; + vector_node_ptr temp_vec_node_; + vds_t vds_; + }; + + template + class unary_vector_node : public unary_node , + public vector_interface + { + public: + + typedef expression_node* expression_ptr; + typedef vector_node* vector_node_ptr; + typedef vector_holder* vector_holder_ptr; + typedef vec_data_store vds_t; + + unary_vector_node(const operator_type& opr, expression_ptr branch0) + : unary_node(opr,branch0), + vec0_node_ptr_(0), + temp_ (0), + temp_vec_node_(0) + { + bool vec0_is_ivec = false; + + if (is_vector_node(unary_node::branch_)) { - return Operation::operation(); + vec0_node_ptr_ = static_cast(unary_node::branch_); } - - inline const T& v() const + else if (is_ivector_node(unary_node::branch_)) { - return v_; + vector_interface* vi = reinterpret_cast*>(0); + + if (0 != (vi = dynamic_cast*>(unary_node::branch_))) + { + vec0_node_ptr_ = vi->vec(); + vec0_is_ivec = true; + } } - - 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 + + if (vec0_node_ptr_) { - return f_(u0_(v0_),u1_(v1_)); + if (vec0_is_ivec) + vds_ = vec0_node_ptr_->vds(); + else + vds_ = vds_t(vec0_node_ptr_->size()); + + temp_ = new vector_holder(vds()); + temp_vec_node_ = new vector_node (vds(),temp_); } - - inline typename expression_node::node_type type() const + } + + ~unary_vector_node() + { + delete temp_; + delete temp_vec_node_; + } + + inline T value() const + { + unary_node::branch_->value(); + + if (vec0_node_ptr_) { - return expression_node::e_uvouv; + T* vec0 = vec0_node_ptr_->vds().data(); + T* vec1 = vds().data(); + + loop_unroll::details lud(size()); + const T* upper_bound = vec0 + lud.upper_bound; + + while (vec0 < upper_bound) + { + #define exprtk_loop(N) \ + vec1[N] = Operation::process(vec0[N]); \ + + exprtk_loop( 0) exprtk_loop( 1) + exprtk_loop( 2) exprtk_loop( 3) + #ifndef exprtk_disable_superscalar_unroll + exprtk_loop( 4) exprtk_loop( 5) + exprtk_loop( 6) exprtk_loop( 7) + exprtk_loop( 8) exprtk_loop( 9) + exprtk_loop(10) exprtk_loop(11) + exprtk_loop(12) exprtk_loop(13) + exprtk_loop(14) exprtk_loop(15) + #endif + + vec0 += lud.batch_size; + vec1 += lud.batch_size; + } + + int i = 0; + + switch (lud.remainder) + { + #define case_stmt(N) \ + case N : { vec1[i] = Operation::process(vec0[i]); ++i; } \ + + #ifndef exprtk_disable_superscalar_unroll + case_stmt(15) case_stmt(14) + case_stmt(13) case_stmt(12) + case_stmt(11) case_stmt(10) + case_stmt( 9) case_stmt( 8) + case_stmt( 7) case_stmt( 6) + case_stmt( 5) case_stmt( 4) + #endif + case_stmt( 3) case_stmt( 2) + case_stmt( 1) + } + + #undef exprtk_loop + #undef case_stmt + + return (vds().data())[0]; } - - inline operator_type operation() const + 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 vds().size(); + } + + vds_t& vds() + { + return vds_; + } + + const vds_t& vds() const + { + return vds_; + } + + private: + + vector_node_ptr vec0_node_ptr_; + vector_holder_ptr temp_; + vector_node_ptr temp_vec_node_; + vds_t vds_; + }; + + 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 { - return details::e_default; - } - - inline const T& v0() + 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 { - return v0_; + T v[N]; + evaluate_branches::execute(v,branch_); + return invoke::execute(*function_,v); } - - inline const T& v1() + #ifdef _MSC_VER + #pragma warning(pop) + #endif + } + + template + struct evaluate_branches + { + static inline void execute(T_ (&v)[BranchCount], const branch_t (&b)[BranchCount]) { - return v1_; + for (std::size_t i = 0; i < BranchCount; ++i) + { + v[i] = b[i].first->value(); + } } - - inline ufunc_t u0() + }; + + 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]) { - return u0_; + v[0] = b[0].first->value(); + v[1] = b[1].first->value(); + v[2] = b[2].first->value(); + v[3] = b[3].first->value(); } - - inline ufunc_t u1() + }; + + template + struct evaluate_branches + { + static inline void execute(T_ (&v)[3], const branch_t (&b)[3]) { - return u1_; + v[0] = b[0].first->value(); + v[1] = b[1].first->value(); + v[2] = b[2].first->value(); } - - inline ufunc_t f() + }; + + template + struct evaluate_branches + { + static inline void execute(T_ (&v)[2], const branch_t (&b)[2]) { - return f_; + v[0] = b[0].first->value(); + v[1] = b[1].first->value(); } - - 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() + }; + + template + struct evaluate_branches + { + static inline void execute(T_ (&v)[1], const branch_t (&b)[1]) { - if (branch_ && branch_deletable_) - { - delete branch_; - branch_ = 0; - } + v[0] = b[0].first->value(); } - - 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 + }; + + 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) { - return Operation::operation(); + if (arg_list_[i] && !details::is_variable_node(arg_list_[i])) + { + delete arg_list_[i]; + arg_list_[i] = 0; + } } - - inline expression_node* branch(const std::size_t&) const + } + + inline bool operator <(const vararg_function_node& fn) const + { + return this < (&fn); + } + + inline T value() const + { + if (function_) { - return branch_; + populate_value_list(); + return (*function_)(value_list_); } - - inline void release() + 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) { - branch_deletable_ = false; + value_list_[i] = arg_list_[i]->value(); } - - 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 + } + + VarArgFunction* function_; + std::vector arg_list_; + mutable std::vector value_list_; + }; + + template + class generic_function_node : public expression_node + { + public: + + typedef type_store type_store_t; + typedef expression_node* expression_ptr; + typedef variable_node variable_node_t; + typedef vector_node vector_node_t; + typedef variable_node_t* variable_node_ptr_t; + typedef vector_node_t* vector_node_ptr_t; + typedef range_interface range_interface_t; + typedef range_data_type range_data_type_t; + typedef 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(const std::vector& arg_list, + GenericFunction* func = (GenericFunction*)(0)) + : function_(func), + arg_list_(arg_list) + {} + + virtual ~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) { - static const typename expression_node::node_type result = nodetype_T0oT1::result; - return result; + type_store_t& ts = typestore_list_[i]; + + if (0 == arg_list_[i]) + return false; + else if (is_ivector_node(arg_list_[i])) + { + vector_interface* vi = reinterpret_cast*>(0); + + if (0 == (vi = dynamic_cast*>(arg_list_[i]))) + return false; + + ts.size = vi->size(); + ts.data = vi->vds().data(); + ts.type = type_store_t::e_vector; + } + #ifndef exprtk_disable_string_capabilities + else if (is_generally_string_node(arg_list_[i])) + { + string_base_node* sbn = reinterpret_cast*>(0); + + if (0 == (sbn = dynamic_cast*>(arg_list_[i]))) + return false; + + ts.size = sbn->size(); + ts.data = reinterpret_cast(const_cast(sbn->base())); + ts.type = type_store_t::e_string; + + range_list_[i].data = ts.data; + range_list_[i].size = ts.size; + range_list_[i].type_size = sizeof(char); + range_list_[i].str_node = sbn; + + range_interface_t* ri = reinterpret_cast(0); + + if (0 == (ri = dynamic_cast(arg_list_[i]))) + return false; + + range_t& rp = ri->range_ref(); + + if ( + rp.const_range() && + is_const_string_range_node(arg_list_[i]) + ) + { + ts.size = rp.const_size(); + ts.data = static_cast(ts.data) + rp.n0_c.second; + range_list_[i].range = reinterpret_cast(0); + } + else + range_list_[i].range = &(ri->range_ref()); + } + #endif + else if (is_variable_node(arg_list_[i])) + { + variable_node_ptr_t var = variable_node_ptr_t(0); + + if (0 == (var = dynamic_cast(arg_list_[i]))) + return false; + + ts.size = 1; + ts.data = &var->ref(); + ts.type = type_store_t::e_scalar; + } + else + { + ts.size = 1; + ts.data = reinterpret_cast(&expr_as_vec1_store_[i]); + ts.type = type_store_t::e_scalar; + } + + branch_[i] = std::make_pair(arg_list_[i],branch_deletable(arg_list_[i])); } - - inline operator_type operation() const + + return true; + } + + inline bool operator <(const generic_function_node& fn) const + { + return this < (&fn); + } + + inline T value() const + { + if (function_) { - return e_default; + if (populate_value_list()) + { + typedef typename GenericFunction::parameter_list_t parameter_list_t; + + return (*function_)(parameter_list_t(typestore_list_)); + } } - - inline T value() const + + 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) { - return f_(t0_,t1_); + expr_as_vec1_store_[i] = branch_[i].first->value(); } - - inline T0 t0() const + + for (std::size_t i = 0; i < branch_.size(); ++i) { - return t0_; + 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(); + #ifndef exprtk_disable_string_capabilities + if (ts.type == type_store_t::e_string) + ts.data = const_cast(rdt.str_node->base()) + rp.cache.first; + else + #endif + ts.data = static_cast(rdt.data) + (rp.cache.first * rdt.type_size); + } + else + return false; + } } - - inline T1 t1() const + + return true; + } + + GenericFunction* function_; + mutable typestore_list_t typestore_list_; + + private: + + std::vector arg_list_; + std::vector branch_; + mutable tmp_vs_t expr_as_vec1_store_; + mutable range_list_t range_list_; + }; + + #ifndef exprtk_disable_string_capabilities + template + class string_function_node : public generic_function_node, + public string_base_node, + public range_interface + { + public: + + typedef generic_function_node gen_function_t; + typedef range_pack range_t; + + string_function_node(StringFunction* func, + const std::vector& arg_list) + : gen_function_t(arg_list,func) + { + range_.n0_c = std::make_pair(true,0); + range_.n1_c = std::make_pair(true,0); + range_.cache.first = range_.n0_c.second; + range_.cache.second = range_.n1_c.second; + } + + inline bool operator <(const string_function_node& fn) const + { + return this < (&fn); + } + + inline T value() const + { + T result = std::numeric_limits::quiet_NaN(); + + if (gen_function_t::function_) { - return t1_; + 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; + } } - - inline bfunc_t f() const + + 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_[0]; + } + + 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_; + }; + #endif + + 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(arg_list,func), + param_seq_index_(param_seq_index) + {} + + inline T value() const + { + T result = std::numeric_limits::quiet_NaN(); + + if (gen_function_t::function_) { - return f_; + 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_)); + } } - - 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 + + return result; + } + + inline typename expression_node::node_type type() const + { + return expression_node::e_genfunction; + } + + private: + + std::size_t param_seq_index_; + }; + + #ifndef exprtk_disable_string_capabilities + template + class multimode_strfunction_node : public string_function_node + { + public: + + typedef string_function_node str_function_t; + typedef 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_) { - static const typename expression_node::node_type result = nodetype_T0oT1oT2::result; - return result; + 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; + } } - - inline operator_type operation() const + + return result; + } + + inline typename expression_node::node_type type() const + { + return expression_node::e_strfunction; + } + + private: + + std::size_t param_seq_index_; + }; + #endif + + class return_exception + {}; + + template + class null_igenfunc + { + public: + + virtual ~null_igenfunc() + {} + + typedef type_store generic_type; + typedef typename generic_type::parameter_list parameter_list_t; + + inline virtual T operator()(parameter_list_t) + { + return std::numeric_limits::quiet_NaN(); + } + }; + + #ifndef exprtk_disable_return_statement + template + class return_node : public generic_function_node > + { + public: + + typedef null_igenfunc igeneric_function_t; + typedef igeneric_function_t* igeneric_function_ptr; + typedef generic_function_node gen_function_t; + typedef results_context results_context_t; + + return_node(const std::vector& arg_list, + results_context_t& rc) + : gen_function_t (arg_list), + results_context_(&rc) + {} + + inline T value() const + { + if ( + (0 != results_context_) && + gen_function_t::populate_value_list() + ) { - return e_default; + typedef typename type_store::parameter_list parameter_list_t; + + results_context_-> + assign(parameter_list_t(gen_function_t::typestore_list_)); + + throw return_exception(); } - - inline T value() const + + return std::numeric_limits::quiet_NaN(); + } + + inline typename expression_node::node_type type() const + { + return expression_node::e_return; + } + + private: + + results_context_t* results_context_; + }; + + template + class return_envelope_node : public expression_node + { + public: + + typedef expression_node* expression_ptr; + typedef results_context results_context_t; + + return_envelope_node(expression_ptr body, results_context_t& rc) + : results_context_(&rc), + return_invoked_ (false), + body_ (body), + body_deletable_ (branch_deletable(body_)) + {} + + ~return_envelope_node() + { + if (body_ && body_deletable_) { - return ProcessMode::process(t0_,t1_,t2_,f0_,f1_); + delete body_; } - - inline T0 t0() const + } + + inline T value() const + { + try { - return t0_; + return_invoked_ = false; + results_context_->clear(); + + return body_->value(); } - - inline T1 t1() const + catch(const return_exception&) { - return t1_; + return_invoked_ = true; + return std::numeric_limits::quiet_NaN(); } - - inline T2 t2() const - { - return t2_; + } + + inline typename expression_node::node_type type() const + { + return expression_node::e_retenv; + } + + inline bool* retinvk_ptr() + { + return &return_invoked_; + } + + private: + + results_context_t* results_context_; + mutable bool return_invoked_; + expression_ptr body_; + bool body_deletable_; + }; + #endif + + #define exprtk_define_unary_op(OpName) \ + template \ + struct OpName##_op \ + { \ + typedef typename functor_t::Type Type; \ + typedef typename expression_node::node_type node_t; \ + \ + static inline T process(Type v) \ + { \ + return numeric:: OpName (v); \ + } \ + \ + static inline node_t type() \ + { \ + return expression_node::e_##OpName; \ + } \ + \ + static inline details::operator_type operation() \ + { \ + return details::e_##OpName; \ + } \ + }; \ + + exprtk_define_unary_op(abs ) + exprtk_define_unary_op(acos ) + exprtk_define_unary_op(acosh) + exprtk_define_unary_op(asin ) + exprtk_define_unary_op(asinh) + exprtk_define_unary_op(atan ) + exprtk_define_unary_op(atanh) + exprtk_define_unary_op(ceil ) + exprtk_define_unary_op(cos ) + exprtk_define_unary_op(cosh ) + exprtk_define_unary_op(cot ) + exprtk_define_unary_op(csc ) + exprtk_define_unary_op(d2g ) + exprtk_define_unary_op(d2r ) + exprtk_define_unary_op(erf ) + exprtk_define_unary_op(erfc ) + exprtk_define_unary_op(exp ) + exprtk_define_unary_op(expm1) + exprtk_define_unary_op(floor) + exprtk_define_unary_op(frac ) + exprtk_define_unary_op(g2d ) + exprtk_define_unary_op(log ) + exprtk_define_unary_op(log10) + exprtk_define_unary_op(log2 ) + exprtk_define_unary_op(log1p) + exprtk_define_unary_op(ncdf ) + exprtk_define_unary_op(neg ) + exprtk_define_unary_op(notl ) + exprtk_define_unary_op(pos ) + exprtk_define_unary_op(r2d ) + exprtk_define_unary_op(round) + exprtk_define_unary_op(sec ) + exprtk_define_unary_op(sgn ) + exprtk_define_unary_op(sin ) + exprtk_define_unary_op(sinc ) + exprtk_define_unary_op(sinh ) + exprtk_define_unary_op(sqrt ) + exprtk_define_unary_op(tan ) + exprtk_define_unary_op(tanh ) + exprtk_define_unary_op(trunc) + #undef exprtk_define_unary_op + + template + struct opr_base + { + typedef typename details::functor_t::Type Type; + typedef typename details::functor_t::RefType RefType; + typedef typename details::functor_t functor_t; + typedef typename functor_t::qfunc_t quaternary_functor_t; + typedef typename functor_t::tfunc_t trinary_functor_t; + typedef typename functor_t::bfunc_t binary_functor_t; + typedef typename functor_t::ufunc_t unary_functor_t; + }; + + template + struct add_op : public opr_base + { + typedef typename opr_base::Type Type; + typedef typename opr_base::RefType RefType; + static inline T process(Type t1, Type t2) { return t1 + t2; } + static inline T process(Type t1, Type t2, Type t3) { return t1 + t2 + t3; } + static inline void assign(RefType t1, Type t2) { t1 += t2; } + static inline typename expression_node::node_type type() { return expression_node::e_add; } + static inline details::operator_type operation() { return details::e_add; } + }; + + template + struct mul_op : public opr_base + { + typedef typename opr_base::Type Type; + typedef typename opr_base::RefType RefType; + static inline T process(Type t1, Type t2) { return t1 * t2; } + static inline T process(Type t1, Type t2, Type t3) { return t1 * t2 * t3; } + static inline void assign(RefType t1, Type t2) { t1 *= t2; } + static inline typename expression_node::node_type type() { return expression_node::e_mul; } + static inline details::operator_type operation() { return details::e_mul; } + }; + + template + struct sub_op : public opr_base + { + typedef typename opr_base::Type Type; + typedef typename opr_base::RefType RefType; + static inline T process(Type t1, Type t2) { return t1 - t2; } + static inline T process(Type t1, Type t2, Type t3) { return t1 - t2 - t3; } + static inline void assign(RefType t1, Type t2) { t1 -= t2; } + static inline typename expression_node::node_type type() { return expression_node::e_sub; } + static inline details::operator_type operation() { return details::e_sub; } + }; + + template + struct div_op : public opr_base + { + typedef typename opr_base::Type Type; + typedef typename opr_base::RefType RefType; + static inline T process(Type t1, Type t2) { return t1 / t2; } + static inline T process(Type t1, Type t2, Type t3) { return t1 / t2 / t3; } + static inline void assign(RefType t1, Type t2) { t1 /= t2; } + static inline typename expression_node::node_type type() { return expression_node::e_div; } + static inline details::operator_type operation() { return details::e_div; } + }; + + template + struct mod_op : public opr_base + { + typedef typename opr_base::Type Type; + typedef typename opr_base::RefType RefType; + static inline T process(Type t1, Type t2) { return numeric::modulus(t1,t2); } + static inline void assign(RefType t1, Type t2) { t1 = numeric::modulus(t1,t2); } + static inline typename expression_node::node_type type() { return expression_node::e_mod; } + static inline details::operator_type operation() { return details::e_mod; } + }; + + template + struct pow_op : public opr_base + { + typedef typename opr_base::Type Type; + typedef typename opr_base::RefType RefType; + static inline T process(Type t1, Type t2) { return numeric::pow(t1,t2); } + static inline void assign(RefType t1, Type t2) { t1 = numeric::pow(t1,t2); } + static inline typename expression_node::node_type type() { return expression_node::e_pow; } + static inline details::operator_type operation() { return details::e_pow; } + }; + + template + struct lt_op : public opr_base + { + typedef typename opr_base::Type Type; + static inline T process(Type t1, Type t2) { return ((t1 < t2) ? T(1) : T(0)); } + static inline T process(const std::string& t1, const std::string& t2) { return ((t1 < t2) ? T(1) : T(0)); } + static inline typename expression_node::node_type type() { return expression_node::e_lt; } + static inline details::operator_type operation() { return details::e_lt; } + }; + + template + struct lte_op : public opr_base + { + typedef typename opr_base::Type Type; + static inline T process(Type t1, Type t2) { return ((t1 <= t2) ? T(1) : T(0)); } + static inline T process(const std::string& t1, const std::string& t2) { return ((t1 <= t2) ? T(1) : T(0)); } + static inline typename expression_node::node_type type() { return expression_node::e_lte; } + static inline details::operator_type operation() { return details::e_lte; } + }; + + template + struct gt_op : public opr_base + { + typedef typename opr_base::Type Type; + static inline T process(Type t1, Type t2) { return ((t1 > t2) ? T(1) : T(0)); } + static inline T process(const std::string& t1, const std::string& t2) { return ((t1 > t2) ? T(1) : T(0)); } + static inline typename expression_node::node_type type() { return expression_node::e_gt; } + static inline details::operator_type operation() { return details::e_gt; } + }; + + template + struct gte_op : public opr_base + { + typedef typename opr_base::Type Type; + static inline T process(Type t1, Type t2) { return ((t1 >= t2) ? T(1) : T(0)); } + static inline T process(const std::string& t1, const std::string& t2) { return ((t1 >= t2) ? T(1) : T(0)); } + static inline typename expression_node::node_type type() { return expression_node::e_gte; } + static inline details::operator_type operation() { return details::e_gte; } + }; + + template + struct eq_op : public opr_base + { + typedef typename opr_base::Type Type; + static inline T process(Type t1, Type t2) { return (std::equal_to()(t1,t2) ? T(1) : T(0)); } + static inline T process(const std::string& t1, const std::string& t2) { return ((t1 == t2) ? T(1) : T(0)); } + static inline typename expression_node::node_type type() { return expression_node::e_eq; } + static inline details::operator_type operation() { return details::e_eq; } + }; + + template + struct equal_op : public opr_base + { + typedef typename opr_base::Type Type; + static inline T process(Type t1, Type t2) { return (numeric::equal(t1,t2) ? 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_equal; } + }; + + template + struct ne_op : public opr_base + { + typedef typename opr_base::Type Type; + static inline T process(Type t1, Type t2) { return (std::not_equal_to()(t1,t2) ? T(1) : T(0)); } + static inline T process(const std::string& t1, const std::string& t2) { return ((t1 != t2) ? T(1) : T(0)); } + static inline typename expression_node::node_type type() { return expression_node::e_ne; } + static inline details::operator_type operation() { return details::e_ne; } + }; + + template + struct and_op : public opr_base + { + typedef typename opr_base::Type Type; + static inline T process(Type t1, Type t2) { return (details::is_true(t1) && details::is_true(t2)) ? T(1) : T(0); } + static inline typename expression_node::node_type type() { return expression_node::e_and; } + static inline details::operator_type operation() { return details::e_and; } + }; + + template + struct nand_op : public opr_base + { + typedef typename opr_base::Type Type; + static inline T process(Type t1, Type t2) { return (details::is_true(t1) && details::is_true(t2)) ? T(0) : T(1); } + static inline typename expression_node::node_type type() { return expression_node::e_nand; } + static inline details::operator_type operation() { return details::e_nand; } + }; + + template + struct or_op : public opr_base + { + typedef typename opr_base::Type Type; + static inline T process(Type t1, Type t2) { return (details::is_true(t1) || details::is_true(t2)) ? T(1) : T(0); } + static inline typename expression_node::node_type type() { return expression_node::e_or; } + static inline details::operator_type operation() { return details::e_or; } + }; + + template + struct nor_op : public opr_base + { + typedef typename opr_base::Type Type; + static inline T process(Type t1, Type t2) { return (details::is_true(t1) || details::is_true(t2)) ? T(0) : T(1); } + static inline typename expression_node::node_type type() { return expression_node::e_nor; } + static inline details::operator_type operation() { return details::e_nor; } + }; + + template + struct xor_op : public opr_base + { + typedef typename opr_base::Type Type; + static inline T process(Type t1, Type t2) { return numeric::xor_opr(t1,t2); } + static inline typename expression_node::node_type type() { return expression_node::e_nor; } + static inline details::operator_type operation() { return details::e_xor; } + }; + + template + struct xnor_op : public opr_base + { + typedef typename opr_base::Type Type; + static inline T process(Type t1, Type t2) { return numeric::xnor_opr(t1,t2); } + static inline typename expression_node::node_type type() { return expression_node::e_nor; } + static inline details::operator_type operation() { return details::e_xnor; } + }; + + template + struct in_op : public opr_base + { + typedef typename opr_base::Type Type; + static inline T process(const T&, const T&) { return std::numeric_limits::quiet_NaN(); } + static inline T process(const std::string& t1, const std::string& t2) { return ((std::string::npos != t2.find(t1)) ? T(1) : T(0)); } + static inline typename expression_node::node_type type() { return expression_node::e_in; } + static inline details::operator_type operation() { return details::e_in; } + }; + + template + struct like_op : public opr_base + { + typedef typename opr_base::Type Type; + static inline T process(const T&, const T&) { return std::numeric_limits::quiet_NaN(); } + static inline T process(const std::string& t1, const std::string& t2) { return (details::wc_match(t2,t1) ? T(1) : T(0)); } + static inline typename expression_node::node_type type() { return expression_node::e_like; } + static inline details::operator_type operation() { return details::e_like; } + }; + + template + struct ilike_op : public opr_base + { + typedef typename opr_base::Type Type; + static inline T process(const T&, const T&) { return std::numeric_limits::quiet_NaN(); } + static inline T process(const std::string& t1, const std::string& t2) { return (details::wc_imatch(t2,t1) ? T(1) : T(0)); } + static inline typename expression_node::node_type type() { return expression_node::e_ilike; } + static inline details::operator_type operation() { return details::e_ilike; } + }; + + template + struct inrange_op : public opr_base + { + typedef typename opr_base::Type Type; + static inline T process(const T& t0, const T& t1, const T& t2) { return ((t0 <= t1) && (t1 <= t2)) ? T(1) : T(0); } + static inline T process(const std::string& t0, const std::string& t1, const std::string& t2) + { + return ((t0 <= t1) && (t1 <= t2)) ? T(1) : T(0); + } + static inline typename expression_node::node_type type() { return expression_node::e_inranges; } + static inline details::operator_type operation() { return details::e_inrange; } + }; + + template + inline T value(details::expression_node* n) + { + return n->value(); + } + + template + inline T value(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; + } } - - bfunc_t f0() const - { - return f0_; + } + + 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; + } } - - bfunc_t f1() const - { - return f1_; + } + + 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; + } } - - std::string type_id() const - { - return id(); + } + + 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; + } } - - 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_; + } + + 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); + } } - - inline bfunc_t f1() const - { - return f1_; + } + + 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); + } } - - inline bfunc_t f2() const - { - return f2_; + } + + 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()); + } } - - inline std::string type_id() const + } + + template + static inline T process_1(const Sequence& arg_list) + { + return value(arg_list[0]); + } + + template + static inline T process_2(const Sequence& arg_list) + { + value(arg_list[0]); + return value(arg_list[1]); + } + + template + static inline T process_3(const Sequence& arg_list) + { + value(arg_list[0]); + value(arg_list[1]); + return value(arg_list[2]); + } + + template + static inline T process_4(const Sequence& arg_list) + { + value(arg_list[0]); + value(arg_list[1]); + value(arg_list[2]); + return value(arg_list[3]); + } + + template + static inline T process_5(const Sequence& arg_list) + { + value(arg_list[0]); + value(arg_list[1]); + value(arg_list[2]); + value(arg_list[3]); + return value(arg_list[4]); + } + + template + static inline T process_6(const Sequence& arg_list) + { + value(arg_list[0]); + value(arg_list[1]); + value(arg_list[2]); + value(arg_list[3]); + value(arg_list[4]); + return value(arg_list[5]); + } + + template + static inline T process_7(const Sequence& arg_list) + { + value(arg_list[0]); + value(arg_list[1]); + value(arg_list[2]); + value(arg_list[3]); + value(arg_list[4]); + value(arg_list[5]); + return value(arg_list[6]); + } + + template + static inline T process_8(const Sequence& arg_list) + { + value(arg_list[0]); + value(arg_list[1]); + value(arg_list[2]); + value(arg_list[3]); + value(arg_list[4]); + value(arg_list[5]); + value(arg_list[6]); + return value(arg_list[7]); + } + }; + + template + struct vec_add_op + { + typedef vector_interface* ivector_ptr; + + static inline T process(const ivector_ptr v) + { + const T* vec = v->vec()->vds().data(); + const std::size_t vec_size = v->vec()->vds().size(); + + loop_unroll::details lud(vec_size); + + if (vec_size <= static_cast(lud.batch_size)) { - return id(); + T result = T(0); + int i = 0; + + switch (vec_size) + { + #define case_stmt(N) \ + case N : result += vec[i++]; \ + + #ifndef exprtk_disable_superscalar_unroll + case_stmt(16) case_stmt(15) + case_stmt(14) case_stmt(13) + case_stmt(12) case_stmt(11) + case_stmt(10) case_stmt( 9) + case_stmt( 8) case_stmt( 7) + case_stmt( 6) case_stmt( 5) + #endif + case_stmt( 4) case_stmt( 3) + case_stmt( 2) case_stmt( 1) + } + + #undef case_stmt + + return result; } - - static inline std::string id() + + T r[] = { + T(0), T(0), T(0), T(0), T(0), T(0), T(0), T(0), + T(0), T(0), T(0), T(0), T(0), T(0), T(0), T(0) + }; + + const T* upper_bound = vec + lud.upper_bound; + + while (vec < upper_bound) { - return process_mode_t::template id(); + #define exprtk_loop(N) \ + r[N] += vec[N]; \ + + exprtk_loop( 0) exprtk_loop( 1) + exprtk_loop( 2) exprtk_loop( 3) + #ifndef exprtk_disable_superscalar_unroll + exprtk_loop( 4) exprtk_loop( 5) + exprtk_loop( 6) exprtk_loop( 7) + exprtk_loop( 8) exprtk_loop( 9) + exprtk_loop(10) exprtk_loop(11) + exprtk_loop(12) exprtk_loop(13) + exprtk_loop(14) exprtk_loop(15) + #endif + + vec += lud.batch_size; } - - 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 + + int i = 0; + + switch (lud.remainder) { - static const typename expression_node::node_type result = nodetype_T0oT1oT2::result; - return result; + #define case_stmt(N) \ + case N : r[0] += vec[i++]; \ + + #ifndef exprtk_disable_superscalar_unroll + case_stmt(15) case_stmt(14) + case_stmt(13) case_stmt(12) + case_stmt(11) case_stmt(10) + case_stmt( 9) case_stmt( 8) + case_stmt( 7) case_stmt( 6) + case_stmt( 5) case_stmt( 4) + #endif + case_stmt( 3) case_stmt( 2) + case_stmt( 1) } - - inline operator_type operation() const + + #undef exprtk_loop + #undef case_stmt + + return (r[ 0] + r[ 1] + r[ 2] + r[ 3]) + #ifndef exprtk_disable_superscalar_unroll + + (r[ 4] + r[ 5] + r[ 6] + r[ 7]) + + (r[ 8] + r[ 9] + r[10] + r[11]) + + (r[12] + r[13] + r[14] + r[15]) + #endif + ; + } + }; + + template + struct vec_mul_op + { + typedef vector_interface* ivector_ptr; + + static inline T process(const ivector_ptr v) + { + const T* vec = v->vec()->vds().data(); + const std::size_t vec_size = v->vec()->vds().size(); + + loop_unroll::details lud(vec_size); + + if (vec_size <= static_cast(lud.batch_size)) { - return e_default; + T result = T(1); + int i = 0; + + switch (vec_size) + { + #define case_stmt(N) \ + case N : result *= vec[i++]; \ + + #ifndef exprtk_disable_superscalar_unroll + case_stmt(16) case_stmt(15) + case_stmt(14) case_stmt(13) + case_stmt(12) case_stmt(11) + case_stmt(10) case_stmt( 9) + case_stmt( 8) case_stmt( 7) + case_stmt( 6) case_stmt( 5) + #endif + case_stmt( 4) case_stmt( 3) + case_stmt( 2) case_stmt( 1) + } + + #undef case_stmt + + return result; } - - inline T value() const + + T r[] = { + T(1), T(1), T(1), T(1), T(1), T(1), T(1), T(1), + T(1), T(1), T(1), T(1), T(1), T(1), T(1), T(1) + }; + + const T* upper_bound = vec + lud.upper_bound; + + while (vec < upper_bound) { - return f_(t0_,t1_,t2_); + #define exprtk_loop(N) \ + r[N] *= vec[N]; \ + + exprtk_loop( 0) exprtk_loop( 1) + exprtk_loop( 2) exprtk_loop( 3) + #ifndef exprtk_disable_superscalar_unroll + exprtk_loop( 4) exprtk_loop( 5) + exprtk_loop( 6) exprtk_loop( 7) + exprtk_loop( 8) exprtk_loop( 9) + exprtk_loop(10) exprtk_loop(11) + exprtk_loop(12) exprtk_loop(13) + exprtk_loop(14) exprtk_loop(15) + #endif + + vec += lud.batch_size; } - - inline T0 t0() const + + int i = 0; + + switch (lud.remainder) { - return t0_; + #define case_stmt(N) \ + case N : r[0] *= vec[i++]; \ + + #ifndef exprtk_disable_superscalar_unroll + case_stmt(15) case_stmt(14) + case_stmt(13) case_stmt(12) + case_stmt(11) case_stmt(10) + case_stmt( 9) case_stmt( 8) + case_stmt( 7) case_stmt( 6) + case_stmt( 5) case_stmt( 4) + #endif + case_stmt( 3) case_stmt( 2) + case_stmt( 1) } - - inline T1 t1() const + + #undef exprtk_loop + #undef case_stmt + + return (r[ 0] * r[ 1] * r[ 2] * r[ 3]) + #ifndef exprtk_disable_superscalar_unroll + + (r[ 4] * r[ 5] * r[ 6] * r[ 7]) + + (r[ 8] * r[ 9] * r[10] * r[11]) + + (r[12] * r[13] * r[14] * r[15]) + #endif + ; + } + }; + + template + struct vec_avg_op + { + typedef vector_interface* ivector_ptr; + + static inline T process(const ivector_ptr v) + { + const std::size_t vec_size = v->vec()->vds().size(); + + return vec_add_op::process(v) / vec_size; + } + }; + + template + struct vec_min_op + { + typedef vector_interface* ivector_ptr; + + static inline T process(const ivector_ptr v) + { + const T* vec = v->vec()->vds().data(); + const std::size_t vec_size = v->vec()->vds().size(); + + T result = vec[0]; + + for (std::size_t i = 1; i < vec_size; ++i) { - return t1_; + T v_i = vec[i]; + + if (v_i < result) + result = v_i; } - - inline T2 t2() const + + return result; + } + }; + + template + struct vec_max_op + { + typedef vector_interface* ivector_ptr; + + static inline T process(const ivector_ptr v) + { + const T* vec = v->vec()->vds().data(); + const std::size_t vec_size = v->vec()->vds().size(); + + T result = vec[0]; + + for (std::size_t i = 1; i < vec_size; ++i) { - return t2_; + T v_i = vec[i]; + + if (v_i > result) + result = v_i; } - - tfunc_t f() const + + return result; + } + }; + + template + class vov_base_node : public expression_node + { + public: + + virtual ~vov_base_node() + {} + + inline virtual operator_type operation() const + { + return details::e_default; + } + + virtual const T& v0() const = 0; + + virtual const T& v1() const = 0; + }; + + template + class cov_base_node : public expression_node + { + public: + + virtual ~cov_base_node() + {} + + inline virtual operator_type operation() const + { + return details::e_default; + } + + virtual const T c() const = 0; + + virtual const T& v() const = 0; + }; + + template + class voc_base_node : public expression_node + { + public: + + virtual ~voc_base_node() + {} + + inline virtual operator_type operation() const + { + return details::e_default; + } + + virtual const T c() const = 0; + + virtual const T& v() const = 0; + }; + + template + class vob_base_node : public expression_node + { + public: + + virtual ~vob_base_node() + {} + + virtual const T& v() const = 0; + }; + + template + class bov_base_node : public expression_node + { + public: + + virtual ~bov_base_node() + {} + + virtual const T& v() const = 0; + }; + + template + class cob_base_node : public expression_node + { + public: + + virtual ~cob_base_node() + {} + + inline virtual operator_type operation() const + { + return details::e_default; + } + + virtual const T c() const = 0; + + virtual void set_c(const T) = 0; + + virtual expression_node* move_branch(const std::size_t& index) = 0; + }; + + template + class boc_base_node : public expression_node + { + public: + + virtual ~boc_base_node() + {} + + inline virtual operator_type operation() const + { + return details::e_default; + } + + virtual const T c() const = 0; + + virtual void set_c(const T) = 0; + + virtual expression_node* move_branch(const std::size_t& index) = 0; + }; + + template + class uv_base_node : public expression_node + { + public: + + virtual ~uv_base_node() + {} + + inline virtual operator_type operation() const + { + return details::e_default; + } + + virtual const T& v() const = 0; + }; + + template + class sos_base_node : public expression_node + { + public: + + virtual ~sos_base_node() + {} + + inline virtual operator_type operation() const + { + return details::e_default; + } + }; + + template + class sosos_base_node : public expression_node + { + public: + + virtual ~sosos_base_node() + {} + + inline virtual operator_type operation() const + { + return details::e_default; + } + }; + + template + class T0oT1oT2_base_node : public expression_node + { + public: + + virtual ~T0oT1oT2_base_node() + {} + + virtual std::string type_id() const = 0; + }; + + template + class T0oT1oT2oT3_base_node : public expression_node + { + public: + + virtual ~T0oT1oT2oT3_base_node() + {} + + virtual std::string type_id() const = 0; + }; + + template + class unary_variable_node : 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_) { - return f_; + delete branch_; + branch_ = 0; } - - std::string type_id() const + } + + 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) { - return id(); + // (T0 o0 T1) o1 T2 + return bf1(bf0(t0,t1),t2); } - + + template 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 ~sf3ext_type_node() - {} - - 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_; + static const std::string result = "(" + exprtk_crtype(T0) + "o" + + exprtk_crtype(T1) + ")o(" + + exprtk_crtype(T2) + ")" ; + return result; } - - std::string type_id() const + }; + + struct mode1 + { + static inline T process(const T& t0, const T& t1, const T& t2, const bfunc_t bf0, const bfunc_t bf1) { - return id(); + // T0 o0 (T1 o1 T2) + return bf0(t0,bf1(t1,t2)); } - + + template static inline std::string id() { - return SF3Operation::id(); + static const std::string result = "(" + exprtk_crtype(T0) + ")o(" + + exprtk_crtype(T1) + "o" + + exprtk_crtype(T2) + ")" ; + return result; } - - 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 + }; + }; + + 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) { - static const typename expression_node::node_type result = nodetype_T0oT1oT2oT3::result; - return result; + // (T0 o0 T1) o1 (T2 o2 T3) + return bf1(bf0(t0,t1),bf2(t2,t3)); } - - inline operator_type operation() const + + template + static inline std::string id() { - return e_default; + static const std::string result = "(" + exprtk_crtype(T0) + "o" + + exprtk_crtype(T1) + ")o" + + "(" + exprtk_crtype(T2) + "o" + + exprtk_crtype(T3) + ")" ; + return result; } - - inline T value() const + }; + + 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) { - return f_(t0_,t1_,t2_,t3_); + // (T0 o0 (T1 o1 (T2 o2 T3)) + return bf0(t0,bf1(t1,bf2(t2,t3))); } - - inline T0 t0() const + template + static inline std::string id() { - return t0_; + static const std::string result = "(" + exprtk_crtype(T0) + ")o((" + + exprtk_crtype(T1) + ")o(" + + exprtk_crtype(T2) + "o" + + exprtk_crtype(T3) + "))" ; + return result; } - - inline T1 t1() const + }; + + 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) { - return t1_; + // (T0 o0 ((T1 o1 T2) o2 T3) + return bf0(t0,bf2(bf1(t1,t2),t3)); } - - inline T2 t2() const + + template + static inline std::string id() { - return t2_; + static const std::string result = "(" + exprtk_crtype(T0) + ")o((" + + exprtk_crtype(T1) + "o" + + exprtk_crtype(T2) + ")o(" + + exprtk_crtype(T3) + "))" ; + return result; } - - inline T3 t3() const + }; + + 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) { - return t3_; + // (((T0 o0 T1) o1 T2) o2 T3) + return bf2(bf1(bf0(t0,t1),t2),t3); } - - qfunc_t f() const + + template + static inline std::string id() { - return f_; + static const std::string result = "((" + exprtk_crtype(T0) + "o" + + exprtk_crtype(T1) + ")o(" + + exprtk_crtype(T2) + "))o(" + + exprtk_crtype(T3) + ")"; + return result; } - - std::string type_id() const + }; + + 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) { - return id(); + // ((T0 o0 (T1 o1 T2)) o2 T3 + return bf2(bf0(t0,bf1(t1,t2)),t3); } - + + template static inline std::string id() { - return "sf4"; + static const std::string result = "((" + exprtk_crtype(T0) + ")o(" + + exprtk_crtype(T1) + "o" + + exprtk_crtype(T2) + "))o(" + + exprtk_crtype(T3) + ")" ; + return result; } - - 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 bipow_node : public expression_node - { - public: - - typedef expression_node* expression_ptr; - typedef std::pair branch_t; - typedef PowOp operation_t; - - explicit bipow_node(expression_ptr brnch) - { - init_branches<1>(branch_, brnch); - } - - ~bipow_node() - { - cleanup_branches::execute(branch_); - } - - inline T value() const - { - return PowOp::result(branch_[0].first->value()); - } - - inline typename expression_node::node_type type() const - { - return expression_node::e_ipow; - } - - private: - - bipow_node(const bipow_node&); - bipow_node& operator=(const bipow_node&); - - branch_t branch_[1]; - }; - - 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 - class bipowninv_node : public expression_node - { - public: - - typedef expression_node* expression_ptr; - typedef std::pair branch_t; - typedef PowOp operation_t; - - explicit bipowninv_node(expression_ptr brnch) - { - init_branches<1>(branch_, brnch); - } - - ~bipowninv_node() - { - cleanup_branches::execute(branch_); - } - - inline T value() const - { - return (T(1) / PowOp::result(branch_[0].first->value())); - } - - inline typename expression_node::node_type type() const - { - return expression_node::e_ipowinv; - } - - private: - - bipowninv_node(const bipowninv_node&); - bipowninv_node& operator=(const bipowninv_node&); - - branch_t branch_[1]; - }; - - template - inline bool is_vov_node(const expression_node* node) - { - return (0 != dynamic_cast*>(node)); - } - - template - inline bool is_cov_node(const expression_node* node) - { - return (0 != dynamic_cast*>(node)); - } - - template - inline bool is_voc_node(const expression_node* node) - { - return (0 != dynamic_cast*>(node)); - } - - template - inline bool is_cob_node(const expression_node* node) - { - return (0 != dynamic_cast*>(node)); - } - - template - inline bool is_boc_node(const expression_node* node) - { - return (0 != dynamic_cast*>(node)); - } - - template - inline bool is_t0ot1ot2_node(const expression_node* node) - { - return (0 != dynamic_cast*>(node)); - } - - template - inline bool is_t0ot1ot2ot3_node(const expression_node* node) - { - return (0 != dynamic_cast*>(node)); - } - - template - inline bool is_uv_node(const expression_node* node) - { - return (0 != dynamic_cast*>(node)); - } - - template - inline bool is_string_node(const expression_node* node) - { - return node && (expression_node::e_stringvar == node->type()); - } - - template - inline bool is_string_range_node(const expression_node* node) - { - return node && (expression_node::e_stringvarrng == node->type()); - } - - template - inline bool is_const_string_node(const expression_node* node) - { - return node && (expression_node::e_stringconst == node->type()); - } - - template - inline bool is_const_string_range_node(const expression_node* node) - { - return node && (expression_node::e_cstringvarrng == node->type()); - } - - template - inline bool is_string_assignment_node(const expression_node* node) - { - return node && (expression_node::e_strass == node->type()); - } - - template - inline bool is_string_concat_node(const expression_node* node) - { - return node && (expression_node::e_strconcat == node->type()); - } - - template - inline bool is_string_function_node(const expression_node* node) - { - return node && (expression_node::e_strfunction == node->type()); - } - - template - inline bool is_string_condition_node(const expression_node* node) - { - return node && (expression_node::e_strcondition == node->type()); - } - - template - inline bool is_string_ccondition_node(const expression_node* node) - { - return node && (expression_node::e_strccondition == node->type()); - } - - template - inline bool is_genricstring_range_node(const expression_node* node) - { - return node && (expression_node::e_strgenrange == node->type()); - } - - template - inline bool is_generally_string_node(const expression_node* node) - { - if (node) - { - switch (node->type()) - { - case expression_node::e_stringvar : - case expression_node::e_stringconst : - case expression_node::e_stringvarrng : - case expression_node::e_cstringvarrng : - case expression_node::e_strgenrange : - case expression_node::e_strass : - case expression_node::e_strconcat : - case expression_node::e_strfunction : - case expression_node::e_strcondition : - case expression_node::e_strccondition : 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 - - class function_traits - { - public: - - function_traits() - : allow_zero_parameters_(false), - has_side_effects_(true), - min_num_args_(0), - max_num_args_(std::numeric_limits::max()) - {} - - inline bool& allow_zero_parameters() - { - return allow_zero_parameters_; - } - - inline bool& has_side_effects() - { - return has_side_effects_; - } - - std::size_t& min_num_args() - { - return min_num_args_; - } - - std::size_t& max_num_args() - { - return max_num_args_; - } - - private: - - bool allow_zero_parameters_; - bool has_side_effects_; - std::size_t min_num_args_; - std::size_t max_num_args_; - }; - - template - void enable_zero_parameters(FunctionType& func) - { - func.allow_zero_parameters() = true; - - if (0 != func.min_num_args()) - { - func.min_num_args() = 0; - } - } - - template - void disable_zero_parameters(FunctionType& func) - { - func.allow_zero_parameters() = false; - } - - template - void enable_has_side_effects(FunctionType& func) - { - func.has_side_effects() = true; - } - - template - void disable_has_side_effects(FunctionType& func) - { - func.has_side_effects() = false; - } - - template - void set_min_num_args(FunctionType& func, const std::size_t& num_args) - { - func.min_num_args() = num_args; - - if ((0 != func.min_num_args()) && func.allow_zero_parameters()) - func.allow_zero_parameters() = false; - } - - template - void set_max_num_args(FunctionType& func, const std::size_t& num_args) - { - func.max_num_args() = num_args; - } - - template - class ifunction : public function_traits - { - public: - - explicit ifunction(const std::size_t& pc) - : param_count(pc) - {} - - virtual ~ifunction() - {} - -#define empty_method_body \ -{ \ -return std::numeric_limits::quiet_NaN(); \ -} \ - - inline virtual T operator()() - empty_method_body - - inline virtual T operator()(const T&) - empty_method_body - - inline virtual T operator()(const T&,const T&) - empty_method_body - - inline virtual T operator()(const T&, const T&, const T&) - empty_method_body - - inline virtual T operator()(const T&, const T&, const T&, const T&) - empty_method_body - - inline virtual T operator()(const T&, const T&, const T&, const T&, const T&) - empty_method_body - - inline virtual T operator()(const T&, const T&, const T&, const T&, const T&, const T&) - empty_method_body - - inline virtual T operator()(const T&, const T&, const T&, const T&, const T&, const T&, const T&) - empty_method_body - - inline virtual T operator()(const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&) - empty_method_body - - inline virtual T operator()(const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&) - empty_method_body - - inline virtual T operator()(const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&) - empty_method_body - - inline virtual T operator()(const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, - const T&) - empty_method_body - - inline virtual T operator()(const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, - const T&, const T&) - empty_method_body - - inline virtual T operator()(const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, - const T&, const T&, const T&) - empty_method_body - - inline virtual T operator()(const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, - const T&, const T&, const T&, const T&) - empty_method_body - - inline virtual T operator()(const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, - const T&, const T&, const T&, const T&, const T&) - empty_method_body - - inline virtual T operator()(const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, - const T&, const T&, const T&, const T&, const T&, const T&) - empty_method_body - - inline virtual T operator()(const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, - const T&, const T&, const T&, const T&, const T&, const T&, const T&) - empty_method_body - - inline virtual T operator()(const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, - const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&) - empty_method_body - - inline virtual T operator()(const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, - const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&) - empty_method_body - - inline virtual T operator()(const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, - const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&) - empty_method_body - -#undef empty_method_body - - std::size_t param_count; - }; - - template - class ivararg_function : public function_traits - { - public: - - virtual ~ivararg_function() - {} - - inline virtual T operator()(const std::vector&) - { - exprtk_debug(("ivararg_function::operator() - Operator has not been overridden.\n")); - return std::numeric_limits::quiet_NaN(); - } - }; - - template - class igeneric_function : public function_traits - { - public: - - enum return_type - { - e_rtrn_scalar = 0, - e_rtrn_string = 1 - }; - - typedef T type; - typedef type_store generic_type; - typedef typename generic_type::parameter_list parameter_list_t; - - igeneric_function(const std::string& param_seq = "", const return_type rtr_type = e_rtrn_scalar) - : parameter_sequence(param_seq), - rtrn_type(rtr_type) - {} - - virtual ~igeneric_function() - {} - -#define igeneric_function_empty_body(N) \ -{ \ -exprtk_debug(("igeneric_function::operator() - Operator has not been overridden. ["#N"]\n")); \ -return std::numeric_limits::quiet_NaN(); \ -} \ - - // f(i_0,i_1,....,i_N) --> Scalar - inline virtual T operator()(parameter_list_t) - igeneric_function_empty_body(1) - - // f(i_0,i_1,....,i_N) --> String - inline virtual T operator()(std::string&, parameter_list_t) - igeneric_function_empty_body(2) - - // f(psi,i_0,i_1,....,i_N) --> Scalar - inline virtual T operator()(const std::size_t&, parameter_list_t) - igeneric_function_empty_body(3) - - // f(psi,i_0,i_1,....,i_N) --> String - inline virtual T operator()(const std::size_t&, std::string&, parameter_list_t) - igeneric_function_empty_body(4) - - std::string parameter_sequence; - return_type rtrn_type; - }; - - template class parser; - template class expression_helper; - - template - class symbol_table - { - public: - - typedef T (*ff1_functor)(T); - typedef T (*ff2_functor)(T,T); - typedef T (*ff3_functor)(T,T,T); - typedef T (*ff4_functor)(T,T,T,T); - typedef T (*ff5_functor)(T,T,T,T,T); - typedef T (*ff6_functor)(T,T,T,T,T,T); - - protected: - - struct freefunc1 : public exprtk::ifunction - { - using exprtk::ifunction::operator(); - - freefunc1(ff1_functor ff) : exprtk::ifunction(1), f(ff) {} - inline T operator()(const T& v0) - { return f(v0); } - ff1_functor f; - }; - - struct freefunc2 : public exprtk::ifunction - { - using exprtk::ifunction::operator(); - - freefunc2(ff2_functor ff) : exprtk::ifunction(2), f(ff) {} - inline T operator()(const T& v0, const T& v1) - { return f(v0,v1); } - ff2_functor f; - }; - - struct freefunc3 : public exprtk::ifunction - { - using exprtk::ifunction::operator(); - - freefunc3(ff3_functor ff) : exprtk::ifunction(3), f(ff) {} - inline T operator()(const T& v0, const T& v1, const T& v2) - { return f(v0,v1,v2); } - ff3_functor f; - }; - - struct freefunc4 : public exprtk::ifunction - { - using exprtk::ifunction::operator(); - - freefunc4(ff4_functor ff) : exprtk::ifunction(4), f(ff) {} - inline T operator()(const T& v0, const T& v1, const T& v2, const T& v3) - { return f(v0,v1,v2,v3); } - ff4_functor f; - }; - - struct freefunc5 : public exprtk::ifunction - { - using exprtk::ifunction::operator(); - - freefunc5(ff5_functor ff) : exprtk::ifunction(5), f(ff) {} - inline T operator()(const T& v0, const T& v1, const T& v2, const T& v3, const T& v4) - { return f(v0,v1,v2,v3,v4); } - ff5_functor f; - }; - - struct freefunc6 : public exprtk::ifunction - { - using exprtk::ifunction::operator(); - - freefunc6(ff6_functor ff) : exprtk::ifunction(6), f(ff) {} - inline T operator()(const T& v0, const T& v1, const T& v2, const T& v3, const T& v4, const T& v5) - { return f(v0,v1,v2,v3,v4,v5); } - ff6_functor f; - }; - - template - struct type_store - { - typedef details::expression_node* expression_ptr; - typedef typename details::variable_node variable_node_t; - typedef ifunction ifunction_t; - typedef ivararg_function ivararg_function_t; - typedef igeneric_function igeneric_function_t; - typedef details::vector_holder vector_t; -#ifndef exprtk_disable_string_capabilities - typedef typename details::stringvar_node stringvar_node_t; -#endif - - typedef Type type_t; - typedef type_t* type_ptr; - typedef std::pair type_pair_t; - typedef std::map type_map_t; - typedef typename type_map_t::iterator tm_itr_t; - typedef typename type_map_t::const_iterator tm_const_itr_t; - - enum { lut_size = 256 }; - - type_map_t map; - std::size_t size; - - type_store() - : size(0) - {} - - 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_vecview - { - static inline std::pair make(exprtk::vector_view& v, const bool is_const = false) - { - return std::make_pair(is_const,new vector_t(v)); - } - }; - - struct tie_stddeq - { - template - static inline std::pair make(std::deque& v, const bool is_const = false) - { - return std::make_pair(is_const,new vector_t(v)); - } - }; - - template - inline bool add(const std::string& symbol_name, T (&v)[v_size], const bool is_const = false) - { - return add_impl >(symbol_name,std::make_pair(v,v_size),is_const); - } - - inline bool add(const std::string& symbol_name, T* v, const std::size_t v_size, const bool is_const = false) - { - return add_impl >(symbol_name,std::make_pair(v,v_size),is_const); - } - - template - inline bool add(const std::string& symbol_name, std::vector& v, const bool is_const = false) - { - return add_impl&>(symbol_name,v,is_const); - } - - inline bool add(const std::string& symbol_name, exprtk::vector_view& v, const bool is_const = false) - { - return add_impl&>(symbol_name,v,is_const); - } - - template - inline bool add(const std::string& symbol_name, std::deque& v, const bool is_const = false) - { - return add_impl&>(symbol_name,v,is_const); - } - - inline bool add(const std::string& symbol_name, RawType& t, const bool is_const = false) - { - struct tie - { - static inline std::pair make(T& t,const bool is_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); - } - }; - - 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 control_block - { - 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]); - } - } - - ~st_data() - { - for (std::size_t i = 0; i < free_function_list_.size(); ++i) - { - delete free_function_list_[i]; - } - } - - inline bool is_reserved_symbol(const std::string& symbol) const - { - return (reserved_symbol_table_.end() != reserved_symbol_table_.find(symbol)); - } - - std::list local_symbol_list_; - std::list local_stringvar_list_; - std::set reserved_symbol_table_; - std::vector*> free_function_list_; - }; - - control_block() - : ref_count(1), - data_(new st_data) - {} - - control_block(st_data* data) - : ref_count(1), - data_(data) - {} - - ~control_block() - { - if (data_ && (0 == ref_count)) - { - delete data_; - data_ = 0; - } - } - - static inline control_block* create() - { - return new control_block; - } - - template - static inline void destroy(control_block*& cntrl_blck, SymTab* sym_tab) - { - if (cntrl_blck) - { - if ( - (0 != cntrl_blck->ref_count) && - (0 == --cntrl_blck->ref_count) - ) - { - if (sym_tab) - sym_tab->clear(); - - delete cntrl_blck; - } - - cntrl_blck = 0; - } - } - - std::size_t ref_count; - st_data* data_; - }; - - public: - - symbol_table() - : control_block_(control_block::create()) - { - clear(); - } - - ~symbol_table() - { - control_block::destroy(control_block_,this); - } - - symbol_table(const symbol_table& st) - { - control_block_ = st.control_block_; - control_block_->ref_count++; - } - - inline symbol_table& operator=(const symbol_table& st) - { - if (this != &st) - { - control_block::destroy(control_block_,reinterpret_cast*>(0)); - - control_block_ = st.control_block_; - control_block_->ref_count++; - } - - return *this; - } - - inline bool operator==(const symbol_table& st) - { - return (this == &st) || (control_block_ == st.control_block_); - } - - inline void clear_variables(const bool delete_node = true) - { - local_data().variable_store.clear(delete_node); - } - - inline void clear_functions() - { - local_data().function_store.clear(); - } - - inline void clear_strings() - { -#ifndef exprtk_disable_string_capabilities - local_data().stringvar_store.clear(); -#endif - } - - inline void clear_vectors() - { - local_data().vector_store.clear(); - } - - inline void clear() - { - 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); - } - - inline bool add_function(const std::string& function_name, generic_function_t& function) - { - if (!valid()) - return false; - else if (!valid_symbol(function_name)) - return false; - else if (symbol_exists(function_name)) - return false; - else if (std::string::npos != function.parameter_sequence.find_first_not_of("STVZ*?|")) - return false; - else if (generic_function_t::e_rtrn_scalar == function.rtrn_type) - return local_data().generic_function_store.add(function_name,function); - else if (generic_function_t::e_rtrn_string == function.rtrn_type) - return local_data().string_function_store.add(function_name, function); - else - return false; - } - - inline bool add_function(const std::string& function_name, ff1_functor function) - { - if (!valid()) - return false; - else if (!valid_symbol(function_name)) - return false; - else if (symbol_exists(function_name)) - return false; - - exprtk::ifunction* ifunc = new freefunc1(function); - - local_data().free_function_list_.push_back(ifunc); - - return add_function(function_name,(*local_data().free_function_list_.back())); - } - - inline bool add_function(const std::string& function_name, ff2_functor function) - { - if (!valid()) - return false; - else if (!valid_symbol(function_name)) - return false; - else if (symbol_exists(function_name)) - return false; - - exprtk::ifunction* ifunc = new freefunc2(function); - - local_data().free_function_list_.push_back(ifunc); - - return add_function(function_name,(*local_data().free_function_list_.back())); - } - - inline bool add_function(const std::string& function_name, ff3_functor function) - { - if (!valid()) - return false; - else if (!valid_symbol(function_name)) - return false; - else if (symbol_exists(function_name)) - return false; - - exprtk::ifunction* ifunc = new freefunc3(function); - - local_data().free_function_list_.push_back(ifunc); - - return add_function(function_name,(*local_data().free_function_list_.back())); - } - - inline bool add_function(const std::string& function_name, ff4_functor function) - { - if (!valid()) - return false; - else if (!valid_symbol(function_name)) - return false; - else if (symbol_exists(function_name)) - return false; - - exprtk::ifunction* ifunc = new freefunc4(function); - - local_data().free_function_list_.push_back(ifunc); - - return add_function(function_name,(*local_data().free_function_list_.back())); - } - - inline bool add_function(const std::string& function_name, ff5_functor function) - { - if (!valid()) - return false; - else if (!valid_symbol(function_name)) - return false; - else if (symbol_exists(function_name)) - return false; - - exprtk::ifunction* ifunc = new freefunc5(function); - - local_data().free_function_list_.push_back(ifunc); - - return add_function(function_name,(*local_data().free_function_list_.back())); - } - - inline bool add_function(const std::string& function_name, ff6_functor function) - { - if (!valid()) - return false; - else if (!valid_symbol(function_name)) - return false; - else if (symbol_exists(function_name)) - return false; - - exprtk::ifunction* ifunc = new freefunc6(function); - - local_data().free_function_list_.push_back(ifunc); - - return add_function(function_name,(*local_data().free_function_list_.back())); - } - - inline bool add_reserved_function(const std::string& function_name, function_t& function) - { - if (!valid()) - return false; - else if (!valid_symbol(function_name,false)) - return false; - else if (symbol_exists(function_name,false)) - return false; - else - return local_data().function_store.add(function_name,function); - } - - inline bool add_reserved_function(const std::string& vararg_function_name, vararg_function_t& vararg_function) - { - if (!valid()) - return false; - else if (!valid_symbol(vararg_function_name,false)) - return false; - else if (symbol_exists(vararg_function_name,false)) - return false; - else - return local_data().vararg_function_store.add(vararg_function_name,vararg_function); - } - - inline bool add_reserved_function(const std::string& function_name, generic_function_t& function) - { - if (!valid()) - return false; - else if (!valid_symbol(function_name,false)) - return false; - else if (symbol_exists(function_name,false)) - return false; - else if (std::string::npos != function.parameter_sequence.find_first_not_of("STV*?|")) - return false; - else if (generic_function_t::e_rtrn_scalar == function.rtrn_type) - return local_data().generic_function_store.add(function_name,function); - else if (generic_function_t::e_rtrn_string == function.rtrn_type) - return local_data().string_function_store.add(function_name, function); - else - 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); - } - - inline bool add_vector(const std::string& vector_name, exprtk::vector_view& v) - { - if (!valid()) - return false; - else if (!valid_symbol(vector_name)) - return false; - else if (symbol_exists(vector_name)) - return false; - else - 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 - inline bool add_package(Package& package) - { - return package.register_package(*this); - } - - template class Sequence> - inline std::size_t get_variable_list(Sequence,Allocator>& vlist) const - { - if (!valid()) - return 0; - else - return local_data().variable_store.get_list(vlist); - } - - template class Sequence> - inline std::size_t get_variable_list(Sequence& vlist) const - { - if (!valid()) - return 0; - else - return local_data().variable_store.get_list(vlist); - } - -#ifndef exprtk_disable_string_capabilities - template class Sequence> - inline std::size_t get_stringvar_list(Sequence,Allocator>& svlist) const - { - if (!valid()) - return 0; - else - return local_data().stringvar_store.get_list(svlist); - } - - template class Sequence> - inline std::size_t get_stringvar_list(Sequence& svlist) const - { - if (!valid()) - return 0; - else - return local_data().stringvar_store.get_list(svlist); - } -#endif - - template class Sequence> - inline std::size_t get_vector_list(Sequence& vlist) const - { - if (!valid()) - return 0; - else - return local_data().vector_store.get_list(vlist); - } - - inline bool symbol_exists(const std::string& symbol_name, const bool check_reserved_symb = true) const - { - /* - Function will return true if symbol_name exists as either a - reserved symbol, variable, stringvar 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 (check_reserved_symb && local_data().is_reserved_symbol(symbol_name)) - return true; - else - return false; - } - - inline bool is_variable(const std::string& variable_name) const - { - if (!valid()) - return false; - else - return local_data().variable_store.symbol_exists(variable_name); - } - -#ifndef exprtk_disable_string_capabilities - inline bool is_stringvar(const std::string& stringvar_name) const - { - if (!valid()) - return false; - else - return local_data().stringvar_store.symbol_exists(stringvar_name); - } - - inline bool is_conststr_stringvar(const std::string& symbol_name) const - { - if (!valid()) - return false; - else if (!valid_symbol(symbol_name)) - return false; - else if (!local_data().stringvar_store.symbol_exists(symbol_name)) - return false; - - return ( - local_data().stringvar_store.symbol_exists(symbol_name) || - local_data().stringvar_store.is_constant (symbol_name) - ); - } -#endif - - inline bool is_function(const std::string& function_name) const - { - if (!valid()) - return false; - else - return local_data().function_store.symbol_exists(function_name); - } - - inline bool is_vararg_function(const std::string& vararg_function_name) const - { - if (!valid()) - return false; - else - return local_data().vararg_function_store.symbol_exists(vararg_function_name); - } - - inline bool is_vector(const std::string& vector_name) const - { - if (!valid()) - return false; - else - return local_data().vector_store.symbol_exists(vector_name); - } - - inline std::string get_variable_name(const expression_ptr& ptr) const - { - return local_data().variable_store.entity_name(ptr); - } - - inline std::string get_vector_name(const vector_holder_ptr& ptr) const - { - return local_data().vector_store.entity_name(ptr); - } - -#ifndef exprtk_disable_string_capabilities - inline std::string get_stringvar_name(const expression_ptr& ptr) const - { - return local_data().stringvar_store.entity_name(ptr); - } - - inline std::string get_conststr_stringvar_name(const expression_ptr& ptr) const - { - return local_data().stringvar_store.entity_name(ptr); - } -#endif - - inline bool valid() const - { - // Symbol table sanity check. - return control_block_ && control_block_->data_; - } - - inline void load_from(const symbol_table& st) - { - { - std::vector name_list; - - st.local_data().function_store.get_list(name_list); - - if (!name_list.empty()) - { - for (std::size_t i = 0; i < name_list.size(); ++i) - { - exprtk::ifunction& ifunc = *st.get_function(name_list[i]); - add_function(name_list[i],ifunc); - } - } - } - - { - std::vector name_list; - - st.local_data().vararg_function_store.get_list(name_list); - - if (!name_list.empty()) - { - for (std::size_t i = 0; i < name_list.size(); ++i) - { - exprtk::ivararg_function& ivafunc = *st.get_vararg_function(name_list[i]); - add_function(name_list[i],ivafunc); - } - } - } - - { - std::vector name_list; - - st.local_data().generic_function_store.get_list(name_list); - - if (!name_list.empty()) - { - for (std::size_t i = 0; i < name_list.size(); ++i) - { - exprtk::igeneric_function& ifunc = *st.get_generic_function(name_list[i]); - add_function(name_list[i],ifunc); - } - } - } - - { - std::vector name_list; - - st.local_data().string_function_store.get_list(name_list); - - if (!name_list.empty()) - { - for (std::size_t i = 0; i < name_list.size(); ++i) - { - exprtk::igeneric_function& ifunc = *st.get_string_function(name_list[i]); - add_function(name_list[i],ifunc); - } - } - } - } - - private: - - inline bool valid_symbol(const std::string& symbol, const bool check_reserved_symb = true) const - { - if (symbol.empty()) - return false; - else if (!details::is_letter(symbol[0])) - return false; - else if (symbol.size() > 1) - { - for (std::size_t i = 1; i < symbol.size(); ++i) - { - if ( - !details::is_letter_or_digit(symbol[i]) && - ('_' != symbol[i]) - ) - { - if (('.' == symbol[i]) && (i < (symbol.size() - 1))) - continue; - else - return false; - } - } - } - - return (check_reserved_symb) ? (!local_data().is_reserved_symbol(symbol)) : true; - } - - inline bool valid_function(const std::string& symbol) const - { - if (symbol.empty()) - return false; - else if (!details::is_letter(symbol[0])) - return false; - else if (symbol.size() > 1) - { - for (std::size_t i = 1; i < symbol.size(); ++i) - { - if ( - !details::is_letter_or_digit(symbol[i]) && - ('_' != symbol[i]) - ) - { - if (('.' == symbol[i]) && (i < (symbol.size() - 1))) - continue; - else - return false; - } - } - } - - return true; - } - - typedef typename control_block::st_data local_data_t; - - inline local_data_t& local_data() - { - return *(control_block_->data_); - } - - inline const local_data_t& local_data() const - { - return *(control_block_->data_); - } - - control_block* control_block_; - - friend class parser; - }; - - template - class function_compositor; - - template - class expression - { - private: - - typedef details::expression_node* expression_ptr; - typedef details::vector_holder* vector_holder_ptr; - typedef std::vector > symtab_list_t; - - struct control_block - { - enum data_type - { - e_unknown , - e_expr , - e_vecholder, - e_data , - e_vecdata , - e_string - }; - - struct data_pack - { - data_pack() - : pointer(0), - type(e_unknown), - size(0) - {} - - data_pack(void* ptr, 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; - typedef results_context results_context_t; - - control_block() - : ref_count(0), - expr (0), - results (0), - retinv_null(false), - return_invoked(&retinv_null) - {} - - control_block(expression_ptr e) - : ref_count(1), - expr (e), - results (0), - retinv_null(false), - return_invoked(&retinv_null) - {} - - ~control_block() - { - if (expr && details::branch_deletable(expr)) - { - delete expr; - expr = reinterpret_cast(0); - } - - 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; - } - } - } - - if (results) - { - delete results; - } - } - - static inline control_block* create(expression_ptr e) - { - return new control_block(e); - } - - static inline void destroy(control_block*& cntrl_blck) - { - if (cntrl_blck) - { - if ( - (0 != cntrl_blck->ref_count) && - (0 == --cntrl_blck->ref_count) - ) - { - delete cntrl_blck; - } - - cntrl_blck = 0; - } - } - - std::size_t ref_count; - expression_ptr expr; - local_data_list_t local_data_list; - results_context_t* results; - bool retinv_null; - bool* return_invoked; - - friend class function_compositor; - }; - - public: - - expression() - : control_block_(0) - { - set_expression(new details::null_node()); - } - - expression(const expression& e) - : control_block_(e.control_block_), - symbol_table_list_(e.symbol_table_list_) - { - control_block_->ref_count++; - } - - inline expression& operator=(const expression& e) - { - if (this != &e) - { - if (control_block_) - { - if ( - (0 != control_block_->ref_count) && - (0 == --control_block_->ref_count) - ) - { - delete control_block_; - } - - control_block_ = 0; - } - - control_block_ = e.control_block_; - control_block_->ref_count++; - symbol_table_list_ = e.symbol_table_list_; - } - - return *this; - } - - inline bool operator==(const expression& e) - { - return (this == &e); - } - - inline bool operator!() const - { - return ( - (0 == control_block_ ) || - (0 == control_block_->expr) - ); - } - - inline expression& release() - { - control_block::destroy(control_block_); - - return *this; - } - - ~expression() - { - control_block::destroy(control_block_); - } - - inline T value() const - { - return control_block_->expr->value(); - } - - inline T operator()() const - { - return value(); - } - - inline operator T() const - { - return value(); - } - - inline operator bool() const - { - return details::is_true(value()); - } - - inline void register_symbol_table(symbol_table& st) - { - symbol_table_list_.push_back(st); - } - - inline const symbol_table& get_symbol_table(const std::size_t& index = 0) const - { - return symbol_table_list_[index]; - } - - inline symbol_table& get_symbol_table(const std::size_t& index = 0) - { - return symbol_table_list_[index]; - } - - typedef results_context results_context_t; - - inline const results_context_t& results() const - { - if (control_block_->results) - return (*control_block_->results); - else - { - static const results_context_t null_results; - return null_results; - } - } - - inline bool return_invoked() const - { - return (*control_block_->return_invoked); - } - - private: - - inline symtab_list_t get_symbol_table_list() const - { - return symbol_table_list_; - } - - inline void set_expression(const expression_ptr expr) - { - if (expr) - { - if (control_block_) - { - if (0 == --control_block_->ref_count) - { - delete control_block_; - } - } - - control_block_ = control_block::create(expr); - } - } - - inline void register_local_var(expression_ptr expr) - { - if (expr) - { - if (control_block_) - { - control_block_-> - local_data_list.push_back( - typename expression::control_block:: - data_pack(reinterpret_cast(expr), - control_block::e_expr)); - } - } - } - - inline void register_local_var(vector_holder_ptr vec_holder) - { - if (vec_holder) - { - if (control_block_) - { - control_block_-> - local_data_list.push_back( - typename expression::control_block:: - data_pack(reinterpret_cast(vec_holder), - control_block::e_vecholder)); - } - } - } - - inline void register_local_data(void* data, const std::size_t& size = 0, const std::size_t data_mode = 0) - { - if (data) - { - if (control_block_) - { - typename control_block::data_type dt = control_block::e_data; - - switch (data_mode) - { - case 0 : dt = control_block::e_data; break; - case 1 : dt = control_block::e_vecdata; break; - case 2 : dt = control_block::e_string; break; - } - - control_block_-> - local_data_list.push_back( - typename expression::control_block:: - data_pack(reinterpret_cast(data),dt,size)); - } - } - } - - inline const typename control_block::local_data_list_t& local_data_list() - { - if (control_block_) - { - return control_block_->local_data_list; - } - else - { - static typename control_block::local_data_list_t null_local_data_list; - return null_local_data_list; - } - } - - inline void register_return_results(results_context_t* rc) - { - if (control_block_ && rc) - { - control_block_->results = rc; - } - } - - inline void set_retinvk(bool* retinvk_ptr) - { - if (control_block_) - { - control_block_->return_invoked = retinvk_ptr; - } - } - - control_block* control_block_; - symtab_list_t symbol_table_list_; - - friend class parser; - friend class expression_helper; - friend class function_compositor; - }; - - template - class expression_helper - { - public: - - static inline bool is_constant(const expression& expr) - { - return details::is_constant_node(expr.control_block_->expr); - } - - static inline bool is_variable(const expression& expr) - { - return details::is_variable_node(expr.control_block_->expr); - } - - static inline bool is_unary(const expression& expr) - { - return details::is_unary_node(expr.control_block_->expr); - } - - static inline bool is_binary(const expression& expr) - { - return details::is_binary_node(expr.control_block_->expr); - } - - static inline bool is_function(const expression& expr) - { - return details::is_function(expr.control_block_->expr); - } - - static inline bool is_null(const expression& expr) - { - return details::is_null_node(expr.control_block_->expr); - } - }; - - template - inline bool is_valid(const expression& expr) - { - return !expression_helper::is_null(expr); - } - - namespace parser_error - { - enum error_mode - { - e_unknown = 0, - e_syntax = 1, - e_token = 2, - e_numeric = 4, - e_symtab = 5, - e_lexer = 6, - e_helper = 7 - }; - - 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(("%s\n",diagnostic .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(("%s\n",diagnostic .c_str())); - return t; - } - - inline std::string to_str(error_mode mode) - { - switch (mode) - { - case e_unknown : return std::string("Unknown Error"); - case e_syntax : return std::string("Syntax Error" ); - case e_token : return std::string("Token Error" ); - case e_numeric : return std::string("Numeric Error"); - case e_symtab : return std::string("Symbol Error" ); - case e_lexer : return std::string("Lexer Error" ); - case e_helper : return std::string("Helper Error" ); - default : return std::string("Unknown Error"); - } - } - - inline bool update_error(type& error, const std::string& expression) - { - if ( - expression.empty() || - (error.token.position > expression.size()) || - (std::numeric_limits::max() == error.token.position) - ) - { - return false; - } - - std::size_t error_line_start = 0; - - for (std::size_t i = error.token.position; i > 0; --i) - { - const details::char_t c = expression[i]; - - if (('\n' == c) || ('\r' == c)) - { - error_line_start = i + 1; - break; - } - } - - std::size_t next_nl_position = std::min(expression.size(), - expression.find_first_of('\n',error.token.position + 1)); - - error.column_no = error.token.position - error_line_start; - error.error_line = expression.substr(error_line_start, - next_nl_position - error_line_start); - - error.line_no = 0; - - for (std::size_t i = 0; i < next_nl_position; ++i) - { - if ('\n' == expression[i]) - ++error.line_no; - } - - return true; - } - - inline void dump_error(const type& error) - { - printf("Position: %02d Type: [%s] Msg: %s\n", - static_cast(error.token.position), - exprtk::parser_error::to_str(error.mode).c_str(), - error.diagnostic.c_str()); - } - } - - template - class parser : public lexer::parser_helper - { - private: - - enum precedence_level - { - e_level00, - e_level01, - e_level02, - e_level03, - e_level04, - e_level05, - e_level06, - e_level07, - e_level08, - e_level09, - e_level10, - e_level11, - e_level12, - e_level13, - e_level14 - }; - - typedef const T& cref_t; - typedef const T const_t; - typedef ifunction F; - typedef ivararg_function VAF; - typedef igeneric_function GF; - typedef ifunction ifunction_t; - typedef ivararg_function ivararg_function_t; - typedef igeneric_function igeneric_function_t; - typedef details::expression_node expression_node_t; - typedef details::literal_node literal_node_t; - typedef details::unary_node unary_node_t; - typedef details::binary_node binary_node_t; - typedef details::trinary_node trinary_node_t; - typedef details::quaternary_node quaternary_node_t; - typedef details::conditional_node conditional_node_t; - typedef details::cons_conditional_node cons_conditional_node_t; - typedef details::while_loop_node while_loop_node_t; - typedef details::repeat_until_loop_node repeat_until_loop_node_t; - typedef details::for_loop_node for_loop_node_t; -#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::rebasevector_elem_node rebasevector_elem_node_t; - typedef details::rebasevector_celem_node rebasevector_celem_node_t; - typedef details::vector_node vector_node_t; - typedef details::range_pack range_t; -#ifndef exprtk_disable_string_capabilities - typedef details::stringvar_node stringvar_node_t; - typedef details::string_literal_node string_literal_node_t; - typedef details::string_range_node string_range_node_t; - typedef details::const_string_range_node const_string_range_node_t; - typedef details::generic_string_range_node generic_string_range_node_t; - typedef details::string_concat_node string_concat_node_t; - typedef details::assignment_string_node assignment_string_node_t; - typedef details::assignment_string_range_node assignment_string_range_node_t; - typedef details::conditional_string_node conditional_string_node_t; - typedef details::cons_conditional_str_node cons_conditional_str_node_t; -#endif - typedef details::assignment_node assignment_node_t; - typedef details::assignment_vec_elem_node assignment_vec_elem_node_t; - typedef details::assignment_rebasevec_elem_node assignment_rebasevec_elem_node_t; - typedef details::assignment_rebasevec_celem_node assignment_rebasevec_celem_node_t; - typedef details::assignment_vec_node assignment_vec_node_t; - typedef details::assignment_vecvec_node assignment_vecvec_node_t; - typedef details::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 typename expression::symtab_list_t symbol_table_list_t; - typedef details::vector_holder* vector_holder_ptr; - - typedef typename details::functor_t functor_t; - typedef typename functor_t::qfunc_t quaternary_functor_t; - typedef typename functor_t::tfunc_t trinary_functor_t; - typedef typename functor_t::bfunc_t binary_functor_t; - typedef typename functor_t::ufunc_t unary_functor_t; - - typedef details::operator_type operator_t; - - typedef std::map unary_op_map_t; - typedef std::map binary_op_map_t; - typedef std::map trinary_op_map_t; - - typedef std::map > sf3_map_t; - typedef std::map > sf4_map_t; - - typedef std::map inv_binary_op_map_t; - typedef std::multimap base_ops_map_t; - typedef std::set disabled_func_set_t; - - typedef details::T0oT1_define vov_t; - typedef details::T0oT1_define cov_t; - typedef details::T0oT1_define voc_t; - - typedef details::T0oT1oT2_define vovov_t; - typedef details::T0oT1oT2_define vovoc_t; - typedef details::T0oT1oT2_define vocov_t; - typedef details::T0oT1oT2_define covov_t; - typedef details::T0oT1oT2_define covoc_t; - typedef details::T0oT1oT2_define cocov_t; - typedef details::T0oT1oT2_define vococ_t; - - typedef details::T0oT1oT2oT3_define vovovov_t; - typedef details::T0oT1oT2oT3_define vovovoc_t; - typedef details::T0oT1oT2oT3_define vovocov_t; - typedef details::T0oT1oT2oT3_define vocovov_t; - typedef details::T0oT1oT2oT3_define covovov_t; - - typedef details::T0oT1oT2oT3_define covocov_t; - typedef details::T0oT1oT2oT3_define vocovoc_t; - typedef details::T0oT1oT2oT3_define covovoc_t; - typedef details::T0oT1oT2oT3_define vococov_t; - - typedef results_context results_context_t; - - typedef parser_helper prsrhlpr_t; - - struct scope_element - { - enum element_type - { - e_none , - e_variable, - e_vector , - e_vecelem , - e_string - }; - - typedef details::vector_holder vector_holder_t; - typedef variable_node_t* variable_node_ptr; - typedef vector_holder_t* vector_holder_ptr; - typedef expression_node_t* expression_node_ptr; -#ifndef exprtk_disable_string_capabilities - typedef stringvar_node_t* stringvar_node_ptr; -#endif - - scope_element() - : name("???"), - size (std::numeric_limits::max()), - index(std::numeric_limits::max()), - depth(std::numeric_limits::max()), - ref_count(0), - ip_index (0), - type (e_none), - active(false), - data (0), - var_node(0), - vec_node(0) -#ifndef exprtk_disable_string_capabilities - ,str_node(0) -#endif - {} - - bool operator < (const scope_element& se) const - { - if (ip_index < se.ip_index) - return true; - else if (ip_index > se.ip_index) - return false; - else if (depth < se.depth) - return true; - else if (depth > se.depth) - return false; - else if (index < se.index) - return true; - else if (index > se.index) - return false; - else - return (name < se.name); - } - - void clear() - { - name = "???"; - size = std::numeric_limits::max(); - index = std::numeric_limits::max(); - depth = std::numeric_limits::max(); - type = e_none; - active = false; - ref_count = 0; - ip_index = 0; - data = 0; - var_node = 0; - vec_node = 0; -#ifndef exprtk_disable_string_capabilities - str_node = 0; -#endif - } - - std::string name; - std::size_t size; - std::size_t index; - std::size_t depth; - std::size_t ref_count; - std::size_t ip_index; - element_type type; - bool active; - void* data; - expression_node_ptr var_node; - vector_holder_ptr vec_node; -#ifndef exprtk_disable_string_capabilities - stringvar_node_ptr str_node; -#endif - }; - - class scope_element_manager - { - public: - - typedef expression_node_t* expression_node_ptr; - typedef variable_node_t* variable_node_ptr; - typedef parser parser_t; - - scope_element_manager(parser& p) - : parser_(p), - input_param_cnt_(0) - {} - - inline std::size_t size() const - { - return element_.size(); - } - - inline bool empty() const - { - return element_.empty(); - } - - inline scope_element& get_element(const std::size_t& index) - { - if (index < element_.size()) - return element_[index]; - else - return null_element_; - } - - inline scope_element& get_element(const std::string& var_name, - const std::size_t index = std::numeric_limits::max()) - { - const std::size_t current_depth = parser_.state_.scope_depth; - - for (std::size_t i = 0; i < element_.size(); ++i) - { - scope_element& se = element_[i]; - - if (se.depth > current_depth) - continue; - else if ( - (se.name == var_name) && - (se.index == index) - ) - return se; - } - - return null_element_; - } - - inline scope_element& get_active_element(const std::string& var_name, - const std::size_t index = std::numeric_limits::max()) - { - const std::size_t current_depth = parser_.state_.scope_depth; - - for (std::size_t i = 0; i < element_.size(); ++i) - { - scope_element& se = element_[i]; - - if (se.depth > current_depth) - continue; - else if ( - (se.name == var_name) && - (se.index == index) && - (se.active) - ) - return se; - } - - return null_element_; - } - - inline bool add_element(const scope_element& se) - { - for (std::size_t i = 0; i < element_.size(); ++i) - { - scope_element& cse = element_[i]; - - if ( - (cse.name == se.name ) && - (cse.depth <= se.depth) && - (cse.index == se.index) && - (cse.size == se.size ) && - (cse.type == se.type ) && - (cse.active) - ) - return false; - } - - element_.push_back(se); - std::sort(element_.begin(),element_.end()); - - return true; - } - - inline void deactivate(const std::size_t& scope_depth) - { - exprtk_debug(("deactivate() - Scope depth: %d\n", - static_cast(parser_.state_.scope_depth))); - - for (std::size_t i = 0; i < element_.size(); ++i) - { - scope_element& se = element_[i]; - - if (se.active && (se.depth >= scope_depth)) - { - exprtk_debug(("deactivate() - element[%02d] '%s'\n", - static_cast(i), - se.name.c_str())); - - se.active = false; - } - } - } - - inline void free_element(scope_element& se) - { - switch (se.type) - { - case scope_element::e_variable : if (se.data ) delete (T*) se.data; - if (se.var_node) delete se.var_node; - break; - - case scope_element::e_vector : if (se.data ) delete[] (T*) se.data; - if (se.vec_node) delete se.vec_node; - break; - - case scope_element::e_vecelem : if (se.var_node) delete se.var_node; - break; - -#ifndef exprtk_disable_string_capabilities - case scope_element::e_string : if (se.data ) delete (std::string*) se.data; - if (se.str_node) delete se.str_node; - break; -#endif - - default : return; - } - - se.clear(); - } - - inline void cleanup() - { - for (std::size_t i = 0; i < element_.size(); ++i) - { - free_element(element_[i]); - } - - element_.clear(); - - input_param_cnt_ = 0; - } - - inline std::size_t next_ip_index() - { - return ++input_param_cnt_; - } - - inline expression_node_ptr get_variable(const T& v) - { - for (std::size_t i = 0; i < element_.size(); ++i) - { - scope_element& se = element_[i]; - - if ( - se.active && - se.var_node && - details::is_variable_node(se.var_node) - ) - { - variable_node_ptr vn = reinterpret_cast(se.var_node); - - if (&(vn->ref()) == (&v)) - { - return se.var_node; - } - } - } - - return expression_node_ptr(0); - } - - private: - - scope_element_manager& 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_.state_.scope_depth++; -#ifdef exprtk_enable_debugging - std::string depth(2 * parser_.state_.scope_depth,'-'); - exprtk_debug(("%s> Scope Depth: %02d\n", - depth.c_str(), - static_cast(parser_.state_.scope_depth))); -#endif - } - - ~scope_handler() - { - parser_.sem_.deactivate(parser_.state_.scope_depth); - parser_.state_.scope_depth--; -#ifdef exprtk_enable_debugging - std::string depth(2 * parser_.state_.scope_depth,'-'); - exprtk_debug(("<%s Scope Depth: %02d\n", - depth.c_str(), - static_cast(parser_.state_.scope_depth))); -#endif - } - - private: - - scope_handler& operator=(const scope_handler&); - - parser_t& parser_; - }; - - struct symtab_store - { - symbol_table_list_t symtab_list_; - - typedef typename symbol_table_t::local_data_t local_data_t; - typedef typename symbol_table_t::variable_ptr variable_ptr; - typedef typename symbol_table_t::function_ptr function_ptr; -#ifndef exprtk_disable_string_capabilities - typedef typename symbol_table_t::stringvar_ptr stringvar_ptr; -#endif - typedef typename symbol_table_t::vector_holder_ptr vector_holder_ptr; - typedef typename symbol_table_t::vararg_function_ptr vararg_function_ptr; - typedef typename symbol_table_t::generic_function_ptr generic_function_ptr; - - inline bool empty() const - { - return symtab_list_.empty(); - } - - inline void clear() - { - symtab_list_.clear(); - } - - inline bool valid() const - { - if (!empty()) - { - for (std::size_t i = 0; i < symtab_list_.size(); ++i) - { - if (symtab_list_[i].valid()) - return true; - } - } - - return false; - } - - inline bool valid_symbol(const std::string& symbol) const - { - if (!symtab_list_.empty()) - return symtab_list_[0].valid_symbol(symbol); - else - return false; - } - - inline bool valid_function_name(const std::string& symbol) const - { - if (!symtab_list_.empty()) - return symtab_list_[0].valid_function(symbol); - else - return false; - } - - inline variable_ptr get_variable(const std::string& variable_name) const - { - if (!valid_symbol(variable_name)) - return reinterpret_cast(0); - - variable_ptr result = reinterpret_cast(0); - - for (std::size_t i = 0; i < symtab_list_.size(); ++i) - { - if (!symtab_list_[i].valid()) - continue; - else - result = local_data(i) - .variable_store.get(variable_name); - - if (result) break; - } - - return result; - } - - inline variable_ptr get_variable(const T& var_ref) const - { - variable_ptr result = reinterpret_cast(0); - - for (std::size_t i = 0; i < symtab_list_.size(); ++i) - { - if (!symtab_list_[i].valid()) - continue; - else - result = local_data(i).variable_store - .get_from_varptr(reinterpret_cast(&var_ref)); - - if (result) break; - } - - return result; - } - -#ifndef exprtk_disable_string_capabilities - inline stringvar_ptr get_stringvar(const std::string& string_name) const - { - if (!valid_symbol(string_name)) - return reinterpret_cast(0); - - stringvar_ptr result = reinterpret_cast(0); - - for (std::size_t i = 0; i < symtab_list_.size(); ++i) - { - if (!symtab_list_[i].valid()) - continue; - else - result = local_data(i) - .stringvar_store.get(string_name); - - if (result) break; - } - - return result; - } -#endif - - inline function_ptr get_function(const std::string& function_name) const - { - if (!valid_function_name(function_name)) - return reinterpret_cast(0); - - function_ptr result = reinterpret_cast(0); - - for (std::size_t i = 0; i < symtab_list_.size(); ++i) - { - if (!symtab_list_[i].valid()) - continue; - else - result = local_data(i) - .function_store.get(function_name); - - if (result) break; - } - - return result; - } - - inline vararg_function_ptr get_vararg_function(const std::string& vararg_function_name) const - { - if (!valid_function_name(vararg_function_name)) - return reinterpret_cast(0); - - vararg_function_ptr result = reinterpret_cast(0); - - for (std::size_t i = 0; i < symtab_list_.size(); ++i) - { - if (!symtab_list_[i].valid()) - continue; - else - result = local_data(i) - .vararg_function_store.get(vararg_function_name); - - if (result) break; - } - - return result; - } - - inline generic_function_ptr get_generic_function(const std::string& function_name) const - { - if (!valid_function_name(function_name)) - return reinterpret_cast(0); - - generic_function_ptr result = reinterpret_cast(0); - - for (std::size_t i = 0; i < symtab_list_.size(); ++i) - { - if (!symtab_list_[i].valid()) - continue; - else - result = local_data(i) - .generic_function_store.get(function_name); - - if (result) break; - } - - return result; - } - - inline generic_function_ptr get_string_function(const std::string& function_name) const - { - if (!valid_function_name(function_name)) - return reinterpret_cast(0); - - generic_function_ptr result = reinterpret_cast(0); - - for (std::size_t i = 0; i < symtab_list_.size(); ++i) - { - if (!symtab_list_[i].valid()) - continue; - else - result = - local_data(i).string_function_store.get(function_name); - - if (result) break; - } - - return result; - } - - inline vector_holder_ptr get_vector(const std::string& vector_name) const - { - if (!valid_symbol(vector_name)) - return reinterpret_cast(0); - - vector_holder_ptr result = reinterpret_cast(0); - - for (std::size_t i = 0; i < symtab_list_.size(); ++i) - { - if (!symtab_list_[i].valid()) - continue; - else - result = - local_data(i).vector_store.get(vector_name); - - if (result) break; - } - - return result; - } - - inline bool is_constant_node(const std::string& symbol_name) const - { - if (!valid_symbol(symbol_name)) - return false; - - for (std::size_t i = 0; i < symtab_list_.size(); ++i) - { - if (!symtab_list_[i].valid()) - continue; - else if (local_data(i).variable_store.is_constant(symbol_name)) - return true; - } - - return false; - } - -#ifndef exprtk_disable_string_capabilities - inline bool is_constant_string(const std::string& symbol_name) const - { - if (!valid_symbol(symbol_name)) - return false; - - for (std::size_t i = 0; i < symtab_list_.size(); ++i) - { - if (!symtab_list_[i].valid()) - continue; - else if (!local_data(i).stringvar_store.symbol_exists(symbol_name)) - continue; - else if ( local_data(i).stringvar_store.is_constant(symbol_name)) - return true; - } - - return false; - } -#endif - - inline bool symbol_exists(const std::string& symbol) const - { - for (std::size_t i = 0; i < symtab_list_.size(); ++i) - { - if (!symtab_list_[i].valid()) - continue; - else if (symtab_list_[i].symbol_exists(symbol)) - return true; - } - - return false; - } - - inline bool is_variable(const std::string& variable_name) const - { - for (std::size_t i = 0; i < symtab_list_.size(); ++i) - { - if (!symtab_list_[i].valid()) - continue; - else if ( - symtab_list_[i].local_data().variable_store - .symbol_exists(variable_name) - ) - return true; - } - - return false; - } - -#ifndef exprtk_disable_string_capabilities - inline bool is_stringvar(const std::string& stringvar_name) const - { - for (std::size_t i = 0; i < symtab_list_.size(); ++i) - { - if (!symtab_list_[i].valid()) - continue; - else if ( - symtab_list_[i].local_data().stringvar_store - .symbol_exists(stringvar_name) - ) - return true; - } - - return false; - } - - inline bool is_conststr_stringvar(const std::string& symbol_name) const - { - for (std::size_t i = 0; i < symtab_list_.size(); ++i) - { - if (!symtab_list_[i].valid()) - continue; - else if ( - symtab_list_[i].local_data().stringvar_store - .symbol_exists(symbol_name) - ) - { - return ( - local_data(i).stringvar_store.symbol_exists(symbol_name) || - local_data(i).stringvar_store.is_constant (symbol_name) - ); - - } - } - - return false; - } -#endif - - inline bool is_function(const std::string& function_name) const - { - for (std::size_t i = 0; i < symtab_list_.size(); ++i) - { - if (!symtab_list_[i].valid()) - continue; - else if ( - local_data(i).vararg_function_store - .symbol_exists(function_name) - ) - return true; - } - - return false; - } - - inline bool is_vararg_function(const std::string& vararg_function_name) const - { - for (std::size_t i = 0; i < symtab_list_.size(); ++i) - { - if (!symtab_list_[i].valid()) - continue; - else if ( - local_data(i).vararg_function_store - .symbol_exists(vararg_function_name) - ) - return true; - } - - return false; - } - - inline bool is_vector(const std::string& vector_name) const - { - for (std::size_t i = 0; i < symtab_list_.size(); ++i) - { - if (!symtab_list_[i].valid()) - continue; - else if ( - local_data(i).vector_store - .symbol_exists(vector_name) - ) - return true; - } - - return false; - } - - inline std::string get_variable_name(const expression_node_ptr& ptr) const - { - return local_data().variable_store.entity_name(ptr); - } - - inline std::string get_vector_name(const vector_holder_ptr& ptr) const - { - return local_data().vector_store.entity_name(ptr); - } - -#ifndef exprtk_disable_string_capabilities - inline std::string get_stringvar_name(const expression_node_ptr& ptr) const - { - return local_data().stringvar_store.entity_name(ptr); - } - - inline std::string get_conststr_stringvar_name(const expression_node_ptr& ptr) const - { - return local_data().stringvar_store.entity_name(ptr); - } -#endif - - inline local_data_t& local_data(const std::size_t& index = 0) - { - return symtab_list_[index].local_data(); - } - - inline const local_data_t& local_data(const std::size_t& index = 0) const - { - return symtab_list_[index].local_data(); - } - - inline symbol_table_t& get_symbol_table(const std::size_t& index = 0) - { - return symtab_list_[index]; - } - }; - - struct parser_state - { - parser_state() - { - reset(); - } - - void reset() - { - parsing_return_stmt = false; - parsing_break_stmt = false; - return_stmt_present = false; - side_effect_present = false; - scope_depth = 0; - } - -#ifndef exprtk_enable_debugging - void activate_side_effect(const std::string&) -#else - void activate_side_effect(const std::string& source) -#endif - { - if (!side_effect_present) - { - side_effect_present = true; - - exprtk_debug(("activate_side_effect() - caller: %s\n",source.c_str())); - } - } - - bool parsing_return_stmt; - bool parsing_break_stmt; - bool return_stmt_present; - bool side_effect_present; - std::size_t scope_depth; - }; - - public: - - 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.clear(); - - 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_vecelem = 3, - e_st_string = 4, - e_st_function = 5, - e_st_local_variable = 6, - e_st_local_vector = 7, - e_st_local_string = 8 - }; - - class dependent_entity_collector - { - public: - - typedef std::pair symbol_t; - typedef std::vector symbol_list_t; - - dependent_entity_collector(const std::size_t options = e_ct_none) - : options_(options), - collect_variables_ ((options_ & e_ct_variables ) == e_ct_variables ), - collect_functions_ ((options_ & e_ct_functions ) == e_ct_functions ), - collect_assignments_((options_ & e_ct_assignments) == e_ct_assignments), - return_present_ (false), - final_stmt_return_(false) - {} - - template class Sequence> - inline std::size_t symbols(Sequence& symbols_list) - { - if (!collect_variables_ && !collect_functions_) - return 0; - else if (symbol_name_list_.empty()) - return 0; - - for (std::size_t i = 0; i < symbol_name_list_.size(); ++i) - { - std::string& s = symbol_name_list_[i].first; -#ifndef MODIFICATION - std::transform(s.begin(),s.end(),s.begin(),static_cast(std::tolower)); -#endif - } - - 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; -#ifndef MODIFICATION - std::transform(s.begin(),s.end(),s.begin(),static_cast(std::tolower)); -#endif - } - - std::sort(assignment_name_list_.begin(),assignment_name_list_.end()); - - std::unique_copy(assignment_name_list_.begin(), - assignment_name_list_.end(), - std::back_inserter(assignment_list)); - - return assignment_list.size(); - } - - void clear() - { - symbol_name_list_ .clear(); - assignment_name_list_.clear(); - retparam_list_ .clear(); - return_present_ = false; - final_stmt_return_ = false; - } - - bool& collect_variables() - { - return collect_variables_; - } - - bool& collect_functions() - { - return collect_functions_; - } - - bool& collect_assignments() - { - return collect_assignments_; - } - - bool return_present() const - { - return return_present_; - } - - bool final_stmt_return() const - { - return final_stmt_return_; - } - - typedef std::vector retparam_list_t; - - retparam_list_t return_param_type_list() const - { - return retparam_list_; - } - - private: - - inline void add_symbol(const std::string& symbol, const symbol_type st) - { - switch (st) - { - case e_st_variable : - case e_st_vector : - case e_st_string : - case e_st_local_variable : - case e_st_local_vector : - case e_st_local_string : - 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_; - bool return_present_; - bool final_stmt_return_; - symbol_list_t symbol_name_list_; - symbol_list_t assignment_name_list_; - retparam_list_t retparam_list_; - - friend class parser; - }; - - class settings_store - { - private: - - typedef std::set disabled_entity_set_t; - typedef disabled_entity_set_t::iterator des_itr_t; - - public: - - enum settings_compilation_options - { - e_unknown = 0, - e_replacer = 1, - e_joiner = 2, - e_numeric_check = 4, - e_bracket_check = 8, - e_sequence_check = 16, - e_commutative_check = 32, - e_strength_reduction = 64, - e_disable_vardef = 128, - e_collect_vars = 256, - e_collect_funcs = 512, - e_collect_assings = 1024, - e_disable_usr_on_rsrvd = 2048, - e_disable_zero_return = 4096 - }; - - enum settings_base_funcs - { - e_bf_unknown = 0, - e_bf_abs , e_bf_acos , e_bf_acosh , e_bf_asin , - e_bf_asinh , e_bf_atan , e_bf_atan2 , e_bf_atanh , - e_bf_avg , e_bf_ceil , e_bf_clamp , e_bf_cos , - e_bf_cosh , e_bf_cot , e_bf_csc , e_bf_equal , - e_bf_erf , e_bf_erfc , e_bf_exp , e_bf_expm1 , - e_bf_floor , e_bf_frac , e_bf_hypot , e_bf_iclamp , - e_bf_like , e_bf_log , e_bf_log10 , e_bf_log1p , - e_bf_log2 , e_bf_logn , e_bf_mand , e_bf_max , - e_bf_min , e_bf_mod , e_bf_mor , e_bf_mul , - e_bf_ncdf , e_bf_pow , e_bf_root , e_bf_round , - e_bf_roundn , e_bf_sec , e_bf_sgn , e_bf_sin , - e_bf_sinc , e_bf_sinh , e_bf_sqrt , e_bf_sum , - e_bf_swap , e_bf_tan , e_bf_tanh , e_bf_trunc , - e_bf_not_equal , e_bf_inrange , e_bf_deg2grad , e_bf_deg2rad, - e_bf_rad2deg , e_bf_grad2deg - }; - - enum settings_control_structs - { - e_ctrl_unknown = 0, - e_ctrl_ifelse, - e_ctrl_switch, - e_ctrl_for_loop, - e_ctrl_while_loop, - e_ctrl_repeat_loop - }; - - enum settings_logic_opr - { - e_logic_unknown = 0, - e_logic_and, e_logic_nand, e_logic_nor, - e_logic_not, e_logic_or, e_logic_xnor, - e_logic_xor, e_logic_scand, e_logic_scor - }; - - enum settings_arithmetic_opr - { - e_arith_unknown = 0, - e_arith_add, e_arith_sub, e_arith_mul, - e_arith_div, e_arith_mod, e_arith_pow - }; - - enum settings_assignment_opr - { - e_assign_unknown = 0, - e_assign_assign, e_assign_addass, e_assign_subass, - e_assign_mulass, e_assign_divass, e_assign_modass - }; - - enum settings_inequality_opr - { - e_ineq_unknown = 0, - e_ineq_lt, e_ineq_lte, e_ineq_eq, - e_ineq_equal, e_ineq_ne, e_ineq_nequal, - e_ineq_gte, e_ineq_gt - }; - - static const std::size_t compile_all_opts = e_replacer + - e_joiner + - e_numeric_check + - e_bracket_check + - e_sequence_check + - e_commutative_check + - e_strength_reduction; - - settings_store(const std::size_t compile_options = compile_all_opts) - { - load_compile_options(compile_options); - } - - settings_store& enable_all_base_functions() - { - disabled_func_set_.clear(); - return *this; - } - - settings_store& enable_all_control_structures() - { - disabled_ctrl_set_.clear(); - return *this; - } - - settings_store& enable_all_logic_ops() - { - disabled_logic_set_.clear(); - return *this; - } - - settings_store& enable_all_arithmetic_ops() - { - disabled_arithmetic_set_.clear(); - return *this; - } - - settings_store& enable_all_assignment_ops() - { - disabled_assignment_set_.clear(); - return *this; - } - - settings_store& enable_all_inequality_ops() - { - disabled_inequality_set_.clear(); - return *this; - } - - settings_store& enable_local_vardef() - { - disable_vardef_ = false; - return *this; - } - - settings_store& disable_all_base_functions() - { - std::copy(details::base_function_list, - details::base_function_list + details::base_function_list_size, - std::insert_iterator - (disabled_func_set_,disabled_func_set_.begin())); - return *this; - } - - settings_store& disable_all_control_structures() - { - std::copy(details::cntrl_struct_list, - details::cntrl_struct_list + details::cntrl_struct_list_size, - std::insert_iterator - (disabled_ctrl_set_,disabled_ctrl_set_.begin())); - return *this; - } - - settings_store& disable_all_logic_ops() - { - std::copy(details::logic_ops_list, - details::logic_ops_list + details::logic_ops_list_size, - std::insert_iterator - (disabled_logic_set_,disabled_logic_set_.begin())); - return *this; - } - - settings_store& disable_all_arithmetic_ops() - { - std::copy(details::arithmetic_ops_list, - details::arithmetic_ops_list + details::arithmetic_ops_list_size, - std::insert_iterator - (disabled_arithmetic_set_,disabled_arithmetic_set_.begin())); - return *this; - } - - settings_store& disable_all_assignment_ops() - { - std::copy(details::assignment_ops_list, - details::assignment_ops_list + details::assignment_ops_list_size, - std::insert_iterator - (disabled_assignment_set_,disabled_assignment_set_.begin())); - return *this; - } - - settings_store& disable_all_inequality_ops() - { - std::copy(details::inequality_ops_list, - details::inequality_ops_list + details::inequality_ops_list_size, - std::insert_iterator - (disabled_inequality_set_,disabled_inequality_set_.begin())); - return *this; - } - - settings_store& disable_local_vardef() - { - disable_vardef_ = true; - return *this; - } - - bool replacer_enabled () const { return enable_replacer_; } - bool commutative_check_enabled () const { return enable_commutative_check_; } - bool joiner_enabled () const { return enable_joiner_; } - bool numeric_check_enabled () const { return enable_numeric_check_; } - bool bracket_check_enabled () const { return enable_bracket_check_; } - bool sequence_check_enabled () const { return enable_sequence_check_; } - bool strength_reduction_enabled () const { return enable_strength_reduction_; } - bool collect_variables_enabled () const { return enable_collect_vars_; } - bool collect_functions_enabled () const { return enable_collect_funcs_; } - bool collect_assignments_enabled() const { return enable_collect_assings_; } - bool vardef_disabled () const { return disable_vardef_; } - bool rsrvd_sym_usr_disabled () const { return disable_rsrvd_sym_usr_; } - bool zero_return_disabled () const { return disable_zero_return_; } - - bool function_enabled(const std::string& function_name) - { - if (disabled_func_set_.empty()) - return true; - else - return (disabled_func_set_.end() == disabled_func_set_.find(function_name)); - } - - bool control_struct_enabled(const std::string& control_struct) - { - if (disabled_ctrl_set_.empty()) - return true; - else - return (disabled_ctrl_set_.end() == disabled_ctrl_set_.find(control_struct)); - } - - bool logic_enabled(const std::string& logic_operation) - { - if (disabled_logic_set_.empty()) - return true; - else - return (disabled_logic_set_.end() == disabled_logic_set_.find(logic_operation)); - } - - bool arithmetic_enabled(const details::operator_type& arithmetic_operation) - { - if (disabled_logic_set_.empty()) - return true; - else - return (disabled_arithmetic_set_.end() == disabled_arithmetic_set_.find(arith_opr_to_string(arithmetic_operation))); - } - - bool assignment_enabled(const details::operator_type& assignment) - { - if (disabled_assignment_set_.empty()) - return true; - else - return (disabled_assignment_set_.end() == disabled_assignment_set_.find(assign_opr_to_string(assignment))); - } - - bool inequality_enabled(const details::operator_type& inequality) - { - if (disabled_inequality_set_.empty()) - return true; - else - return (disabled_inequality_set_.end() == disabled_inequality_set_.find(inequality_opr_to_string(inequality))); - } - - bool function_disabled(const std::string& function_name) - { - if (disabled_func_set_.empty()) - return false; - else - return (disabled_func_set_.end() != disabled_func_set_.find(function_name)); - } - - bool control_struct_disabled(const std::string& control_struct) - { - if (disabled_ctrl_set_.empty()) - return false; - else - return (disabled_ctrl_set_.end() != disabled_ctrl_set_.find(control_struct)); - } - - bool logic_disabled(const std::string& logic_operation) - { - if (disabled_logic_set_.empty()) - return false; - else - return (disabled_logic_set_.end() != disabled_logic_set_.find(logic_operation)); - } - - bool assignment_disabled(const details::operator_type assignment_operation) - { - if (disabled_assignment_set_.empty()) - return false; - else - return (disabled_assignment_set_.end() != disabled_assignment_set_.find(assign_opr_to_string(assignment_operation))); - } - - bool arithmetic_disabled(const details::operator_type arithmetic_operation) - { - if (disabled_arithmetic_set_.empty()) - return false; - else - return (disabled_arithmetic_set_.end() != disabled_arithmetic_set_.find(arith_opr_to_string(arithmetic_operation))); - } - - bool inequality_disabled(const details::operator_type& inequality) - { - if (disabled_inequality_set_.empty()) - return false; - else - return (disabled_inequality_set_.end() != disabled_inequality_set_.find(inequality_opr_to_string(inequality))); - } - - settings_store& disable_base_function(settings_base_funcs bf) - { - if ( - (e_bf_unknown != bf) && - (static_cast(bf) < (details::base_function_list_size + 1)) - ) - { - disabled_func_set_.insert(details::base_function_list[bf - 1]); - } - - return *this; - } - - settings_store& disable_control_structure(settings_control_structs ctrl_struct) - { - if ( - (e_ctrl_unknown != ctrl_struct) && - (static_cast(ctrl_struct) < (details::cntrl_struct_list_size + 1)) - ) - { - disabled_ctrl_set_.insert(details::cntrl_struct_list[ctrl_struct - 1]); - } - - return *this; - } - - settings_store& disable_logic_operation(settings_logic_opr logic) - { - if ( - (e_logic_unknown != logic) && - (static_cast(logic) < (details::logic_ops_list_size + 1)) - ) - { - disabled_logic_set_.insert(details::logic_ops_list[logic - 1]); - } - - return *this; - } - - settings_store& disable_arithmetic_operation(settings_arithmetic_opr arithmetic) - { - if ( - (e_arith_unknown != arithmetic) && - (static_cast(arithmetic) < (details::arithmetic_ops_list_size + 1)) - ) - { - disabled_arithmetic_set_.insert(details::arithmetic_ops_list[arithmetic - 1]); - } - - return *this; - } - - settings_store& disable_assignment_operation(settings_assignment_opr assignment) - { - if ( - (e_assign_unknown != assignment) && - (static_cast(assignment) < (details::assignment_ops_list_size + 1)) - ) - { - disabled_assignment_set_.insert(details::assignment_ops_list[assignment - 1]); - } - - return *this; - } - - settings_store& disable_inequality_operation(settings_inequality_opr inequality) - { - if ( - (e_ineq_unknown != inequality) && - (static_cast(inequality) < (details::inequality_ops_list_size + 1)) - ) - { - disabled_inequality_set_.insert(details::inequality_ops_list[inequality - 1]); - } - - return *this; - } - - settings_store& enable_base_function(settings_base_funcs bf) - { - if ( - (e_bf_unknown != bf) && - (static_cast(bf) < (details::base_function_list_size + 1)) - ) - { - des_itr_t itr = disabled_func_set_.find(details::base_function_list[bf - 1]); - - if (disabled_func_set_.end() != itr) - { - disabled_func_set_.erase(itr); - } - } - - return *this; - } - - settings_store& enable_control_structure(settings_control_structs ctrl_struct) - { - if ( - (e_ctrl_unknown != ctrl_struct) && - (static_cast(ctrl_struct) < (details::cntrl_struct_list_size + 1)) - ) - { - des_itr_t itr = disabled_ctrl_set_.find(details::cntrl_struct_list[ctrl_struct - 1]); - - if (disabled_ctrl_set_.end() != itr) - { - disabled_ctrl_set_.erase(itr); - } - } - - return *this; - } - - settings_store& enable_logic_operation(settings_logic_opr logic) - { - if ( - (e_logic_unknown != logic) && - (static_cast(logic) < (details::logic_ops_list_size + 1)) - ) - { - des_itr_t itr = disabled_logic_set_.find(details::logic_ops_list[logic - 1]); - - if (disabled_logic_set_.end() != itr) - { - disabled_logic_set_.erase(itr); - } - } - - return *this; - } - - settings_store& enable_arithmetic_operation(settings_arithmetic_opr arithmetic) - { - if ( - (e_arith_unknown != arithmetic) && - (static_cast(arithmetic) < (details::arithmetic_ops_list_size + 1)) - ) - { - des_itr_t itr = disabled_arithmetic_set_.find(details::arithmetic_ops_list[arithmetic - 1]); - - if (disabled_arithmetic_set_.end() != itr) - { - disabled_arithmetic_set_.erase(itr); - } - } - - return *this; - } - - settings_store& enable_assignment_operation(settings_assignment_opr assignment) - { - if ( - (e_assign_unknown != assignment) && - (static_cast(assignment) < (details::assignment_ops_list_size + 1)) - ) - { - des_itr_t itr = disabled_assignment_set_.find(details::assignment_ops_list[assignment - 1]); - - if (disabled_assignment_set_.end() != itr) - { - disabled_assignment_set_.erase(itr); - } - } - - return *this; - } - - settings_store& enable_inequality_operation(settings_inequality_opr inequality) - { - if ( - (e_ineq_unknown != inequality) && - (static_cast(inequality) < (details::inequality_ops_list_size + 1)) - ) - { - des_itr_t itr = disabled_inequality_set_.find(details::inequality_ops_list[inequality - 1]); - - if (disabled_inequality_set_.end() != itr) - { - disabled_inequality_set_.erase(itr); - } - } - - return *this; - } - - private: - - void load_compile_options(const std::size_t compile_options) - { - enable_replacer_ = (compile_options & e_replacer ) == e_replacer; - enable_joiner_ = (compile_options & e_joiner ) == e_joiner; - enable_numeric_check_ = (compile_options & e_numeric_check ) == e_numeric_check; - enable_bracket_check_ = (compile_options & e_bracket_check ) == e_bracket_check; - enable_sequence_check_ = (compile_options & e_sequence_check ) == e_sequence_check; - enable_commutative_check_ = (compile_options & e_commutative_check ) == e_commutative_check; - enable_strength_reduction_ = (compile_options & e_strength_reduction ) == e_strength_reduction; - enable_collect_vars_ = (compile_options & e_collect_vars ) == e_collect_vars; - enable_collect_funcs_ = (compile_options & e_collect_funcs ) == e_collect_funcs; - enable_collect_assings_ = (compile_options & e_collect_assings ) == e_collect_assings; - disable_vardef_ = (compile_options & e_disable_vardef ) == e_disable_vardef; - disable_rsrvd_sym_usr_ = (compile_options & e_disable_usr_on_rsrvd) == e_disable_usr_on_rsrvd; - disable_zero_return_ = (compile_options & e_disable_zero_return ) == e_disable_zero_return; - } - - std::string assign_opr_to_string(details::operator_type opr) - { - switch (opr) - { - case details::e_assign : return ":="; - case details::e_addass : return "+="; - case details::e_subass : return "-="; - case details::e_mulass : return "*="; - case details::e_divass : return "/="; - case details::e_modass : return "%="; - default : return ""; - } - } - - std::string arith_opr_to_string(details::operator_type opr) - { - switch (opr) - { - case details::e_add : return "+"; - case details::e_sub : return "-"; - case details::e_mul : return "*"; - case details::e_div : return "/"; - case details::e_mod : return "%"; - default : return ""; - } - } - - std::string inequality_opr_to_string(details::operator_type opr) - { - switch (opr) - { - case details::e_lt : return "<"; - case details::e_lte : return "<="; - case details::e_eq : return "=="; - case details::e_equal : return "="; - case details::e_ne : return "!="; - case details::e_nequal: return "<>"; - case details::e_gte : return ">="; - case details::e_gt : return ">"; - default : return ""; - } - } - - bool enable_replacer_; - bool enable_joiner_; - bool enable_numeric_check_; - bool enable_bracket_check_; - bool enable_sequence_check_; - bool enable_commutative_check_; - bool enable_strength_reduction_; - bool enable_collect_vars_; - bool enable_collect_funcs_; - bool enable_collect_assings_; - bool disable_vardef_; - bool disable_rsrvd_sym_usr_; - bool disable_zero_return_; - - disabled_entity_set_t disabled_func_set_ ; - disabled_entity_set_t disabled_ctrl_set_ ; - disabled_entity_set_t disabled_logic_set_; - disabled_entity_set_t disabled_arithmetic_set_; - disabled_entity_set_t disabled_assignment_set_; - disabled_entity_set_t disabled_inequality_set_; - - friend class parser; - }; - - typedef settings_store settings_t; - - parser(const settings_t& settings = settings_t()) - : settings_(settings), - resolve_unknown_symbol_(false), - results_context_(0), - unknown_symbol_resolver_(reinterpret_cast(0)), -#ifdef _MSC_VER -#pragma warning(push) -#pragma warning (disable:4355) -#endif - sem_(*this), -#ifdef _MSC_VER -#pragma warning(pop) -#endif - operator_joiner_2_(2), - operator_joiner_3_(3) - { - init_precompilation(); - - load_operations_map (base_ops_map_ ); - load_unary_operations_map (unary_op_map_ ); - load_binary_operations_map (binary_op_map_ ); - load_inv_binary_operations_map(inv_binary_op_map_); - load_sf3_map (sf3_map_ ); - load_sf4_map (sf4_map_ ); - - expression_generator_.init_synthesize_map(); - expression_generator_.set_parser(*this); - expression_generator_.set_uom(unary_op_map_); - expression_generator_.set_bom(binary_op_map_); - expression_generator_.set_ibom(inv_binary_op_map_); - expression_generator_.set_sf3m(sf3_map_); - expression_generator_.set_sf4m(sf4_map_); - expression_generator_.set_strength_reduction_state(settings_.strength_reduction_enabled()); - } - - ~parser() - {} - - inline void init_precompilation() - { - if (settings_.collect_variables_enabled()) - dec_.collect_variables() = true; - - if (settings_.collect_functions_enabled()) - dec_.collect_functions() = true; - - if (settings_.collect_assignments_enabled()) - dec_.collect_assignments() = true; - - if (settings_.replacer_enabled()) - { - symbol_replacer_.clear(); - symbol_replacer_.add_replace("true" ,"1",lexer::token::e_number); - symbol_replacer_.add_replace("false","0",lexer::token::e_number); - helper_assembly_.token_modifier_list.clear(); - helper_assembly_.register_modifier(&symbol_replacer_); - } - - if (settings_.commutative_check_enabled()) - { - for (std::size_t i = 0; i < details::reserved_words_size; ++i) - { - commutative_inserter_.ignore_symbol(details::reserved_words[i]); - } - - helper_assembly_.token_inserter_list.clear(); - helper_assembly_.register_inserter(&commutative_inserter_); - } - - if (settings_.joiner_enabled()) - { - helper_assembly_.token_joiner_list.clear(); - helper_assembly_.register_joiner(&operator_joiner_2_); - helper_assembly_.register_joiner(&operator_joiner_3_); - } - - if ( - settings_.numeric_check_enabled () || - settings_.bracket_check_enabled () || - settings_.sequence_check_enabled() - ) - { - helper_assembly_.token_scanner_list.clear(); - - if (settings_.numeric_check_enabled()) - { - helper_assembly_.register_scanner(&numeric_checker_); - } - - if (settings_.bracket_check_enabled()) - { - helper_assembly_.register_scanner(&bracket_checker_); - } - - if (settings_.sequence_check_enabled()) - { - helper_assembly_.register_scanner(&sequence_validator_); - } - } - } - - inline bool compile(const std::string& expression_string, expression& expr) - { - state_ .reset(); - error_list_ .clear(); - brkcnt_list_ .clear(); - synthesis_error_.clear(); - sem_ .cleanup(); - - return_cleanup(); - - expression_generator_.set_allocator(node_allocator_); - - if (expression_string.empty()) - { - set_error( - make_error(parser_error::e_syntax, - "ERR000 - Empty expression!")); - - return false; - } - - if (!init(expression_string)) - { - process_lexer_errors(); - return false; - } - - if (lexer().empty()) - { - set_error( - make_error(parser_error::e_syntax, - "ERR001 - Empty expression!")); - - return false; - } - - if (!run_assemblies()) - { - return false; - } - - symtab_store_.symtab_list_ = expr.get_symbol_table_list(); - dec_.clear(); - - lexer().begin(); - - next_token(); - - expression_node_ptr e = parse_corpus(); - - if ((0 != e) && (token_t::e_eof == current_token().type)) - { - bool* retinvk_ptr = 0; - - if (state_.return_stmt_present) - { - dec_.return_present_ = true; - - e = expression_generator_ - .return_envelope(e,results_context_,retinvk_ptr); - } - - expr.set_expression(e); - expr.set_retinvk(retinvk_ptr); - - register_local_vars(expr); - register_return_results(expr); - - return !(!expr); - } - else - { - if (error_list_.empty()) - { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR002 - Invalid expression encountered")); - } - - dec_.clear (); - sem_.cleanup (); - return_cleanup(); - - if ((0 != e) && branch_deletable(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 = "ERR003 - "; - - 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 run_assemblies() - { - if (settings_.commutative_check_enabled()) - { - helper_assembly_.run_inserters(lexer()); - } - - if (settings_.joiner_enabled()) - { - helper_assembly_.run_joiners(lexer()); - } - - if (settings_.replacer_enabled()) - { - helper_assembly_.run_modifiers(lexer()); - } - - if ( - settings_.numeric_check_enabled () || - settings_.bracket_check_enabled () || - settings_.sequence_check_enabled() - ) - { - if (!helper_assembly_.run_scanners(lexer())) - { - if (helper_assembly_.error_token_scanner) - { - lexer::helper::bracket_checker* bracket_checker_ptr = 0; - lexer::helper::numeric_checker* numeric_checker_ptr = 0; - lexer::helper::sequence_validator* sequence_validator_ptr = 0; - - if (0 != (bracket_checker_ptr = dynamic_cast(helper_assembly_.error_token_scanner))) - { - set_error( - make_error(parser_error::e_token, - bracket_checker_ptr->error_token(), - "ERR004 - Mismatched brackets: '" + bracket_checker_ptr->error_token().value + "'")); - } - 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, - "ERR005 - 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, - "ERR006 - 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 settings_store& settings() - { - return settings_; - } - - 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 (!settings_.replacer_enabled()) - return false; - else if (details::is_reserved_word(old_symbol)) - return false; - else - return symbol_replacer_.add_replace(old_symbol,new_symbol,lexer::token::e_symbol); - } - - inline bool remove_replace_symbol(const std::string& symbol) - { - if (!settings_.replacer_enabled()) - return false; - else if (details::is_reserved_word(symbol)) - return false; - else - return symbol_replacer_.remove(symbol); - } - - inline void enable_unknown_symbol_resolver(unknown_symbol_resolver* usr = reinterpret_cast(0)) - { - resolve_unknown_symbol_ = true; - - if (usr) - unknown_symbol_resolver_ = usr; - else - unknown_symbol_resolver_ = &default_usr_; - } - - inline void 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 settings_.function_enabled(symbol) && - (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) - ) && - settings_.function_enabled(symbol); - } - - bool is_invalid_arithmetic_operation(const details::operator_type operation) - { - return settings_.arithmetic_disabled(operation); - } - - bool is_invalid_assignment_operation(const details::operator_type operation) - { - return settings_.assignment_disabled(operation); - } - - bool is_invalid_inequality_operation(const details::operator_type operation) - { - return settings_.inequality_disabled(operation); - } - -#ifdef exprtk_enable_debugging - inline void next_token() - { - std::string ct_str = current_token().value; - parser_helper::next_token(); - std::string depth(2 * state_.scope_depth,' '); - exprtk_debug(("%s" - "prev[%s] --> curr[%s]\n", - depth.c_str(), - ct_str.c_str(), - current_token().value.c_str())); - } -#endif - - inline expression_node_ptr parse_corpus() - { - std::vector arg_list; - std::vector side_effect_list; - - expression_node_ptr result = error_node(); - - scoped_vec_delete sdd(*this,arg_list); - - lexer::token begin_token; - lexer::token end_token; - - for ( ; ; ) - { - state_.side_effect_present = false; - - begin_token = current_token(); - - expression_node_ptr arg = parse_expression(); - - if (0 == arg) - { - if (error_list_.empty()) - { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR007 - Invalid expression encountered")); - } - - return error_node(); - } - else - { - arg_list.push_back(arg); - - side_effect_list.push_back(state_.side_effect_present); - - end_token = current_token(); - - std::string sub_expr = construct_subexpr(begin_token,end_token); - - exprtk_debug(("parse_corpus(%02d) Subexpr: %s\n", - static_cast(arg_list.size() - 1), - sub_expr.c_str())); - - exprtk_debug(("parse_corpus(%02d) - Side effect present: %s\n", - static_cast(arg_list.size() - 1), - state_.side_effect_present ? "true" : "false")); - - exprtk_debug(("-------------------------------------------------\n")); - } - - if (lexer().finished()) - break; - else if (token_is(token_t::e_eof,prsrhlpr_t::e_hold)) - { - if (lexer().finished()) - break; - else - next_token(); - } - } - - if ( - !arg_list.empty() && - is_return_node(arg_list.back()) - ) - { - dec_.final_stmt_return_ = true; - } - - result = simplify(arg_list,side_effect_list); - - sdd.delete_ptr = (0 == result); - - return result; - } - - std::string construct_subexpr(lexer::token& begin_token, lexer::token& end_token) - { - std::string result = lexer().substr(begin_token.position,end_token.position); - - for (std::size_t i = 0; i < result.size(); ++i) - { - if (details::is_whitespace(result[i])) result[i] = ' '; - } - - return result; - } - - static const precedence_level default_precedence = e_level00; - - struct state_t - { - inline void set(const precedence_level& l, - const precedence_level& r, - const details::operator_type& o) - { - left = l; - right = r; - operation = o; - } - - inline void reset() - { - left = e_level00; - right = e_level00; - operation = details::e_default; - } - - precedence_level left; - precedence_level right; - details::operator_type operation; - }; - - inline expression_node_ptr parse_expression(precedence_level precedence = e_level00) - { - 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_level03,e_level04,details::e_and); - break; - } - else if (details::imatch(current_token().value,s_and1)) - { -#ifndef exprtk_disable_sc_andor - current_state.set(e_level03,e_level04,details::e_scand); -#else - current_state.set(e_level03,e_level04,details::e_and); -#endif - break; - } - else if (details::imatch(current_token().value,s_nand)) - { - current_state.set(e_level03,e_level04,details::e_nand); - break; - } - else if (details::imatch(current_token().value,s_or)) - { - current_state.set(e_level01,e_level02,details::e_or); - break; - } - else if (details::imatch(current_token().value,s_or1)) - { -#ifndef exprtk_disable_sc_andor - current_state.set(e_level01,e_level02,details::e_scor); -#else - current_state.set(e_level01,e_level02,details::e_or); -#endif - break; - } - else if (details::imatch(current_token().value,s_nor)) - { - current_state.set(e_level01,e_level02,details::e_nor); - break; - } - else if (details::imatch(current_token().value,s_xor)) - { - current_state.set(e_level01,e_level02,details::e_xor); - break; - } - else if (details::imatch(current_token().value,s_xnor)) - { - current_state.set(e_level01,e_level02,details::e_xnor); - break; - } - else if (details::imatch(current_token().value,s_in)) - { - current_state.set(e_level04,e_level04,details::e_in); - break; - } - else if (details::imatch(current_token().value,s_like)) - { - current_state.set(e_level04,e_level04,details::e_like); - break; - } - else if (details::imatch(current_token().value,s_ilike)) - { - current_state.set(e_level04,e_level04,details::e_ilike); - break; - } - } - - 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 (is_invalid_arithmetic_operation(current_state.operation)) - { - free_node(node_allocator_,expression); - - set_error( - make_error(parser_error::e_syntax, - prev_token, - "ERR008 - Invalid arithmetic operation '" + details::to_str(current_state.operation) + "'")); - - return error_node(); - } - else if (is_invalid_inequality_operation(current_state.operation)) - { - free_node(node_allocator_,expression); - - set_error( - make_error(parser_error::e_syntax, - prev_token, - "ERR009 - Invalid inequality operation '" + details::to_str(current_state.operation) + "'")); - - return error_node(); - } - else if (is_invalid_assignment_operation(current_state.operation)) - { - free_node(node_allocator_,expression); - - set_error( - make_error(parser_error::e_syntax, - prev_token, - "ERR010 - Invalid assignment operation '" + details::to_str(current_state.operation) + "'")); - - return error_node(); - } - - if (0 != (right_branch = parse_expression(current_state.right))) - { - if ( - details::is_return_node( expression) || - details::is_return_node(right_branch) - ) - { - free_node(node_allocator_, expression); - free_node(node_allocator_,right_branch); - - set_error( - make_error(parser_error::e_syntax, - prev_token, - "ERR011 - Return statements cannot be part of sub-expressions")); - - return error_node(); - } - - new_expression = expression_generator_ - ( - current_state.operation, - expression, - right_branch - ); - } - - if (0 == new_expression) - { - if (error_list_.empty()) - { - set_error( - make_error(parser_error::e_syntax, - prev_token, - !synthesis_error_.empty() ? - synthesis_error_ : - "ERR012 - General parsing error at token: '" + prev_token.value + "'")); - } - - free_node(node_allocator_,expression); - - return error_node(); - } - else - { - if ( - token_is(token_t::e_ternary,prsrhlpr_t::e_hold) && - (precedence == e_level00) - ) - { - expression = parse_ternary_conditional_statement(new_expression); - } - else - expression = new_expression; - - 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 > uvn_t; - - uvn_t* n = dynamic_cast(node); - - if (n) - { - const T& v = n->v(); - expression_node_ptr return_node = error_node(); - - if ( - (0 != (return_node = symtab_store_.get_variable(v))) || - (0 != (return_node = sem_ .get_variable(v))) - ) - { - free_node(node_allocator_,node); - node = return_node; - - return true; - } - else - { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR013 - 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&); - }; - - struct scoped_bool_negator - { - scoped_bool_negator(bool& bb) - : b(bb) - { b = !b; } - - ~scoped_bool_negator() - { b = !b; } - - bool& b; - }; - - struct scoped_bool_or_restorer - { - scoped_bool_or_restorer(bool& bb) - : b(bb), - original_value_(bb) - {} - - ~scoped_bool_or_restorer() - { - b = b || original_value_; - } - - bool& b; - bool original_value_; - }; - - 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(), - "ERR014 - 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(), - "ERR015 - 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) - { -#ifdef _MSC_VER -#pragma warning(push) -#pragma warning(disable: 4127) -#endif - if (0 == NumberofParameters) - { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR016 - Expecting ifunction '" + function_name + "' to have non-zero parameter count")); - - return error_node(); - } -#ifdef _MSC_VER -#pragma warning(pop) -#endif - - expression_node_ptr branch[NumberofParameters]; - expression_node_ptr result = error_node(); - - std::fill_n(branch,NumberofParameters,reinterpret_cast(0)); - scoped_delete sd(*this,branch); - - next_token(); - - if (!token_is(token_t::e_lbracket)) - { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR017 - 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(), - "ERR018 - 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(), - "ERR019 - 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(), - "ERR020 - 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); - - state_.side_effect_present = function->has_side_effects(); - - next_token(); - - if ( - token_is(token_t::e_lbracket) && - !token_is(token_t::e_rbracket) - ) - { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR021 - 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(), - "ERR022 - 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(), - "ERR023 - 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(), - "ERR024 - No entry found for base operation: " + operation_name)); - - return error_node(); - } - - static const std::size_t MaxNumberofParameters = 4; - 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 <= MaxNumberofParameters) - { - 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) -#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(), - "ERR025 - 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(), - "ERR026 - 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(), - "ERR027 - 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(), - "ERR028 - 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(), - "ERR029 - 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(), - "ERR030 - Expected ')' at the end of if-statement")); - result = false; - } - -#ifndef exprtk_disable_string_capabilities - if (result) - { - const bool consq_is_str = is_generally_string_node( consequent); - const bool alter_is_str = is_generally_string_node(alternative); - - if (consq_is_str || alter_is_str) - { - if (consq_is_str && alter_is_str) - { - return expression_generator_ - .conditional_string(condition,consequent,alternative); - } - - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR031 - Return types of ternary if-statement differ")); - - result = false; - } - } -#endif - - if (!result) - { - free_node(node_allocator_, condition); - free_node(node_allocator_, consequent); - free_node(node_allocator_,alternative); - - return error_node(); - } - else - return expression_generator_ - .conditional(condition,consequent,alternative); - } - - inline expression_node_ptr parse_conditional_statement_02(expression_node_ptr condition) - { - expression_node_ptr consequent = error_node(); - expression_node_ptr alternative = error_node(); - - bool result = true; - - if (token_is(token_t::e_lcrlbracket,prsrhlpr_t::e_hold)) - { - if (0 == (consequent = parse_multi_sequence("if-statement-01"))) - { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR032 - Failed to parse body of consequent for if-statement")); - result = false; - } - } - else - { - if ( - settings_.commutative_check_enabled() && - token_is(token_t::e_mul,prsrhlpr_t::e_hold) - ) - { - next_token(); - } - - if (0 != (consequent = parse_expression())) - { - if (!token_is(token_t::e_eof)) - { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR033 - Expected ';' at the end of the consequent for if-statement")); - result = false; - } - } - else - { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR034 - 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,prsrhlpr_t::e_hold)) - { - if (0 == (alternative = parse_multi_sequence("else-statement-01"))) - { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR035 - 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(), - "ERR036 - 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(), - "ERR037 - 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(), - "ERR038 - Failed to parse body of the 'else' for if-statement")); - result = false; - } - } - } - -#ifndef exprtk_disable_string_capabilities - if (result) - { - const bool consq_is_str = is_generally_string_node( consequent); - const bool alter_is_str = is_generally_string_node(alternative); - - if (consq_is_str || alter_is_str) - { - if (consq_is_str && alter_is_str) - { - return expression_generator_ - .conditional_string(condition,consequent,alternative); - } - - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR039 - Return types of ternary if-statement differ")); - - result = false; - } - } -#endif - - 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(), - "ERR040 - 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(), - "ERR041 - Failed to parse condition for if-statement")); - - return error_node(); - } - else if (token_is(token_t::e_comma,prsrhlpr_t::e_hold)) - { - // if (x,y,z) - return parse_conditional_statement_01(condition); - } - else if (token_is(token_t::e_rbracket)) - { - // 00. if (x) y; - // 01. if (x) y; else z; - // 02. if (x) y; else {z0; ... zn;} - // 03. if (x) y; else if (z) w; - // 04. if (x) y; else if (z) w; else u; - // 05. if (x) y; else if (z) w; else {u0; ... un;} - // 06. if (x) y; else if (z) {w0; ... wn;} - // 07. if (x) {y0; ... yn;} - // 08. if (x) {y0; ... yn;} else z; - // 09. if (x) {y0; ... yn;} else {z0; ... zn;}; - // 10. if (x) {y0; ... yn;} else if (z) w; - // 11. if (x) {y0; ... yn;} else if (z) w; else u; - // 12. if (x) {y0; ... nex;} else if (z) w; else {u0 ... un;} - // 13. if (x) {y0; ... yn;} else if (z) {w0; ... wn;} - return parse_conditional_statement_02(condition); - } - - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR042 - 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(), - "ERR043 - 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(), - "ERR044 - 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(), - "ERR045 - Failed to parse consequent for ternary if-statement")); - - result = false; - } - else if (!token_is(token_t::e_colon)) - { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR046 - 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(), - "ERR047 - Failed to parse alternative for ternary if-statement")); - - result = false; - } - -#ifndef exprtk_disable_string_capabilities - if (result) - { - const bool consq_is_str = is_generally_string_node( consequent); - const bool alter_is_str = is_generally_string_node(alternative); - - if (consq_is_str || alter_is_str) - { - if (consq_is_str && alter_is_str) - { - return expression_generator_ - .conditional_string(condition,consequent,alternative); - } - - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR048 - Return types of ternary if-statement differ")); - - result = false; - } - } -#endif - - 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(), - "ERR049 - 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(), - "ERR050 - 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(), - "ERR051 - 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(), - "ERR052 - 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(), - "ERR053 - 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; - std::vector side_effect_list; - - scoped_vec_delete sdd(*this,arg_list); - - brkcnt_list_.push_front(false); - - if (details::imatch(current_token().value,"until")) - { - next_token(); - branch = node_allocator_.allocate >(); - } - else - { - token_t::token_type seperator = token_t::e_eof; - - scope_handler sh(*this); - - scoped_bool_or_restorer sbr(state_.side_effect_present); - - for ( ; ; ) - { - state_.side_effect_present = false; - - expression_node_ptr arg = parse_expression(); - - if (0 == arg) - return error_node(); - else - { - arg_list.push_back(arg); - side_effect_list.push_back(state_.side_effect_present); - } - - if (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(), - "ERR054 - Expected '" + token_t::to_str(seperator) + "' in body of repeat until loop")); - - return error_node(); - } - - if (details::imatch(current_token().value,"until")) - { - next_token(); - break; - } - } - - branch = simplify(arg_list,side_effect_list); - - sdd.delete_ptr = (0 == branch); - - if (sdd.delete_ptr) - { - brkcnt_list_.pop_front(); - - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR055 - 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(), - "ERR056 - 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(), - "ERR057 - 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(), - "ERR058 - 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(), - "ERR059 - 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(), - "ERR060 - Expected '(' at start of for-loop")); - - return error_node(); - } - - if (!token_is(token_t::e_eof)) - { - if ( - !token_is(token_t::e_symbol,prsrhlpr_t::e_hold) && - details::imatch(current_token().value,"var") - ) - { - next_token(); - - if (!token_is(token_t::e_symbol,prsrhlpr_t::e_hold)) - { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR061 - 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(), - "ERR062 - 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(), - "ERR063 - For-loop variable '" + loop_counter_symbol+ "' is being shadowed by a previous declaration")); - - return error_node(); - } - else if (!symtab_store_.is_variable(loop_counter_symbol)) - { - if ( - !se->active && - (se->name == loop_counter_symbol) && - (se->type == scope_element::e_variable) - ) - { - se->active = true; - se->ref_count++; - } - else - { - scope_element nse; - nse.name = loop_counter_symbol; - nse.active = true; - nse.ref_count = 1; - nse.type = scope_element::e_variable; - nse.depth = state_.scope_depth; - nse.data = new T(T(0)); - nse.var_node = node_allocator_.allocate(*(T*)(nse.data)); - - if (!sem_.add_element(nse)) - { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR064 - Failed to add new local variable '" + loop_counter_symbol + "' to SEM")); - - sem_.free_element(nse); - - result = false; - } - else - { - exprtk_debug(("parse_for_loop() - INFO - Added new local variable: %s\n",nse.name.c_str())); - - state_.activate_side_effect("parse_for_loop()"); - } - } - } - } - - if (0 == (initialiser = parse_expression())) - { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR065 - Failed to parse initialiser of for-loop")); - result = false; - } - else if (!token_is(token_t::e_eof)) - { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR066 - 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(), - "ERR067 - 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(), - "ERR068 - 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(), - "ERR069 - 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(), - "ERR070 - 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(), - "ERR071 - 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(), - "ERR072 - 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(), - "ERR073 - 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(), - "ERR074 - 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(), - "ERR075 - 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(), - "ERR076 - Expected ';' at end of case for switch statement")); - - return error_node(); - } - - // Can we optimise away the case statement? - if (is_constant_node(condition) && is_false(condition)) - { - free_node(node_allocator_, condition); - free_node(node_allocator_,consequent); - - 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(), - "ERR077 - Expected ':' for default of switch statement")); - - return error_node(); - } - - expression_node_ptr default_statement = error_node(); - - if (token_is(token_t::e_lcrlbracket,prsrhlpr_t::e_hold)) - default_statement = parse_multi_sequence("switch-default"); - else - default_statement = parse_expression(); - - if (0 == default_statement) - return error_node(); - else if (!token_is(token_t::e_eof)) - { - free_node(node_allocator_,default_statement); - - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR078 - 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(), - "ERR079 - 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(), - "ERR080 - 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(), - "ERR081 - 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(), - "ERR082 - 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(), - "ERR083 - 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(), - "ERR084 - Expected ';' at end of case for [*] statement")); - - return error_node(); - } - - // Can we optimise away the case statement? - if (is_constant_node(condition) && is_false(condition)) - { - free_node(node_allocator_, condition); - free_node(node_allocator_,consequent); - - condition = 0; - consequent = 0; - } - else - { - arg_list.push_back(condition); - arg_list.push_back(consequent); - } - - if (token_is(token_t::e_rcrlbracket,prsrhlpr_t::e_hold)) - { - break; - } - } - - if (!token_is(token_t::e_rcrlbracket)) - { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR085 - 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(), - "ERR086 - Unsupported vararg function: " + symbol)); - - return error_node(); - } - - scoped_vec_delete sdd(*this,arg_list); - - lodge_symbol(symbol,e_st_function); - - next_token(); - - if (!token_is(token_t::e_lbracket)) - { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR087 - 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(), - "ERR088 - 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; - } - -#ifndef exprtk_disable_string_capabilities - inline expression_node_ptr parse_string_range_statement(expression_node_ptr& expression) - { - if (!token_is(token_t::e_lsqrbracket)) - { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR089 - 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(), - "ERR090 - Failed to generate string range node")); - - free_node(node_allocator_,expression); - } - - rp.clear(); - - return result; - } -#else - inline expression_node_ptr parse_string_range_statement(expression_node_ptr&) - { - return error_node(); - } -#endif - - inline void parse_pending_string_rangesize(expression_node_ptr& expression) - { - // Allow no more than 100 range calls, eg: s[][][]...[][] - const std::size_t max_rangesize_parses = 100; - - std::size_t i = 0; - - while - ( - (0 != expression) && - (i++ < max_rangesize_parses) && - error_list_.empty() && - is_generally_string_node(expression) && - token_is(token_t::e_lsqrbracket,prsrhlpr_t::e_hold) - ) - { - expression = parse_string_range_statement(expression); - } - } - - template class Sequence> - inline expression_node_ptr simplify(Sequence& expression_list, - Sequence& side_effect_list) - { - if (expression_list.empty()) - return error_node(); - else if (1 == expression_list.size()) - return expression_list[0]; - - Sequence tmp_expression_list; - - bool return_node_present = false; - - for (std::size_t i = 0; i < (expression_list.size() - 1); ++i) - { - if (is_variable_node(expression_list[i])) - continue; - else if ( - is_return_node (expression_list[i]) || - is_break_node (expression_list[i]) || - is_continue_node(expression_list[i]) - ) - { - tmp_expression_list.push_back(expression_list[i]); - - // Remove all subexpressions after first short-circuit - // node has been encountered. - - for (std::size_t j = i + 1; j < expression_list.size(); ++j) - { - free_node(node_allocator_,expression_list[j]); - } - - return_node_present = true; - - break; - } - else if ( - is_constant_node(expression_list[i]) || - is_null_node (expression_list[i]) || - !side_effect_list[i] - ) - { - free_node(node_allocator_,expression_list[i]); - continue; - } - else - tmp_expression_list.push_back(expression_list[i]); - } - - if (!return_node_present) - { - tmp_expression_list.push_back(expression_list.back()); - } - - expression_list.swap(tmp_expression_list); - - if (tmp_expression_list.size() > expression_list.size()) - { - exprtk_debug(("simplify() - Reduced subexpressions from %d to %d\n", - static_cast(tmp_expression_list.size()), - static_cast(expression_list .size()))); - } - - if ( - return_node_present || - side_effect_list.back() || - (expression_list.size() > 1) - ) - state_.activate_side_effect("simplify()"); - - if (1 == expression_list.size()) - return expression_list[0]; - else - 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(), - "ERR091 - 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; - std::vector side_effect_list; - - expression_node_ptr result = error_node(); - - scoped_vec_delete sdd(*this,arg_list); - - scope_handler sh(*this); - - scoped_bool_or_restorer sbr(state_.side_effect_present); - - for ( ; ; ) - { - state_.side_effect_present = false; - - expression_node_ptr arg = parse_expression(); - - if (0 == arg) - return error_node(); - else - { - arg_list.push_back(arg); - side_effect_list.push_back(state_.side_effect_present); - } - - if (token_is(close_bracket)) - break; - - 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(), - "ERR092 - 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,side_effect_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(), - "ERR093 - 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(), - "ERR094 - 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(), - "ERR095 - 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(), - "ERR096 - 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(), - "ERR097 - 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(), - "ERR098 - 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(), - "ERR099 - 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(), - "ERR100 - 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); - } - -#ifndef exprtk_disable_string_capabilities - inline expression_node_ptr parse_string() - { - const std::string symbol = current_token().value; - - typedef details::stringvar_node* strvar_node_t; - - expression_node_ptr result = error_node(); - strvar_node_t const_str_node = static_cast(0); - bool is_const_string = false; - - scope_element& se = sem_.get_active_element(symbol); - - if (scope_element::e_string == se.type) - { - se.active = true; - result = se.str_node; - lodge_symbol(symbol,e_st_local_string); - } - else - { - if (!symtab_store_.is_conststr_stringvar(symbol)) - { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR101 - Unknown string symbol")); - - return error_node(); - } - - result = symtab_store_.get_stringvar(symbol); - - is_const_string = symtab_store_.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; - } -#else - inline expression_node_ptr parse_string() - { - return error_node(); - } -#endif - -#ifndef exprtk_disable_string_capabilities - inline expression_node_ptr parse_const_string() - { - const std::string const_str = current_token().value; - expression_node_ptr result = expression_generator_(const_str); - - if (peek_token_is(token_t::e_lsqrbracket)) - { - next_token(); - - if (peek_token_is(token_t::e_rsqrbracket)) - { - next_token(); - next_token(); - - free_node(node_allocator_,result); - - return expression_generator_(T(const_str.size())); - } - - range_t rp; - - if (!parse_range(rp)) - { - free_node(node_allocator_,result); - - 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(), - "ERR102 - Overflow in range for string: '" + const_str + "'[" + - (rp.n0_c.first ? details::to_str(static_cast(rp.n0_c.second)) : "?") + ":" + - (rp.n1_c.first ? details::to_str(static_cast(rp.n1_c.second)) : "?") + "]")); - - return error_node(); - } - - result = expression_generator_(const_str,rp); - - if (result) - rp.clear(); - } - else - next_token(); - - return result; - } -#else - inline expression_node_ptr parse_const_string() - { - return error_node(); - } -#endif - - inline expression_node_ptr parse_vector() - { - const std::string symbol = current_token().value; - - vector_holder_ptr vec = vector_holder_ptr(0); - - const scope_element& se = sem_.get_active_element(symbol); - - if ( - (se.name != symbol) || - (se.depth > state_.scope_depth) || - (scope_element::e_vector != se.type) - ) - { - if (0 == (vec = symtab_store_.get_vector(symbol))) - { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR103 - 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(), - "ERR104 - 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(), - "ERR105 - 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)) - { - if (!vararg_function->allow_zero_parameters()) - { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR106 - Zero parameter call to vararg function: " - + vararg_function_name + " not allowed")); - - return error_node(); - } - } - else - { - for ( ; ; ) - { - expression_node_ptr arg = parse_expression(); - - if (0 == arg) - return error_node(); - else - arg_list.push_back(arg); - - if (token_is(token_t::e_rbracket)) - break; - else if (!token_is(token_t::e_comma)) - { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR107 - Expected ',' for call to vararg function: " - + vararg_function_name)); - - return error_node(); - } - } - } - } - else if (!vararg_function->allow_zero_parameters()) - { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR108 - Zero parameter call to vararg function: " - + vararg_function_name + " not allowed")); - - return error_node(); - } - - if (arg_list.size() < vararg_function->min_num_args()) - { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR109 - Invalid number of parameters to call to vararg function: " - + vararg_function_name + ", require at least " - + details::to_str(static_cast(vararg_function->min_num_args())) + " parameters")); - - return error_node(); - } - else if (arg_list.size() > vararg_function->max_num_args()) - { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR110 - Invalid number of parameters to call to vararg function: " - + vararg_function_name + ", require no more than " - + details::to_str(static_cast(vararg_function->max_num_args())) + " parameters")); - - 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) - { - details::char_t diff_value = 0; - std::size_t diff_index = 0; - - bool result = details::sequence_match(param_seq_list_[i], - param_seq, - diff_index,diff_value); - - 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(), - "ERR111 - 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(), - "ERR112 - 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_; - } - - bool allow_zero_parameters() const - { - return - param_seq_list_.end() != std::find(param_seq_list_.begin(), - param_seq_list_.end(), - "Z"); - } - - 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 ("Z" == curr_str) - { - psl.push_back(curr_str); - return true; - } - else if (std::string::npos == curr_str.find_first_not_of("STV*?|")) - { - psl.push_back(curr_str); - return true; - } - } - - 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(), - "ERR113 - 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(), - "ERR114 - 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(), - "ERR115 - Type checker instantiation failure for generic function: " + function_name)); - - return error_node(); - } - - if ( - !function->parameter_sequence.empty() && - function->allow_zero_parameters () && - !tc .allow_zero_parameters () - ) - { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR116 - Mismatch in zero parameter condition for generic function: " - + function_name)); - - return error_node(); - } - - if (token_is(token_t::e_lbracket)) - { - if (token_is(token_t::e_rbracket)) - { - if ( - !function->allow_zero_parameters() && - !tc .allow_zero_parameters() - ) - { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR117 - Zero parameter call to generic function: " - + function_name + " not allowed")); - - return error_node(); - } - } - else - { - for ( ; ; ) - { - expression_node_ptr arg = parse_expression(); - - if (0 == arg) - return error_node(); - - if (is_ivector_node(arg)) - param_type_list += 'V'; - else if (is_generally_string_node(arg)) - param_type_list += 'S'; - else // Everything else is assumed to be a scalar returning expression - param_type_list += 'T'; - - arg_list.push_back(arg); - - if (token_is(token_t::e_rbracket)) - break; - else if (!token_is(token_t::e_comma)) - { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR118 - Expected ',' for call to generic function: " + function_name)); - - return error_node(); - } - } - } - } - else if ( - !function->parameter_sequence.empty() && - function->allow_zero_parameters () && - !tc .allow_zero_parameters () - ) - { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR119 - Zero parameter call to generic function: " - + function_name + " not allowed")); - - 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(), - "ERR120 - 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); - + }; + }; + + #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 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(), - "ERR121 - 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(), - "ERR122 - 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); - + } + + 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; - } - - 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(), - "ERR123 - 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(), - "ERR124 - 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(), - "ERR125 - 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(), - "ERR126 - 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 (state_.parsing_break_stmt) - { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR127 - Break call within a break call is not allowed")); - - return error_node(); - } - - scoped_bool_negator sbn(state_.parsing_break_stmt); - - if (!brkcnt_list_.empty()) - { - next_token(); - - brkcnt_list_.front() = true; - - expression_node_ptr return_expr = error_node(); - - if (token_is(token_t::e_lsqrbracket)) - { - if (0 == (return_expr = parse_expression())) - { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR128 - 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(), - "ERR129 - Expected ']' at the completion of break's return expression")); - - free_node(node_allocator_,return_expr); - - return error_node(); - } - } - - state_.activate_side_effect("parse_break_statement()"); - - return node_allocator_.allocate >(return_expr); - } - else - { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR130 - 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; - state_.activate_side_effect("parse_continue_statement()"); - - return node_allocator_.allocate >(); - } - else - { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR131 - 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(), - "ERR132 - 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(), - "ERR133 - 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(), - "ERR134 - 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(), - "ERR135 - 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; - bool vec_to_vec_initialiser = false; - bool null_initialisation = false; - - if (!token_is(token_t::e_rsqrbracket)) - { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR136 - 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(), - "ERR137 - 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(), - "ERR138 - 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(), - "ERR139 - Expected ']' to close single value vector initialiser")); - - return error_node(); - } - - single_value_initialiser = true; - } - else if (!token_is(token_t::e_lcrlbracket)) - { - expression_node_ptr initialiser = error_node(); - - // Is this a vector to vector assignment and initialisation? - if (token_t::e_symbol == current_token().type) - { - // Is it a locally defined vector? - scope_element& se = sem_.get_active_element(current_token().value); - - if (scope_element::e_vector == se.type) - { - if (0 != (initialiser = parse_expression())) - vec_initilizer_list.push_back(initialiser); - else - return error_node(); - } - // Are we dealing with a user defined vector? - else if (symtab_store_.is_vector(current_token().value)) - { - lodge_symbol(current_token().value,e_st_vector); - - if (0 != (initialiser = parse_expression())) - vec_initilizer_list.push_back(initialiser); - else - return error_node(); - } - // Are we dealing with a null initialisation vector definition? - else if (token_is(token_t::e_symbol,"null")) - null_initialisation = true; - } - - if (!null_initialisation) - { - if (0 == initialiser) - { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR140 - Expected '{' as part of vector initialiser list")); - - return error_node(); - } - else - vec_to_vec_initialiser = true; - } - } - else if (!token_is(token_t::e_rcrlbracket)) - { - for ( ; ; ) - { - expression_node_ptr initialiser = parse_expression(); - - if (0 == initialiser) - { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR141 - 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(), - "ERR142 - Expected ',' between vector initialisers")); - - return error_node(); - } - - if (token_is(token_t::e_rcrlbracket)) - break; - } - } - - if ( - !token_is(token_t::e_rbracket ,prsrhlpr_t::e_hold) && - !token_is(token_t::e_rcrlbracket,prsrhlpr_t::e_hold) && - !token_is(token_t::e_rsqrbracket,prsrhlpr_t::e_hold) - ) - { - if (!token_is(token_t::e_eof)) - { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR143 - 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(), - "ERR144 - 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(), - "ERR145 - 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.depth = state_.scope_depth; - se.ref_count++; - } - } - - if (0 == vec_holder) - { - scope_element nse; - nse.name = vec_name; - nse.active = true; - nse.ref_count = 1; - nse.type = scope_element::e_vector; - nse.depth = state_.scope_depth; - nse.size = vec_size; - nse.data = new T[vec_size]; - nse.vec_node = new typename scope_element::vector_holder_t((T*)(nse.data),nse.size); - - if (!sem_.add_element(nse)) - { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR146 - Failed to add new local vector '" + vec_name + "' to SEM")); - - sem_.free_element(nse); - - return error_node(); - } - - vec_holder = nse.vec_node; - - exprtk_debug(("parse_define_vector_statement() - INFO - Added new local vector: %s[%d]\n", - nse.name.c_str(), - static_cast(nse.size))); - } - - state_.activate_side_effect("parse_define_vector_statement()"); - - lodge_symbol(vec_name,e_st_local_vector); - - expression_node_ptr result = error_node(); - - if (null_initialisation) - result = expression_generator_(T(0.0)); - else if (vec_to_vec_initialiser) - result = expression_generator_( - details::e_assign, - node_allocator_.allocate(vec_holder), - vec_initilizer_list[0]); - else - result = node_allocator_ - .allocate >( - (*vec_holder)[0], - vec_size, - vec_initilizer_list, - single_value_initialiser); - - svd.delete_ptr = (0 == result); - + } + + 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; - } - -#ifndef exprtk_disable_string_capabilities - inline expression_node_ptr parse_define_string_statement(const std::string& str_name, expression_node_ptr initialisation_expression) - { - stringvar_node_t* str_node = reinterpret_cast(0); - - scope_element& se = sem_.get_element(str_name); - - if (se.name == str_name) - { - if (se.active) - { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR147 - Illegal redefinition of local variable: '" + str_name + "'")); - - free_node(node_allocator_,initialisation_expression); - - return error_node(); - } - else if (scope_element::e_string == se.type) - { - str_node = se.str_node; - se.active = true; - se.depth = state_.scope_depth; - se.ref_count++; - } - } - - if (0 == str_node) - { - scope_element nse; - nse.name = str_name; - nse.active = true; - nse.ref_count = 1; - nse.type = scope_element::e_string; - nse.depth = state_.scope_depth; - nse.data = new std::string; - nse.str_node = new stringvar_node_t(*(std::string*)(nse.data)); - - if (!sem_.add_element(nse)) - { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR148 - Failed to add new local string variable '" + str_name + "' to SEM")); - - free_node(node_allocator_,initialisation_expression); - - sem_.free_element(nse); - - return error_node(); - } - - str_node = nse.str_node; - - exprtk_debug(("parse_define_string_statement() - INFO - Added new local string variable: %s\n",nse.name.c_str())); - } - - lodge_symbol(str_name,e_st_local_string); - - state_.activate_side_effect("parse_define_string_statement()"); - - expression_node_ptr branch[2] = {0}; - - branch[0] = str_node; - branch[1] = initialisation_expression; - - return expression_generator_(details::e_assign,branch); - } -#else - inline expression_node_ptr parse_define_string_statement(const std::string&, expression_node_ptr) - { - return error_node(); - } -#endif - - inline bool local_variable_is_shadowed(const std::string& symbol) - { - const scope_element& se = sem_.get_element(symbol); - return (se.name == symbol) && se.active; - } - - inline expression_node_ptr parse_define_var_statement() - { - if (settings_.vardef_disabled()) - { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR149 - 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(), - "ERR150 - 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(), - "ERR151 - Illegal redefinition of reserved keyword: '" + var_name + "'")); - - return error_node(); - } - else if (symtab_store_.symbol_exists(var_name)) - { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR152 - 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(), - "ERR153 - Illegal redefinition of local variable: '" + var_name + "'")); - - return error_node(); - } - else if (token_is(token_t::e_lsqrbracket,prsrhlpr_t::e_hold)) - { - return parse_define_vector_statement(var_name); - } - else if (token_is(token_t::e_lcrlbracket,prsrhlpr_t::e_hold)) - { - return parse_uninitialised_var_statement(var_name); - } - else if (token_is(token_t::e_assign)) - { - if (0 == (initialisation_expression = parse_expression())) - { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR154 - Failed to parse initialisation expression")); - - return error_node(); - } - } - - if ( - !token_is(token_t::e_rbracket ,prsrhlpr_t::e_hold) && - !token_is(token_t::e_rcrlbracket,prsrhlpr_t::e_hold) && - !token_is(token_t::e_rsqrbracket,prsrhlpr_t::e_hold) - ) - { - if (!token_is(token_t::e_eof,prsrhlpr_t::e_hold)) - { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR155 - Expected ';' after variable definition")); - - free_node(node_allocator_,initialisation_expression); - - return error_node(); - } - } - - if ( - (0 != initialisation_expression) && - details::is_generally_string_node(initialisation_expression) - ) - { - return parse_define_string_statement(var_name,initialisation_expression); - } - - expression_node_ptr var_node = reinterpret_cast(0); - - scope_element& se = sem_.get_element(var_name); - - if (se.name == var_name) - { - if (se.active) - { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR156 - 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.depth = state_.scope_depth; - se.ref_count++; - } - } - - if (0 == var_node) - { - scope_element nse; - nse.name = var_name; - nse.active = true; - nse.ref_count = 1; - nse.type = scope_element::e_variable; - nse.depth = state_.scope_depth; - nse.data = new T(T(0)); - nse.var_node = node_allocator_.allocate(*(T*)(nse.data)); - - if (!sem_.add_element(nse)) - { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR157 - Failed to add new local variable '" + var_name + "' to SEM")); - - free_node(node_allocator_,initialisation_expression); - - sem_.free_element(nse); - - return error_node(); - } - - var_node = nse.var_node; - - exprtk_debug(("parse_define_var_statement() - INFO - Added new local variable: %s\n",nse.name.c_str())); - } - - state_.activate_side_effect("parse_define_var_statement()"); - - lodge_symbol(var_name,e_st_local_variable); - - expression_node_ptr branch[2] = {0}; - - branch[0] = var_node; - branch[1] = initialisation_expression ? initialisation_expression : expression_generator_(T(0)); - - return expression_generator_(details::e_assign,branch); - } - - inline expression_node_ptr parse_uninitialised_var_statement(const std::string& var_name) - { - if ( - !token_is(token_t::e_lcrlbracket) || - !token_is(token_t::e_rcrlbracket) - ) - { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR158 - Expected a '{}' for uninitialised var definition")); - - return error_node(); - } - else if (!token_is(token_t::e_eof,prsrhlpr_t::e_hold)) - { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR159 - Expected ';' after uninitialised variable definition")); - - return error_node(); - } - - expression_node_ptr var_node = reinterpret_cast(0); - - scope_element& se = sem_.get_element(var_name); - - if (se.name == var_name) - { - if (se.active) - { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR160 - 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 = state_.scope_depth; - nse.ip_index = sem_.next_ip_index(); - nse.data = new T(T(0)); - nse.var_node = node_allocator_.allocate(*(T*)(nse.data)); - - if (!sem_.add_element(nse)) - { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR161 - Failed to add new local variable '" + var_name + "' to SEM")); - - sem_.free_element(nse); - - return error_node(); - } - - exprtk_debug(("parse_uninitialised_var_statement() - INFO - Added new local variable: %s\n", - nse.name.c_str())); - } - - lodge_symbol(var_name,e_st_local_variable); - - state_.activate_side_effect("parse_uninitialised_var_statement()"); - - return expression_generator_(T(0)); - } - - inline expression_node_ptr parse_swap_statement() - { - if (!details::imatch(current_token().value,"swap")) - { - return error_node(); - } - else - next_token(); - - if (!token_is(token_t::e_lbracket)) - { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR162 - 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,prsrhlpr_t::e_hold)) - { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR163 - 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(), - "ERR164 - First parameter to swap is an invalid vector element: '" + var0_name + "'")); - - return error_node(); - } - - variable0_generated = true; - } + } + + 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 ~sf3ext_type_node() + {} + + 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 - { - if (symtab_store_.is_variable(var0_name)) - { - variable0 = symtab_store_.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(), - "ERR165 - 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(), - "ERR166 - 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,prsrhlpr_t::e_hold)) - { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR167 - 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(), - "ERR168 - 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; - } + 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 - { - if (symtab_store_.is_variable(var1_name)) - { - variable1 = symtab_store_.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(), - "ERR169 - 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(), - "ERR170 - 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); - - expression_node_ptr result = error_node(); - + 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 ( - (0 != (v0 = dynamic_cast(variable0))) && - (0 != (v1 = dynamic_cast(variable1))) - ) - { - result = node_allocator_.allocate >(v0,v1); - - if (variable0_generated) - { - free_node(node_allocator_,variable0); - } - - if (variable1_generated) - { - free_node(node_allocator_,variable1); - } - } - else - result = node_allocator_.allocate >(variable0,variable1); - - state_.activate_side_effect("parse_swap_statement()"); - - return result; - } - - inline expression_node_ptr parse_return_statement() - { - if (state_.parsing_return_stmt) + rp0_(r0_0,r1_0,s0_.size()) && + rp1_(r0_1,r1_1,s1_.size()) + ) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR171 - Return call within a return call is not allowed")); - - return error_node(); - } - - scoped_bool_negator sbn(state_.parsing_return_stmt); - - std::vector arg_list; - - scoped_vec_delete sdd(*this,arg_list); - - if (!details::imatch(current_token().value,"return")) - { - return error_node(); + return Operation::process( + s0_.substr(r0_0,(r1_0 - r0_0) + 1), + s1_.substr(r0_1,(r1_1 - r0_1) + 1) + ); } else - next_token(); - - if (!token_is(token_t::e_lsqrbracket)) - { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR172 - Expected '[' at start of return statement")); - - return error_node(); - } - else if (!token_is(token_t::e_rsqrbracket)) - { - for ( ; ; ) - { - expression_node_ptr arg = parse_expression(); - - if (0 == arg) - return error_node(); - - arg_list.push_back(arg); - - if (token_is(token_t::e_rsqrbracket)) - break; - else if (!token_is(token_t::e_comma)) - { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR173 - Expected ',' between values during call to return")); - - return error_node(); - } - } + 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()); } - else if (settings_.zero_return_disabled()) + + if (is_generally_string_node(binary_node::branch_[1].first)) { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR174 - Zero parameter return statement not allowed")); - - return error_node(); + 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()); } - - lexer::token prev_token = current_token(); - - if (token_is(token_t::e_rsqrbracket)) - { - if (!arg_list.empty()) - { - set_error( - make_error(parser_error::e_syntax, - prev_token, - "ERR175 - Invalid ']' found during return call")); - - return error_node(); - } - } - - std::string ret_param_type_list; - - for (std::size_t i = 0; i < arg_list.size(); ++i) - { - if (0 == arg_list[i]) - return error_node(); - else if (is_ivector_node(arg_list[i])) - ret_param_type_list += 'V'; - else if (is_generally_string_node(arg_list[i])) - ret_param_type_list += 'S'; - else - ret_param_type_list += 'T'; - } - - dec_.retparam_list_.push_back(ret_param_type_list); - - expression_node_ptr result = expression_generator_.return_call(arg_list); - - sdd.delete_ptr = (0 == result); - - state_.return_stmt_present = true; - - state_.activate_side_effect("parse_return_statement()"); - - return result; - } - - inline bool post_variable_process(const std::string& symbol) - { + } + + inline T value() const + { if ( - peek_token_is(token_t::e_lbracket ) || - peek_token_is(token_t::e_lcrlbracket) || - peek_token_is(token_t::e_lsqrbracket) - ) - { - if (!settings_.commutative_check_enabled()) - { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR176 - 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; - - const lexer::parser_helper::token_advance_mode hold = prsrhlpr_t::e_hold; - - switch (token) - { - case token_t::e_lcrlbracket : implied_mul = token_is(token_t::e_lbracket ,hold) || - token_is(token_t::e_lcrlbracket,hold) || - token_is(token_t::e_lsqrbracket,hold) ; - break; - - case token_t::e_lbracket : implied_mul = token_is(token_t::e_lbracket ,hold) || - token_is(token_t::e_lcrlbracket,hold) || - token_is(token_t::e_lsqrbracket,hold) ; - break; - - case token_t::e_lsqrbracket : implied_mul = token_is(token_t::e_lbracket ,hold) || - token_is(token_t::e_lcrlbracket,hold) || - token_is(token_t::e_lsqrbracket,hold) ; - break; - - default : return true; - } - - if (implied_mul) - { - if (!settings_.commutative_check_enabled()) - { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR177 - 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 = symtab_store_.get_variable(symbol); - - if (variable) - { - if (symtab_store_.is_constant_node(symbol)) - { - variable = expression_generator_(variable->value()); - } - - if (!post_variable_process(symbol)) - return error_node(); - - lodge_symbol(symbol,e_st_variable); - next_token(); - - return variable; - } - - // Are we dealing with a locally defined variable, vector or string? - if (!sem_.empty()) - { - scope_element& se = sem_.get_active_element(symbol); - - if (se.active && (se.name == symbol)) - { - if (scope_element::e_variable == se.type) - { - se.active = true; - lodge_symbol(symbol,e_st_local_variable); - - if (!post_variable_process(symbol)) - return error_node(); - - next_token(); - - return se.var_node; - } - else if (scope_element::e_vector == se.type) - { - return parse_vector(); - } -#ifndef exprtk_disable_string_capabilities - else if (scope_element::e_string == se.type) - { - return parse_string(); - } -#endif - } - } - -#ifndef exprtk_disable_string_capabilities - // Are we dealing with a string variable? - if (symtab_store_.is_stringvar(symbol)) - { - return parse_string(); - } -#endif - - { - // Are we dealing with a function? - ifunction* function = symtab_store_.get_function(symbol); - - if (function) - { - lodge_symbol(symbol,e_st_function); - - expression_node_ptr func_node = - parse_function_invocation(function,symbol); - - if (func_node) - return func_node; - else - { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR178 - Failed to generate node for function: '" + symbol + "'")); - - return error_node(); - } - } - } - - { - // Are we dealing with a vararg function? - ivararg_function* vararg_function = symtab_store_.get_vararg_function(symbol); - - if (vararg_function) - { - lodge_symbol(symbol,e_st_function); - - expression_node_ptr vararg_func_node = - parse_vararg_function_call(vararg_function,symbol); - - if (vararg_func_node) - return vararg_func_node; - else - { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR179 - Failed to generate node for vararg function: '" + symbol + "'")); - - return error_node(); - } - } - } - - { - // Are we dealing with a vararg generic function? - igeneric_function* generic_function = symtab_store_.get_generic_function(symbol); - - if (generic_function) - { - lodge_symbol(symbol,e_st_function); - - expression_node_ptr genericfunc_node = - parse_generic_function_call(generic_function,symbol); - - if (genericfunc_node) - return genericfunc_node; - else - { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR180 - Failed to generate node for generic function: '" + symbol + "'")); - - return error_node(); - } - } - } - - { - // Are we dealing with a vararg string returning function? - igeneric_function* string_function = symtab_store_.get_string_function(symbol); - - if (string_function) - { - lodge_symbol(symbol,e_st_function); - - expression_node_ptr stringfunc_node = - parse_string_function_call(string_function,symbol); - - if (stringfunc_node) - return stringfunc_node; - else - { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR181 - Failed to generate node for string function: '" + symbol + "'")); - - return error_node(); - } - } - } - - // Are we dealing with a vector? - if (symtab_store_.is_vector(symbol)) - { - lodge_symbol(symbol,e_st_vector); - return parse_vector(); - } - - if (details::is_reserved_symbol(symbol)) - { - if (settings_.function_enabled(symbol) || !details::is_base_function(symbol)) - { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR182 - Invalid use of reserved symbol '" + symbol + "'")); - - return error_node(); - } - } - - // Should we handle unknown symbols? - if (resolve_unknown_symbol_ && unknown_symbol_resolver_) - { - if (!(settings_.rsrvd_sym_usr_disabled() && details::is_reserved_symbol(symbol))) - { - 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; - - symbol_table_t& symtab = symtab_store_.get_symbol_table(); - - switch (usr_symbol_type) - { - case unknown_symbol_resolver::e_usr_variable_type : create_result = symtab.create_variable(symbol,default_value); - break; - - case unknown_symbol_resolver::e_usr_constant_type : create_result = symtab.add_constant(symbol,default_value); - break; - - default : create_result = false; - } - - if (create_result) - { - expression_node_ptr var = symtab_store_.get_variable(symbol); - - if (var) - { - if (symtab_store_.is_constant_node(symbol)) - { - var = expression_generator_(var->value()); - } - - lodge_symbol(symbol,e_st_variable); - - if (!post_variable_process(symbol)) - return error_node(); - - next_token(); - - return var; - } - } - - set_error( - make_error(parser_error::e_symtab, - current_token(), - "ERR183 - Failed to create variable: '" + symbol + "'")); - - return error_node(); - } - } - } - - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR184 - 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" ; - static const std::string symbol_return = "return" ; - - 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) && - settings_.control_struct_enabled(current_token().value) - ) - { - return parse_conditional_statement(); - } - else if ( - details::imatch(current_token().value,symbol_while) && - settings_.control_struct_enabled(current_token().value) - ) - { - return parse_while_loop(); - } - else if ( - details::imatch(current_token().value,symbol_repeat) && - settings_.control_struct_enabled(current_token().value) - ) - { - return parse_repeat_until_loop(); - } - else if ( - details::imatch(current_token().value,symbol_for) && - settings_.control_struct_enabled(current_token().value) - ) - { - return parse_for_loop(); - } - else if ( - details::imatch(current_token().value,symbol_switch) && - settings_.control_struct_enabled(current_token().value) - ) - { - 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 (details::imatch(current_token().value,symbol_return)) - { - return parse_return_statement(); - } - else if (symtab_store_.valid() || !sem_.empty()) - { - return parse_symtab_symbol(); + 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 bipow_node : public expression_node + { + public: + + typedef expression_node* expression_ptr; + typedef std::pair branch_t; + typedef PowOp operation_t; + + explicit bipow_node(expression_ptr brnch) + { + init_branches<1>(branch_, brnch); + } + + ~bipow_node() + { + cleanup_branches::execute(branch_); + } + + inline T value() const + { + return PowOp::result(branch_[0].first->value()); + } + + inline typename expression_node::node_type type() const + { + return expression_node::e_ipow; + } + + private: + + bipow_node(const bipow_node&); + bipow_node& operator=(const bipow_node&); + + branch_t branch_[1]; + }; + + 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 + class bipowninv_node : public expression_node + { + public: + + typedef expression_node* expression_ptr; + typedef std::pair branch_t; + typedef PowOp operation_t; + + explicit bipowninv_node(expression_ptr brnch) + { + init_branches<1>(branch_, brnch); + } + + ~bipowninv_node() + { + cleanup_branches::execute(branch_); + } + + inline T value() const + { + return (T(1) / PowOp::result(branch_[0].first->value())); + } + + inline typename expression_node::node_type type() const + { + return expression_node::e_ipowinv; + } + + private: + + bipowninv_node(const bipowninv_node&); + bipowninv_node& operator=(const bipowninv_node&); + + branch_t branch_[1]; + }; + + template + inline bool is_vov_node(const expression_node* node) + { + return (0 != dynamic_cast*>(node)); + } + + template + inline bool is_cov_node(const expression_node* node) + { + return (0 != dynamic_cast*>(node)); + } + + template + inline bool is_voc_node(const expression_node* node) + { + return (0 != dynamic_cast*>(node)); + } + + template + inline bool is_cob_node(const expression_node* node) + { + return (0 != dynamic_cast*>(node)); + } + + template + inline bool is_boc_node(const expression_node* node) + { + return (0 != dynamic_cast*>(node)); + } + + template + inline bool is_t0ot1ot2_node(const expression_node* node) + { + return (0 != dynamic_cast*>(node)); + } + + template + inline bool is_t0ot1ot2ot3_node(const expression_node* node) + { + return (0 != dynamic_cast*>(node)); + } + + template + inline bool is_uv_node(const expression_node* node) + { + return (0 != dynamic_cast*>(node)); + } + + template + inline bool is_string_node(const expression_node* node) + { + return node && (expression_node::e_stringvar == node->type()); + } + + template + inline bool is_string_range_node(const expression_node* node) + { + return node && (expression_node::e_stringvarrng == node->type()); + } + + template + inline bool is_const_string_node(const expression_node* node) + { + return node && (expression_node::e_stringconst == node->type()); + } + + template + inline bool is_const_string_range_node(const expression_node* node) + { + return node && (expression_node::e_cstringvarrng == node->type()); + } + + template + inline bool is_string_assignment_node(const expression_node* node) + { + return node && (expression_node::e_strass == node->type()); + } + + template + inline bool is_string_concat_node(const expression_node* node) + { + return node && (expression_node::e_strconcat == node->type()); + } + + template + inline bool is_string_function_node(const expression_node* node) + { + return node && (expression_node::e_strfunction == node->type()); + } + + template + inline bool is_string_condition_node(const expression_node* node) + { + return node && (expression_node::e_strcondition == node->type()); + } + + template + inline bool is_string_ccondition_node(const expression_node* node) + { + return node && (expression_node::e_strccondition == node->type()); + } + + template + inline bool is_string_vararg_node(const expression_node* node) + { + return node && (expression_node::e_stringvararg == node->type()); + } + + template + inline bool is_genricstring_range_node(const expression_node* node) + { + return node && (expression_node::e_strgenrange == node->type()); + } + + template + inline bool is_generally_string_node(const expression_node* node) + { + if (node) + { + switch (node->type()) + { + case expression_node::e_stringvar : + case expression_node::e_stringconst : + case expression_node::e_stringvarrng : + case expression_node::e_cstringvarrng : + case expression_node::e_strgenrange : + case expression_node::e_strass : + case expression_node::e_strconcat : + case expression_node::e_strfunction : + case expression_node::e_strcondition : + case expression_node::e_strccondition : + case expression_node::e_stringvararg : return true; + default : return false; + } + } + + return false; + } + + class node_allocator + { + public: + + template + inline expression_node* allocate(OpType& operation, ExprNode (&branch)[1]) + { + 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 + + class function_traits + { + public: + + function_traits() + : allow_zero_parameters_(false), + has_side_effects_(true), + min_num_args_(0), + max_num_args_(std::numeric_limits::max()) + {} + + inline bool& allow_zero_parameters() + { + return allow_zero_parameters_; + } + + inline bool& has_side_effects() + { + return has_side_effects_; + } + + std::size_t& min_num_args() + { + return min_num_args_; + } + + std::size_t& max_num_args() + { + return max_num_args_; + } + + private: + + bool allow_zero_parameters_; + bool has_side_effects_; + std::size_t min_num_args_; + std::size_t max_num_args_; + }; + + template + void enable_zero_parameters(FunctionType& func) + { + func.allow_zero_parameters() = true; + + if (0 != func.min_num_args()) + { + func.min_num_args() = 0; + } + } + + template + void disable_zero_parameters(FunctionType& func) + { + func.allow_zero_parameters() = false; + } + + template + void enable_has_side_effects(FunctionType& func) + { + func.has_side_effects() = true; + } + + template + void disable_has_side_effects(FunctionType& func) + { + func.has_side_effects() = false; + } + + template + void set_min_num_args(FunctionType& func, const std::size_t& num_args) + { + func.min_num_args() = num_args; + + if ((0 != func.min_num_args()) && func.allow_zero_parameters()) + func.allow_zero_parameters() = false; + } + + template + void set_max_num_args(FunctionType& func, const std::size_t& num_args) + { + func.max_num_args() = num_args; + } + + template + class ifunction : public function_traits + { + public: + + explicit ifunction(const std::size_t& pc) + : param_count(pc) + {} + + virtual ~ifunction() + {} + + #define empty_method_body \ + { \ + return std::numeric_limits::quiet_NaN(); \ + } \ + + inline virtual T operator()() + empty_method_body + + inline virtual T operator()(const T&) + empty_method_body + + inline virtual T operator()(const T&,const T&) + empty_method_body + + inline virtual T operator()(const T&, const T&, const T&) + empty_method_body + + inline virtual T operator()(const T&, const T&, const T&, const T&) + empty_method_body + + inline virtual T operator()(const T&, const T&, const T&, const T&, const T&) + empty_method_body + + inline virtual T operator()(const T&, const T&, const T&, const T&, const T&, const T&) + empty_method_body + + inline virtual T operator()(const T&, const T&, const T&, const T&, const T&, const T&, const T&) + empty_method_body + + inline virtual T operator()(const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&) + empty_method_body + + inline virtual T operator()(const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&) + empty_method_body + + inline virtual T operator()(const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&) + empty_method_body + + inline virtual T operator()(const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, + const T&) + empty_method_body + + inline virtual T operator()(const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, + const T&, const T&) + empty_method_body + + inline virtual T operator()(const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, + const T&, const T&, const T&) + empty_method_body + + inline virtual T operator()(const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, + const T&, const T&, const T&, const T&) + empty_method_body + + inline virtual T operator()(const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, + const T&, const T&, const T&, const T&, const T&) + empty_method_body + + inline virtual T operator()(const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, + const T&, const T&, const T&, const T&, const T&, const T&) + empty_method_body + + inline virtual T operator()(const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, + const T&, const T&, const T&, const T&, const T&, const T&, const T&) + empty_method_body + + inline virtual T operator()(const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, + const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&) + empty_method_body + + inline virtual T operator()(const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, + const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&) + empty_method_body + + inline virtual T operator()(const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, + const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&) + empty_method_body + + #undef empty_method_body + + std::size_t param_count; + }; + + template + class ivararg_function : public function_traits + { + public: + + virtual ~ivararg_function() + {} + + inline virtual T operator()(const std::vector&) + { + exprtk_debug(("ivararg_function::operator() - Operator has not been overridden.\n")); + return std::numeric_limits::quiet_NaN(); + } + }; + + template + class igeneric_function : public function_traits + { + public: + + enum return_type + { + e_rtrn_scalar = 0, + e_rtrn_string = 1 + }; + + typedef T type; + typedef type_store generic_type; + typedef typename generic_type::parameter_list parameter_list_t; + + igeneric_function(const std::string& param_seq = "", const return_type rtr_type = e_rtrn_scalar) + : parameter_sequence(param_seq), + rtrn_type(rtr_type) + {} + + virtual ~igeneric_function() + {} + + #define igeneric_function_empty_body(N) \ + { \ + exprtk_debug(("igeneric_function::operator() - Operator has not been overridden. ["#N"]\n")); \ + return std::numeric_limits::quiet_NaN(); \ + } \ + + // f(i_0,i_1,....,i_N) --> Scalar + inline virtual T operator()(parameter_list_t) + igeneric_function_empty_body(1) + + // f(i_0,i_1,....,i_N) --> String + inline virtual T operator()(std::string&, parameter_list_t) + igeneric_function_empty_body(2) + + // f(psi,i_0,i_1,....,i_N) --> Scalar + inline virtual T operator()(const std::size_t&, parameter_list_t) + igeneric_function_empty_body(3) + + // f(psi,i_0,i_1,....,i_N) --> String + inline virtual T operator()(const std::size_t&, std::string&, parameter_list_t) + igeneric_function_empty_body(4) + + std::string parameter_sequence; + return_type rtrn_type; + }; + + template class parser; + template class expression_helper; + + template + class symbol_table + { + public: + + typedef T (*ff01_functor)(T); + typedef T (*ff02_functor)(T,T); + typedef T (*ff03_functor)(T,T,T); + typedef T (*ff04_functor)(T,T,T,T); + typedef T (*ff05_functor)(T,T,T,T,T); + typedef T (*ff06_functor)(T,T,T,T,T,T); + typedef T (*ff07_functor)(T,T,T,T,T,T,T); + typedef T (*ff08_functor)(T,T,T,T,T,T,T,T); + typedef T (*ff09_functor)(T,T,T,T,T,T,T,T,T); + typedef T (*ff10_functor)(T,T,T,T,T,T,T,T,T,T); + typedef T (*ff11_functor)(T,T,T,T,T,T,T,T,T,T,T); + typedef T (*ff12_functor)(T,T,T,T,T,T,T,T,T,T,T,T); + typedef T (*ff13_functor)(T,T,T,T,T,T,T,T,T,T,T,T,T); + typedef T (*ff14_functor)(T,T,T,T,T,T,T,T,T,T,T,T,T,T); + typedef T (*ff15_functor)(T,T,T,T,T,T,T,T,T,T,T,T,T,T,T); + + protected: + + struct freefunc01 : public exprtk::ifunction + { + using exprtk::ifunction::operator(); + + freefunc01(ff01_functor ff) : exprtk::ifunction(1), f(ff) {} + inline T operator()(const T& v0) + { return f(v0); } + ff01_functor f; + }; + + struct freefunc02 : public exprtk::ifunction + { + using exprtk::ifunction::operator(); + + freefunc02(ff02_functor ff) : exprtk::ifunction(2), f(ff) {} + inline T operator()(const T& v0, const T& v1) + { return f(v0,v1); } + ff02_functor f; + }; + + struct freefunc03 : public exprtk::ifunction + { + using exprtk::ifunction::operator(); + + freefunc03(ff03_functor ff) : exprtk::ifunction(3), f(ff) {} + inline T operator()(const T& v0, const T& v1, const T& v2) + { return f(v0,v1,v2); } + ff03_functor f; + }; + + struct freefunc04 : public exprtk::ifunction + { + using exprtk::ifunction::operator(); + + freefunc04(ff04_functor ff) : exprtk::ifunction(4), f(ff) {} + inline T operator()(const T& v0, const T& v1, const T& v2, const T& v3) + { return f(v0,v1,v2,v3); } + ff04_functor f; + }; + + struct freefunc05 : public exprtk::ifunction + { + using exprtk::ifunction::operator(); + + freefunc05(ff05_functor ff) : exprtk::ifunction(5), f(ff) {} + inline T operator()(const T& v0, const T& v1, const T& v2, const T& v3, const T& v4) + { return f(v0,v1,v2,v3,v4); } + ff05_functor f; + }; + + struct freefunc06 : public exprtk::ifunction + { + using exprtk::ifunction::operator(); + + freefunc06(ff06_functor ff) : exprtk::ifunction(6), f(ff) {} + inline T operator()(const T& v0, const T& v1, const T& v2, const T& v3, const T& v4, const T& v5) + { return f(v0,v1,v2,v3,v4,v5); } + ff06_functor f; + }; + + struct freefunc07 : public exprtk::ifunction + { + using exprtk::ifunction::operator(); + + freefunc07(ff07_functor ff) : exprtk::ifunction(7), f(ff) {} + inline T operator()(const T& v0, const T& v1, const T& v2, const T& v3, const T& v4, + const T& v5, const T& v6) + { return f(v0,v1,v2,v3,v4,v5,v6); } + ff07_functor f; + }; + + struct freefunc08 : public exprtk::ifunction + { + using exprtk::ifunction::operator(); + + freefunc08(ff08_functor ff) : exprtk::ifunction(8), f(ff) {} + inline T operator()(const T& v0, const T& v1, const T& v2, const T& v3, const T& v4, + const T& v5, const T& v6, const T& v7) + { return f(v0,v1,v2,v3,v4,v5,v6,v7); } + ff08_functor f; + }; + + struct freefunc09 : public exprtk::ifunction + { + using exprtk::ifunction::operator(); + + freefunc09(ff09_functor ff) : exprtk::ifunction(9), f(ff) {} + inline T operator()(const T& v0, const T& v1, const T& v2, const T& v3, const T& v4, + const T& v5, const T& v6, const T& v7, const T& v8) + { return f(v0,v1,v2,v3,v4,v5,v6,v7,v8); } + ff09_functor f; + }; + + struct freefunc10 : public exprtk::ifunction + { + using exprtk::ifunction::operator(); + + freefunc10(ff10_functor ff) : exprtk::ifunction(10), f(ff) {} + inline T operator()(const T& v0, const T& v1, const T& v2, const T& v3, const T& v4, + const T& v5, const T& v6, const T& v7, const T& v8, const T& v9) + { return f(v0,v1,v2,v3,v4,v5,v6,v7,v8,v9); } + ff10_functor f; + }; + + struct freefunc11 : public exprtk::ifunction + { + using exprtk::ifunction::operator(); + + freefunc11(ff11_functor ff) : exprtk::ifunction(11), f(ff) {} + inline T operator()(const T& v0, const T& v1, const T& v2, const T& v3, const T& v4, + const T& v5, const T& v6, const T& v7, const T& v8, const T& v9, const T& v10) + { return f(v0,v1,v2,v3,v4,v5,v6,v7,v8,v9,v10); } + ff11_functor f; + }; + + struct freefunc12 : public exprtk::ifunction + { + using exprtk::ifunction::operator(); + + freefunc12(ff12_functor ff) : exprtk::ifunction(12), f(ff) {} + inline T operator()(const T& v00, const T& v01, const T& v02, const T& v03, const T& v04, + const T& v05, const T& v06, const T& v07, const T& v08, const T& v09, + const T& v10, const T& v11) + { return f(v00,v01,v02,v03,v04,v05,v06,v07,v08,v09,v10,v11); } + ff12_functor f; + }; + + struct freefunc13 : public exprtk::ifunction + { + using exprtk::ifunction::operator(); + + freefunc13(ff13_functor ff) : exprtk::ifunction(13), f(ff) {} + inline T operator()(const T& v00, const T& v01, const T& v02, const T& v03, const T& v04, + const T& v05, const T& v06, const T& v07, const T& v08, const T& v09, + const T& v10, const T& v11, const T& v12) + { return f(v00,v01,v02,v03,v04,v05,v06,v07,v08,v09,v10,v11,v12); } + ff13_functor f; + }; + + struct freefunc14 : public exprtk::ifunction + { + using exprtk::ifunction::operator(); + + freefunc14(ff14_functor ff) : exprtk::ifunction(14), f(ff) {} + inline T operator()(const T& v00, const T& v01, const T& v02, const T& v03, const T& v04, + const T& v05, const T& v06, const T& v07, const T& v08, const T& v09, + const T& v10, const T& v11, const T& v12, const T& v13) + { return f(v00,v01,v02,v03,v04,v05,v06,v07,v08,v09,v10,v11,v12,v13); } + ff14_functor f; + }; + + struct freefunc15 : public exprtk::ifunction + { + using exprtk::ifunction::operator(); + + freefunc15(ff15_functor ff) : exprtk::ifunction(15), f(ff) {} + inline T operator()(const T& v00, const T& v01, const T& v02, const T& v03, const T& v04, + const T& v05, const T& v06, const T& v07, const T& v08, const T& v09, + const T& v10, const T& v11, const T& v12, const T& v13, const T& v14) + { return f(v00,v01,v02,v03,v04,v05,v06,v07,v08,v09,v10,v11,v12,v13,v14); } + ff15_functor f; + }; + + template + struct type_store + { + typedef details::expression_node* expression_ptr; + typedef typename details::variable_node variable_node_t; + typedef ifunction ifunction_t; + typedef ivararg_function ivararg_function_t; + typedef igeneric_function igeneric_function_t; + typedef details::vector_holder vector_t; + #ifndef exprtk_disable_string_capabilities + typedef typename details::stringvar_node stringvar_node_t; + #endif + + typedef Type type_t; + typedef type_t* type_ptr; + typedef std::pair type_pair_t; + typedef std::map type_map_t; + typedef typename type_map_t::iterator tm_itr_t; + typedef typename type_map_t::const_iterator tm_const_itr_t; + + enum { lut_size = 256 }; + + type_map_t map; + std::size_t size; + + type_store() + : size(0) + {} + + 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) { - set_error( - make_error(parser_error::e_symtab, - current_token(), - "ERR185 - 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(), - "ERR186 - 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(), - "ERR187 - 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(), - "ERR188 - 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(), - "ERR189 - 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(), - "ERR190 - Premature end of expression[1]")); - - return error_node(); + 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 { - set_error( - make_error(parser_error::e_syntax, - current_token(), - "ERR191 - Premature end of expression[2]")); - - return error_node(); - } - - if ( - branch && - (e_level00 == precedence) && - token_is(token_t::e_ternary,prsrhlpr_t::e_hold) - ) - { - branch = parse_ternary_conditional_statement(branch); - } - - parse_pending_string_rangesize(branch); - - return branch; - } - - template - class expression_generator - { - public: - - typedef details::expression_node* expression_node_ptr; - typedef expression_node_ptr (*synthesize_functor_t)(expression_generator&, const details::operator_type& operation, expression_node_ptr (&branch)[2]); - typedef std::map synthesize_map_t; - typedef typename exprtk::parser parser_t; - typedef const Type& vtype; - typedef const Type ctype; - - inline void init_synthesize_map() - { -#ifndef exprtk_disable_enhanced_features - synthesize_map_["(v)o(v)"] = synthesize_vov_expression::process; - synthesize_map_["(c)o(v)"] = synthesize_cov_expression::process; - synthesize_map_["(v)o(c)"] = synthesize_voc_expression::process; - -#define register_synthezier(S) \ -synthesize_map_[S ::node_type::id()] = S ::process; \ - - register_synthezier(synthesize_vovov_expression0) - register_synthezier(synthesize_vovov_expression1) - register_synthezier(synthesize_vovoc_expression0) - register_synthezier(synthesize_vovoc_expression1) - register_synthezier(synthesize_vocov_expression0) - register_synthezier(synthesize_vocov_expression1) - register_synthezier(synthesize_covov_expression0) - register_synthezier(synthesize_covov_expression1) - register_synthezier(synthesize_covoc_expression0) - register_synthezier(synthesize_covoc_expression1) - register_synthezier(synthesize_cocov_expression1) - register_synthezier(synthesize_vococ_expression0) - - register_synthezier(synthesize_vovovov_expression0) - register_synthezier(synthesize_vovovoc_expression0) - register_synthezier(synthesize_vovocov_expression0) - register_synthezier(synthesize_vocovov_expression0) - register_synthezier(synthesize_covovov_expression0) - register_synthezier(synthesize_covocov_expression0) - register_synthezier(synthesize_vocovoc_expression0) - register_synthezier(synthesize_covovoc_expression0) - register_synthezier(synthesize_vococov_expression0) - - register_synthezier(synthesize_vovovov_expression1) - register_synthezier(synthesize_vovovoc_expression1) - register_synthezier(synthesize_vovocov_expression1) - register_synthezier(synthesize_vocovov_expression1) - register_synthezier(synthesize_covovov_expression1) - register_synthezier(synthesize_covocov_expression1) - register_synthezier(synthesize_vocovoc_expression1) - register_synthezier(synthesize_covovoc_expression1) - register_synthezier(synthesize_vococov_expression1) - - register_synthezier(synthesize_vovovov_expression2) - register_synthezier(synthesize_vovovoc_expression2) - register_synthezier(synthesize_vovocov_expression2) - register_synthezier(synthesize_vocovov_expression2) - register_synthezier(synthesize_covovov_expression2) - register_synthezier(synthesize_covocov_expression2) - register_synthezier(synthesize_vocovoc_expression2) - register_synthezier(synthesize_covovoc_expression2) - - register_synthezier(synthesize_vovovov_expression3) - register_synthezier(synthesize_vovovoc_expression3) - register_synthezier(synthesize_vovocov_expression3) - register_synthezier(synthesize_vocovov_expression3) - register_synthezier(synthesize_covovov_expression3) - register_synthezier(synthesize_covocov_expression3) - register_synthezier(synthesize_vocovoc_expression3) - register_synthezier(synthesize_covovoc_expression3) - register_synthezier(synthesize_vococov_expression3) - - register_synthezier(synthesize_vovovov_expression4) - register_synthezier(synthesize_vovovoc_expression4) - register_synthezier(synthesize_vovocov_expression4) - register_synthezier(synthesize_vocovov_expression4) - register_synthezier(synthesize_covovov_expression4) - register_synthezier(synthesize_covocov_expression4) - register_synthezier(synthesize_vocovoc_expression4) - register_synthezier(synthesize_covovoc_expression4) -#endif - } - - inline void set_parser(parser_t& p) - { - parser_ = &p; - } - - inline void set_uom(unary_op_map_t& unary_op_map) - { - unary_op_map_ = &unary_op_map; + tm_const_itr_t itr = map.find(symbol_name); + + if (map.end() == itr) + return false; + else + return (*itr).second.first; } - - inline void set_bom(binary_op_map_t& binary_op_map) - { - binary_op_map_ = &binary_op_map; + } + + 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; + } + } } - - inline void set_ibom(inv_binary_op_map_t& inv_binary_op_map) + + tm_itr_t itr = map.find(symbol_name); + + if (map.end() == itr) { - inv_binary_op_map_ = &inv_binary_op_map; + map[symbol_name] = Tie::make(t,is_const); + ++size; } - - inline void set_sf3m(sf3_map_t& sf3_map) + + return true; + } + + struct tie_array + { + static inline std::pair make(std::pair v, const bool is_const = false) { - sf3_map_ = &sf3_map; + return std::make_pair(is_const,new vector_t(v.first,v.second)); } - - inline void set_sf4m(sf4_map_t& sf4_map) + }; + + struct tie_stdvec + { + template + static inline std::pair make(std::vector& v, const bool is_const = false) { - sf4_map_ = &sf4_map; + return std::make_pair(is_const,new vector_t(v)); } - - inline void set_allocator(details::node_allocator& na) + }; + + struct tie_vecview + { + static inline std::pair make(exprtk::vector_view& v, const bool is_const = false) { - node_allocator_ = &na; + return std::make_pair(is_const,new vector_t(v)); } - - inline void set_strength_reduction_state(const bool enabled) + }; + + struct tie_stddeq + { + template + static inline std::pair make(std::deque& v, const bool is_const = false) { - strength_reduction_enabled_ = enabled; + return std::make_pair(is_const,new vector_t(v)); } - - inline bool strength_reduction_enabled() const + }; + + template + inline bool add(const std::string& symbol_name, T (&v)[v_size], const bool is_const = false) + { + return add_impl >(symbol_name,std::make_pair(v,v_size),is_const); + } + + inline bool add(const std::string& symbol_name, T* v, const std::size_t v_size, const bool is_const = false) + { + return add_impl >(symbol_name,std::make_pair(v,v_size),is_const); + } + + template + inline bool add(const std::string& symbol_name, std::vector& v, const bool is_const = false) + { + return add_impl&>(symbol_name,v,is_const); + } + + inline bool add(const std::string& symbol_name, exprtk::vector_view& v, const bool is_const = false) + { + return add_impl&>(symbol_name,v,is_const); + } + + template + inline bool add(const std::string& symbol_name, std::deque& v, const bool is_const = false) + { + return add_impl&>(symbol_name,v,is_const); + } + + inline bool add(const std::string& symbol_name, RawType& t, const bool is_const = false) + { + struct tie + { + static inline std::pair make(T& t,const bool is_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); + } + }; + + tm_itr_t itr = map.find(symbol_name); + + if (map.end() == itr) { - return strength_reduction_enabled_; + map[symbol_name] = tie::make(t,is_const); + ++size; } - - inline bool valid_operator(const details::operator_type& operation, binary_functor_t& bop) + + 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*) { - 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; + return false; } - - inline bool valid_operator(const details::operator_type& operation, unary_functor_t& uop) + }; + + template + struct ptr_match + { + static inline bool test(const variable_node_t* p, const void* ptr) { - 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; + exprtk_debug(("ptr_match::test() - %p <--> %p\n",(void*)(&(p->ref())),ptr)); + return (&(p->ref()) == ptr); } - - inline details::operator_type get_operator(const binary_functor_t& bop) + }; + + inline type_ptr get_from_varptr(const void* ptr) const + { + tm_const_itr_t itr = map.begin(); + + while (map.end() != itr) { - return (*inv_binary_op_map_).find(bop)->second; + type_ptr ret_ptr = itr->second.second; + + if (ptr_match::test(ret_ptr,ptr)) + { + return ret_ptr; + } + + ++itr; } - - inline expression_node_ptr operator()(const Type& v) const - { - return node_allocator_->allocate(v); + + 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; } - -#ifndef exprtk_disable_string_capabilities - inline expression_node_ptr operator()(const std::string& s) const + 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()) { - return node_allocator_->allocate(s); + 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(); } - - inline expression_node_ptr operator()(std::string& s, range_t& rp) const + + size = 0; + } + + template class Sequence> + inline std::size_t get_list(Sequence,Allocator>& list) const + { + std::size_t count = 0; + + if (!map.empty()) { - return node_allocator_->allocate_rr(s,rp); + 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; + } } - - inline expression_node_ptr operator()(const std::string& s, range_t& rp) const + + return count; + } + + template class Sequence> + inline std::size_t get_list(Sequence& vlist) const + { + std::size_t count = 0; + + if (!map.empty()) { - return node_allocator_->allocate_tt(s,rp); + tm_const_itr_t itr = map.begin(); + tm_const_itr_t end = map.end(); + + while (end != itr) + { + vlist.push_back((*itr).first); + ++itr; + ++count; + } } - - inline expression_node_ptr operator()(expression_node_ptr branch, range_t& rp) const + + return count; + } + }; + + typedef details::expression_node* expression_ptr; + typedef typename details::variable_node variable_t; + typedef typename details::vector_holder vector_holder_t; + typedef variable_t* variable_ptr; + #ifndef exprtk_disable_string_capabilities + typedef typename details::stringvar_node stringvar_t; + typedef stringvar_t* stringvar_ptr; + #endif + typedef ifunction function_t; + typedef ivararg_function vararg_function_t; + typedef igeneric_function generic_function_t; + typedef function_t* function_ptr; + typedef vararg_function_t* vararg_function_ptr; + typedef generic_function_t* generic_function_ptr; + + static const std::size_t lut_size = 256; + + // Symbol Table Holder + struct control_block + { + struct st_data + { + type_store,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() { - if (is_generally_string_node(branch)) - return node_allocator_->allocate_tt(branch,rp); - else - return error_node(); - } -#endif - - inline bool unary_optimisable(const details::operator_type& operation) const - { - return (details::e_abs == operation) || (details::e_acos == operation) || - (details::e_acosh == operation) || (details::e_asin == operation) || - (details::e_asinh == operation) || (details::e_atan == operation) || - (details::e_atanh == operation) || (details::e_ceil == operation) || - (details::e_cos == operation) || (details::e_cosh == operation) || - (details::e_exp == operation) || (details::e_expm1 == operation) || - (details::e_floor == operation) || (details::e_log == operation) || - (details::e_log10 == operation) || (details::e_log2 == operation) || - (details::e_log1p == operation) || (details::e_neg == operation) || - (details::e_pos == operation) || (details::e_round == operation) || - (details::e_sin == operation) || (details::e_sinc == operation) || - (details::e_sinh == operation) || (details::e_sqrt == operation) || - (details::e_tan == operation) || (details::e_tanh == operation) || - (details::e_cot == operation) || (details::e_sec == operation) || - (details::e_csc == operation) || (details::e_r2d == operation) || - (details::e_d2r == operation) || (details::e_d2g == operation) || - (details::e_g2d == operation) || (details::e_notl == operation) || - (details::e_sgn == operation) || (details::e_erf == operation) || - (details::e_erfc == operation) || (details::e_ncdf == operation) || - (details::e_frac == operation) || (details::e_trunc == operation); - } - - inline bool sf3_optimisable(const std::string& sf3id, trinary_functor_t& tfunc) - { - 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_optimisable(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_optimisable(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_optimisable(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_optimisable(operation) && details::is_variable_node(branch[0])) - return synthesize_uv_expression(operation,branch); - else if (unary_optimisable(operation) && details::is_ivector_node(branch[0])) - return synthesize_uvec_expression(operation,branch); - else - return synthesize_unary_expression(operation,branch); - } - - inline bool is_assignment_operation(const details::operator_type& operation) const - { - return ( - (details::e_addass == operation) || - (details::e_subass == operation) || - (details::e_mulass == operation) || - (details::e_divass == operation) || - (details::e_modass == operation) - ) && - parser_->settings_.assignment_enabled(operation); - } - -#ifndef exprtk_disable_string_capabilities - inline bool valid_string_operation(const details::operator_type& operation) const - { - return (details::e_add == operation) || - (details::e_lt == operation) || - (details::e_lte == operation) || - (details::e_gt == operation) || - (details::e_gte == operation) || - (details::e_eq == operation) || - (details::e_ne == operation) || - (details::e_in == operation) || - (details::e_like == operation) || - (details::e_ilike == operation) || - (details::e_assign == operation) || - (details::e_addass == operation) || - (details::e_swap == operation) ; + 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]); + } } -#else - inline bool valid_string_operation(const details::operator_type&) const + + ~st_data() { - return false; - } -#endif - - inline std::string to_str(const details::operator_type& operation) const - { - switch (operation) - { - case details::e_add : return "+"; - case details::e_sub : return "-"; - case details::e_mul : return "*"; - case details::e_div : return "/"; - case details::e_mod : return "%"; - case details::e_pow : return "^"; - case details::e_lt : return "<"; - case details::e_lte : return "<="; - case details::e_gt : return ">"; - case details::e_gte : return ">="; - case details::e_eq : return "=="; - case details::e_ne : return "!="; - case details::e_and : return "and"; - case details::e_nand : return "nand"; - case details::e_or : return "or"; - case details::e_nor : return "nor"; - case details::e_xor : return "xor"; - case details::e_xnor : return "xnor"; - default : return "UNKNOWN"; - } - } - - inline bool operation_optimisable(const details::operator_type& operation) const - { - return (details::e_add == operation) || - (details::e_sub == operation) || - (details::e_mul == operation) || - (details::e_div == operation) || - (details::e_mod == operation) || - (details::e_pow == operation) || - (details::e_lt == operation) || - (details::e_lte == operation) || - (details::e_gt == operation) || - (details::e_gte == operation) || - (details::e_eq == operation) || - (details::e_ne == operation) || - (details::e_and == operation) || - (details::e_nand == operation) || - (details::e_or == operation) || - (details::e_nor == operation) || - (details::e_xor == operation) || - (details::e_xnor == operation) ; - } - - inline std::string branch_to_id(expression_node_ptr branch) - { - 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_optimisable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const - { - if (!operation_optimisable(operation)) - return false; - else - return (details::is_constant_node(branch[0]) && details::is_variable_node(branch[1])); - } - - inline bool voc_optimisable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const - { - if (!operation_optimisable(operation)) - return false; - else - return (details::is_variable_node(branch[0]) && details::is_constant_node(branch[1])); - } - - inline bool vov_optimisable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const - { - if (!operation_optimisable(operation)) - return false; - else - return (details::is_variable_node(branch[0]) && details::is_variable_node(branch[1])); - } - - inline bool cob_optimisable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const - { - if (!operation_optimisable(operation)) - return false; - else - return (details::is_constant_node(branch[0]) && !details::is_constant_node(branch[1])); - } - - inline bool boc_optimisable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const - { - if (!operation_optimisable(operation)) - return false; - else - return (!details::is_constant_node(branch[0]) && details::is_constant_node(branch[1])); - } - - inline bool cocob_optimisable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const - { - if ( - (details::e_add == operation) || - (details::e_sub == operation) || - (details::e_mul == operation) || - (details::e_div == operation) - ) - { - return (details::is_constant_node(branch[0]) && details::is_cob_node(branch[1])) || - (details::is_constant_node(branch[1]) && details::is_cob_node(branch[0])); - } - else - return false; + for (std::size_t i = 0; i < free_function_list_.size(); ++i) + { + delete free_function_list_[i]; + } } - - inline bool coboc_optimisable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const + + inline bool is_reserved_symbol(const std::string& symbol) const { - if ( - (details::e_add == operation) || - (details::e_sub == operation) || - (details::e_mul == operation) || - (details::e_div == operation) - ) - { - return (details::is_constant_node(branch[0]) && details::is_boc_node(branch[1])) || - (details::is_constant_node(branch[1]) && details::is_boc_node(branch[0])); - } - else - return false; - } - - inline bool uvouv_optimisable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const - { - if (!operation_optimisable(operation)) - return false; - else - return (details::is_uv_node(branch[0]) && details::is_uv_node(branch[1])); - } - - inline bool vob_optimisable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const - { - if (!operation_optimisable(operation)) - return false; - else - return (details::is_variable_node(branch[0]) && !details::is_variable_node(branch[1])); - } - - inline bool bov_optimisable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const - { - if (!operation_optimisable(operation)) - return false; - else - return (!details::is_variable_node(branch[0]) && details::is_variable_node(branch[1])); - } - - inline bool binext_optimisable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const - { - if (!operation_optimisable(operation)) - return false; - else - return (!details::is_constant_node(branch[0]) || !details::is_constant_node(branch[1])); - } - - inline bool is_invalid_assignment_op(const details::operator_type& operation, expression_node_ptr (&branch)[2]) - { - if (is_assignment_operation(operation)) - { - const bool b1_is_genstring = details::is_generally_string_node(branch[1]); - - if (details::is_string_node(branch[0])) - return !b1_is_genstring; - else - return ( - !details::is_variable_node (branch[0]) && - !details::is_vector_elem_node (branch[0]) && - !details::is_rebasevector_elem_node (branch[0]) && - !details::is_rebasevector_celem_node(branch[0]) && - !details::is_vector_node (branch[0]) - ) - || b1_is_genstring; - } - else - return false; - } - - inline bool is_constpow_operation(const details::operator_type& operation, expression_node_ptr(&branch)[2]) - { - if ( - !is_constant_node(branch[1]) || - is_constant_node(branch[0]) || - is_variable_node(branch[0]) || - is_vector_node (branch[0]) || - is_generally_string_node(branch[0]) - ) - return false; - - const Type c = static_cast*>(branch[1])->value(); - - return cardinal_pow_optimisable(operation, c); - } - - inline bool is_invalid_break_continue_op(expression_node_ptr (&branch)[2]) - { - 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) - ); + return (reserved_symbol_table_.end() != reserved_symbol_table_.find(symbol)); } -#else - inline bool is_shortcircuit_expression(const details::operator_type&) + + std::list local_symbol_list_; + std::list local_stringvar_list_; + std::set reserved_symbol_table_; + std::vector*> free_function_list_; + }; + + control_block() + : ref_count(1), + data_(new st_data) + {} + + control_block(st_data* data) + : ref_count(1), + data_(data) + {} + + ~control_block() + { + if (data_ && (0 == ref_count)) { - return false; + delete data_; + data_ = 0; } -#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_logic_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) || - (details::e_equal == operation) || - (details::e_and == operation) || - (details::e_nand == operation) || - (details:: e_or == operation) || - (details:: e_nor == operation) || - (details:: e_xor == operation) || - (details::e_xnor == operation) - ); - } - - inline bool is_vector_arithmetic_operation(const details::operator_type& operation, expression_node_ptr (&branch)[2]) - { - if (!is_ivector_node(branch[0]) && !is_ivector_node(branch[1])) - return false; - else - return ( - (details::e_add == operation) || - (details::e_sub == operation) || - (details::e_mul == operation) || - (details::e_div == operation) || - (details::e_pow == operation) - ); - } - - inline expression_node_ptr operator()(const details::operator_type& operation, expression_node_ptr (&branch)[2]) - { - if ((0 == branch[0]) || (0 == branch[1])) - return error_node(); - else if (is_invalid_string_op(operation,branch)) - return error_node(); - else if (is_invalid_assignment_op(operation,branch)) - return error_node(); - else if (is_invalid_break_continue_op(branch)) - return error_node(); - else if (details::e_assign == operation) - return synthesize_assignment_expression(operation,branch); - else if (details::e_swap == operation) - return synthesize_swap_expression(branch); - else if (is_assignment_operation(operation)) - return synthesize_assignment_operation_expression(operation,branch); - else if (is_vector_eqineq_logic_operation(operation,branch)) - return synthesize_veceqineqlogic_operation_expression(operation,branch); - else if (is_vector_arithmetic_operation(operation,branch)) - return synthesize_vecarithmetic_operation_expression(operation,branch); - else if (is_shortcircuit_expression(operation)) - return synthesize_shortcircuit_expression(operation,branch); - else if (is_string_operation(operation,branch)) - return synthesize_string_expression(operation,branch); - else if (is_null_present(branch)) - return synthesize_null_expression(operation, branch); -#ifndef exprtk_disable_cardinal_pow_optimisation - else if (is_constpow_operation(operation, branch)) - return cardinal_pow_optimisation(branch); -#endif - - expression_node_ptr result = error_node(); - -#ifndef exprtk_disable_enhanced_features - if (synthesize_expression(operation,branch,result)) - return result; - else -#endif - - { - /* - Possible reductions: - 1. c o cob -> cob - 2. cob o c -> cob - 3. c o boc -> boc - 4. boc o c -> boc - */ - result = error_node(); - - if (cocob_optimisable(operation,branch)) - result = synthesize_cocob_expression::process(*this,operation,branch); - else if (coboc_optimisable(operation,branch) && (0 == result)) - result = synthesize_coboc_expression::process(*this,operation,branch); - - if (result) - return result; - } - - if (uvouv_optimisable(operation,branch)) - return synthesize_uvouv_expression(operation,branch); - else if (vob_optimisable(operation,branch)) - return synthesize_vob_expression::process(*this,operation,branch); - else if (bov_optimisable(operation,branch)) - return synthesize_bov_expression::process(*this,operation,branch); - else if (cob_optimisable(operation,branch)) - return synthesize_cob_expression::process(*this,operation,branch); - else if (boc_optimisable(operation,branch)) - return synthesize_boc_expression::process(*this,operation,branch); -#ifndef exprtk_disable_enhanced_features - else if (cov_optimisable(operation,branch)) - return synthesize_cov_expression::process(*this,operation,branch); -#endif - else if (binext_optimisable(operation,branch)) - return synthesize_binary_ext_expression::process(*this,operation,branch); - else - return synthesize_expression(operation,branch); - } - - inline expression_node_ptr operator()(const details::operator_type& operation, expression_node_ptr (&branch)[3]) - { - if ( - (0 == branch[0]) || - (0 == branch[1]) || - (0 == branch[2]) - ) - { - details::free_all_nodes(*node_allocator_,branch); - - return error_node(); - } - else if (is_invalid_string_op(operation,branch)) - return error_node(); - else if (is_string_operation(operation,branch)) - return synthesize_string_expression(operation,branch); - else - return synthesize_expression(operation,branch); - } - - inline expression_node_ptr operator()(const details::operator_type& operation, expression_node_ptr (&branch)[4]) - { - return synthesize_expression(operation,branch); - } - - inline expression_node_ptr operator()(const details::operator_type& operation, expression_node_ptr b0) - { - expression_node_ptr branch[1] = { b0 }; - return (*this)(operation,branch); - } - - inline expression_node_ptr operator()(const details::operator_type& operation, expression_node_ptr b0, expression_node_ptr b1) - { - 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 optimise. - 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); - } - -#ifndef exprtk_disable_string_capabilities - inline expression_node_ptr conditional_string(expression_node_ptr condition, - expression_node_ptr consequent, - expression_node_ptr alternative) const - { - if ((0 == condition) || (0 == consequent)) - { - 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 optimise. - 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_c >(""); - } - } - else if ((0 != consequent) && (0 != alternative)) - return node_allocator_-> - allocate(condition,consequent,alternative); - else - return error_node(); + } + + static inline control_block* create() + { + return new control_block; + } + + template + static inline void destroy(control_block*& cntrl_blck, SymTab* sym_tab) + { + if (cntrl_blck) + { + if ( + (0 != cntrl_blck->ref_count) && + (0 == --cntrl_blck->ref_count) + ) + { + if (sym_tab) + sym_tab->clear(); + + delete cntrl_blck; + } + + cntrl_blck = 0; } -#else - inline expression_node_ptr conditional_string(expression_node_ptr, - expression_node_ptr, - expression_node_ptr) const + } + + std::size_t ref_count; + st_data* data_; + }; + + public: + + symbol_table() + : control_block_(control_block::create()) + { + clear(); + } + + ~symbol_table() + { + control_block::destroy(control_block_,this); + } + + symbol_table(const symbol_table& st) + { + control_block_ = st.control_block_; + control_block_->ref_count++; + } + + inline symbol_table& operator=(const symbol_table& st) + { + if (this != &st) + { + control_block::destroy(control_block_,reinterpret_cast*>(0)); + + control_block_ = st.control_block_; + control_block_->ref_count++; + } + + return *this; + } + + inline bool operator==(const symbol_table& st) + { + return (this == &st) || (control_block_ == st.control_block_); + } + + inline void clear_variables(const bool delete_node = true) + { + local_data().variable_store.clear(delete_node); + } + + inline void clear_functions() + { + local_data().function_store.clear(); + } + + inline void clear_strings() + { + #ifndef exprtk_disable_string_capabilities + local_data().stringvar_store.clear(); + #endif + } + + inline void clear_vectors() + { + local_data().vector_store.clear(); + } + + inline void clear_local_constants() + { + local_data().local_symbol_list_.clear(); + } + + inline void clear() + { + if (!valid()) return; + clear_variables (); + clear_functions (); + clear_strings (); + clear_vectors (); + clear_local_constants(); + } + + inline std::size_t variable_count() const + { + if (valid()) + return local_data().variable_store.size; + else + return 0; + } + + #ifndef exprtk_disable_string_capabilities + inline std::size_t stringvar_count() const + { + if (valid()) + return local_data().stringvar_store.size; + else + return 0; + } + #endif + + inline std::size_t function_count() const + { + if (valid()) + return local_data().function_store.size; + else + return 0; + } + + inline std::size_t vector_count() const + { + if (valid()) + return local_data().vector_store.size; + else + return 0; + } + + inline variable_ptr get_variable(const std::string& variable_name) const + { + if (!valid()) + return reinterpret_cast(0); + else if (!valid_symbol(variable_name)) + return reinterpret_cast(0); + else + return local_data().variable_store.get(variable_name); + } + + inline variable_ptr get_variable(const T& var_ref) const + { + if (!valid()) + return reinterpret_cast(0); + else + return local_data().variable_store.get_from_varptr( + reinterpret_cast(&var_ref)); + } + + #ifndef exprtk_disable_string_capabilities + inline stringvar_ptr get_stringvar(const std::string& string_name) const + { + if (!valid()) + return reinterpret_cast(0); + else if (!valid_symbol(string_name)) + return reinterpret_cast(0); + else + return local_data().stringvar_store.get(string_name); + } + #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); + } + + inline bool add_function(const std::string& function_name, generic_function_t& function) + { + if (!valid()) + return false; + else if (!valid_symbol(function_name)) + return false; + else if (symbol_exists(function_name)) + return false; + else if (std::string::npos != function.parameter_sequence.find_first_not_of("STVZ*?|")) + return false; + else if (generic_function_t::e_rtrn_scalar == function.rtrn_type) + return local_data().generic_function_store.add(function_name,function); + else if (generic_function_t::e_rtrn_string == function.rtrn_type) + return local_data().string_function_store.add(function_name, function); + else + return false; + } + + #define exprtk_define_freefunction(NN) \ + inline bool add_function(const std::string& function_name, ff##NN##_functor function) \ + { \ + if (!valid()) \ + return false; \ + else if (!valid_symbol(function_name)) \ + return false; \ + else if (symbol_exists(function_name)) \ + return false; \ + \ + exprtk::ifunction* ifunc = new freefunc##NN(function); \ + \ + local_data().free_function_list_.push_back(ifunc); \ + \ + return add_function(function_name,(*local_data().free_function_list_.back())); \ + } \ + + exprtk_define_freefunction(01) exprtk_define_freefunction(02) + exprtk_define_freefunction(03) exprtk_define_freefunction(04) + exprtk_define_freefunction(05) exprtk_define_freefunction(06) + exprtk_define_freefunction(07) exprtk_define_freefunction(08) + exprtk_define_freefunction(09) exprtk_define_freefunction(10) + exprtk_define_freefunction(11) exprtk_define_freefunction(12) + exprtk_define_freefunction(13) exprtk_define_freefunction(14) + exprtk_define_freefunction(15) + + #undef exprtk_define_freefunction + + inline bool add_reserved_function(const std::string& function_name, function_t& function) + { + if (!valid()) + return false; + else if (!valid_symbol(function_name,false)) + return false; + else if (symbol_exists(function_name,false)) + return false; + else + return local_data().function_store.add(function_name,function); + } + + inline bool add_reserved_function(const std::string& vararg_function_name, vararg_function_t& vararg_function) + { + if (!valid()) + return false; + else if (!valid_symbol(vararg_function_name,false)) + return false; + else if (symbol_exists(vararg_function_name,false)) + return false; + else + return local_data().vararg_function_store.add(vararg_function_name,vararg_function); + } + + inline bool add_reserved_function(const std::string& function_name, generic_function_t& function) + { + if (!valid()) + return false; + else if (!valid_symbol(function_name,false)) + return false; + else if (symbol_exists(function_name,false)) + return false; + else if (std::string::npos != function.parameter_sequence.find_first_not_of("STV*?|")) + return false; + else if (generic_function_t::e_rtrn_scalar == function.rtrn_type) + return local_data().generic_function_store.add(function_name,function); + else if (generic_function_t::e_rtrn_string == function.rtrn_type) + return local_data().string_function_store.add(function_name, function); + else + 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); + } + + inline bool add_vector(const std::string& vector_name, exprtk::vector_view& v) + { + if (!valid()) + return false; + else if (!valid_symbol(vector_name)) + return false; + else if (symbol_exists(vector_name)) + return false; + else + 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 + inline bool add_package(Package& package) + { + return package.register_package(*this); + } + + template class Sequence> + inline std::size_t get_variable_list(Sequence,Allocator>& vlist) const + { + if (!valid()) + return 0; + else + return local_data().variable_store.get_list(vlist); + } + + template class Sequence> + inline std::size_t get_variable_list(Sequence& vlist) const + { + if (!valid()) + return 0; + else + return local_data().variable_store.get_list(vlist); + } + + #ifndef exprtk_disable_string_capabilities + template class Sequence> + inline std::size_t get_stringvar_list(Sequence,Allocator>& svlist) const + { + if (!valid()) + return 0; + else + return local_data().stringvar_store.get_list(svlist); + } + + template class Sequence> + inline std::size_t get_stringvar_list(Sequence& svlist) const + { + if (!valid()) + return 0; + else + return local_data().stringvar_store.get_list(svlist); + } + #endif + + template class Sequence> + inline std::size_t get_vector_list(Sequence& vlist) const + { + if (!valid()) + return 0; + else + return local_data().vector_store.get_list(vlist); + } + + inline bool symbol_exists(const std::string& symbol_name, const bool check_reserved_symb = true) const + { + /* + Function will return true if symbol_name exists as either a + reserved symbol, variable, stringvar 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 (check_reserved_symb && local_data().is_reserved_symbol(symbol_name)) + return true; + else + return false; + } + + inline bool is_variable(const std::string& variable_name) const + { + if (!valid()) + return false; + else + return local_data().variable_store.symbol_exists(variable_name); + } + + #ifndef exprtk_disable_string_capabilities + inline bool is_stringvar(const std::string& stringvar_name) const + { + if (!valid()) + return false; + else + return local_data().stringvar_store.symbol_exists(stringvar_name); + } + + inline bool is_conststr_stringvar(const std::string& symbol_name) const + { + if (!valid()) + return false; + else if (!valid_symbol(symbol_name)) + return false; + else if (!local_data().stringvar_store.symbol_exists(symbol_name)) + return false; + + return ( + local_data().stringvar_store.symbol_exists(symbol_name) || + local_data().stringvar_store.is_constant (symbol_name) + ); + } + #endif + + inline bool is_function(const std::string& function_name) const + { + if (!valid()) + return false; + else + return local_data().function_store.symbol_exists(function_name); + } + + inline bool is_vararg_function(const std::string& vararg_function_name) const + { + if (!valid()) + return false; + else + return local_data().vararg_function_store.symbol_exists(vararg_function_name); + } + + inline bool is_vector(const std::string& vector_name) const + { + if (!valid()) + return false; + else + return local_data().vector_store.symbol_exists(vector_name); + } + + inline std::string get_variable_name(const expression_ptr& ptr) const + { + return local_data().variable_store.entity_name(ptr); + } + + inline std::string get_vector_name(const vector_holder_ptr& ptr) const + { + return local_data().vector_store.entity_name(ptr); + } + + #ifndef exprtk_disable_string_capabilities + inline std::string get_stringvar_name(const expression_ptr& ptr) const + { + return local_data().stringvar_store.entity_name(ptr); + } + + inline std::string get_conststr_stringvar_name(const expression_ptr& ptr) const + { + return local_data().stringvar_store.entity_name(ptr); + } + #endif + + inline bool valid() const + { + // Symbol table sanity check. + return control_block_ && control_block_->data_; + } + + inline void load_from(const symbol_table& st) + { + { + std::vector name_list; + + st.local_data().function_store.get_list(name_list); + + if (!name_list.empty()) { - return error_node(); - } -#endif - - 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 + 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); + } } - - template class Sequence> - inline expression_node_ptr const_optimise_switch(Sequence& arg_list) - { - expression_node_ptr result = error_node(); - - for (std::size_t i = 0; i < (arg_list.size() / 2); ++i) - { - expression_node_ptr condition = arg_list[(2 * i) ]; - expression_node_ptr consequent = arg_list[(2 * i) + 1]; - - if ((0 == result) && details::is_true(condition)) - { - result = consequent; - break; - } - } - - if (0 == result) - { - result = arg_list.back(); - } - - for (std::size_t i = 0; i < arg_list.size(); ++i) - { - expression_node_ptr current_expr = arg_list[i]; - - if (current_expr && (current_expr != result)) - { - free_node(*node_allocator_,current_expr); - } - } - - return result; - } - - template class Sequence> - inline expression_node_ptr const_optimise_mswitch(Sequence& arg_list) - { - expression_node_ptr result = error_node(); - - for (std::size_t i = 0; i < (arg_list.size() / 2); ++i) - { - expression_node_ptr condition = arg_list[(2 * i) ]; - expression_node_ptr consequent = arg_list[(2 * i) + 1]; - - if (details::is_true(condition)) - { - result = consequent; - } - } - - if (0 == result) - { - T zero = T(0); - result = node_allocator_->allocate(zero); - } - - for (std::size_t i = 0; i < arg_list.size(); ++i) - { - expression_node_ptr& current_expr = arg_list[i]; - - if (current_expr && (current_expr != result)) - { - free_node(*node_allocator_,current_expr); - } - } - - return result; - } - - struct switch_nodes - { - typedef std::vector arg_list_t; - -#define case_stmt(N) \ -if (is_true(arg[(2 * N)])) { return arg[(2 * N) + 1]->value(); } \ - - struct switch_1 - { - static inline T process(const arg_list_t& arg) - { - case_stmt(0) - return arg.back()->value(); - } - }; - - struct switch_2 - { - static inline T process(const arg_list_t& arg) - { - case_stmt(0) case_stmt(1) - return arg.back()->value(); - } - }; - - struct switch_3 - { - static inline T process(const arg_list_t& arg) - { - case_stmt(0) case_stmt(1) - case_stmt(2) - return arg.back()->value(); - } - }; - - struct switch_4 - { - static inline T process(const arg_list_t& arg) - { - case_stmt(0) case_stmt(1) - case_stmt(2) case_stmt(3) - return arg.back()->value(); - } - }; - - struct switch_5 - { - static inline T process(const arg_list_t& arg) - { - case_stmt(0) case_stmt(1) - case_stmt(2) case_stmt(3) - case_stmt(4) - return arg.back()->value(); - } - }; - - struct switch_6 - { - static inline T process(const arg_list_t& arg) - { - case_stmt(0) case_stmt(1) - case_stmt(2) case_stmt(3) - case_stmt(4) case_stmt(5) - return arg.back()->value(); - } - }; - - struct switch_7 - { - static inline T process(const arg_list_t& arg) - { - case_stmt(0) case_stmt(1) - case_stmt(2) case_stmt(3) - case_stmt(4) case_stmt(5) - case_stmt(6) - return arg.back()->value(); - } - }; - -#undef case_stmt - }; - - template class Sequence> - inline expression_node_ptr switch_statement(Sequence& arg_list) - { - if (arg_list.empty()) - return error_node(); - else if ( - !all_nodes_valid(arg_list) || - (arg_list.size() < 3) || - ((arg_list.size() % 2) != 1) - ) - { - details::free_all_nodes(*node_allocator_,arg_list); - - return error_node(); - } - else if (is_constant_foldable(arg_list)) - return const_optimise_switch(arg_list); - - switch ((arg_list.size() - 1) / 2) - { -#define case_stmt(N) \ -case N : \ -return node_allocator_-> \ -allocate >(arg_list); \ - - case_stmt(1) - case_stmt(2) - case_stmt(3) - case_stmt(4) - case_stmt(5) - case_stmt(6) - case_stmt(7) -#undef case_stmt - - default : return node_allocator_->allocate >(arg_list); - } - } - - template class Sequence> - inline expression_node_ptr multi_switch_statement(Sequence& arg_list) - { - if (!all_nodes_valid(arg_list)) - { - details::free_all_nodes(*node_allocator_,arg_list); - - return error_node(); - } - else if (is_constant_foldable(arg_list)) - return const_optimise_mswitch(arg_list); - else - return node_allocator_->allocate >(arg_list); - } - -#define unary_opr_switch_statements \ -case_stmt(details:: e_abs,details:: abs_op) \ -case_stmt(details:: e_acos,details:: acos_op) \ -case_stmt(details::e_acosh,details::acosh_op) \ -case_stmt(details:: e_asin,details:: asin_op) \ -case_stmt(details::e_asinh,details::asinh_op) \ -case_stmt(details:: e_atan,details:: atan_op) \ -case_stmt(details::e_atanh,details::atanh_op) \ -case_stmt(details:: e_ceil,details:: ceil_op) \ -case_stmt(details:: e_cos,details:: cos_op) \ -case_stmt(details:: e_cosh,details:: cosh_op) \ -case_stmt(details:: e_exp,details:: exp_op) \ -case_stmt(details::e_expm1,details::expm1_op) \ -case_stmt(details::e_floor,details::floor_op) \ -case_stmt(details:: e_log,details:: log_op) \ -case_stmt(details::e_log10,details::log10_op) \ -case_stmt(details:: e_log2,details:: log2_op) \ -case_stmt(details::e_log1p,details::log1p_op) \ -case_stmt(details:: e_neg,details:: neg_op) \ -case_stmt(details:: e_pos,details:: pos_op) \ -case_stmt(details::e_round,details::round_op) \ -case_stmt(details:: e_sin,details:: sin_op) \ -case_stmt(details:: e_sinc,details:: sinc_op) \ -case_stmt(details:: e_sinh,details:: sinh_op) \ -case_stmt(details:: e_sqrt,details:: sqrt_op) \ -case_stmt(details:: e_tan,details:: tan_op) \ -case_stmt(details:: e_tanh,details:: tanh_op) \ -case_stmt(details:: e_cot,details:: cot_op) \ -case_stmt(details:: e_sec,details:: sec_op) \ -case_stmt(details:: e_csc,details:: csc_op) \ -case_stmt(details:: e_r2d,details:: r2d_op) \ -case_stmt(details:: e_d2r,details:: d2r_op) \ -case_stmt(details:: e_d2g,details:: d2g_op) \ -case_stmt(details:: e_g2d,details:: g2d_op) \ -case_stmt(details:: e_notl,details:: notl_op) \ -case_stmt(details:: e_sgn,details:: sgn_op) \ -case_stmt(details:: e_erf,details:: erf_op) \ -case_stmt(details:: e_erfc,details:: erfc_op) \ -case_stmt(details:: e_ncdf,details:: ncdf_op) \ -case_stmt(details:: e_frac,details:: frac_op) \ -case_stmt(details::e_trunc,details::trunc_op) \ - - inline expression_node_ptr synthesize_uv_expression(const details::operator_type& operation, - expression_node_ptr (&branch)[1]) - { - T& v = static_cast*>(branch[0])->ref(); - - switch (operation) - { -#define case_stmt(op0,op1) \ -case op0 : return node_allocator_-> \ -allocate > >(v); \ - - unary_opr_switch_statements -#undef case_stmt - default : return error_node(); - } - } - - inline expression_node_ptr synthesize_uvec_expression(const details::operator_type& operation, - expression_node_ptr (&branch)[1]) - { - switch (operation) - { -#define case_stmt(op0,op1) \ -case op0 : return node_allocator_-> \ -allocate > > \ -(operation,branch[0]); \ - - unary_opr_switch_statements -#undef case_stmt - default : return error_node(); - } - } - - inline expression_node_ptr synthesize_unary_expression(const details::operator_type& operation, - expression_node_ptr (&branch)[1]) - { - switch (operation) - { -#define case_stmt(op0,op1) \ -case op0 : return node_allocator_-> \ -allocate > >(branch[0]); \ - - unary_opr_switch_statements -#undef case_stmt - default : return error_node(); - } - } - - inline expression_node_ptr const_optimise_sf3(const details::operator_type& operation, - expression_node_ptr (&branch)[3]) - { - expression_node_ptr temp_node = error_node(); - - switch (operation) - { -#define case_stmt(op) \ -case details::e_sf##op : temp_node = node_allocator_-> \ -allocate > > \ -(operation,branch); \ -break; \ - - case_stmt(00) case_stmt(01) case_stmt(02) case_stmt(03) - case_stmt(04) case_stmt(05) case_stmt(06) case_stmt(07) - case_stmt(08) case_stmt(09) case_stmt(10) case_stmt(11) - case_stmt(12) case_stmt(13) case_stmt(14) case_stmt(15) - case_stmt(16) case_stmt(17) case_stmt(18) case_stmt(19) - case_stmt(20) case_stmt(21) case_stmt(22) case_stmt(23) - case_stmt(24) case_stmt(25) case_stmt(26) case_stmt(27) - case_stmt(28) case_stmt(29) case_stmt(30) case_stmt(31) - case_stmt(32) case_stmt(33) case_stmt(34) case_stmt(35) - case_stmt(36) case_stmt(37) case_stmt(38) case_stmt(39) - case_stmt(40) case_stmt(41) case_stmt(42) case_stmt(43) - case_stmt(44) case_stmt(45) case_stmt(46) case_stmt(47) -#undef case_stmt - default : return error_node(); - } - - T v = temp_node->value(); - - details::free_node(*node_allocator_,temp_node); - - return node_allocator_->allocate(v); - } - - inline expression_node_ptr varnode_optimise_sf3(const details::operator_type& operation, expression_node_ptr (&branch)[3]) - { - typedef details::variable_node* variable_ptr; - - const Type& v0 = static_cast(branch[0])->ref(); - const Type& v1 = static_cast(branch[1])->ref(); - const Type& v2 = static_cast(branch[2])->ref(); - - switch (operation) - { -#define case_stmt(op) \ -case details::e_sf##op : return node_allocator_-> \ -allocate_rrr > > \ -(v0,v1,v2); \ - - case_stmt(00) case_stmt(01) case_stmt(02) case_stmt(03) - case_stmt(04) case_stmt(05) case_stmt(06) case_stmt(07) - case_stmt(08) case_stmt(09) case_stmt(10) case_stmt(11) - case_stmt(12) case_stmt(13) case_stmt(14) case_stmt(15) - case_stmt(16) case_stmt(17) case_stmt(18) case_stmt(19) - case_stmt(20) case_stmt(21) case_stmt(22) case_stmt(23) - case_stmt(24) case_stmt(25) case_stmt(26) case_stmt(27) - case_stmt(28) case_stmt(29) case_stmt(30) case_stmt(31) - case_stmt(32) case_stmt(33) case_stmt(34) case_stmt(35) - case_stmt(36) case_stmt(37) case_stmt(38) case_stmt(39) - case_stmt(40) case_stmt(41) case_stmt(42) case_stmt(43) - case_stmt(44) case_stmt(45) case_stmt(46) case_stmt(47) -#undef case_stmt - default : return error_node(); - } - } - - inline expression_node_ptr special_function(const details::operator_type& operation, expression_node_ptr (&branch)[3]) - { - if (!all_nodes_valid(branch)) - return error_node(); - else if (is_constant_foldable(branch)) - return const_optimise_sf3(operation,branch); - else if (all_nodes_variables(branch)) - return varnode_optimise_sf3(operation,branch); - else - { - switch (operation) - { -#define case_stmt(op) \ -case details::e_sf##op : return node_allocator_-> \ -allocate > > \ -(operation,branch); \ - - case_stmt(00) case_stmt(01) case_stmt(02) case_stmt(03) - case_stmt(04) case_stmt(05) case_stmt(06) case_stmt(07) - case_stmt(08) case_stmt(09) case_stmt(10) case_stmt(11) - case_stmt(12) case_stmt(13) case_stmt(14) case_stmt(15) - case_stmt(16) case_stmt(17) case_stmt(18) case_stmt(19) - case_stmt(20) case_stmt(21) case_stmt(22) case_stmt(23) - case_stmt(24) case_stmt(25) case_stmt(26) case_stmt(27) - case_stmt(28) case_stmt(29) case_stmt(30) case_stmt(31) - case_stmt(32) case_stmt(33) case_stmt(34) case_stmt(35) - case_stmt(36) case_stmt(37) case_stmt(38) case_stmt(39) - case_stmt(40) case_stmt(41) case_stmt(42) case_stmt(43) - case_stmt(44) case_stmt(45) case_stmt(46) case_stmt(47) -#undef case_stmt - default : return error_node(); - } - } - } - - inline expression_node_ptr const_optimise_sf4(const details::operator_type& operation, expression_node_ptr (&branch)[4]) - { - expression_node_ptr temp_node = error_node(); - - switch (operation) - { -#define case_stmt(op) \ -case details::e_sf##op : temp_node = node_allocator_-> \ -allocate > > \ -(operation,branch); \ -break; \ - - case_stmt(48) case_stmt(49) case_stmt(50) case_stmt(51) - case_stmt(52) case_stmt(53) case_stmt(54) case_stmt(55) - case_stmt(56) case_stmt(57) case_stmt(58) case_stmt(59) - case_stmt(60) case_stmt(61) case_stmt(62) case_stmt(63) - case_stmt(64) case_stmt(65) case_stmt(66) case_stmt(67) - case_stmt(68) case_stmt(69) case_stmt(70) case_stmt(71) - case_stmt(72) case_stmt(73) case_stmt(74) case_stmt(75) - case_stmt(76) case_stmt(77) case_stmt(78) case_stmt(79) - case_stmt(80) case_stmt(81) case_stmt(82) case_stmt(83) - case_stmt(84) case_stmt(85) case_stmt(86) case_stmt(87) - case_stmt(88) case_stmt(89) case_stmt(90) case_stmt(91) - case_stmt(92) case_stmt(93) case_stmt(94) case_stmt(95) - case_stmt(96) case_stmt(97) case_stmt(98) case_stmt(99) -#undef case_stmt - default : return error_node(); - } - - T v = temp_node->value(); - details::free_node(*node_allocator_,temp_node); - - return node_allocator_->allocate(v); - } - - inline expression_node_ptr varnode_optimise_sf4(const details::operator_type& operation, expression_node_ptr (&branch)[4]) - { - typedef details::variable_node* variable_ptr; - - const Type& v0 = static_cast(branch[0])->ref(); - const Type& v1 = static_cast(branch[1])->ref(); - const Type& v2 = static_cast(branch[2])->ref(); - const Type& v3 = static_cast(branch[3])->ref(); - - switch (operation) - { -#define case_stmt(op) \ -case details::e_sf##op : return node_allocator_-> \ -allocate_rrrr > > \ -(v0,v1,v2,v3); \ - - case_stmt(48) case_stmt(49) case_stmt(50) case_stmt(51) - case_stmt(52) case_stmt(53) case_stmt(54) case_stmt(55) - case_stmt(56) case_stmt(57) case_stmt(58) case_stmt(59) - case_stmt(60) case_stmt(61) case_stmt(62) case_stmt(63) - case_stmt(64) case_stmt(65) case_stmt(66) case_stmt(67) - case_stmt(68) case_stmt(69) case_stmt(70) case_stmt(71) - case_stmt(72) case_stmt(73) case_stmt(74) case_stmt(75) - case_stmt(76) case_stmt(77) case_stmt(78) case_stmt(79) - case_stmt(80) case_stmt(81) case_stmt(82) case_stmt(83) - case_stmt(84) case_stmt(85) case_stmt(86) case_stmt(87) - case_stmt(88) case_stmt(89) case_stmt(90) case_stmt(91) - case_stmt(92) case_stmt(93) case_stmt(94) case_stmt(95) - case_stmt(96) case_stmt(97) case_stmt(98) case_stmt(99) -#undef case_stmt - default : return error_node(); - } - } - - inline expression_node_ptr special_function(const details::operator_type& operation, expression_node_ptr (&branch)[4]) - { - if (!all_nodes_valid(branch)) - return error_node(); - else if (is_constant_foldable(branch)) - return const_optimise_sf4(operation,branch); - else if (all_nodes_variables(branch)) - return varnode_optimise_sf4(operation,branch); - switch (operation) - { -#define case_stmt(op) \ -case details::e_sf##op : return node_allocator_-> \ -allocate > > \ -(operation,branch); \ - - case_stmt(48) case_stmt(49) case_stmt(50) case_stmt(51) - case_stmt(52) case_stmt(53) case_stmt(54) case_stmt(55) - case_stmt(56) case_stmt(57) case_stmt(58) case_stmt(59) - case_stmt(60) case_stmt(61) case_stmt(62) case_stmt(63) - case_stmt(64) case_stmt(65) case_stmt(66) case_stmt(67) - case_stmt(68) case_stmt(69) case_stmt(70) case_stmt(71) - case_stmt(72) case_stmt(73) case_stmt(74) case_stmt(75) - case_stmt(76) case_stmt(77) case_stmt(78) case_stmt(79) - case_stmt(80) case_stmt(81) case_stmt(82) case_stmt(83) - case_stmt(84) case_stmt(85) case_stmt(86) case_stmt(87) - case_stmt(88) case_stmt(89) case_stmt(90) case_stmt(91) - case_stmt(92) case_stmt(93) case_stmt(94) case_stmt(95) - case_stmt(96) case_stmt(97) case_stmt(98) case_stmt(99) -#undef case_stmt - default : return error_node(); - } - } - - template class Sequence> - inline expression_node_ptr const_optimise_varargfunc(const details::operator_type& operation, Sequence& arg_list) - { - expression_node_ptr temp_node = error_node(); - - switch (operation) - { -#define case_stmt(op0,op1) \ -case op0 : temp_node = node_allocator_-> \ -allocate > > \ -(arg_list); \ -break; \ - - case_stmt(details::e_sum, details::vararg_add_op ) - case_stmt(details::e_prod, details::vararg_mul_op ) - case_stmt(details::e_avg, details::vararg_avg_op ) - case_stmt(details::e_min, details::vararg_min_op ) - case_stmt(details::e_max, details::vararg_max_op ) - case_stmt(details::e_mand, details::vararg_mand_op ) - case_stmt(details::e_mor, details::vararg_mor_op ) - case_stmt(details::e_multi,details::vararg_multi_op) -#undef case_stmt - default : return error_node(); - } - - 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_optimise_varargfunc(const details::operator_type& operation, Sequence& arg_list) - { - switch (operation) - { -#define case_stmt(op0,op1) \ -case op0 : return node_allocator_-> \ -allocate > >(arg_list); \ - - case_stmt(details::e_sum, details::vararg_add_op ) - case_stmt(details::e_prod, details::vararg_mul_op ) - case_stmt(details::e_avg, details::vararg_avg_op ) - case_stmt(details::e_min, details::vararg_min_op ) - case_stmt(details::e_max, details::vararg_max_op ) - case_stmt(details::e_mand, details::vararg_mand_op ) - case_stmt(details::e_mor, details::vararg_mor_op ) - case_stmt(details::e_multi,details::vararg_multi_op) -#undef case_stmt - default : return error_node(); - } - } - - template class Sequence> - inline expression_node_ptr vectorize_func(const details::operator_type& operation, Sequence& arg_list) - { - if (1 == arg_list.size()) - { - switch (operation) - { -#define case_stmt(op0,op1) \ -case op0 : return node_allocator_-> \ -allocate > >(arg_list[0]); \ - - case_stmt(details::e_sum, details::vec_add_op) - case_stmt(details::e_prod, details::vec_mul_op) - case_stmt(details::e_avg, details::vec_avg_op) - case_stmt(details::e_min, details::vec_min_op) - case_stmt(details::e_max, details::vec_max_op) -#undef case_stmt - default : return error_node(); - } - } - else - return error_node(); - } - - template class Sequence> - inline expression_node_ptr vararg_function(const details::operator_type& operation, Sequence& arg_list) - { - if (!all_nodes_valid(arg_list)) - { - details::free_all_nodes(*node_allocator_,arg_list); - - return error_node(); - } - else if (is_constant_foldable(arg_list)) - return const_optimise_varargfunc(operation,arg_list); - else if ((arg_list.size() == 1) && details::is_ivector_node(arg_list[0])) - return vectorize_func(operation,arg_list); - else if ((arg_list.size() == 1) && special_one_parameter_vararg(operation)) - return arg_list[0]; - else if (all_nodes_variables(arg_list)) - return varnode_optimise_varargfunc(operation,arg_list); - - switch (operation) - { -#define case_stmt(op0,op1) \ -case op0 : return node_allocator_-> \ -allocate > >(arg_list); \ - - case_stmt(details::e_sum, details::vararg_add_op ) - case_stmt(details::e_prod, details::vararg_mul_op ) - case_stmt(details::e_avg, details::vararg_avg_op ) - case_stmt(details::e_min, details::vararg_min_op ) - case_stmt(details::e_max, details::vararg_max_op ) - case_stmt(details::e_mand, details::vararg_mand_op ) - case_stmt(details::e_mor, details::vararg_mor_op ) - case_stmt(details::e_multi,details::vararg_multi_op) -#undef case_stmt - default : return error_node(); - } - } - - template - inline expression_node_ptr function(ifunction_t* f, expression_node_ptr (&b)[N]) - { - typedef typename details::function_N_node function_N_node_t; - expression_node_ptr result = synthesize_expression(f,b); - - if (0 == result) - return error_node(); - else - { - // Can the function call be completely optimised? - if (details::is_constant_node(result)) - return result; - else if (!all_nodes_valid(b)) - 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); - } - - parser_->state_.activate_side_effect("vararg_function_call()"); - - return result; - } - - inline expression_node_ptr generic_function_call(igeneric_function_t* gf, - std::vector& arg_list, - const std::size_t& param_seq_index = std::numeric_limits::max()) - { - if (!all_nodes_valid(arg_list)) - { - details::free_all_nodes(*node_allocator_,arg_list); - return error_node(); - } - - typedef details::generic_function_node alloc_type1; - typedef details::multimode_genfunction_node alloc_type2; - - const std::size_t no_psi = std::numeric_limits::max(); - - expression_node_ptr result = error_node(); - - if (no_psi == param_seq_index) - result = node_allocator_->allocate(arg_list,gf); - else - result = node_allocator_->allocate(gf,param_seq_index,arg_list); - - alloc_type1* genfunc_node_ptr = static_cast(result); - - if ( - !arg_list.empty() && - !gf->has_side_effects() && - 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()) - { - parser_->state_.activate_side_effect("generic_function_call()"); - return result; - } - else - { - details::free_node(*node_allocator_,result); - details::free_all_nodes(*node_allocator_,arg_list); - return error_node(); - } - } - - 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()) - { - parser_->state_.activate_side_effect("string_function_call()"); - - return result; - } - else - { - details::free_node(*node_allocator_,result); - details::free_all_nodes(*node_allocator_,arg_list); - - return error_node(); - } - } - - inline expression_node_ptr return_call(std::vector& arg_list) - { - if (!all_nodes_valid(arg_list)) - { - details::free_all_nodes(*node_allocator_,arg_list); - return error_node(); - } - - typedef details::return_node alloc_type; - - expression_node_ptr result = node_allocator_-> - allocate_rr(arg_list,parser_->results_ctx()); - - alloc_type* return_node_ptr = static_cast(result); - - if (return_node_ptr->init_branches()) - { - parser_->state_.activate_side_effect("return_call()"); - - return result; - } - else - { - details::free_node(*node_allocator_,result); - details::free_all_nodes(*node_allocator_,arg_list); - - return error_node(); - } - } - - inline expression_node_ptr return_envelope(expression_node_ptr body, - results_context_t* rc, - bool*& return_invoked) - { - typedef details::return_envelope_node alloc_type; - - expression_node_ptr result = node_allocator_-> - allocate_cr(body,(*rc)); - - return_invoked = static_cast(result)->retinvk_ptr(); - - return result; - } - - inline expression_node_ptr vector_element(const std::string& symbol, - vector_holder_ptr vector_base, - expression_node_ptr index) - { - expression_node_ptr result = error_node(); - - if (details::is_constant_node(index)) - { - std::size_t i = static_cast(details::numeric::to_int64(index->value())); - - details::free_node(*node_allocator_,index); - - if (vector_base->rebaseable()) - { - return node_allocator_->allocate(i,vector_base); - } - - scope_element& se = parser_->sem_.get_element(symbol,i); - - if (se.index == i) - { - result = se.var_node; - } - else - { - scope_element nse; - nse.name = symbol; - nse.active = true; - nse.ref_count = 1; - nse.type = scope_element::e_vecelem; - nse.index = i; - nse.depth = parser_->state_.scope_depth; - nse.data = 0; - nse.var_node = node_allocator_->allocate((*(*vector_base)[i])); - - if (!parser_->sem_.add_element(nse)) - { - parser_->set_synthesis_error("Failed to add new local vector element to SEM [1]"); - - parser_->sem_.free_element(nse); - - result = error_node(); - } - - exprtk_debug(("vector_element() - INFO - Added new local vector element: %s\n",nse.name.c_str())); - - parser_->state_.activate_side_effect("vector_element()"); - - result = nse.var_node; - } - } - else if (vector_base->rebaseable()) - result = node_allocator_->allocate(index,vector_base); - else - result = node_allocator_->allocate(index,vector_base); - - return result; - } - - private: - - template - inline bool is_constant_foldable(NodePtr (&b)[N]) const - { - for (std::size_t i = 0; i < N; ++i) - { - if (0 == b[i]) - return false; - else if (!details::is_constant_node(b[i])) - return false; - } - - return true; - } - - template class Sequence> - inline bool is_constant_foldable(const Sequence& b) const - { - for (std::size_t i = 0; i < b.size(); ++i) - { - if (0 == b[i]) - return false; - else if (!details::is_constant_node(b[i])) - return false; - } - - return true; - } - - void lodge_assignment(symbol_type cst, expression_node_ptr node) - { - parser_->state_.activate_side_effect("lodge_assignment()"); - - if (!parser_->dec_.collect_assignments()) - return; - - std::string symbol_name; - - switch (cst) - { - case e_st_variable : symbol_name = parser_->symtab_store_ - .get_variable_name(node); - break; - -#ifndef exprtk_disable_string_capabilities - case e_st_string : symbol_name = parser_->symtab_store_ - .get_stringvar_name(node); - break; -#endif - - case e_st_vector : { - typedef details::vector_holder vector_holder_t; - - vector_holder_t& vh = static_cast(node)->vec_holder(); - - symbol_name = parser_->symtab_store_.get_vector_name(&vh); - } - break; - - case e_st_vecelem : { - typedef details::vector_holder vector_holder_t; - - vector_holder_t& vh = static_cast(node)->vec_holder(); - - symbol_name = parser_->symtab_store_.get_vector_name(&vh); - - cst = e_st_vector; - } - break; - - default : return; - } - - if (!symbol_name.empty()) - { - parser_->dec_.add_assignment(symbol_name,cst); - } - } - - inline expression_node_ptr synthesize_assignment_expression(const details::operator_type& operation, expression_node_ptr (&branch)[2]) - { - if (details::is_variable_node(branch[0])) - { - lodge_assignment(e_st_variable,branch[0]); - - return synthesize_expression(operation,branch); - } - else if (details::is_vector_elem_node(branch[0])) - { - lodge_assignment(e_st_vecelem,branch[0]); - - return synthesize_expression(operation, branch); - } - else if (details::is_rebasevector_elem_node(branch[0])) - { - lodge_assignment(e_st_vecelem,branch[0]); - - return synthesize_expression(operation, branch); - } - else if (details::is_rebasevector_celem_node(branch[0])) - { - lodge_assignment(e_st_vecelem,branch[0]); - - return synthesize_expression(operation, branch); - } -#ifndef exprtk_disable_string_capabilities - else if (details::is_string_node(branch[0])) - { - lodge_assignment(e_st_string,branch[0]); - - return synthesize_expression(operation,branch); - } - else if (details::is_string_range_node(branch[0])) - { - lodge_assignment(e_st_string,branch[0]); - - return synthesize_expression(operation,branch); - } -#endif - else if (details::is_vector_node(branch[0])) - { - lodge_assignment(e_st_vector,branch[0]); - - if (details::is_ivector_node(branch[1])) - return synthesize_expression(operation,branch); - else - return synthesize_expression(operation,branch); - } - else - { - parser_->set_synthesis_error("Invalid assignment operation.[1]"); - - return error_node(); - } - } - - inline expression_node_ptr synthesize_assignment_operation_expression(const details::operator_type& operation, - expression_node_ptr (&branch)[2]) + } + + { + std::vector name_list; + + st.local_data().vararg_function_store.get_list(name_list); + + if (!name_list.empty()) { - 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_rebasevector_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_rebasevector_celem_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(); - } - } - } -#ifndef exprtk_disable_string_capabilities - else if ( - (details::e_addass == operation) && - details::is_string_node(branch[0]) - ) - { - typedef details::assignment_string_node addass_t; - - lodge_assignment(e_st_string,branch[0]); - - return synthesize_expression(operation,branch); - } -#endif - else - { - parser_->set_synthesis_error("Invalid assignment operation[2]"); - - return error_node(); - } - } - - inline expression_node_ptr synthesize_veceqineqlogic_operation_expression(const details::operator_type& operation, - expression_node_ptr (&branch)[2]) - { - const bool is_b0_ivec = details::is_ivector_node(branch[0]); - const bool is_b1_ivec = details::is_ivector_node(branch[1]); - -#define batch_eqineq_logic_case \ -case_stmt(details:: e_lt,details:: lt_op) \ -case_stmt(details:: e_lte,details:: lte_op) \ -case_stmt(details:: e_gt,details:: gt_op) \ -case_stmt(details:: e_gte,details:: gte_op) \ -case_stmt(details:: e_eq,details:: eq_op) \ -case_stmt(details:: e_ne,details:: ne_op) \ -case_stmt(details::e_equal,details::equal_op) \ -case_stmt(details:: e_and, details::and_op) \ -case_stmt(details:: e_nand, details::nand_op) \ -case_stmt(details:: e_or, details:: or_op) \ -case_stmt(details:: e_nor, details:: nor_op) \ -case_stmt(details:: e_xor, details:: xor_op) \ -case_stmt(details:: e_xnor, details::xnor_op) \ - - if (is_b0_ivec && is_b1_ivec) - { - switch (operation) - { -#define case_stmt(op0,op1) \ -case op0 : return node_allocator_-> \ -template allocate_rrr > > \ -(operation,branch[0],branch[1]); \ - - batch_eqineq_logic_case -#undef case_stmt - default : return error_node(); - } - } - else if (is_b0_ivec && !is_b1_ivec) - { - switch (operation) - { -#define case_stmt(op0,op1) \ -case op0 : return node_allocator_-> \ -template allocate_rrr > > \ -(operation,branch[0],branch[1]); \ - - batch_eqineq_logic_case -#undef case_stmt - default : return error_node(); - } - } - else if (!is_b0_ivec && is_b1_ivec) - { - switch (operation) - { -#define case_stmt(op0,op1) \ -case op0 : return node_allocator_-> \ -template allocate_rrr > > \ -(operation,branch[0],branch[1]); \ - - batch_eqineq_logic_case -#undef case_stmt - default : return error_node(); - } - } - else - return error_node(); - -#undef batch_eqineq_logic_case - } - - inline expression_node_ptr synthesize_vecarithmetic_operation_expression(const details::operator_type& operation, - expression_node_ptr (&branch)[2]) - { - const bool is_b0_ivec = details::is_ivector_node(branch[0]); - const bool is_b1_ivec = details::is_ivector_node(branch[1]); - -#define vector_ops \ -case_stmt(details::e_add,details::add_op) \ -case_stmt(details::e_sub,details::sub_op) \ -case_stmt(details::e_mul,details::mul_op) \ -case_stmt(details::e_div,details::div_op) \ -case_stmt(details::e_mod,details::mod_op) \ - - if (is_b0_ivec && is_b1_ivec) - { - switch (operation) - { -#define case_stmt(op0,op1) \ -case op0 : return node_allocator_-> \ -template allocate_rrr > > \ -(operation,branch[0],branch[1]); \ - - vector_ops - case_stmt(details::e_pow,details:: pow_op) -#undef case_stmt - default : return error_node(); - } - } - else if (is_b0_ivec && !is_b1_ivec) - { - switch (operation) - { -#define case_stmt(op0,op1) \ -case op0 : return node_allocator_-> \ -template allocate_rrr > > \ -(operation,branch[0],branch[1]); \ - - vector_ops - case_stmt(details::e_pow,details:: pow_op) -#undef case_stmt - default : return error_node(); - } - } - else if (!is_b0_ivec && is_b1_ivec) - { - switch (operation) - { -#define case_stmt(op0,op1) \ -case op0 : return node_allocator_-> \ -template allocate_rrr > > \ -(operation,branch[0],branch[1]); \ - - vector_ops -#undef case_stmt - default : return error_node(); - } - } - else - return error_node(); - -#undef vector_ops - } - - inline expression_node_ptr synthesize_swap_expression(expression_node_ptr (&branch)[2]) - { - const bool v0_is_ivar = details::is_ivariable_node(branch[0]); - const bool v1_is_ivar = details::is_ivariable_node(branch[1]); - - const bool v0_is_ivec = details::is_ivector_node(branch[0]); - const bool v1_is_ivec = details::is_ivector_node(branch[1]); - -#ifndef exprtk_disable_string_capabilities - const bool v0_is_str = details::is_generally_string_node(branch[0]); - const bool v1_is_str = details::is_generally_string_node(branch[1]); -#endif - - expression_node_ptr result = error_node(); - - if (v0_is_ivar && v1_is_ivar) - { - typedef details::variable_node* variable_node_ptr; - - variable_node_ptr v0 = variable_node_ptr(0); - variable_node_ptr v1 = variable_node_ptr(0); - - if ( - (0 != (v0 = dynamic_cast(branch[0]))) && - (0 != (v1 = dynamic_cast(branch[1]))) - ) - { - result = node_allocator_->allocate >(v0,v1); - } - else - result = node_allocator_->allocate >(branch[0],branch[1]); - } - else if (v0_is_ivec && v1_is_ivec) - { - result = node_allocator_->allocate >(branch[0],branch[1]); - } -#ifndef exprtk_disable_string_capabilities - else if (v0_is_str && v1_is_str) - { - if (is_string_node(branch[0]) && is_string_node(branch[1])) - result = node_allocator_->allocate >(branch[0],branch[1]); - else - result = node_allocator_->allocate >(branch[0],branch[1]); - } -#endif - else - { - parser_->set_synthesis_error("Only variables, strings, vectors or vector elements can be swapped"); - - return error_node(); - } - - parser_->state_.activate_side_effect("synthesize_swap_expression()"); - - return result; - } - -#ifndef exprtk_disable_sc_andor - inline expression_node_ptr synthesize_shortcircuit_expression(const details::operator_type& operation, expression_node_ptr (&branch)[2]) - { - expression_node_ptr result = error_node(); - - if (details::is_constant_node(branch[0])) - { - if ( - (details::e_scand == operation) && - std::equal_to()(T(0),branch[0]->value()) - ) - result = node_allocator_->allocate_c(T(0)); - else if ( - (details::e_scor == operation) && - std::not_equal_to()(T(0),branch[0]->value()) - ) - result = node_allocator_->allocate_c(T(1)); - } - - if (details::is_constant_node(branch[1]) && (0 == result)) - { - if ( - (details::e_scand == operation) && - std::equal_to()(T(0),branch[1]->value()) - ) - result = node_allocator_->allocate_c(T(0)); - else if ( - (details::e_scor == operation) && - std::not_equal_to()(T(0),branch[1]->value()) - ) - result = node_allocator_->allocate_c(T(1)); - } - - if (result) - { - 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(); + 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); + } } -#else - inline expression_node_ptr synthesize_shortcircuit_expression(const details::operator_type&, expression_node_ptr (&)[2]) + } + + { + std::vector name_list; + + st.local_data().generic_function_store.get_list(name_list); + + if (!name_list.empty()) { - return error_node(); + 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); + } } -#endif - -#define basic_opr_switch_statements \ -case_stmt(details::e_add,details::add_op) \ -case_stmt(details::e_sub,details::sub_op) \ -case_stmt(details::e_mul,details::mul_op) \ -case_stmt(details::e_div,details::div_op) \ -case_stmt(details::e_mod,details::mod_op) \ -case_stmt(details::e_pow,details::pow_op) \ - -#define extended_opr_switch_statements \ -case_stmt(details:: e_lt,details:: lt_op) \ -case_stmt(details:: e_lte,details:: lte_op) \ -case_stmt(details:: e_gt,details:: gt_op) \ -case_stmt(details:: e_gte,details:: gte_op) \ -case_stmt(details:: e_eq,details:: eq_op) \ -case_stmt(details:: e_ne,details:: ne_op) \ -case_stmt(details:: e_and,details:: and_op) \ -case_stmt(details::e_nand,details::nand_op) \ -case_stmt(details:: e_or,details:: or_op) \ -case_stmt(details:: e_nor,details:: nor_op) \ -case_stmt(details:: e_xor,details:: xor_op) \ -case_stmt(details::e_xnor,details::xnor_op) \ - -#ifndef exprtk_disable_cardinal_pow_optimisation - template class IPowNode> - inline expression_node_ptr cardinal_pow_optimisation_impl(const TType& v, const unsigned int& p) - { - switch (p) - { -#define case_stmt(cp) \ -case cp : return node_allocator_-> \ -allocate > >(v); \ - - case_stmt( 1) case_stmt( 2) case_stmt( 3) case_stmt( 4) - case_stmt( 5) case_stmt( 6) case_stmt( 7) case_stmt( 8) - case_stmt( 9) case_stmt(10) case_stmt(11) case_stmt(12) - case_stmt(13) case_stmt(14) case_stmt(15) case_stmt(16) - case_stmt(17) case_stmt(18) case_stmt(19) case_stmt(20) - case_stmt(21) case_stmt(22) case_stmt(23) case_stmt(24) - case_stmt(25) case_stmt(26) case_stmt(27) case_stmt(28) - case_stmt(29) case_stmt(30) case_stmt(31) case_stmt(32) - case_stmt(33) case_stmt(34) case_stmt(35) case_stmt(36) - case_stmt(37) case_stmt(38) case_stmt(39) case_stmt(40) - case_stmt(41) case_stmt(42) case_stmt(43) case_stmt(44) - case_stmt(45) case_stmt(46) case_stmt(47) case_stmt(48) - case_stmt(49) case_stmt(50) case_stmt(51) case_stmt(52) - case_stmt(53) case_stmt(54) case_stmt(55) case_stmt(56) - case_stmt(57) case_stmt(58) case_stmt(59) case_stmt(60) -#undef case_stmt - default : return error_node(); - } - } - - inline expression_node_ptr cardinal_pow_optimisation(const T& v, const T& c) - { - const bool not_recipricol = (c >= T(0)); - const int p = details::numeric::to_int32(details::numeric::abs(c)); - - if (0 == p) - return node_allocator_->allocate_c(T(1)); - else if (std::equal_to()(T(2),c)) - { - return node_allocator_-> - template allocate_rr > >(v,v); - } - else - { - if (not_recipricol) - return cardinal_pow_optimisation_impl(v,p); - else - return cardinal_pow_optimisation_impl(v,p); - } - } - - inline bool cardinal_pow_optimisable(const details::operator_type& operation, const T& c) - { - return (details::e_pow == operation) && (details::numeric::abs(c) <= T(60)) && details::numeric::is_integer(c); - } - - inline expression_node_ptr cardinal_pow_optimisation(expression_node_ptr (&branch)[2]) - { - const Type c = static_cast*>(branch[1])->value(); - const bool not_recipricol = (c >= T(0)); - const int p = details::numeric::to_int32(details::numeric::abs(c)); - - node_allocator_->free(branch[1]); - - if (0 == p) - { - details::free_all_nodes(*node_allocator_, branch); - return node_allocator_->allocate_c(T(1)); - } - else if (not_recipricol) - return cardinal_pow_optimisation_impl(branch[0],p); - else - return cardinal_pow_optimisation_impl(branch[0],p); - } -#else - inline expression_node_ptr cardinal_pow_optimisation(T&, const T&) + } + + { + std::vector name_list; + + st.local_data().string_function_store.get_list(name_list); + + if (!name_list.empty()) { - return error_node(); + 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); + } } - - inline bool cardinal_pow_optimisable(const details::operator_type&, const T&) + } + } + + private: + + inline bool valid_symbol(const std::string& symbol, const bool check_reserved_symb = true) const + { + if (symbol.empty()) + return false; + else if (!details::is_letter(symbol[0])) + return false; + else if (symbol.size() > 1) + { + for (std::size_t i = 1; i < symbol.size(); ++i) + { + if ( + !details::is_letter_or_digit(symbol[i]) && + ('_' != symbol[i]) + ) + { + if (('.' == symbol[i]) && (i < (symbol.size() - 1))) + continue; + else + return false; + } + } + } + + return (check_reserved_symb) ? (!local_data().is_reserved_symbol(symbol)) : true; + } + + inline bool valid_function(const std::string& symbol) const + { + if (symbol.empty()) + return false; + else if (!details::is_letter(symbol[0])) + return false; + else if (symbol.size() > 1) + { + for (std::size_t i = 1; i < symbol.size(); ++i) + { + if ( + !details::is_letter_or_digit(symbol[i]) && + ('_' != symbol[i]) + ) + { + if (('.' == symbol[i]) && (i < (symbol.size() - 1))) + continue; + else + return false; + } + } + } + + return true; + } + + typedef typename control_block::st_data local_data_t; + + inline local_data_t& local_data() + { + return *(control_block_->data_); + } + + inline const local_data_t& local_data() const + { + return *(control_block_->data_); + } + + control_block* control_block_; + + friend class parser; + }; + + template + class function_compositor; + + template + class expression + { + private: + + typedef details::expression_node* expression_ptr; + typedef details::vector_holder* vector_holder_ptr; + typedef std::vector > symtab_list_t; + + struct control_block + { + enum data_type + { + e_unknown , + e_expr , + e_vecholder, + e_data , + e_vecdata , + e_string + }; + + struct data_pack + { + data_pack() + : pointer(0), + type(e_unknown), + size(0) + {} + + data_pack(void* ptr, 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; + typedef results_context results_context_t; + + control_block() + : ref_count(0), + expr (0), + results (0), + retinv_null(false), + return_invoked(&retinv_null) + {} + + control_block(expression_ptr e) + : ref_count(1), + expr (e), + results (0), + retinv_null(false), + return_invoked(&retinv_null) + {} + + ~control_block() + { + if (expr && details::branch_deletable(expr)) { - return false; + delete expr; + expr = reinterpret_cast(0); } - - inline expression_node_ptr cardinal_pow_optimisation(expression_node_ptr(&)[2]) + + if (!local_data_list.empty()) { - return error_node(); - } -#endif - - struct synthesize_binary_ext_expression - { - static inline expression_node_ptr process(expression_generator& expr_gen, - const details::operator_type& operation, - expression_node_ptr (&branch)[2]) - { - const bool left_neg = is_neg_unary_node(branch[0]); - const bool right_neg = is_neg_unary_node(branch[1]); - - if (left_neg && right_neg) - { - if ( - (details::e_add == operation) || - (details::e_sub == operation) || - (details::e_mul == operation) || - (details::e_div == operation) - ) - { - if ( - !expr_gen.parser_->simplify_unary_negation_branch(branch[0]) || - !expr_gen.parser_->simplify_unary_negation_branch(branch[1]) - ) - { - details::free_all_nodes(*expr_gen.node_allocator_,branch); - - return error_node(); - } - } - - switch (operation) - { - // -f(x + 1) + -g(y + 1) --> -(f(x + 1) + g(y + 1)) - case details::e_add : return expr_gen(details::e_neg, - expr_gen.node_allocator_-> - template allocate > > - (branch[0],branch[1])); - - // -f(x + 1) - -g(y + 1) --> g(y + 1) - f(x + 1) - case details::e_sub : return expr_gen.node_allocator_-> - template allocate > > - (branch[1],branch[0]); - - default : break; - } - } - else if (left_neg && !right_neg) - { - if ( - (details::e_add == operation) || - (details::e_sub == operation) || - (details::e_mul == operation) || - (details::e_div == operation) - ) - { - if (!expr_gen.parser_->simplify_unary_negation_branch(branch[0])) - { - details::free_all_nodes(*expr_gen.node_allocator_,branch); - - return error_node(); - } - - switch (operation) - { - // -f(x + 1) + g(y + 1) --> g(y + 1) - f(x + 1) - case details::e_add : return expr_gen.node_allocator_-> - template allocate > > - (branch[1],branch[0]); - - // -f(x + 1) - g(y + 1) --> -(f(x + 1) + g(y + 1)) - case details::e_sub : return expr_gen(details::e_neg, - expr_gen.node_allocator_-> - template allocate > > - (branch[0],branch[1])); - - // -f(x + 1) * g(y + 1) --> -(f(x + 1) * g(y + 1)) - case details::e_mul : return expr_gen(details::e_neg, - expr_gen.node_allocator_-> - template allocate > > - (branch[0],branch[1])); - - // -f(x + 1) / g(y + 1) --> -(f(x + 1) / g(y + 1)) - case details::e_div : return expr_gen(details::e_neg, - expr_gen.node_allocator_-> - template allocate > > - (branch[0],branch[1])); - - default : return error_node(); - } - } - } - else if (!left_neg && right_neg) - { - if ( - (details::e_add == operation) || - (details::e_sub == operation) || - (details::e_mul == operation) || - (details::e_div == operation) - ) - { - if (!expr_gen.parser_->simplify_unary_negation_branch(branch[1])) - { - details::free_all_nodes(*expr_gen.node_allocator_,branch); - - return error_node(); - } - - switch (operation) - { - // f(x + 1) + -g(y + 1) --> f(x + 1) - g(y + 1) - case details::e_add : return expr_gen.node_allocator_-> - template allocate > > - (branch[0],branch[1]); - - // f(x + 1) - - g(y + 1) --> f(x + 1) + g(y + 1) - case details::e_sub : return expr_gen.node_allocator_-> - template allocate > > - (branch[0],branch[1]); - - // f(x + 1) * -g(y + 1) --> -(f(x + 1) * g(y + 1)) - case details::e_mul : return expr_gen(details::e_neg, - expr_gen.node_allocator_-> - template allocate > > - (branch[0],branch[1])); - - // f(x + 1) / -g(y + 1) --> -(f(x + 1) / g(y + 1)) - case details::e_div : return expr_gen(details::e_neg, - expr_gen.node_allocator_-> - template allocate > > - (branch[0],branch[1])); - - default : return error_node(); - } - } - } - - switch (operation) - { -#define case_stmt(op0,op1) \ -case op0 : return expr_gen.node_allocator_-> \ -template allocate > > \ -(branch[0],branch[1]); \ - - basic_opr_switch_statements - extended_opr_switch_statements -#undef case_stmt - default : return error_node(); - } - } - }; - - struct synthesize_vob_expression - { - static inline expression_node_ptr process(expression_generator& expr_gen, - const details::operator_type& operation, - expression_node_ptr (&branch)[2]) - { - const Type& v = static_cast*>(branch[0])->ref(); - -#ifndef exprtk_disable_enhanced_features - if (details::is_sf3ext_node(branch[1])) - { - expression_node_ptr result = error_node(); - - if (synthesize_sf4ext_expression::template compile_right(expr_gen,v,operation,branch[1],result)) - { - free_node(*expr_gen.node_allocator_,branch[1]); - return result; - } - } -#endif - - if ( - (details::e_mul == operation) || - (details::e_div == operation) - ) - { - if (details::is_uv_node(branch[1])) - { - typedef details::uv_base_node* uvbn_ptr_t; - - details::operator_type o = static_cast(branch[1])->operation(); - - if (details::e_neg == o) - { - const Type& v1 = static_cast(branch[1])->v(); - - free_node(*expr_gen.node_allocator_,branch[1]); - - switch (operation) - { - case details::e_mul : return expr_gen(details::e_neg, - expr_gen.node_allocator_-> - template allocate_rr > >(v,v1)); - - case details::e_div : return expr_gen(details::e_neg, - expr_gen.node_allocator_-> - template allocate_rr > >(v,v1)); - - default : break; - } - } - } - } - - switch (operation) - { -#define case_stmt(op0,op1) \ -case op0 : return expr_gen.node_allocator_-> \ -template allocate_rc > > \ -(v,branch[1]); \ - - basic_opr_switch_statements - extended_opr_switch_statements -#undef case_stmt - default : return error_node(); - } - } - }; - - struct synthesize_bov_expression - { - static inline expression_node_ptr process(expression_generator& expr_gen, - const details::operator_type& operation, - expression_node_ptr (&branch)[2]) - { - const Type& v = static_cast*>(branch[1])->ref(); - -#ifndef exprtk_disable_enhanced_features - if (details::is_sf3ext_node(branch[0])) - { - expression_node_ptr result = error_node(); - - if (synthesize_sf4ext_expression::template compile_left(expr_gen,v,operation,branch[0],result)) - { - free_node(*expr_gen.node_allocator_,branch[0]); - - return result; - } - } -#endif - - if ( - (details::e_add == operation) || - (details::e_sub == operation) || - (details::e_mul == operation) || - (details::e_div == operation) - ) - { - if (details::is_uv_node(branch[0])) - { - typedef details::uv_base_node* uvbn_ptr_t; - - details::operator_type o = static_cast(branch[0])->operation(); - - if (details::e_neg == o) - { - const Type& v0 = static_cast(branch[0])->v(); - - free_node(*expr_gen.node_allocator_,branch[0]); - - switch (operation) - { - case details::e_add : return expr_gen.node_allocator_-> - template allocate_rr > >(v,v0); - - case details::e_sub : return expr_gen(details::e_neg, - expr_gen.node_allocator_-> - template allocate_rr > >(v0,v)); - - case details::e_mul : return expr_gen(details::e_neg, - expr_gen.node_allocator_-> - template allocate_rr > >(v0,v)); - - case details::e_div : return expr_gen(details::e_neg, - expr_gen.node_allocator_-> - template allocate_rr > >(v0,v)); - default : break; - } - } - } - } - - switch (operation) - { -#define case_stmt(op0,op1) \ -case op0 : return expr_gen.node_allocator_-> \ -template allocate_cr > > \ -(branch[0],v); \ - - basic_opr_switch_statements - extended_opr_switch_statements -#undef case_stmt - default : return error_node(); - } - } - }; - - struct synthesize_cob_expression - { - static inline expression_node_ptr process(expression_generator& expr_gen, - const details::operator_type& operation, - expression_node_ptr (&branch)[2]) - { - const Type c = static_cast*>(branch[0])->value(); - - free_node(*expr_gen.node_allocator_,branch[0]); - - if ((T(0) == c) && (details::e_mul == operation)) - { - free_node(*expr_gen.node_allocator_,branch[1]); - - return expr_gen(T(0)); - } - else if ((T(0) == c) && (details::e_div == operation)) - { - free_node(*expr_gen.node_allocator_, branch[1]); - - return expr_gen(T(0)); - } - else if ((T(0) == c) && (details::e_add == operation)) - return branch[1]; - else if ((T(1) == c) && (details::e_mul == operation)) - return branch[1]; - - if (details::is_cob_node(branch[1])) - { - // Simplify expressions of the form: - // 1. (1 * (2 * (3 * (4 * (5 * (6 * (7 * (8 * (9 + x))))))))) --> 40320 * (9 + x) - // 2. (1 + (2 + (3 + (4 + (5 + (6 + (7 + (8 + (9 + x))))))))) --> 45 + x - if ( - (operation == details::e_mul) || - (operation == details::e_add) - ) - { - details::cob_base_node* cobnode = static_cast*>(branch[1]); - - if (operation == cobnode->operation()) - { - switch (operation) - { - case details::e_add : cobnode->set_c(c + cobnode->c()); break; - case details::e_mul : cobnode->set_c(c * cobnode->c()); break; - default : return error_node(); - } - - return cobnode; - } - } - - if (operation == details::e_mul) - { - details::cob_base_node* cobnode = static_cast*>(branch[1]); - details::operator_type cob_opr = cobnode->operation(); - - if ( - (details::e_div == cob_opr) || - (details::e_mul == cob_opr) - ) - { - switch (cob_opr) - { - case details::e_div : cobnode->set_c(c * cobnode->c()); break; - case details::e_mul : cobnode->set_c(cobnode->c() / c); break; - default : return error_node(); - } - - return cobnode; - } - } - else if (operation == details::e_div) - { - details::cob_base_node* cobnode = static_cast*>(branch[1]); - details::operator_type cob_opr = cobnode->operation(); - - if ( - (details::e_div == cob_opr) || - (details::e_mul == cob_opr) - ) - { - details::expression_node* new_cobnode = error_node(); - - switch (cob_opr) - { - case details::e_div : new_cobnode = expr_gen.node_allocator_-> - template allocate_tt > > - (c / cobnode->c(),cobnode->move_branch(0)); + 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 details::e_mul : new_cobnode = expr_gen.node_allocator_-> - template allocate_tt > > - (c / cobnode->c(),cobnode->move_branch(0)); + + case e_vecdata : delete [] (T*)(local_data_list[i].pointer); break; - - default : return error_node(); - } - - free_node(*expr_gen.node_allocator_,branch[1]); - - return new_cobnode; - } - } - } -#ifndef exprtk_disable_enhanced_features - else if (details::is_sf3ext_node(branch[1])) - { - expression_node_ptr result = error_node(); - - if (synthesize_sf4ext_expression::template compile_right(expr_gen,c,operation,branch[1],result)) - { - free_node(*expr_gen.node_allocator_,branch[1]); - - return result; - } - } -#endif - - switch (operation) - { -#define case_stmt(op0,op1) \ -case op0 : return expr_gen.node_allocator_-> \ -template allocate_tt > > \ -(c,branch[1]); \ - - basic_opr_switch_statements - extended_opr_switch_statements -#undef case_stmt - default : return error_node(); - } - } - }; - - struct synthesize_boc_expression - { - static inline expression_node_ptr process(expression_generator& expr_gen, - const details::operator_type& operation, - expression_node_ptr (&branch)[2]) - { - const Type c = static_cast*>(branch[1])->value(); - - details::free_node(*(expr_gen.node_allocator_),branch[1]); - - if ((T(0) == c) && (details::e_mul == operation)) - { - free_node(*expr_gen.node_allocator_,branch[0]); - - return expr_gen(T(0)); - } - else if ((T(0) == c) && (details::e_div == operation)) - { - free_node(*expr_gen.node_allocator_, branch[0]); - - return expr_gen(std::numeric_limits::quiet_NaN()); - } - else if ((T(0) == c) && (details::e_add == operation)) - return branch[0]; - else if ((T(1) == c) && (details::e_mul == operation)) - return branch[0]; - - if (details::is_boc_node(branch[0])) - { - // Simplify expressions of the form: - // 1. (((((((((x + 9) * 8) * 7) * 6) * 5) * 4) * 3) * 2) * 1) --> (x + 9) * 40320 - // 2. (((((((((x + 9) + 8) + 7) + 6) + 5) + 4) + 3) + 2) + 1) --> x + 45 - if ( - (operation == details::e_mul) || - (operation == details::e_add) - ) - { - details::boc_base_node* bocnode = static_cast*>(branch[0]); - - if (operation == bocnode->operation()) - { - switch (operation) - { - case details::e_add : bocnode->set_c(c + bocnode->c()); break; - case details::e_mul : bocnode->set_c(c * bocnode->c()); break; - default : return error_node(); - } - - return bocnode; - } - } - else if (operation == details::e_div) - { - details::boc_base_node* bocnode = static_cast*>(branch[0]); - details::operator_type boc_opr = bocnode->operation(); - - if ( - (details::e_div == boc_opr) || - (details::e_mul == boc_opr) - ) - { - switch (boc_opr) - { - case details::e_div : bocnode->set_c(c * bocnode->c()); break; - case details::e_mul : bocnode->set_c(bocnode->c() / c); break; - default : return error_node(); - } - - return bocnode; - } - } - else if (operation == details::e_pow) - { - // (v ^ c0) ^ c1 --> v ^(c0 * c1) - details::boc_base_node* bocnode = static_cast*>(branch[0]); - details::operator_type boc_opr = bocnode->operation(); - - if (details::e_pow == boc_opr) - { - bocnode->set_c(bocnode->c() * c); - - return bocnode; - } - } - } - -#ifndef exprtk_disable_enhanced_features - if (details::is_sf3ext_node(branch[0])) - { - expression_node_ptr result = error_node(); - - if (synthesize_sf4ext_expression::template compile_left(expr_gen,c,operation,branch[0],result)) - { - free_node(*expr_gen.node_allocator_,branch[0]); - - return result; - } - } -#endif - - switch (operation) - { -#define case_stmt(op0,op1) \ -case op0 : return expr_gen.node_allocator_-> \ -template allocate_cr > > \ -(branch[0],c); \ - - basic_opr_switch_statements - extended_opr_switch_statements -#undef case_stmt - default : return error_node(); - } - } - }; - - struct synthesize_cocob_expression - { - static inline expression_node_ptr process(expression_generator& expr_gen, - const details::operator_type& operation, - expression_node_ptr (&branch)[2]) - { - expression_node_ptr result = error_node(); - - // (cob) o c --> cob - if (details::is_cob_node(branch[0])) - { - details::cob_base_node* cobnode = static_cast*>(branch[0]); - const Type c = static_cast*>(branch[1])->value(); - - if ((T(0) == c) && (details::e_mul == operation)) - { - free_node(*expr_gen.node_allocator_,branch[0]); - free_node(*expr_gen.node_allocator_,branch[1]); - - return expr_gen(T(0)); - } - else if ((T(0) == c) && (details::e_div == operation)) - { - free_node(*expr_gen.node_allocator_,branch[0]); - free_node(*expr_gen.node_allocator_,branch[1]); - - return expr_gen(T(std::numeric_limits::quiet_NaN())); - } - else if ((T(0) == c) && (details::e_add == operation)) - { - free_node(*expr_gen.node_allocator_, branch[1]); - return branch[0]; - } - else if ((T(1) == c) && (details::e_mul == operation)) - { - free_node(*expr_gen.node_allocator_, branch[1]); - return branch[0]; - } - else if ((T(1) == c) && (details::e_div == operation)) - { - free_node(*expr_gen.node_allocator_, branch[1]); - return branch[0]; - } - - bool op_addsub = (details::e_add == cobnode->operation()) || - (details::e_sub == cobnode->operation()); - - if (op_addsub) - { - switch (operation) - { - case details::e_add : cobnode->set_c(cobnode->c() + c); break; - case details::e_sub : cobnode->set_c(cobnode->c() - c); break; - default : return error_node(); - } - - result = cobnode; - } - else if (details::e_mul == cobnode->operation()) - { - switch (operation) - { - case details::e_mul : cobnode->set_c(cobnode->c() * c); break; - case details::e_div : cobnode->set_c(cobnode->c() / c); break; - default : return error_node(); - } - - result = cobnode; - } - else if (details::e_div == cobnode->operation()) - { - if (details::e_mul == operation) - { - cobnode->set_c(cobnode->c() * c); - result = cobnode; - } - else if (details::e_div == operation) - { - result = expr_gen.node_allocator_-> - template allocate_tt > > - (cobnode->c() / c,cobnode->move_branch(0)); - - free_node(*expr_gen.node_allocator_,branch[0]); - } - } - - if (result) - { - free_node(*expr_gen.node_allocator_,branch[1]); - } - } - - // c o (cob) --> cob - else if (details::is_cob_node(branch[1])) - { - details::cob_base_node* cobnode = static_cast*>(branch[1]); - const Type c = static_cast*>(branch[0])->value(); - - if ((T(0) == c) && (details::e_mul == operation)) - { - free_node(*expr_gen.node_allocator_,branch[0]); - free_node(*expr_gen.node_allocator_,branch[1]); - - return expr_gen(T(0)); - } - else if ((T(0) == c) && (details::e_div == operation)) - { - free_node(*expr_gen.node_allocator_,branch[0]); - free_node(*expr_gen.node_allocator_,branch[1]); - - return expr_gen(T(0)); - } - else if ((T(0) == c) && (details::e_add == operation)) - { - free_node(*expr_gen.node_allocator_, branch[0]); - return branch[1]; - } - else if ((T(1) == c) && (details::e_mul == operation)) - { - free_node(*expr_gen.node_allocator_, branch[0]); - return branch[1]; - } - - if (details::e_add == cobnode->operation()) - { - if (details::e_add == operation) - { - cobnode->set_c(c + cobnode->c()); - result = cobnode; - } - else if (details::e_sub == operation) - { - result = expr_gen.node_allocator_-> - template allocate_tt > > - (c - cobnode->c(),cobnode->move_branch(0)); - - free_node(*expr_gen.node_allocator_,branch[1]); - } - } - else if (details::e_sub == cobnode->operation()) - { - if (details::e_add == operation) - { - cobnode->set_c(c + cobnode->c()); - result = cobnode; - } - else if (details::e_sub == operation) - { - result = expr_gen.node_allocator_-> - template allocate_tt > > - (c - cobnode->c(),cobnode->move_branch(0)); - - free_node(*expr_gen.node_allocator_,branch[1]); - } - } - else if (details::e_mul == cobnode->operation()) - { - if (details::e_mul == operation) - { - cobnode->set_c(c * cobnode->c()); - result = cobnode; - } - else if (details::e_div == operation) - { - result = expr_gen.node_allocator_-> - template allocate_tt > > - (c / cobnode->c(),cobnode->move_branch(0)); - - free_node(*expr_gen.node_allocator_,branch[1]); - } - } - else if (details::e_div == cobnode->operation()) - { - if (details::e_mul == operation) - { - cobnode->set_c(c * cobnode->c()); - result = cobnode; - } - else if (details::e_div == operation) - { - result = expr_gen.node_allocator_-> - template allocate_tt > > - (c / cobnode->c(),cobnode->move_branch(0)); - - free_node(*expr_gen.node_allocator_,branch[1]); - } - } - - if (result) - { - free_node(*expr_gen.node_allocator_,branch[0]); - } - } - - return result; - } - }; - - struct synthesize_coboc_expression - { - static inline expression_node_ptr process(expression_generator& expr_gen, - const details::operator_type& operation, - expression_node_ptr (&branch)[2]) - { - expression_node_ptr result = error_node(); - - // (boc) o c --> boc - if (details::is_boc_node(branch[0])) - { - details::boc_base_node* bocnode = static_cast*>(branch[0]); - const Type c = static_cast*>(branch[1])->value(); - - if (details::e_add == bocnode->operation()) - { - switch (operation) - { - case details::e_add : bocnode->set_c(bocnode->c() + c); break; - case details::e_sub : bocnode->set_c(bocnode->c() - c); break; - default : return error_node(); - } - - result = bocnode; - } - else if (details::e_mul == bocnode->operation()) - { - switch (operation) - { - case details::e_mul : bocnode->set_c(bocnode->c() * c); break; - case details::e_div : bocnode->set_c(bocnode->c() / c); break; - default : return error_node(); - } - - result = bocnode; - } - else if (details::e_sub == bocnode->operation()) - { - if (details::e_add == operation) - { - result = expr_gen.node_allocator_-> - template allocate_tt > > - (bocnode->move_branch(0),c - bocnode->c()); - - free_node(*expr_gen.node_allocator_,branch[0]); - } - else if (details::e_sub == operation) - { - bocnode->set_c(bocnode->c() + c); - result = bocnode; - } - } - else if (details::e_div == bocnode->operation()) - { - switch (operation) - { - case details::e_div : bocnode->set_c(bocnode->c() * c); break; - case details::e_mul : bocnode->set_c(bocnode->c() / c); break; - default : return error_node(); - } - - result = bocnode; - } - - if (result) - { - free_node(*expr_gen.node_allocator_,branch[1]); - } - } - - // c o (boc) --> boc - else if (details::is_boc_node(branch[1])) - { - details::boc_base_node* bocnode = static_cast*>(branch[1]); - const Type c = static_cast*>(branch[0])->value(); - - if (details::e_add == bocnode->operation()) - { - if (details::e_add == operation) - { - bocnode->set_c(c + bocnode->c()); - result = bocnode; - } - else if (details::e_sub == operation) - { - result = expr_gen.node_allocator_-> - template allocate_tt > > - (c - bocnode->c(),bocnode->move_branch(0)); - - free_node(*expr_gen.node_allocator_,branch[1]); - } - } - else if (details::e_sub == bocnode->operation()) - { - if (details::e_add == operation) - { - result = expr_gen.node_allocator_-> - template allocate_tt > > - (bocnode->move_branch(0),c - bocnode->c()); - - free_node(*expr_gen.node_allocator_,branch[1]); - } - else if (details::e_sub == operation) - { - result = expr_gen.node_allocator_-> - template allocate_tt > > - (c + bocnode->c(),bocnode->move_branch(0)); - - free_node(*expr_gen.node_allocator_,branch[1]); - } - } - else if (details::e_mul == bocnode->operation()) - { - if (details::e_mul == operation) - { - bocnode->set_c(c * bocnode->c()); - result = bocnode; - } - else if (details::e_div == operation) - { - result = expr_gen.node_allocator_-> - template allocate_tt > > - (c / bocnode->c(),bocnode->move_branch(0)); - - free_node(*expr_gen.node_allocator_,branch[1]); - } - } - else if (details::e_div == bocnode->operation()) - { - if (details::e_mul == operation) - { - bocnode->set_c(bocnode->c() / c); - result = bocnode; - } - else if (details::e_div == operation) - { - result = expr_gen.node_allocator_-> - template allocate_tt > > - (c * bocnode->c(),bocnode->move_branch(0)); - - free_node(*expr_gen.node_allocator_,branch[1]); - } - } - - if (result) - { - free_node(*expr_gen.node_allocator_,branch[0]); - } - } - - return result; - } - }; - -#ifndef exprtk_disable_enhanced_features - inline bool synthesize_expression(const details::operator_type& operation, - expression_node_ptr (&branch)[2], - expression_node_ptr& result) - { - result = error_node(); - - if (!operation_optimisable(operation)) - return false; - - const std::string node_id = branch_to_id(branch); - typename synthesize_map_t::iterator itr = synthesize_map_.find(node_id); - - if (synthesize_map_.end() != itr) - { - result = itr->second(*this,operation,branch); - - return true; - } - else - return false; - } - - struct synthesize_vov_expression - { - static inline expression_node_ptr process(expression_generator& expr_gen, - const details::operator_type& operation, - expression_node_ptr (&branch)[2]) - { - const Type& v1 = static_cast*>(branch[0])->ref(); - const Type& v2 = static_cast*>(branch[1])->ref(); - - switch (operation) - { -#define case_stmt(op0,op1) \ -case op0 : return expr_gen.node_allocator_-> \ -template allocate_rr > > \ -(v1,v2); \ - - basic_opr_switch_statements - extended_opr_switch_statements -#undef case_stmt - default : return error_node(); - } - } - }; - - struct synthesize_cov_expression - { - static inline expression_node_ptr process(expression_generator& expr_gen, - const details::operator_type& operation, - expression_node_ptr (&branch)[2]) - { - const Type c = static_cast*> (branch[0])->value(); - const Type& v = static_cast*>(branch[1])->ref(); - - details::free_node(*(expr_gen.node_allocator_),branch[0]); - - if ((T(0) == c) && (details::e_mul == operation)) - return expr_gen(T(0)); - else if ((T(0) == c) && (details::e_div == operation)) - return expr_gen(T(0)); - else if ((T(0) == c) && (details::e_add == operation)) - return static_cast*>(branch[1]); - else if ((T(1) == c) && (details::e_mul == operation)) - return static_cast*>(branch[1]); - - switch (operation) - { -#define case_stmt(op0,op1) \ -case op0 : return expr_gen.node_allocator_-> \ -template allocate_cr > > \ -(c,v); \ - - basic_opr_switch_statements - extended_opr_switch_statements -#undef case_stmt - default : return error_node(); - } - } - }; - - struct synthesize_voc_expression - { - static inline expression_node_ptr process(expression_generator& expr_gen, - const details::operator_type& operation, - expression_node_ptr (&branch)[2]) - { - const Type& v = static_cast*>(branch[0])->ref(); - const Type c = static_cast*> (branch[1])->value(); - - details::free_node(*(expr_gen.node_allocator_),branch[1]); - - if (expr_gen.cardinal_pow_optimisable(operation,c)) - { - if (std::equal_to()(T(1),c)) - return branch[0]; - else - return expr_gen.cardinal_pow_optimisation(v,c); - } - else if ((T(0) == c) && (details::e_mul == operation)) - return expr_gen(T(0)); - else if ((T(0) == c) && (details::e_div == operation)) - return expr_gen(std::numeric_limits::quiet_NaN()); - else if ((T(0) == c) && (details::e_add == operation)) - return static_cast*>(branch[0]); - else if ((T(1) == c) && (details::e_mul == operation)) - return static_cast*>(branch[0]); - else if ((T(1) == c) && (details::e_div == operation)) - return static_cast*>(branch[0]); - - switch (operation) - { -#define case_stmt(op0,op1) \ -case op0 : return expr_gen.node_allocator_-> \ -template allocate_rc > > \ -(v,c); \ - - basic_opr_switch_statements - extended_opr_switch_statements -#undef case_stmt - default : return error_node(); - } - } - }; - - struct synthesize_sf3ext_expression - { - template - static inline expression_node_ptr process(expression_generator& expr_gen, - const details::operator_type& sf3opr, - T0 t0, T1 t1, T2 t2) - { - switch (sf3opr) - { -#define case_stmt(op) \ -case details::e_sf##op : return details::T0oT1oT2_sf3ext >:: \ -allocate(*(expr_gen.node_allocator_),t0,t1,t2); \ - - case_stmt(00) case_stmt(01) case_stmt(02) case_stmt(03) - case_stmt(04) case_stmt(05) case_stmt(06) case_stmt(07) - case_stmt(08) case_stmt(09) case_stmt(10) case_stmt(11) - case_stmt(12) case_stmt(13) case_stmt(14) case_stmt(15) - case_stmt(16) case_stmt(17) case_stmt(18) case_stmt(19) - case_stmt(20) case_stmt(21) case_stmt(22) case_stmt(23) - case_stmt(24) case_stmt(25) case_stmt(26) case_stmt(27) - case_stmt(28) case_stmt(29) case_stmt(30) -#undef case_stmt - default : return error_node(); - } - } - - template - static inline bool compile(expression_generator& expr_gen, const std::string& id, - T0 t0, T1 t1, T2 t2, - expression_node_ptr& result) - { - details::operator_type sf3opr; - - if (!expr_gen.sf3_optimisable(id,sf3opr)) - return false; - else - result = synthesize_sf3ext_expression::template process(expr_gen,sf3opr,t0,t1,t2); - - return true; - } - }; - - struct synthesize_sf4ext_expression - { - template - static inline expression_node_ptr process(expression_generator& expr_gen, - const details::operator_type& sf4opr, - T0 t0, T1 t1, T2 t2, T3 t3) - { - switch (sf4opr) - { -#define case_stmt0(op) \ -case details::e_sf##op : return details::T0oT1oT2oT3_sf4ext >:: \ -allocate(*(expr_gen.node_allocator_),t0,t1,t2,t3); \ - - -#define case_stmt1(op) \ -case details::e_sf4ext##op : return details::T0oT1oT2oT3_sf4ext >:: \ -allocate(*(expr_gen.node_allocator_),t0,t1,t2,t3); \ - - case_stmt0(48) case_stmt0(49) case_stmt0(50) case_stmt0(51) - case_stmt0(52) case_stmt0(53) case_stmt0(54) case_stmt0(55) - case_stmt0(56) case_stmt0(57) case_stmt0(58) case_stmt0(59) - case_stmt0(60) case_stmt0(61) case_stmt0(62) case_stmt0(63) - case_stmt0(64) case_stmt0(65) case_stmt0(66) case_stmt0(67) - case_stmt0(68) case_stmt0(69) case_stmt0(70) case_stmt0(71) - case_stmt0(72) case_stmt0(73) case_stmt0(74) case_stmt0(75) - case_stmt0(76) case_stmt0(77) case_stmt0(78) case_stmt0(79) - case_stmt0(80) case_stmt0(81) case_stmt0(82) case_stmt0(83) - - case_stmt1(00) case_stmt1(01) case_stmt1(02) case_stmt1(03) - case_stmt1(04) case_stmt1(05) case_stmt1(06) case_stmt1(07) - case_stmt1(08) case_stmt1(09) case_stmt1(10) case_stmt1(11) - case_stmt1(12) case_stmt1(13) case_stmt1(14) case_stmt1(15) - case_stmt1(16) case_stmt1(17) case_stmt1(18) case_stmt1(19) - case_stmt1(20) case_stmt1(21) case_stmt1(22) case_stmt1(23) - case_stmt1(24) case_stmt1(25) case_stmt1(26) case_stmt1(27) - case_stmt1(28) case_stmt1(29) case_stmt1(30) case_stmt1(31) - case_stmt1(32) case_stmt1(33) case_stmt1(34) case_stmt1(35) - case_stmt1(36) case_stmt1(37) case_stmt1(38) case_stmt1(39) - case_stmt1(40) case_stmt1(41) case_stmt1(42) case_stmt1(43) - case_stmt1(44) case_stmt1(45) case_stmt1(46) case_stmt1(47) - case_stmt1(48) case_stmt1(49) case_stmt1(50) case_stmt1(51) - case_stmt1(52) case_stmt1(53) case_stmt1(54) case_stmt1(55) - case_stmt1(56) case_stmt1(57) case_stmt1(58) case_stmt1(59) - case_stmt1(60) - -#undef case_stmt0 -#undef case_stmt1 - default : return error_node(); - } - } - - template - static inline bool compile(expression_generator& expr_gen, const std::string& id, - T0 t0, T1 t1, T2 t2, T3 t3, - expression_node_ptr& result) - { - details::operator_type sf4opr; - - if (!expr_gen.sf4_optimisable(id,sf4opr)) - return false; - else - result = synthesize_sf4ext_expression::template process(expr_gen,sf4opr,t0,t1,t2,t3); - - return true; - } - - // T o (sf3ext) - template - static inline bool compile_right(expression_generator& expr_gen, - ExternalType t, - const details::operator_type& operation, - expression_node_ptr& sf3node, - expression_node_ptr& result) - { - if (!details::is_sf3ext_node(sf3node)) - return false; - - typedef details::T0oT1oT2_base_node* sf3ext_base_ptr; - - sf3ext_base_ptr n = static_cast(sf3node); - std::string id = "t" + expr_gen.to_str(operation) + "(" + n->type_id() + ")"; - - switch (n->type()) - { - case details::expression_node::e_covoc : return compile_right_impl - - (expr_gen,id,t,sf3node,result); - - case details::expression_node::e_covov : return compile_right_impl - - (expr_gen,id,t,sf3node,result); - - case details::expression_node::e_vocov : return compile_right_impl - - (expr_gen,id,t,sf3node,result); - - case details::expression_node::e_vovoc : return compile_right_impl - - (expr_gen,id,t,sf3node,result); - - case details::expression_node::e_vovov : return compile_right_impl - - (expr_gen,id,t,sf3node,result); - - default : return false; - } - } - - // (sf3ext) o T - template - static inline bool compile_left(expression_generator& expr_gen, - ExternalType t, - const details::operator_type& operation, - expression_node_ptr& sf3node, - expression_node_ptr& result) - { - if (!details::is_sf3ext_node(sf3node)) - return false; - - typedef details::T0oT1oT2_base_node* sf3ext_base_ptr; - - sf3ext_base_ptr n = static_cast(sf3node); - std::string id = "(" + n->type_id() + ")" + expr_gen.to_str(operation) + "t"; - - switch (n->type()) - { - case details::expression_node::e_covoc : return compile_left_impl - - (expr_gen,id,t,sf3node,result); - - case details::expression_node::e_covov : return compile_left_impl - - (expr_gen,id,t,sf3node,result); - - case details::expression_node::e_vocov : return compile_left_impl - - (expr_gen,id,t,sf3node,result); - - case details::expression_node::e_vovoc : return compile_left_impl - - (expr_gen,id,t,sf3node,result); - - case details::expression_node::e_vovov : return compile_left_impl - - (expr_gen,id,t,sf3node,result); - - default : return false; - } - } - - template - static inline bool compile_right_impl(expression_generator& expr_gen, - const std::string& id, - ExternalType t, - expression_node_ptr& node, - expression_node_ptr& result) - { - SF3TypeNode* n = dynamic_cast(node); - - if (n) - { - T0 t0 = n->t0(); - T1 t1 = n->t1(); - T2 t2 = n->t2(); - - return synthesize_sf4ext_expression:: - template compile(expr_gen,id,t,t0,t1,t2,result); - } - else - return false; - } - - template - static inline bool compile_left_impl(expression_generator& expr_gen, - const std::string& id, - ExternalType t, - expression_node_ptr& node, - expression_node_ptr& result) - { - SF3TypeNode* n = dynamic_cast(node); - - if (n) - { - T0 t0 = n->t0(); - T1 t1 = n->t1(); - T2 t2 = n->t2(); - - return synthesize_sf4ext_expression:: - template compile(expr_gen,id,t0,t1,t2,t,result); - } - else - return false; - } - }; - - struct synthesize_vovov_expression0 - { - typedef typename vovov_t::type0 node_type; - typedef typename vovov_t::sf3_type sf3_type; - - static inline expression_node_ptr process(expression_generator& expr_gen, - const details::operator_type& operation, - expression_node_ptr (&branch)[2]) - { - // (v0 o0 v1) o1 (v2) - const details::vov_base_node* vov = static_cast*>(branch[0]); - const Type& v0 = vov->v0(); - const Type& v1 = vov->v1(); - const Type& v2 = static_cast*>(branch[1])->ref(); - const details::operator_type o0 = vov->operation(); - const details::operator_type o1 = operation; - - binary_functor_t f0 = reinterpret_cast(0); - binary_functor_t f1 = reinterpret_cast(0); - - details::free_node(*(expr_gen.node_allocator_),branch[0]); - - expression_node_ptr result = error_node(); - - if (expr_gen.parser_->settings_.strength_reduction_enabled()) - { - // (v0 / v1) / v2 --> (vovov) v0 / (v1 * v2) - if ((details::e_div == o0) && (details::e_div == o1)) - { - const bool synthesis_result = - synthesize_sf3ext_expression:: - template compile(expr_gen,"t/(t*t)",v0,v1,v2,result); - - exprtk_debug(("(v0 / v1) / v2 --> (vovov) v0 / (v1 * v2)\n")); - - return (synthesis_result) ? result : error_node(); - } - } - - if (synthesize_sf3ext_expression::template compile(expr_gen,id(expr_gen,o0,o1),v0,v1,v2,result)) - return result; - else if (!expr_gen.valid_operator(o0,f0)) - return error_node(); - else if (!expr_gen.valid_operator(o1,f1)) - return error_node(); - else - return node_type::allocate(*(expr_gen.node_allocator_),v0,v1,v2,f0,f1); - } - - static inline std::string id(expression_generator& expr_gen, - const details::operator_type o0, const details::operator_type o1) - { - return (details::build_string() << "(t" << expr_gen.to_str(o0) << "t)" << expr_gen.to_str(o1) << "t"); - } - }; - - struct synthesize_vovov_expression1 - { - typedef typename vovov_t::type1 node_type; - typedef typename vovov_t::sf3_type sf3_type; - - static inline expression_node_ptr process(expression_generator& expr_gen, - const details::operator_type& operation, - expression_node_ptr (&branch)[2]) - { - // (v0) o0 (v1 o1 v2) - const details::vov_base_node* vov = static_cast*>(branch[1]); - const Type& v0 = static_cast*>(branch[0])->ref(); - const Type& v1 = vov->v0(); - const Type& v2 = vov->v1(); - const details::operator_type o0 = operation; - const details::operator_type o1 = vov->operation(); - - binary_functor_t f0 = reinterpret_cast(0); - binary_functor_t f1 = reinterpret_cast(0); - - details::free_node(*(expr_gen.node_allocator_),branch[1]); - - expression_node_ptr result = error_node(); - - if (expr_gen.parser_->settings_.strength_reduction_enabled()) - { - // v0 / (v1 / v2) --> (vovov) (v0 * v2) / v1 - if ((details::e_div == o0) && (details::e_div == o1)) - { - const bool synthesis_result = - synthesize_sf3ext_expression:: - template compile(expr_gen,"(t*t)/t",v0,v2,v1,result); - - exprtk_debug(("v0 / (v1 / v2) --> (vovov) (v0 * v2) / v1\n")); - - return (synthesis_result) ? result : error_node(); - } - } - - if (synthesize_sf3ext_expression::template compile(expr_gen,id(expr_gen,o0,o1),v0,v1,v2,result)) - return result; - else if (!expr_gen.valid_operator(o0,f0)) - return error_node(); - else if (!expr_gen.valid_operator(o1,f1)) - return error_node(); - else - return node_type::allocate(*(expr_gen.node_allocator_),v0,v1,v2,f0,f1); - } - - static inline std::string id(expression_generator& expr_gen, - const details::operator_type o0, const details::operator_type o1) - { - return (details::build_string() << "t" << expr_gen.to_str(o0) << "(t" << expr_gen.to_str(o1) << "t)"); - } - }; - - struct synthesize_vovoc_expression0 - { - typedef typename vovoc_t::type0 node_type; - typedef typename vovoc_t::sf3_type sf3_type; - - static inline expression_node_ptr process(expression_generator& expr_gen, - const details::operator_type& operation, - expression_node_ptr (&branch)[2]) - { - // (v0 o0 v1) o1 (c) - const details::vov_base_node* vov = static_cast*>(branch[0]); - const Type& v0 = vov->v0(); - const Type& v1 = vov->v1(); - const Type c = static_cast*>(branch[1])->value(); - const details::operator_type o0 = vov->operation(); - const details::operator_type o1 = operation; - - binary_functor_t f0 = reinterpret_cast(0); - binary_functor_t f1 = reinterpret_cast(0); - - details::free_node(*(expr_gen.node_allocator_),branch[0]); - details::free_node(*(expr_gen.node_allocator_),branch[1]); - - expression_node_ptr result = error_node(); - - if (expr_gen.parser_->settings_.strength_reduction_enabled()) - { - // (v0 / v1) / c --> (vovoc) v0 / (v1 * c) - if ((details::e_div == o0) && (details::e_div == o1)) - { - const bool synthesis_result = - synthesize_sf3ext_expression:: - template compile(expr_gen,"t/(t*t)",v0,v1,c,result); - - exprtk_debug(("(v0 / v1) / c --> (vovoc) v0 / (v1 * c)\n")); - - return (synthesis_result) ? result : error_node(); - } - } - - if (synthesize_sf3ext_expression::template compile(expr_gen,id(expr_gen,o0,o1),v0,v1,c,result)) - return result; - else if (!expr_gen.valid_operator(o0,f0)) - return error_node(); - else if (!expr_gen.valid_operator(o1,f1)) - return error_node(); - else - return node_type::allocate(*(expr_gen.node_allocator_),v0,v1,c,f0,f1); - } - - static inline std::string id(expression_generator& expr_gen, - const details::operator_type o0, const details::operator_type o1) - { - return (details::build_string() << "(t" << expr_gen.to_str(o0) << "t)" << expr_gen.to_str(o1) << "t"); - } - }; - - struct synthesize_vovoc_expression1 - { - typedef typename vovoc_t::type1 node_type; - typedef typename vovoc_t::sf3_type sf3_type; - - static inline expression_node_ptr process(expression_generator& expr_gen, - const details::operator_type& operation, - expression_node_ptr (&branch)[2]) - { - // (v0) o0 (v1 o1 c) - const details::voc_base_node* voc = static_cast*>(branch[1]); - const Type& v0 = static_cast*>(branch[0])->ref(); - const Type& v1 = voc->v(); - const Type c = voc->c(); - const details::operator_type o0 = operation; - const details::operator_type o1 = voc->operation(); - - binary_functor_t f0 = reinterpret_cast(0); - binary_functor_t f1 = reinterpret_cast(0); - - details::free_node(*(expr_gen.node_allocator_),branch[1]); - - expression_node_ptr result = error_node(); - - if (expr_gen.parser_->settings_.strength_reduction_enabled()) - { - // v0 / (v1 / c) --> (vocov) (v0 * c) / v1 - if ((details::e_div == o0) && (details::e_div == o1)) - { - const bool synthesis_result = - synthesize_sf3ext_expression:: - template compile(expr_gen,"(t*t)/t",v0,c,v1,result); - - exprtk_debug(("v0 / (v1 / c) --> (vocov) (v0 * c) / v1\n")); - - return (synthesis_result) ? result : error_node(); - } - } - - if (synthesize_sf3ext_expression::template compile(expr_gen,id(expr_gen,o0,o1),v0,v1,c,result)) - return result; - else if (!expr_gen.valid_operator(o0,f0)) - return error_node(); - else if (!expr_gen.valid_operator(o1,f1)) - return error_node(); - else - return node_type::allocate(*(expr_gen.node_allocator_),v0,v1,c,f0,f1); - } - - static inline std::string id(expression_generator& expr_gen, - const details::operator_type o0, const details::operator_type o1) - { - return (details::build_string() << "t" << expr_gen.to_str(o0) << "(t" << expr_gen.to_str(o1) << "t)"); - } - }; - - struct synthesize_vocov_expression0 - { - typedef typename vocov_t::type0 node_type; - typedef typename vocov_t::sf3_type sf3_type; - - static inline expression_node_ptr process(expression_generator& expr_gen, - const details::operator_type& operation, - expression_node_ptr (&branch)[2]) - { - // (v0 o0 c) o1 (v1) - const details::voc_base_node* voc = static_cast*>(branch[0]); - const Type& v0 = voc->v(); - const Type c = voc->c(); - const Type& v1 = static_cast*>(branch[1])->ref(); - const details::operator_type o0 = voc->operation(); - const details::operator_type o1 = operation; - - binary_functor_t f0 = reinterpret_cast(0); - binary_functor_t f1 = reinterpret_cast(0); - - details::free_node(*(expr_gen.node_allocator_),branch[0]); - - expression_node_ptr result = error_node(); - - if (expr_gen.parser_->settings_.strength_reduction_enabled()) - { - // (v0 / c) / v1 --> (vovoc) v0 / (v1 * c) - if ((details::e_div == o0) && (details::e_div == o1)) - { - const bool synthesis_result = - synthesize_sf3ext_expression:: - template compile(expr_gen,"t/(t*t)",v0,v1,c,result); - - exprtk_debug(("(v0 / c) / v1 --> (vovoc) v0 / (v1 * c)\n")); - - return (synthesis_result) ? result : error_node(); - } - } - - if (synthesize_sf3ext_expression::template compile(expr_gen,id(expr_gen,o0,o1),v0,c,v1,result)) - return result; - else if (!expr_gen.valid_operator(o0,f0)) - return error_node(); - else if (!expr_gen.valid_operator(o1,f1)) - return error_node(); - else - return node_type::allocate(*(expr_gen.node_allocator_),v0,c,v1,f0,f1); - } - - static inline std::string id(expression_generator& expr_gen, - const details::operator_type o0, const details::operator_type o1) - { - return (details::build_string() << "(t" << expr_gen.to_str(o0) << "t)" << expr_gen.to_str(o1) << "t"); - } - }; - - struct synthesize_vocov_expression1 - { - typedef typename vocov_t::type1 node_type; - typedef typename vocov_t::sf3_type sf3_type; - - static inline expression_node_ptr process(expression_generator& expr_gen, - const details::operator_type& operation, - expression_node_ptr (&branch)[2]) - { - // (v0) o0 (c o1 v1) - const details::cov_base_node* cov = static_cast*>(branch[1]); - const Type& v0 = static_cast*>(branch[0])->ref(); - const Type c = cov->c(); - const Type& v1 = cov->v(); - const details::operator_type o0 = operation; - const details::operator_type o1 = cov->operation(); - - binary_functor_t f0 = reinterpret_cast(0); - binary_functor_t f1 = reinterpret_cast(0); - - details::free_node(*(expr_gen.node_allocator_),branch[1]); - - expression_node_ptr result = error_node(); - - if (expr_gen.parser_->settings_.strength_reduction_enabled()) - { - // v0 / (c / v1) --> (vovoc) (v0 * v1) / c - if ((details::e_div == o0) && (details::e_div == o1)) - { - const bool synthesis_result = - synthesize_sf3ext_expression:: - template compile(expr_gen,"(t*t)/t",v0,v1,c,result); - - exprtk_debug(("v0 / (c / v1) --> (vovoc) (v0 * v1) / c\n")); - - return (synthesis_result) ? result : error_node(); - } - } - - if (synthesize_sf3ext_expression::template compile(expr_gen,id(expr_gen,o0,o1),v0,c,v1,result)) - return result; - else if (!expr_gen.valid_operator(o0,f0)) - return error_node(); - else if (!expr_gen.valid_operator(o1,f1)) - return error_node(); - else - return node_type::allocate(*(expr_gen.node_allocator_),v0,c,v1,f0,f1); - } - - static inline std::string id(expression_generator& expr_gen, - const details::operator_type o0, const details::operator_type o1) - { - return (details::build_string() << "t" << expr_gen.to_str(o0) << "(t" << expr_gen.to_str(o1) << "t)"); - } - }; - - struct synthesize_covov_expression0 - { - typedef typename covov_t::type0 node_type; - typedef typename covov_t::sf3_type sf3_type; - - static inline expression_node_ptr process(expression_generator& expr_gen, - const details::operator_type& operation, - expression_node_ptr (&branch)[2]) - { - // (c o0 v0) o1 (v1) - const details::cov_base_node* cov = static_cast*>(branch[0]); - const Type c = cov->c(); - const Type& v0 = cov->v(); - const Type& v1 = static_cast*>(branch[1])->ref(); - const details::operator_type o0 = cov->operation(); - const details::operator_type o1 = operation; - - binary_functor_t f0 = reinterpret_cast(0); - binary_functor_t f1 = reinterpret_cast(0); - - details::free_node(*(expr_gen.node_allocator_),branch[0]); - - expression_node_ptr result = error_node(); - - if (expr_gen.parser_->settings_.strength_reduction_enabled()) - { - // (c / v0) / v1 --> (covov) c / (v0 * v1) - if ((details::e_div == o0) && (details::e_div == o1)) - { - const bool synthesis_result = - synthesize_sf3ext_expression:: - template compile(expr_gen,"t/(t*t)",c,v0,v1,result); - - exprtk_debug(("(c / v0) / v1 --> (covov) c / (v0 * v1)\n")); - - return (synthesis_result) ? result : error_node(); - } - } - - if (synthesize_sf3ext_expression::template compile(expr_gen,id(expr_gen,o0,o1),c,v0,v1,result)) - return result; - else if (!expr_gen.valid_operator(o0,f0)) - return error_node(); - else if (!expr_gen.valid_operator(o1,f1)) - return error_node(); - else - return node_type::allocate(*(expr_gen.node_allocator_),c,v0,v1,f0,f1); - } - - static inline std::string id(expression_generator& expr_gen, - const details::operator_type o0, const details::operator_type o1) - { - return (details::build_string() << "(t" << expr_gen.to_str(o0) << "t)" << expr_gen.to_str(o1) << "t"); - } - }; - - struct synthesize_covov_expression1 - { - typedef typename covov_t::type1 node_type; - typedef typename covov_t::sf3_type sf3_type; - - static inline expression_node_ptr process(expression_generator& expr_gen, - const details::operator_type& operation, - expression_node_ptr (&branch)[2]) - { - // (c) o0 (v0 o1 v1) - const details::vov_base_node* vov = static_cast*>(branch[1]); - const Type c = static_cast*>(branch[0])->value(); - const Type& v0 = vov->v0(); - const Type& v1 = vov->v1(); - const details::operator_type o0 = operation; - const details::operator_type o1 = vov->operation(); - - binary_functor_t f0 = reinterpret_cast(0); - binary_functor_t f1 = reinterpret_cast(0); - - details::free_node(*(expr_gen.node_allocator_),branch[0]); - details::free_node(*(expr_gen.node_allocator_),branch[1]); - - expression_node_ptr result = error_node(); - - if (expr_gen.parser_->settings_.strength_reduction_enabled()) - { - // c / (v0 / v1) --> (covov) (c * v1) / v0 - if ((details::e_div == o0) && (details::e_div == o1)) - { - const bool synthesis_result = - synthesize_sf3ext_expression:: - template compile(expr_gen,"(t*t)/t",c,v1,v0,result); - - exprtk_debug(("c / (v0 / v1) --> (covov) (c * v1) / v0\n")); - - return (synthesis_result) ? result : error_node(); - } - } - - if (synthesize_sf3ext_expression::template compile(expr_gen,id(expr_gen,o0,o1),c,v0,v1,result)) - return result; - else if (!expr_gen.valid_operator(o0,f0)) - return error_node(); - else if (!expr_gen.valid_operator(o1,f1)) - return error_node(); - else - return node_type::allocate(*(expr_gen.node_allocator_),c,v0,v1,f0,f1); - } - - static inline std::string id(expression_generator& expr_gen, const details::operator_type o0, const details::operator_type o1) - { - return (details::build_string() << "t" << expr_gen.to_str(o0) << "(t" << expr_gen.to_str(o1) << "t)"); - } - }; - - struct synthesize_covoc_expression0 - { - typedef typename covoc_t::type0 node_type; - typedef typename covoc_t::sf3_type sf3_type; - - static inline expression_node_ptr process(expression_generator& expr_gen, - const details::operator_type& operation, - expression_node_ptr (&branch)[2]) - { - // (c0 o0 v) o1 (c1) - const details::cov_base_node* cov = static_cast*>(branch[0]); - const Type c0 = cov->c(); - const Type& v = cov->v(); - const Type c1 = static_cast*>(branch[1])->value(); - const details::operator_type o0 = cov->operation(); - const details::operator_type o1 = operation; - - binary_functor_t f0 = reinterpret_cast(0); - binary_functor_t f1 = reinterpret_cast(0); - - details::free_node(*(expr_gen.node_allocator_),branch[0]); - details::free_node(*(expr_gen.node_allocator_),branch[1]); - - expression_node_ptr result = error_node(); - - if (expr_gen.parser_->settings_.strength_reduction_enabled()) - { - // (c0 + v) + c1 --> (cov) (c0 + c1) + v - if ((details::e_add == o0) && (details::e_add == o1)) - { - exprtk_debug(("(c0 + v) + c1 --> (cov) (c0 + c1) + v\n")); - - return expr_gen.node_allocator_-> - template allocate_cr > >(c0 + c1,v); - } - // (c0 + v) - c1 --> (cov) (c0 - c1) + v - else if ((details::e_add == o0) && (details::e_sub == o1)) - { - exprtk_debug(("(c0 + v) - c1 --> (cov) (c0 - c1) + v\n")); - - return expr_gen.node_allocator_-> - template allocate_cr > >(c0 - c1,v); - } - // (c0 - v) + c1 --> (cov) (c0 + c1) - v - else if ((details::e_sub == o0) && (details::e_add == o1)) - { - exprtk_debug(("(c0 - v) + c1 --> (cov) (c0 + c1) - v\n")); - - return expr_gen.node_allocator_-> - template allocate_cr > >(c0 + c1,v); - } - // (c0 - v) - c1 --> (cov) (c0 - c1) - v - else if ((details::e_sub == o0) && (details::e_sub == o1)) - { - exprtk_debug(("(c0 - v) - c1 --> (cov) (c0 - c1) - v\n")); - - return expr_gen.node_allocator_-> - template allocate_cr > >(c0 - c1,v); - } - // (c0 * v) * c1 --> (cov) (c0 * c1) * v - else if ((details::e_mul == o0) && (details::e_mul == o1)) - { - exprtk_debug(("(c0 * v) * c1 --> (cov) (c0 * c1) * v\n")); - - return expr_gen.node_allocator_-> - template allocate_cr > >(c0 * c1,v); - } - // (c0 * v) / c1 --> (cov) (c0 / c1) * v - else if ((details::e_mul == o0) && (details::e_div == o1)) - { - exprtk_debug(("(c0 * v) / c1 --> (cov) (c0 / c1) * v\n")); - - return expr_gen.node_allocator_-> - template allocate_cr > >(c0 / c1,v); - } - // (c0 / v) * c1 --> (cov) (c0 * c1) / v - else if ((details::e_div == o0) && (details::e_mul == o1)) - { - exprtk_debug(("(c0 / v) * c1 --> (cov) (c0 * c1) / v\n")); - - return expr_gen.node_allocator_-> - template allocate_cr > >(c0 * c1,v); - } - // (c0 / v) / c1 --> (cov) (c0 / c1) / v - else if ((details::e_div == o0) && (details::e_div == o1)) - { - exprtk_debug(("(c0 / v) / c1 --> (cov) (c0 / c1) / v\n")); - - return expr_gen.node_allocator_-> - template allocate_cr > >(c0 / c1,v); - } - } - - if (synthesize_sf3ext_expression::template compile(expr_gen,id(expr_gen,o0,o1),c0,v,c1,result)) - return result; - else if (!expr_gen.valid_operator(o0,f0)) - return error_node(); - else if (!expr_gen.valid_operator(o1,f1)) - return error_node(); - else - return node_type::allocate(*(expr_gen.node_allocator_),c0,v,c1,f0,f1); - } - - static inline std::string id(expression_generator& expr_gen, - const details::operator_type o0, const details::operator_type o1) - { - return (details::build_string() << "(t" << expr_gen.to_str(o0) << "t)" << expr_gen.to_str(o1) << "t"); - } - }; - - struct synthesize_covoc_expression1 - { - typedef typename covoc_t::type1 node_type; - typedef typename covoc_t::sf3_type sf3_type; - - static inline expression_node_ptr process(expression_generator& expr_gen, - const details::operator_type& operation, - expression_node_ptr (&branch)[2]) - { - // (c0) o0 (v o1 c1) - const details::voc_base_node* voc = static_cast*>(branch[1]); - const Type c0 = static_cast*>(branch[0])->value(); - const Type& v = voc->v(); - const Type c1 = voc->c(); - const details::operator_type o0 = operation; - const details::operator_type o1 = voc->operation(); - - binary_functor_t f0 = reinterpret_cast(0); - binary_functor_t f1 = reinterpret_cast(0); - - details::free_node(*(expr_gen.node_allocator_),branch[0]); - details::free_node(*(expr_gen.node_allocator_),branch[1]); - - expression_node_ptr result = error_node(); - - if (expr_gen.parser_->settings_.strength_reduction_enabled()) - { - // (c0) + (v + c1) --> (cov) (c0 + c1) + v - if ((details::e_add == o0) && (details::e_add == o1)) - { - exprtk_debug(("(c0) + (v + c1) --> (cov) (c0 + c1) + v\n")); - - return expr_gen.node_allocator_-> - template allocate_cr > >(c0 + c1,v); - } - // (c0) + (v - c1) --> (cov) (c0 - c1) + v - else if ((details::e_add == o0) && (details::e_sub == o1)) - { - exprtk_debug(("(c0) + (v - c1) --> (cov) (c0 - c1) + v\n")); - - return expr_gen.node_allocator_-> - template allocate_cr > >(c0 - c1,v); - } - // (c0) - (v + c1) --> (cov) (c0 - c1) - v - else if ((details::e_sub == o0) && (details::e_add == o1)) - { - exprtk_debug(("(c0) - (v + c1) --> (cov) (c0 - c1) - v\n")); - - return expr_gen.node_allocator_-> - template allocate_cr > >(c0 - c1,v); - } - // (c0) - (v - c1) --> (cov) (c0 + c1) - v - else if ((details::e_sub == o0) && (details::e_sub == o1)) - { - exprtk_debug(("(c0) - (v - c1) --> (cov) (c0 + c1) - v\n")); - - return expr_gen.node_allocator_-> - template allocate_cr > >(c0 + c1,v); - } - // (c0) * (v * c1) --> (voc) v * (c0 * c1) - else if ((details::e_mul == o0) && (details::e_mul == o1)) - { - exprtk_debug(("(c0) * (v * c1) --> (voc) v * (c0 * c1)\n")); - - return expr_gen.node_allocator_-> - template allocate_cr > >(c0 * c1,v); - } - // (c0) * (v / c1) --> (cov) (c0 / c1) * v - else if ((details::e_mul == o0) && (details::e_div == o1)) - { - exprtk_debug(("(c0) * (v / c1) --> (cov) (c0 / c1) * v\n")); - - return expr_gen.node_allocator_-> - template allocate_cr > >(c0 / c1,v); - } - // (c0) / (v * c1) --> (cov) (c0 / c1) / v - else if ((details::e_div == o0) && (details::e_mul == o1)) - { - exprtk_debug(("(c0) / (v * c1) --> (cov) (c0 / c1) / v\n")); - - return expr_gen.node_allocator_-> - template allocate_cr > >(c0 / c1,v); - } - // (c0) / (v / c1) --> (cov) (c0 * c1) / v - else if ((details::e_div == o0) && (details::e_div == o1)) - { - exprtk_debug(("(c0) / (v / c1) --> (cov) (c0 * c1) / v\n")); - - return expr_gen.node_allocator_-> - template allocate_cr > >(c0 * c1,v); - } - } - - if (synthesize_sf3ext_expression::template compile(expr_gen,id(expr_gen,o0,o1),c0,v,c1,result)) - return result; - else if (!expr_gen.valid_operator(o0,f0)) - return error_node(); - else if (!expr_gen.valid_operator(o1,f1)) - return error_node(); - else - return node_type::allocate(*(expr_gen.node_allocator_),c0,v,c1,f0,f1); - } - - static inline std::string id(expression_generator& expr_gen, - const details::operator_type o0, const details::operator_type o1) - { - return (details::build_string() << "t" << expr_gen.to_str(o0) << "(t" << expr_gen.to_str(o1) << "t)"); - } - }; - - struct synthesize_cocov_expression0 - { - typedef typename cocov_t::type0 node_type; - static inline expression_node_ptr process(expression_generator&, const details::operator_type&, expression_node_ptr (&)[2]) - { - // (c0 o0 c1) o1 (v) - Not possible. - return error_node(); - } - }; - - struct synthesize_cocov_expression1 - { - typedef typename cocov_t::type1 node_type; - typedef typename cocov_t::sf3_type sf3_type; - - static inline expression_node_ptr process(expression_generator& expr_gen, - const details::operator_type& operation, - expression_node_ptr (&branch)[2]) - { - // (c0) o0 (c1 o1 v) - const details::cov_base_node* cov = static_cast*>(branch[1]); - const Type c0 = static_cast*>(branch[0])->value(); - const Type c1 = cov->c(); - const Type& v = cov->v(); - const details::operator_type o0 = operation; - const details::operator_type o1 = cov->operation(); - - binary_functor_t f0 = reinterpret_cast(0); - binary_functor_t f1 = reinterpret_cast(0); - - details::free_node(*(expr_gen.node_allocator_),branch[0]); - details::free_node(*(expr_gen.node_allocator_),branch[1]); - - expression_node_ptr result = error_node(); - - if (expr_gen.parser_->settings_.strength_reduction_enabled()) - { - // (c0) + (c1 + v) --> (cov) (c0 + c1) + v - if ((details::e_add == o0) && (details::e_add == o1)) - { - exprtk_debug(("(c0) + (c1 + v) --> (cov) (c0 + c1) + v\n")); - - return expr_gen.node_allocator_-> - template allocate_cr > >(c0 + c1,v); - } - // (c0) + (c1 - v) --> (cov) (c0 + c1) - v - else if ((details::e_add == o0) && (details::e_sub == o1)) - { - exprtk_debug(("(c0) + (c1 - v) --> (cov) (c0 + c1) - v\n")); - - return expr_gen.node_allocator_-> - template allocate_cr > >(c0 + c1,v); - } - // (c0) - (c1 + v) --> (cov) (c0 - c1) - v - else if ((details::e_sub == o0) && (details::e_add == o1)) - { - exprtk_debug(("(c0) - (c1 + v) --> (cov) (c0 - c1) - v\n")); - - return expr_gen.node_allocator_-> - template allocate_cr > >(c0 - c1,v); - } - // (c0) - (c1 - v) --> (cov) (c0 - c1) + v - else if ((details::e_sub == o0) && (details::e_sub == o1)) - { - exprtk_debug(("(c0) - (c1 - v) --> (cov) (c0 - c1) + v\n")); - - return expr_gen.node_allocator_-> - template allocate_cr > >(c0 - c1,v); - } - // (c0) * (c1 * v) --> (cov) (c0 * c1) * v - else if ((details::e_mul == o0) && (details::e_mul == o1)) - { - exprtk_debug(("(c0) * (c1 * v) --> (cov) (c0 * c1) * v\n")); - - return expr_gen.node_allocator_-> - template allocate_cr > >(c0 * c1,v); - } - // (c0) * (c1 / v) --> (cov) (c0 * c1) / v - else if ((details::e_mul == o0) && (details::e_div == o1)) - { - exprtk_debug(("(c0) * (c1 / v) --> (cov) (c0 * c1) / v\n")); - - return expr_gen.node_allocator_-> - template allocate_cr > >(c0 * c1,v); - } - // (c0) / (c1 * v) --> (cov) (c0 / c1) / v - else if ((details::e_div == o0) && (details::e_mul == o1)) - { - exprtk_debug(("(c0) / (c1 * v) --> (cov) (c0 / c1) / v\n")); - - return expr_gen.node_allocator_-> - template allocate_cr > >(c0 / c1,v); - } - // (c0) / (c1 / v) --> (cov) (c0 / c1) * v - else if ((details::e_div == o0) && (details::e_div == o1)) - { - exprtk_debug(("(c0) / (c1 / v) --> (cov) (c0 / c1) * v\n")); - - return expr_gen.node_allocator_-> - template allocate_cr > >(c0 / c1,v); - } - } - - if (synthesize_sf3ext_expression::template compile(expr_gen,id(expr_gen,o0,o1),c0,c1,v,result)) - return result; - else if (!expr_gen.valid_operator(o0,f0)) - return error_node(); - else if (!expr_gen.valid_operator(o1,f1)) - return error_node(); - else - return node_type::allocate(*(expr_gen.node_allocator_),c0,c1,v,f0,f1); - } - - static inline std::string id(expression_generator& expr_gen, const details::operator_type o0, const details::operator_type o1) - { - return (details::build_string() << "t" << expr_gen.to_str(o0) << "(t" << expr_gen.to_str(o1) << "t)"); - } + + case e_string : delete (std::string*)(local_data_list[i].pointer); + break; + + default : break; + } + } + } + + if (results) + { + delete results; + } + } + + static inline control_block* create(expression_ptr e) + { + return new control_block(e); + } + + static inline void destroy(control_block*& cntrl_blck) + { + if (cntrl_blck) + { + if ( + (0 != cntrl_blck->ref_count) && + (0 == --cntrl_blck->ref_count) + ) + { + delete cntrl_blck; + } + + cntrl_blck = 0; + } + } + + std::size_t ref_count; + expression_ptr expr; + local_data_list_t local_data_list; + results_context_t* results; + bool retinv_null; + bool* return_invoked; + + friend class function_compositor; + }; + + public: + + expression() + : control_block_(0) + { + set_expression(new details::null_node()); + } + + expression(const expression& e) + : control_block_(e.control_block_), + symbol_table_list_(e.symbol_table_list_) + { + control_block_->ref_count++; + } + + inline expression& operator=(const expression& e) + { + if (this != &e) + { + if (control_block_) + { + if ( + (0 != control_block_->ref_count) && + (0 == --control_block_->ref_count) + ) + { + delete control_block_; + } + + control_block_ = 0; + } + + control_block_ = e.control_block_; + control_block_->ref_count++; + symbol_table_list_ = e.symbol_table_list_; + } + + return *this; + } + + inline bool operator==(const expression& e) + { + return (this == &e); + } + + inline bool operator!() const + { + return ( + (0 == control_block_ ) || + (0 == control_block_->expr) + ); + } + + inline expression& release() + { + control_block::destroy(control_block_); + + return *this; + } + + ~expression() + { + control_block::destroy(control_block_); + } + + inline T value() const + { + return control_block_->expr->value(); + } + + inline T operator()() const + { + return value(); + } + + inline operator T() const + { + return value(); + } + + inline operator bool() const + { + return details::is_true(value()); + } + + inline void register_symbol_table(symbol_table& st) + { + symbol_table_list_.push_back(st); + } + + inline const symbol_table& get_symbol_table(const std::size_t& index = 0) const + { + return symbol_table_list_[index]; + } + + inline symbol_table& get_symbol_table(const std::size_t& index = 0) + { + return symbol_table_list_[index]; + } + + typedef results_context results_context_t; + + inline const results_context_t& results() const + { + if (control_block_->results) + return (*control_block_->results); + else + { + static const results_context_t null_results; + return null_results; + } + } + + inline bool return_invoked() const + { + return (*control_block_->return_invoked); + } + + private: + + inline symtab_list_t get_symbol_table_list() const + { + return symbol_table_list_; + } + + inline void set_expression(const expression_ptr expr) + { + if (expr) + { + if (control_block_) + { + if (0 == --control_block_->ref_count) + { + delete control_block_; + } + } + + control_block_ = control_block::create(expr); + } + } + + inline void register_local_var(expression_ptr expr) + { + if (expr) + { + if (control_block_) + { + control_block_-> + local_data_list.push_back( + typename expression::control_block:: + data_pack(reinterpret_cast(expr), + control_block::e_expr)); + } + } + } + + inline void register_local_var(vector_holder_ptr vec_holder) + { + if (vec_holder) + { + if (control_block_) + { + control_block_-> + local_data_list.push_back( + typename expression::control_block:: + data_pack(reinterpret_cast(vec_holder), + control_block::e_vecholder)); + } + } + } + + inline void register_local_data(void* data, const std::size_t& size = 0, const std::size_t data_mode = 0) + { + if (data) + { + if (control_block_) + { + typename control_block::data_type dt = control_block::e_data; + + switch (data_mode) + { + case 0 : dt = control_block::e_data; break; + case 1 : dt = control_block::e_vecdata; break; + case 2 : dt = control_block::e_string; break; + } + + control_block_-> + local_data_list.push_back( + typename expression::control_block:: + data_pack(reinterpret_cast(data),dt,size)); + } + } + } + + inline const typename control_block::local_data_list_t& local_data_list() + { + if (control_block_) + { + return control_block_->local_data_list; + } + else + { + static typename control_block::local_data_list_t null_local_data_list; + return null_local_data_list; + } + } + + inline void register_return_results(results_context_t* rc) + { + if (control_block_ && rc) + { + control_block_->results = rc; + } + } + + inline void set_retinvk(bool* retinvk_ptr) + { + if (control_block_) + { + control_block_->return_invoked = retinvk_ptr; + } + } + + control_block* control_block_; + symtab_list_t symbol_table_list_; + + friend class parser; + friend class expression_helper; + friend class function_compositor; + }; + + template + class expression_helper + { + public: + + static inline bool is_constant(const expression& expr) + { + return details::is_constant_node(expr.control_block_->expr); + } + + static inline bool is_variable(const expression& expr) + { + return details::is_variable_node(expr.control_block_->expr); + } + + static inline bool is_unary(const expression& expr) + { + return details::is_unary_node(expr.control_block_->expr); + } + + static inline bool is_binary(const expression& expr) + { + return details::is_binary_node(expr.control_block_->expr); + } + + static inline bool is_function(const expression& expr) + { + return details::is_function(expr.control_block_->expr); + } + + static inline bool is_null(const expression& expr) + { + return details::is_null_node(expr.control_block_->expr); + } + }; + + template + inline bool is_valid(const expression& expr) + { + return !expression_helper::is_null(expr); + } + + namespace parser_error + { + enum error_mode + { + e_unknown = 0, + e_syntax = 1, + e_token = 2, + e_numeric = 4, + e_symtab = 5, + e_lexer = 6, + e_helper = 7 + }; + + 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(("%s\n",diagnostic .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(("%s\n",diagnostic .c_str())); + return t; + } + + inline std::string to_str(error_mode mode) + { + switch (mode) + { + case e_unknown : return std::string("Unknown Error"); + case e_syntax : return std::string("Syntax Error" ); + case e_token : return std::string("Token Error" ); + case e_numeric : return std::string("Numeric Error"); + case e_symtab : return std::string("Symbol Error" ); + case e_lexer : return std::string("Lexer Error" ); + case e_helper : return std::string("Helper Error" ); + default : return std::string("Unknown Error"); + } + } + + inline bool update_error(type& error, const std::string& expression) + { + if ( + expression.empty() || + (error.token.position > expression.size()) || + (std::numeric_limits::max() == error.token.position) + ) + { + return false; + } + + std::size_t error_line_start = 0; + + for (std::size_t i = error.token.position; i > 0; --i) + { + const details::char_t c = expression[i]; + + if (('\n' == c) || ('\r' == c)) + { + error_line_start = i + 1; + break; + } + } + + std::size_t next_nl_position = std::min(expression.size(), + expression.find_first_of('\n',error.token.position + 1)); + + error.column_no = error.token.position - error_line_start; + error.error_line = expression.substr(error_line_start, + next_nl_position - error_line_start); + + error.line_no = 0; + + for (std::size_t i = 0; i < next_nl_position; ++i) + { + if ('\n' == expression[i]) + ++error.line_no; + } + + return true; + } + + inline void dump_error(const type& error) + { + printf("Position: %02d Type: [%s] Msg: %s\n", + static_cast(error.token.position), + exprtk::parser_error::to_str(error.mode).c_str(), + error.diagnostic.c_str()); + } + } + + namespace details + { + template + inline void disable_type_checking(Parser& p) + { + p.state_.type_check_enabled = false; + } + } + + template + class parser : public lexer::parser_helper + { + private: + + enum precedence_level + { + e_level00, + e_level01, + e_level02, + e_level03, + e_level04, + e_level05, + e_level06, + e_level07, + e_level08, + e_level09, + e_level10, + e_level11, + e_level12, + e_level13, + e_level14 + }; + + typedef const T& cref_t; + typedef const T const_t; + typedef ifunction F; + typedef ivararg_function VAF; + typedef igeneric_function GF; + typedef ifunction ifunction_t; + typedef ivararg_function ivararg_function_t; + typedef igeneric_function igeneric_function_t; + typedef details::expression_node expression_node_t; + typedef details::literal_node literal_node_t; + typedef details::unary_node unary_node_t; + typedef details::binary_node binary_node_t; + typedef details::trinary_node trinary_node_t; + typedef details::quaternary_node quaternary_node_t; + typedef details::conditional_node conditional_node_t; + typedef details::cons_conditional_node cons_conditional_node_t; + typedef details::while_loop_node while_loop_node_t; + typedef details::repeat_until_loop_node repeat_until_loop_node_t; + typedef details::for_loop_node for_loop_node_t; + #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::rebasevector_elem_node rebasevector_elem_node_t; + typedef details::rebasevector_celem_node rebasevector_celem_node_t; + typedef details::vector_node vector_node_t; + typedef details::range_pack range_t; + #ifndef exprtk_disable_string_capabilities + typedef details::stringvar_node stringvar_node_t; + typedef details::string_literal_node string_literal_node_t; + typedef details::string_range_node string_range_node_t; + typedef details::const_string_range_node const_string_range_node_t; + typedef details::generic_string_range_node generic_string_range_node_t; + typedef details::string_concat_node string_concat_node_t; + typedef details::assignment_string_node assignment_string_node_t; + typedef details::assignment_string_range_node assignment_string_range_node_t; + typedef details::conditional_string_node conditional_string_node_t; + typedef details::cons_conditional_str_node cons_conditional_str_node_t; + #endif + typedef details::assignment_node assignment_node_t; + typedef details::assignment_vec_elem_node assignment_vec_elem_node_t; + typedef details::assignment_rebasevec_elem_node assignment_rebasevec_elem_node_t; + typedef details::assignment_rebasevec_celem_node assignment_rebasevec_celem_node_t; + typedef details::assignment_vec_node assignment_vec_node_t; + typedef details::assignment_vecvec_node assignment_vecvec_node_t; + typedef details::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 typename expression::symtab_list_t symbol_table_list_t; + typedef details::vector_holder* vector_holder_ptr; + + typedef typename details::functor_t functor_t; + typedef typename functor_t::qfunc_t quaternary_functor_t; + typedef typename functor_t::tfunc_t trinary_functor_t; + typedef typename functor_t::bfunc_t binary_functor_t; + typedef typename functor_t::ufunc_t unary_functor_t; + + typedef details::operator_type operator_t; + + typedef std::map unary_op_map_t; + typedef std::map binary_op_map_t; + typedef std::map trinary_op_map_t; + + typedef std::map > sf3_map_t; + typedef std::map > sf4_map_t; + + typedef std::map inv_binary_op_map_t; + typedef std::multimap base_ops_map_t; + typedef std::set disabled_func_set_t; + + typedef details::T0oT1_define vov_t; + typedef details::T0oT1_define cov_t; + typedef details::T0oT1_define voc_t; + + typedef details::T0oT1oT2_define vovov_t; + typedef details::T0oT1oT2_define vovoc_t; + typedef details::T0oT1oT2_define vocov_t; + typedef details::T0oT1oT2_define covov_t; + typedef details::T0oT1oT2_define covoc_t; + typedef details::T0oT1oT2_define cocov_t; + typedef details::T0oT1oT2_define vococ_t; + + typedef details::T0oT1oT2oT3_define vovovov_t; + typedef details::T0oT1oT2oT3_define vovovoc_t; + typedef details::T0oT1oT2oT3_define vovocov_t; + typedef details::T0oT1oT2oT3_define vocovov_t; + typedef details::T0oT1oT2oT3_define covovov_t; + + typedef details::T0oT1oT2oT3_define covocov_t; + typedef details::T0oT1oT2oT3_define vocovoc_t; + typedef details::T0oT1oT2oT3_define covovoc_t; + typedef details::T0oT1oT2oT3_define vococov_t; + + typedef results_context results_context_t; + + typedef parser_helper prsrhlpr_t; + + struct scope_element + { + enum element_type + { + e_none , + e_variable, + e_vector , + e_vecelem , + e_string + }; + + typedef details::vector_holder vector_holder_t; + typedef variable_node_t* variable_node_ptr; + typedef vector_holder_t* vector_holder_ptr; + typedef expression_node_t* expression_node_ptr; + #ifndef exprtk_disable_string_capabilities + typedef stringvar_node_t* stringvar_node_ptr; + #endif + + scope_element() + : name("???"), + size (std::numeric_limits::max()), + index(std::numeric_limits::max()), + depth(std::numeric_limits::max()), + ref_count(0), + ip_index (0), + type (e_none), + active(false), + data (0), + var_node(0), + vec_node(0) + #ifndef exprtk_disable_string_capabilities + ,str_node(0) + #endif + {} + + bool operator < (const scope_element& se) const + { + if (ip_index < se.ip_index) + return true; + else if (ip_index > se.ip_index) + return false; + else if (depth < se.depth) + return true; + else if (depth > se.depth) + return false; + else if (index < se.index) + return true; + else if (index > se.index) + return false; + else + return (name < se.name); + } + + void clear() + { + name = "???"; + size = std::numeric_limits::max(); + index = std::numeric_limits::max(); + depth = std::numeric_limits::max(); + type = e_none; + active = false; + ref_count = 0; + ip_index = 0; + data = 0; + var_node = 0; + vec_node = 0; + #ifndef exprtk_disable_string_capabilities + str_node = 0; + #endif + } + + std::string name; + std::size_t size; + std::size_t index; + std::size_t depth; + std::size_t ref_count; + std::size_t ip_index; + element_type type; + bool active; + void* data; + expression_node_ptr var_node; + vector_holder_ptr vec_node; + #ifndef exprtk_disable_string_capabilities + stringvar_node_ptr str_node; + #endif + }; + + class scope_element_manager + { + public: + + typedef expression_node_t* expression_node_ptr; + typedef variable_node_t* variable_node_ptr; + typedef parser parser_t; + + scope_element_manager(parser& p) + : parser_(p), + input_param_cnt_(0) + {} + + inline std::size_t size() const + { + return element_.size(); + } + + inline bool empty() const + { + return element_.empty(); + } + + inline scope_element& get_element(const std::size_t& index) + { + if (index < element_.size()) + return element_[index]; + else + return null_element_; + } + + inline scope_element& get_element(const std::string& var_name, + const std::size_t index = std::numeric_limits::max()) + { + const std::size_t current_depth = parser_.state_.scope_depth; + + for (std::size_t i = 0; i < element_.size(); ++i) + { + scope_element& se = element_[i]; + + if (se.depth > current_depth) + continue; + else if ( + (se.name == var_name) && + (se.index == index) + ) + return se; + } + + return null_element_; + } + + inline scope_element& get_active_element(const std::string& var_name, + const std::size_t index = std::numeric_limits::max()) + { + const std::size_t current_depth = parser_.state_.scope_depth; + + for (std::size_t i = 0; i < element_.size(); ++i) + { + scope_element& se = element_[i]; + + if (se.depth > current_depth) + continue; + else if ( + (se.name == var_name) && + (se.index == index) && + (se.active) + ) + return se; + } + + return null_element_; + } + + inline bool add_element(const scope_element& se) + { + for (std::size_t i = 0; i < element_.size(); ++i) + { + scope_element& cse = element_[i]; + + if ( + (cse.name == se.name ) && + (cse.depth <= se.depth) && + (cse.index == se.index) && + (cse.size == se.size ) && + (cse.type == se.type ) && + (cse.active) + ) + return false; + } + + element_.push_back(se); + std::sort(element_.begin(),element_.end()); + + return true; + } + + inline void deactivate(const std::size_t& scope_depth) + { + exprtk_debug(("deactivate() - Scope depth: %d\n", + static_cast(parser_.state_.scope_depth))); + + for (std::size_t i = 0; i < element_.size(); ++i) + { + scope_element& se = element_[i]; + + if (se.active && (se.depth >= scope_depth)) + { + exprtk_debug(("deactivate() - element[%02d] '%s'\n", + static_cast(i), + se.name.c_str())); + + se.active = false; + } + } + } + + inline void free_element(scope_element& se) + { + switch (se.type) + { + case scope_element::e_variable : if (se.data ) delete (T*) se.data; + if (se.var_node) delete se.var_node; + break; + + case scope_element::e_vector : if (se.data ) delete[] (T*) se.data; + if (se.vec_node) delete se.vec_node; + break; + + case scope_element::e_vecelem : if (se.var_node) delete se.var_node; + break; + + #ifndef exprtk_disable_string_capabilities + case scope_element::e_string : if (se.data ) delete (std::string*) se.data; + if (se.str_node) delete se.str_node; + break; + #endif + + default : return; + } + + se.clear(); + } + + inline void cleanup() + { + for (std::size_t i = 0; i < element_.size(); ++i) + { + free_element(element_[i]); + } + + element_.clear(); + + input_param_cnt_ = 0; + } + + inline std::size_t next_ip_index() + { + return ++input_param_cnt_; + } + + inline expression_node_ptr get_variable(const T& v) + { + for (std::size_t i = 0; i < element_.size(); ++i) + { + scope_element& se = element_[i]; + + if ( + se.active && + se.var_node && + details::is_variable_node(se.var_node) + ) + { + variable_node_ptr vn = reinterpret_cast(se.var_node); + + if (&(vn->ref()) == (&v)) + { + return se.var_node; + } + } + } + + return expression_node_ptr(0); + } + + private: + + scope_element_manager& 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_.state_.scope_depth++; + #ifdef exprtk_enable_debugging + std::string depth(2 * parser_.state_.scope_depth,'-'); + exprtk_debug(("%s> Scope Depth: %02d\n", + depth.c_str(), + static_cast(parser_.state_.scope_depth))); + #endif + } + + ~scope_handler() + { + parser_.sem_.deactivate(parser_.state_.scope_depth); + parser_.state_.scope_depth--; + #ifdef exprtk_enable_debugging + std::string depth(2 * parser_.state_.scope_depth,'-'); + exprtk_debug(("<%s Scope Depth: %02d\n", + depth.c_str(), + static_cast(parser_.state_.scope_depth))); + #endif + } + + private: + + scope_handler& operator=(const scope_handler&); + + parser_t& parser_; + }; + + struct symtab_store + { + symbol_table_list_t symtab_list_; + + typedef typename symbol_table_t::local_data_t local_data_t; + typedef typename symbol_table_t::variable_ptr variable_ptr; + typedef typename symbol_table_t::function_ptr function_ptr; + #ifndef exprtk_disable_string_capabilities + typedef typename symbol_table_t::stringvar_ptr stringvar_ptr; + #endif + typedef typename symbol_table_t::vector_holder_ptr vector_holder_ptr; + typedef typename symbol_table_t::vararg_function_ptr vararg_function_ptr; + typedef typename symbol_table_t::generic_function_ptr generic_function_ptr; + + inline bool empty() const + { + return symtab_list_.empty(); + } + + inline void clear() + { + symtab_list_.clear(); + } + + inline bool valid() const + { + if (!empty()) + { + for (std::size_t i = 0; i < symtab_list_.size(); ++i) + { + if (symtab_list_[i].valid()) + return true; + } + } + + return false; + } + + inline bool valid_symbol(const std::string& symbol) const + { + if (!symtab_list_.empty()) + return symtab_list_[0].valid_symbol(symbol); + else + return false; + } + + inline bool valid_function_name(const std::string& symbol) const + { + if (!symtab_list_.empty()) + return symtab_list_[0].valid_function(symbol); + else + return false; + } + + inline variable_ptr get_variable(const std::string& variable_name) const + { + if (!valid_symbol(variable_name)) + return reinterpret_cast(0); + + variable_ptr result = reinterpret_cast(0); + + for (std::size_t i = 0; i < symtab_list_.size(); ++i) + { + if (!symtab_list_[i].valid()) + continue; + else + result = local_data(i) + .variable_store.get(variable_name); + + if (result) break; + } + + return result; + } + + inline variable_ptr get_variable(const T& var_ref) const + { + variable_ptr result = reinterpret_cast(0); + + for (std::size_t i = 0; i < symtab_list_.size(); ++i) + { + if (!symtab_list_[i].valid()) + continue; + else + result = local_data(i).variable_store + .get_from_varptr(reinterpret_cast(&var_ref)); + + if (result) break; + } + + return result; + } + + #ifndef exprtk_disable_string_capabilities + inline stringvar_ptr get_stringvar(const std::string& string_name) const + { + if (!valid_symbol(string_name)) + return reinterpret_cast(0); + + stringvar_ptr result = reinterpret_cast(0); + + for (std::size_t i = 0; i < symtab_list_.size(); ++i) + { + if (!symtab_list_[i].valid()) + continue; + else + result = local_data(i) + .stringvar_store.get(string_name); + + if (result) break; + } + + return result; + } + #endif + + inline function_ptr get_function(const std::string& function_name) const + { + if (!valid_function_name(function_name)) + return reinterpret_cast(0); + + function_ptr result = reinterpret_cast(0); + + for (std::size_t i = 0; i < symtab_list_.size(); ++i) + { + if (!symtab_list_[i].valid()) + continue; + else + result = local_data(i) + .function_store.get(function_name); + + if (result) break; + } + + return result; + } + + inline vararg_function_ptr get_vararg_function(const std::string& vararg_function_name) const + { + if (!valid_function_name(vararg_function_name)) + return reinterpret_cast(0); + + vararg_function_ptr result = reinterpret_cast(0); + + for (std::size_t i = 0; i < symtab_list_.size(); ++i) + { + if (!symtab_list_[i].valid()) + continue; + else + result = local_data(i) + .vararg_function_store.get(vararg_function_name); + + if (result) break; + } + + return result; + } + + inline generic_function_ptr get_generic_function(const std::string& function_name) const + { + if (!valid_function_name(function_name)) + return reinterpret_cast(0); + + generic_function_ptr result = reinterpret_cast(0); + + for (std::size_t i = 0; i < symtab_list_.size(); ++i) + { + if (!symtab_list_[i].valid()) + continue; + else + result = local_data(i) + .generic_function_store.get(function_name); + + if (result) break; + } + + return result; + } + + inline generic_function_ptr get_string_function(const std::string& function_name) const + { + if (!valid_function_name(function_name)) + return reinterpret_cast(0); + + generic_function_ptr result = reinterpret_cast(0); + + for (std::size_t i = 0; i < symtab_list_.size(); ++i) + { + if (!symtab_list_[i].valid()) + continue; + else + result = + local_data(i).string_function_store.get(function_name); + + if (result) break; + } + + return result; + } + + inline vector_holder_ptr get_vector(const std::string& vector_name) const + { + if (!valid_symbol(vector_name)) + return reinterpret_cast(0); + + vector_holder_ptr result = reinterpret_cast(0); + + for (std::size_t i = 0; i < symtab_list_.size(); ++i) + { + if (!symtab_list_[i].valid()) + continue; + else + result = + local_data(i).vector_store.get(vector_name); + + if (result) break; + } + + return result; + } + + inline bool is_constant_node(const std::string& symbol_name) const + { + if (!valid_symbol(symbol_name)) + return false; + + for (std::size_t i = 0; i < symtab_list_.size(); ++i) + { + if (!symtab_list_[i].valid()) + continue; + else if (local_data(i).variable_store.is_constant(symbol_name)) + return true; + } + + return false; + } + + #ifndef exprtk_disable_string_capabilities + inline bool is_constant_string(const std::string& symbol_name) const + { + if (!valid_symbol(symbol_name)) + return false; + + for (std::size_t i = 0; i < symtab_list_.size(); ++i) + { + if (!symtab_list_[i].valid()) + continue; + else if (!local_data(i).stringvar_store.symbol_exists(symbol_name)) + continue; + else if ( local_data(i).stringvar_store.is_constant(symbol_name)) + return true; + } + + return false; + } + #endif + + inline bool symbol_exists(const std::string& symbol) const + { + for (std::size_t i = 0; i < symtab_list_.size(); ++i) + { + if (!symtab_list_[i].valid()) + continue; + else if (symtab_list_[i].symbol_exists(symbol)) + return true; + } + + return false; + } + + inline bool is_variable(const std::string& variable_name) const + { + for (std::size_t i = 0; i < symtab_list_.size(); ++i) + { + if (!symtab_list_[i].valid()) + continue; + else if ( + symtab_list_[i].local_data().variable_store + .symbol_exists(variable_name) + ) + return true; + } + + return false; + } + + #ifndef exprtk_disable_string_capabilities + inline bool is_stringvar(const std::string& stringvar_name) const + { + for (std::size_t i = 0; i < symtab_list_.size(); ++i) + { + if (!symtab_list_[i].valid()) + continue; + else if ( + symtab_list_[i].local_data().stringvar_store + .symbol_exists(stringvar_name) + ) + return true; + } + + return false; + } + + inline bool is_conststr_stringvar(const std::string& symbol_name) const + { + for (std::size_t i = 0; i < symtab_list_.size(); ++i) + { + if (!symtab_list_[i].valid()) + continue; + else if ( + symtab_list_[i].local_data().stringvar_store + .symbol_exists(symbol_name) + ) + { + return ( + local_data(i).stringvar_store.symbol_exists(symbol_name) || + local_data(i).stringvar_store.is_constant (symbol_name) + ); + + } + } + + return false; + } + #endif + + inline bool is_function(const std::string& function_name) const + { + for (std::size_t i = 0; i < symtab_list_.size(); ++i) + { + if (!symtab_list_[i].valid()) + continue; + else if ( + local_data(i).vararg_function_store + .symbol_exists(function_name) + ) + return true; + } + + return false; + } + + inline bool is_vararg_function(const std::string& vararg_function_name) const + { + for (std::size_t i = 0; i < symtab_list_.size(); ++i) + { + if (!symtab_list_[i].valid()) + continue; + else if ( + local_data(i).vararg_function_store + .symbol_exists(vararg_function_name) + ) + return true; + } + + return false; + } + + inline bool is_vector(const std::string& vector_name) const + { + for (std::size_t i = 0; i < symtab_list_.size(); ++i) + { + if (!symtab_list_[i].valid()) + continue; + else if ( + local_data(i).vector_store + .symbol_exists(vector_name) + ) + return true; + } + + return false; + } + + inline std::string get_variable_name(const expression_node_ptr& ptr) const + { + return local_data().variable_store.entity_name(ptr); + } + + inline std::string get_vector_name(const vector_holder_ptr& ptr) const + { + return local_data().vector_store.entity_name(ptr); + } + + #ifndef exprtk_disable_string_capabilities + inline std::string get_stringvar_name(const expression_node_ptr& ptr) const + { + return local_data().stringvar_store.entity_name(ptr); + } + + inline std::string get_conststr_stringvar_name(const expression_node_ptr& ptr) const + { + return local_data().stringvar_store.entity_name(ptr); + } + #endif + + inline local_data_t& local_data(const std::size_t& index = 0) + { + return symtab_list_[index].local_data(); + } + + inline const local_data_t& local_data(const std::size_t& index = 0) const + { + return symtab_list_[index].local_data(); + } + + inline symbol_table_t& get_symbol_table(const std::size_t& index = 0) + { + return symtab_list_[index]; + } + }; + + struct parser_state + { + parser_state() + : type_check_enabled(true) + { + reset(); + } + + void reset() + { + parsing_return_stmt = false; + parsing_break_stmt = false; + return_stmt_present = false; + side_effect_present = false; + scope_depth = 0; + } + + #ifndef exprtk_enable_debugging + void activate_side_effect(const std::string&) + #else + void activate_side_effect(const std::string& source) + #endif + { + if (!side_effect_present) + { + side_effect_present = true; + + exprtk_debug(("activate_side_effect() - caller: %s\n",source.c_str())); + } + } + + bool parsing_return_stmt; + bool parsing_break_stmt; + bool return_stmt_present; + bool side_effect_present; + bool type_check_enabled; + std::size_t scope_depth; + }; + + public: + + 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.clear(); + + 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_vecelem = 3, + e_st_string = 4, + e_st_function = 5, + e_st_local_variable = 6, + e_st_local_vector = 7, + e_st_local_string = 8 + }; + + class dependent_entity_collector + { + public: + + typedef std::pair symbol_t; + typedef std::vector symbol_list_t; + + dependent_entity_collector(const std::size_t options = e_ct_none) + : options_(options), + collect_variables_ ((options_ & e_ct_variables ) == e_ct_variables ), + collect_functions_ ((options_ & e_ct_functions ) == e_ct_functions ), + collect_assignments_((options_ & e_ct_assignments) == e_ct_assignments), + return_present_ (false), + final_stmt_return_(false) + {} + + template class Sequence> + inline std::size_t symbols(Sequence& symbols_list) + { + if (!collect_variables_ && !collect_functions_) + return 0; + else if (symbol_name_list_.empty()) + return 0; + + for (std::size_t i = 0; i < symbol_name_list_.size(); ++i) + { + std::string& s = symbol_name_list_[i].first; + #ifndef MODIFICATION + std::transform(s.begin(),s.end(),s.begin(),static_cast(std::tolower)); + #endif + } + + 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; + #ifndef MODIFICATION + std::transform(s.begin(),s.end(),s.begin(),static_cast(std::tolower)); + #endif + } + + std::sort(assignment_name_list_.begin(),assignment_name_list_.end()); + + std::unique_copy(assignment_name_list_.begin(), + assignment_name_list_.end(), + std::back_inserter(assignment_list)); + + return assignment_list.size(); + } + + void clear() + { + symbol_name_list_ .clear(); + assignment_name_list_.clear(); + retparam_list_ .clear(); + return_present_ = false; + final_stmt_return_ = false; + } + + bool& collect_variables() + { + return collect_variables_; + } + + bool& collect_functions() + { + return collect_functions_; + } + + bool& collect_assignments() + { + return collect_assignments_; + } + + bool return_present() const + { + return return_present_; + } + + bool final_stmt_return() const + { + return final_stmt_return_; + } + + typedef std::vector retparam_list_t; + + retparam_list_t return_param_type_list() const + { + return retparam_list_; + } + + private: + + inline void add_symbol(const std::string& symbol, const symbol_type st) + { + switch (st) + { + case e_st_variable : + case e_st_vector : + case e_st_string : + case e_st_local_variable : + case e_st_local_vector : + case e_st_local_string : if (collect_variables_) + symbol_name_list_.push_back(std::make_pair(symbol,st)); + break; + + case e_st_function : if (collect_functions_) + symbol_name_list_.push_back(std::make_pair(symbol,st)); + break; + + default : return; + } + } + + inline void add_assignment(const std::string& symbol, const symbol_type st) + { + switch (st) + { + case e_st_variable : + case e_st_vector : + case e_st_string : + if (collect_assignments_) + assignment_name_list_.push_back(std::make_pair(symbol,st)); + break; + + default : return; + } + } + + std::size_t options_; + bool collect_variables_; + bool collect_functions_; + bool collect_assignments_; + bool return_present_; + bool final_stmt_return_; + symbol_list_t symbol_name_list_; + symbol_list_t assignment_name_list_; + retparam_list_t retparam_list_; + + friend class parser; + }; + + class settings_store + { + private: + + typedef std::set disabled_entity_set_t; + typedef disabled_entity_set_t::iterator des_itr_t; + + public: + + enum settings_compilation_options + { + e_unknown = 0, + e_replacer = 1, + e_joiner = 2, + e_numeric_check = 4, + e_bracket_check = 8, + e_sequence_check = 16, + e_commutative_check = 32, + e_strength_reduction = 64, + e_disable_vardef = 128, + e_collect_vars = 256, + e_collect_funcs = 512, + e_collect_assings = 1024, + e_disable_usr_on_rsrvd = 2048, + e_disable_zero_return = 4096 + }; + + enum settings_base_funcs + { + e_bf_unknown = 0, + e_bf_abs , e_bf_acos , e_bf_acosh , e_bf_asin , + e_bf_asinh , e_bf_atan , e_bf_atan2 , e_bf_atanh , + e_bf_avg , e_bf_ceil , e_bf_clamp , e_bf_cos , + e_bf_cosh , e_bf_cot , e_bf_csc , e_bf_equal , + e_bf_erf , e_bf_erfc , e_bf_exp , e_bf_expm1 , + e_bf_floor , e_bf_frac , e_bf_hypot , e_bf_iclamp , + e_bf_like , e_bf_log , e_bf_log10 , e_bf_log1p , + e_bf_log2 , e_bf_logn , e_bf_mand , e_bf_max , + e_bf_min , e_bf_mod , e_bf_mor , e_bf_mul , + e_bf_ncdf , e_bf_pow , e_bf_root , e_bf_round , + e_bf_roundn , e_bf_sec , e_bf_sgn , e_bf_sin , + e_bf_sinc , e_bf_sinh , e_bf_sqrt , e_bf_sum , + e_bf_swap , e_bf_tan , e_bf_tanh , e_bf_trunc , + e_bf_not_equal , e_bf_inrange , e_bf_deg2grad , e_bf_deg2rad, + e_bf_rad2deg , e_bf_grad2deg + }; + + enum settings_control_structs + { + e_ctrl_unknown = 0, + e_ctrl_ifelse, + e_ctrl_switch, + e_ctrl_for_loop, + e_ctrl_while_loop, + e_ctrl_repeat_loop, + e_ctrl_return + }; + + enum settings_logic_opr + { + e_logic_unknown = 0, + e_logic_and, e_logic_nand, e_logic_nor, + e_logic_not, e_logic_or, e_logic_xnor, + e_logic_xor, e_logic_scand, e_logic_scor + }; + + enum settings_arithmetic_opr + { + e_arith_unknown = 0, + e_arith_add, e_arith_sub, e_arith_mul, + e_arith_div, e_arith_mod, e_arith_pow + }; + + enum settings_assignment_opr + { + e_assign_unknown = 0, + e_assign_assign, e_assign_addass, e_assign_subass, + e_assign_mulass, e_assign_divass, e_assign_modass + }; + + enum settings_inequality_opr + { + e_ineq_unknown = 0, + e_ineq_lt, e_ineq_lte, e_ineq_eq, + e_ineq_equal, e_ineq_ne, e_ineq_nequal, + e_ineq_gte, e_ineq_gt + }; + + static const std::size_t compile_all_opts = e_replacer + + e_joiner + + e_numeric_check + + e_bracket_check + + e_sequence_check + + e_commutative_check + + e_strength_reduction; + + settings_store(const std::size_t compile_options = compile_all_opts) + { + load_compile_options(compile_options); + } + + settings_store& enable_all_base_functions() + { + disabled_func_set_.clear(); + return *this; + } + + settings_store& enable_all_control_structures() + { + disabled_ctrl_set_.clear(); + return *this; + } + + settings_store& enable_all_logic_ops() + { + disabled_logic_set_.clear(); + return *this; + } + + settings_store& enable_all_arithmetic_ops() + { + disabled_arithmetic_set_.clear(); + return *this; + } + + settings_store& enable_all_assignment_ops() + { + disabled_assignment_set_.clear(); + return *this; + } + + settings_store& enable_all_inequality_ops() + { + disabled_inequality_set_.clear(); + return *this; + } + + settings_store& enable_local_vardef() + { + disable_vardef_ = false; + return *this; + } + + settings_store& disable_all_base_functions() + { + std::copy(details::base_function_list, + details::base_function_list + details::base_function_list_size, + std::insert_iterator + (disabled_func_set_,disabled_func_set_.begin())); + return *this; + } + + settings_store& disable_all_control_structures() + { + std::copy(details::cntrl_struct_list, + details::cntrl_struct_list + details::cntrl_struct_list_size, + std::insert_iterator + (disabled_ctrl_set_,disabled_ctrl_set_.begin())); + return *this; + } + + settings_store& disable_all_logic_ops() + { + std::copy(details::logic_ops_list, + details::logic_ops_list + details::logic_ops_list_size, + std::insert_iterator + (disabled_logic_set_,disabled_logic_set_.begin())); + return *this; + } + + settings_store& disable_all_arithmetic_ops() + { + std::copy(details::arithmetic_ops_list, + details::arithmetic_ops_list + details::arithmetic_ops_list_size, + std::insert_iterator + (disabled_arithmetic_set_,disabled_arithmetic_set_.begin())); + return *this; + } + + settings_store& disable_all_assignment_ops() + { + std::copy(details::assignment_ops_list, + details::assignment_ops_list + details::assignment_ops_list_size, + std::insert_iterator + (disabled_assignment_set_,disabled_assignment_set_.begin())); + return *this; + } + + settings_store& disable_all_inequality_ops() + { + std::copy(details::inequality_ops_list, + details::inequality_ops_list + details::inequality_ops_list_size, + std::insert_iterator + (disabled_inequality_set_,disabled_inequality_set_.begin())); + return *this; + } + + settings_store& disable_local_vardef() + { + disable_vardef_ = true; + return *this; + } + + bool replacer_enabled () const { return enable_replacer_; } + bool commutative_check_enabled () const { return enable_commutative_check_; } + bool joiner_enabled () const { return enable_joiner_; } + bool numeric_check_enabled () const { return enable_numeric_check_; } + bool bracket_check_enabled () const { return enable_bracket_check_; } + bool sequence_check_enabled () const { return enable_sequence_check_; } + bool strength_reduction_enabled () const { return enable_strength_reduction_; } + bool collect_variables_enabled () const { return enable_collect_vars_; } + bool collect_functions_enabled () const { return enable_collect_funcs_; } + bool collect_assignments_enabled() const { return enable_collect_assings_; } + bool vardef_disabled () const { return disable_vardef_; } + bool rsrvd_sym_usr_disabled () const { return disable_rsrvd_sym_usr_; } + bool zero_return_disabled () const { return disable_zero_return_; } + + bool function_enabled(const std::string& function_name) + { + if (disabled_func_set_.empty()) + return true; + else + return (disabled_func_set_.end() == disabled_func_set_.find(function_name)); + } + + bool control_struct_enabled(const std::string& control_struct) + { + if (disabled_ctrl_set_.empty()) + return true; + else + return (disabled_ctrl_set_.end() == disabled_ctrl_set_.find(control_struct)); + } + + bool logic_enabled(const std::string& logic_operation) + { + if (disabled_logic_set_.empty()) + return true; + else + return (disabled_logic_set_.end() == disabled_logic_set_.find(logic_operation)); + } + + bool arithmetic_enabled(const details::operator_type& arithmetic_operation) + { + if (disabled_logic_set_.empty()) + return true; + else + return (disabled_arithmetic_set_.end() == disabled_arithmetic_set_.find(arith_opr_to_string(arithmetic_operation))); + } + + bool assignment_enabled(const details::operator_type& assignment) + { + if (disabled_assignment_set_.empty()) + return true; + else + return (disabled_assignment_set_.end() == disabled_assignment_set_.find(assign_opr_to_string(assignment))); + } + + bool inequality_enabled(const details::operator_type& inequality) + { + if (disabled_inequality_set_.empty()) + return true; + else + return (disabled_inequality_set_.end() == disabled_inequality_set_.find(inequality_opr_to_string(inequality))); + } + + bool function_disabled(const std::string& function_name) + { + if (disabled_func_set_.empty()) + return false; + else + return (disabled_func_set_.end() != disabled_func_set_.find(function_name)); + } + + bool control_struct_disabled(const std::string& control_struct) + { + if (disabled_ctrl_set_.empty()) + return false; + else + return (disabled_ctrl_set_.end() != disabled_ctrl_set_.find(control_struct)); + } + + bool logic_disabled(const std::string& logic_operation) + { + if (disabled_logic_set_.empty()) + return false; + else + return (disabled_logic_set_.end() != disabled_logic_set_.find(logic_operation)); + } + + bool assignment_disabled(const details::operator_type assignment_operation) + { + if (disabled_assignment_set_.empty()) + return false; + else + return (disabled_assignment_set_.end() != disabled_assignment_set_.find(assign_opr_to_string(assignment_operation))); + } + + bool arithmetic_disabled(const details::operator_type arithmetic_operation) + { + if (disabled_arithmetic_set_.empty()) + return false; + else + return (disabled_arithmetic_set_.end() != disabled_arithmetic_set_.find(arith_opr_to_string(arithmetic_operation))); + } + + bool inequality_disabled(const details::operator_type& inequality) + { + if (disabled_inequality_set_.empty()) + return false; + else + return (disabled_inequality_set_.end() != disabled_inequality_set_.find(inequality_opr_to_string(inequality))); + } + + settings_store& disable_base_function(settings_base_funcs bf) + { + if ( + (e_bf_unknown != bf) && + (static_cast(bf) < (details::base_function_list_size + 1)) + ) + { + disabled_func_set_.insert(details::base_function_list[bf - 1]); + } + + return *this; + } + + settings_store& disable_control_structure(settings_control_structs ctrl_struct) + { + if ( + (e_ctrl_unknown != ctrl_struct) && + (static_cast(ctrl_struct) < (details::cntrl_struct_list_size + 1)) + ) + { + disabled_ctrl_set_.insert(details::cntrl_struct_list[ctrl_struct - 1]); + } + + return *this; + } + + settings_store& disable_logic_operation(settings_logic_opr logic) + { + if ( + (e_logic_unknown != logic) && + (static_cast(logic) < (details::logic_ops_list_size + 1)) + ) + { + disabled_logic_set_.insert(details::logic_ops_list[logic - 1]); + } + + return *this; + } + + settings_store& disable_arithmetic_operation(settings_arithmetic_opr arithmetic) + { + if ( + (e_arith_unknown != arithmetic) && + (static_cast(arithmetic) < (details::arithmetic_ops_list_size + 1)) + ) + { + disabled_arithmetic_set_.insert(details::arithmetic_ops_list[arithmetic - 1]); + } + + return *this; + } + + settings_store& disable_assignment_operation(settings_assignment_opr assignment) + { + if ( + (e_assign_unknown != assignment) && + (static_cast(assignment) < (details::assignment_ops_list_size + 1)) + ) + { + disabled_assignment_set_.insert(details::assignment_ops_list[assignment - 1]); + } + + return *this; + } + + settings_store& disable_inequality_operation(settings_inequality_opr inequality) + { + if ( + (e_ineq_unknown != inequality) && + (static_cast(inequality) < (details::inequality_ops_list_size + 1)) + ) + { + disabled_inequality_set_.insert(details::inequality_ops_list[inequality - 1]); + } + + return *this; + } + + settings_store& enable_base_function(settings_base_funcs bf) + { + if ( + (e_bf_unknown != bf) && + (static_cast(bf) < (details::base_function_list_size + 1)) + ) + { + des_itr_t itr = disabled_func_set_.find(details::base_function_list[bf - 1]); + + if (disabled_func_set_.end() != itr) + { + disabled_func_set_.erase(itr); + } + } + + return *this; + } + + settings_store& enable_control_structure(settings_control_structs ctrl_struct) + { + if ( + (e_ctrl_unknown != ctrl_struct) && + (static_cast(ctrl_struct) < (details::cntrl_struct_list_size + 1)) + ) + { + des_itr_t itr = disabled_ctrl_set_.find(details::cntrl_struct_list[ctrl_struct - 1]); + + if (disabled_ctrl_set_.end() != itr) + { + disabled_ctrl_set_.erase(itr); + } + } + + return *this; + } + + settings_store& enable_logic_operation(settings_logic_opr logic) + { + if ( + (e_logic_unknown != logic) && + (static_cast(logic) < (details::logic_ops_list_size + 1)) + ) + { + des_itr_t itr = disabled_logic_set_.find(details::logic_ops_list[logic - 1]); + + if (disabled_logic_set_.end() != itr) + { + disabled_logic_set_.erase(itr); + } + } + + return *this; + } + + settings_store& enable_arithmetic_operation(settings_arithmetic_opr arithmetic) + { + if ( + (e_arith_unknown != arithmetic) && + (static_cast(arithmetic) < (details::arithmetic_ops_list_size + 1)) + ) + { + des_itr_t itr = disabled_arithmetic_set_.find(details::arithmetic_ops_list[arithmetic - 1]); + + if (disabled_arithmetic_set_.end() != itr) + { + disabled_arithmetic_set_.erase(itr); + } + } + + return *this; + } + + settings_store& enable_assignment_operation(settings_assignment_opr assignment) + { + if ( + (e_assign_unknown != assignment) && + (static_cast(assignment) < (details::assignment_ops_list_size + 1)) + ) + { + des_itr_t itr = disabled_assignment_set_.find(details::assignment_ops_list[assignment - 1]); + + if (disabled_assignment_set_.end() != itr) + { + disabled_assignment_set_.erase(itr); + } + } + + return *this; + } + + settings_store& enable_inequality_operation(settings_inequality_opr inequality) + { + if ( + (e_ineq_unknown != inequality) && + (static_cast(inequality) < (details::inequality_ops_list_size + 1)) + ) + { + des_itr_t itr = disabled_inequality_set_.find(details::inequality_ops_list[inequality - 1]); + + if (disabled_inequality_set_.end() != itr) + { + disabled_inequality_set_.erase(itr); + } + } + + return *this; + } + + private: + + void load_compile_options(const std::size_t compile_options) + { + enable_replacer_ = (compile_options & e_replacer ) == e_replacer; + enable_joiner_ = (compile_options & e_joiner ) == e_joiner; + enable_numeric_check_ = (compile_options & e_numeric_check ) == e_numeric_check; + enable_bracket_check_ = (compile_options & e_bracket_check ) == e_bracket_check; + enable_sequence_check_ = (compile_options & e_sequence_check ) == e_sequence_check; + enable_commutative_check_ = (compile_options & e_commutative_check ) == e_commutative_check; + enable_strength_reduction_ = (compile_options & e_strength_reduction ) == e_strength_reduction; + enable_collect_vars_ = (compile_options & e_collect_vars ) == e_collect_vars; + enable_collect_funcs_ = (compile_options & e_collect_funcs ) == e_collect_funcs; + enable_collect_assings_ = (compile_options & e_collect_assings ) == e_collect_assings; + disable_vardef_ = (compile_options & e_disable_vardef ) == e_disable_vardef; + disable_rsrvd_sym_usr_ = (compile_options & e_disable_usr_on_rsrvd) == e_disable_usr_on_rsrvd; + disable_zero_return_ = (compile_options & e_disable_zero_return ) == e_disable_zero_return; + } + + std::string assign_opr_to_string(details::operator_type opr) + { + switch (opr) + { + case details::e_assign : return ":="; + case details::e_addass : return "+="; + case details::e_subass : return "-="; + case details::e_mulass : return "*="; + case details::e_divass : return "/="; + case details::e_modass : return "%="; + default : return ""; + } + } + + std::string arith_opr_to_string(details::operator_type opr) + { + switch (opr) + { + case details::e_add : return "+"; + case details::e_sub : return "-"; + case details::e_mul : return "*"; + case details::e_div : return "/"; + case details::e_mod : return "%"; + default : return ""; + } + } + + std::string inequality_opr_to_string(details::operator_type opr) + { + switch (opr) + { + case details::e_lt : return "<"; + case details::e_lte : return "<="; + case details::e_eq : return "=="; + case details::e_equal : return "="; + case details::e_ne : return "!="; + case details::e_nequal: return "<>"; + case details::e_gte : return ">="; + case details::e_gt : return ">"; + default : return ""; + } + } + + bool enable_replacer_; + bool enable_joiner_; + bool enable_numeric_check_; + bool enable_bracket_check_; + bool enable_sequence_check_; + bool enable_commutative_check_; + bool enable_strength_reduction_; + bool enable_collect_vars_; + bool enable_collect_funcs_; + bool enable_collect_assings_; + bool disable_vardef_; + bool disable_rsrvd_sym_usr_; + bool disable_zero_return_; + + disabled_entity_set_t disabled_func_set_ ; + disabled_entity_set_t disabled_ctrl_set_ ; + disabled_entity_set_t disabled_logic_set_; + disabled_entity_set_t disabled_arithmetic_set_; + disabled_entity_set_t disabled_assignment_set_; + disabled_entity_set_t disabled_inequality_set_; + + friend class parser; + }; + + typedef settings_store settings_t; + + parser(const settings_t& settings = settings_t()) + : settings_(settings), + resolve_unknown_symbol_(false), + results_context_(0), + unknown_symbol_resolver_(reinterpret_cast(0)), + #ifdef _MSC_VER + #pragma warning(push) + #pragma warning (disable:4355) + #endif + sem_(*this), + #ifdef _MSC_VER + #pragma warning(pop) + #endif + operator_joiner_2_(2), + operator_joiner_3_(3) + { + init_precompilation(); + + load_operations_map (base_ops_map_ ); + load_unary_operations_map (unary_op_map_ ); + load_binary_operations_map (binary_op_map_ ); + load_inv_binary_operations_map(inv_binary_op_map_); + load_sf3_map (sf3_map_ ); + load_sf4_map (sf4_map_ ); + + expression_generator_.init_synthesize_map(); + expression_generator_.set_parser(*this); + expression_generator_.set_uom(unary_op_map_); + expression_generator_.set_bom(binary_op_map_); + expression_generator_.set_ibom(inv_binary_op_map_); + expression_generator_.set_sf3m(sf3_map_); + expression_generator_.set_sf4m(sf4_map_); + expression_generator_.set_strength_reduction_state(settings_.strength_reduction_enabled()); + } + + ~parser() + {} + + inline void init_precompilation() + { + if (settings_.collect_variables_enabled()) + dec_.collect_variables() = true; + + if (settings_.collect_functions_enabled()) + dec_.collect_functions() = true; + + if (settings_.collect_assignments_enabled()) + dec_.collect_assignments() = true; + + if (settings_.replacer_enabled()) + { + symbol_replacer_.clear(); + symbol_replacer_.add_replace("true" ,"1",lexer::token::e_number); + symbol_replacer_.add_replace("false","0",lexer::token::e_number); + helper_assembly_.token_modifier_list.clear(); + helper_assembly_.register_modifier(&symbol_replacer_); + } + + if (settings_.commutative_check_enabled()) + { + for (std::size_t i = 0; i < details::reserved_words_size; ++i) + { + commutative_inserter_.ignore_symbol(details::reserved_words[i]); + } + + helper_assembly_.token_inserter_list.clear(); + helper_assembly_.register_inserter(&commutative_inserter_); + } + + if (settings_.joiner_enabled()) + { + helper_assembly_.token_joiner_list.clear(); + helper_assembly_.register_joiner(&operator_joiner_2_); + helper_assembly_.register_joiner(&operator_joiner_3_); + } + + if ( + settings_.numeric_check_enabled () || + settings_.bracket_check_enabled () || + settings_.sequence_check_enabled() + ) + { + helper_assembly_.token_scanner_list.clear(); + + if (settings_.numeric_check_enabled()) + { + helper_assembly_.register_scanner(&numeric_checker_); + } + + if (settings_.bracket_check_enabled()) + { + helper_assembly_.register_scanner(&bracket_checker_); + } + + if (settings_.sequence_check_enabled()) + { + helper_assembly_.register_scanner(&sequence_validator_); + } + } + } + + inline bool compile(const std::string& expression_string, expression& expr) + { + state_ .reset(); + error_list_ .clear(); + brkcnt_list_ .clear(); + synthesis_error_.clear(); + sem_ .cleanup(); + + return_cleanup(); + + expression_generator_.set_allocator(node_allocator_); + + if (expression_string.empty()) + { + set_error( + make_error(parser_error::e_syntax, + "ERR000 - Empty expression!")); + + return false; + } + + if (!init(expression_string)) + { + process_lexer_errors(); + return false; + } + + if (lexer().empty()) + { + set_error( + make_error(parser_error::e_syntax, + "ERR001 - Empty expression!")); + + return false; + } + + if (!run_assemblies()) + { + return false; + } + + symtab_store_.symtab_list_ = expr.get_symbol_table_list(); + dec_.clear(); + + lexer().begin(); + + next_token(); + + expression_node_ptr e = parse_corpus(); + + if ((0 != e) && (token_t::e_eof == current_token().type)) + { + bool* retinvk_ptr = 0; + + if (state_.return_stmt_present) + { + dec_.return_present_ = true; + + e = expression_generator_ + .return_envelope(e,results_context_,retinvk_ptr); + } + + expr.set_expression(e); + expr.set_retinvk(retinvk_ptr); + + register_local_vars(expr); + register_return_results(expr); + + return !(!expr); + } + else + { + if (error_list_.empty()) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR002 - Invalid expression encountered")); + } + + dec_.clear (); + sem_.cleanup (); + return_cleanup(); + + if ((0 != e) && branch_deletable(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 = "ERR003 - "; + + 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 run_assemblies() + { + if (settings_.commutative_check_enabled()) + { + helper_assembly_.run_inserters(lexer()); + } + + if (settings_.joiner_enabled()) + { + helper_assembly_.run_joiners(lexer()); + } + + if (settings_.replacer_enabled()) + { + helper_assembly_.run_modifiers(lexer()); + } + + if ( + settings_.numeric_check_enabled () || + settings_.bracket_check_enabled () || + settings_.sequence_check_enabled() + ) + { + if (!helper_assembly_.run_scanners(lexer())) + { + if (helper_assembly_.error_token_scanner) + { + lexer::helper::bracket_checker* bracket_checker_ptr = 0; + lexer::helper::numeric_checker* numeric_checker_ptr = 0; + lexer::helper::sequence_validator* sequence_validator_ptr = 0; + + if (0 != (bracket_checker_ptr = dynamic_cast(helper_assembly_.error_token_scanner))) + { + set_error( + make_error(parser_error::e_token, + bracket_checker_ptr->error_token(), + "ERR004 - Mismatched brackets: '" + bracket_checker_ptr->error_token().value + "'")); + } + 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, + "ERR005 - 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, + "ERR006 - 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 settings_store& settings() + { + return settings_; + } + + 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 (!settings_.replacer_enabled()) + return false; + else if (details::is_reserved_word(old_symbol)) + return false; + else + return symbol_replacer_.add_replace(old_symbol,new_symbol,lexer::token::e_symbol); + } + + inline bool remove_replace_symbol(const std::string& symbol) + { + if (!settings_.replacer_enabled()) + return false; + else if (details::is_reserved_word(symbol)) + return false; + else + return symbol_replacer_.remove(symbol); + } + + inline void enable_unknown_symbol_resolver(unknown_symbol_resolver* usr = reinterpret_cast(0)) + { + resolve_unknown_symbol_ = true; + + if (usr) + unknown_symbol_resolver_ = usr; + else + unknown_symbol_resolver_ = &default_usr_; + } + + inline void 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 settings_.function_enabled(symbol) && + (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) + ) && + settings_.function_enabled(symbol); + } + + bool is_invalid_arithmetic_operation(const details::operator_type operation) + { + return settings_.arithmetic_disabled(operation); + } + + bool is_invalid_assignment_operation(const details::operator_type operation) + { + return settings_.assignment_disabled(operation); + } + + bool is_invalid_inequality_operation(const details::operator_type operation) + { + return settings_.inequality_disabled(operation); + } + + #ifdef exprtk_enable_debugging + inline void next_token() + { + std::string ct_str = current_token().value; + parser_helper::next_token(); + std::string depth(2 * state_.scope_depth,' '); + exprtk_debug(("%s" + "prev[%s] --> curr[%s]\n", + depth.c_str(), + ct_str.c_str(), + current_token().value.c_str())); + } + #endif + + inline expression_node_ptr parse_corpus() + { + std::vector arg_list; + std::vector side_effect_list; + + expression_node_ptr result = error_node(); + + scoped_vec_delete sdd(*this,arg_list); + + lexer::token begin_token; + lexer::token end_token; + + for ( ; ; ) + { + state_.side_effect_present = false; + + begin_token = current_token(); + + expression_node_ptr arg = parse_expression(); + + if (0 == arg) + { + if (error_list_.empty()) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR007 - Invalid expression encountered")); + } + + return error_node(); + } + else + { + arg_list.push_back(arg); + + side_effect_list.push_back(state_.side_effect_present); + + end_token = current_token(); + + std::string sub_expr = construct_subexpr(begin_token,end_token); + + exprtk_debug(("parse_corpus(%02d) Subexpr: %s\n", + static_cast(arg_list.size() - 1), + sub_expr.c_str())); + + exprtk_debug(("parse_corpus(%02d) - Side effect present: %s\n", + static_cast(arg_list.size() - 1), + state_.side_effect_present ? "true" : "false")); + + exprtk_debug(("-------------------------------------------------\n")); + } + + if (lexer().finished()) + break; + else if (token_is(token_t::e_eof,prsrhlpr_t::e_hold)) + { + if (lexer().finished()) + break; + else + next_token(); + } + } + + if ( + !arg_list.empty() && + is_return_node(arg_list.back()) + ) + { + dec_.final_stmt_return_ = true; + } + + result = simplify(arg_list,side_effect_list); + + sdd.delete_ptr = (0 == result); + + return result; + } + + std::string construct_subexpr(lexer::token& begin_token, lexer::token& end_token) + { + std::string result = lexer().substr(begin_token.position,end_token.position); + + for (std::size_t i = 0; i < result.size(); ++i) + { + if (details::is_whitespace(result[i])) result[i] = ' '; + } + + return result; + } + + static const precedence_level default_precedence = e_level00; + + struct state_t + { + inline void set(const precedence_level& l, + const precedence_level& r, + const details::operator_type& o) + { + left = l; + right = r; + operation = o; + } + + inline void reset() + { + left = e_level00; + right = e_level00; + operation = details::e_default; + } + + precedence_level left; + precedence_level right; + details::operator_type operation; + }; + + inline expression_node_ptr parse_expression(precedence_level precedence = e_level00) + { + 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_level03,e_level04,details::e_and); + break; + } + else if (details::imatch(current_token().value,s_and1)) + { + #ifndef exprtk_disable_sc_andor + current_state.set(e_level03,e_level04,details::e_scand); + #else + current_state.set(e_level03,e_level04,details::e_and); + #endif + break; + } + else if (details::imatch(current_token().value,s_nand)) + { + current_state.set(e_level03,e_level04,details::e_nand); + break; + } + else if (details::imatch(current_token().value,s_or)) + { + current_state.set(e_level01,e_level02,details::e_or); + break; + } + else if (details::imatch(current_token().value,s_or1)) + { + #ifndef exprtk_disable_sc_andor + current_state.set(e_level01,e_level02,details::e_scor); + #else + current_state.set(e_level01,e_level02,details::e_or); + #endif + break; + } + else if (details::imatch(current_token().value,s_nor)) + { + current_state.set(e_level01,e_level02,details::e_nor); + break; + } + else if (details::imatch(current_token().value,s_xor)) + { + current_state.set(e_level01,e_level02,details::e_xor); + break; + } + else if (details::imatch(current_token().value,s_xnor)) + { + current_state.set(e_level01,e_level02,details::e_xnor); + break; + } + else if (details::imatch(current_token().value,s_in)) + { + current_state.set(e_level04,e_level04,details::e_in); + break; + } + else if (details::imatch(current_token().value,s_like)) + { + current_state.set(e_level04,e_level04,details::e_like); + break; + } + else if (details::imatch(current_token().value,s_ilike)) + { + current_state.set(e_level04,e_level04,details::e_ilike); + break; + } + } + + 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 (is_invalid_arithmetic_operation(current_state.operation)) + { + free_node(node_allocator_,expression); + + set_error( + make_error(parser_error::e_syntax, + prev_token, + "ERR008 - Invalid arithmetic operation '" + details::to_str(current_state.operation) + "'")); + + return error_node(); + } + else if (is_invalid_inequality_operation(current_state.operation)) + { + free_node(node_allocator_,expression); + + set_error( + make_error(parser_error::e_syntax, + prev_token, + "ERR009 - Invalid inequality operation '" + details::to_str(current_state.operation) + "'")); + + return error_node(); + } + else if (is_invalid_assignment_operation(current_state.operation)) + { + free_node(node_allocator_,expression); + + set_error( + make_error(parser_error::e_syntax, + prev_token, + "ERR010 - Invalid assignment operation '" + details::to_str(current_state.operation) + "'")); + + return error_node(); + } + + if (0 != (right_branch = parse_expression(current_state.right))) + { + if ( + details::is_return_node( expression) || + details::is_return_node(right_branch) + ) + { + free_node(node_allocator_, expression); + free_node(node_allocator_,right_branch); + + set_error( + make_error(parser_error::e_syntax, + prev_token, + "ERR011 - Return statements cannot be part of sub-expressions")); + + return error_node(); + } + + new_expression = expression_generator_ + ( + current_state.operation, + expression, + right_branch + ); + } + + if (0 == new_expression) + { + if (error_list_.empty()) + { + set_error( + make_error(parser_error::e_syntax, + prev_token, + !synthesis_error_.empty() ? + synthesis_error_ : + "ERR012 - General parsing error at token: '" + prev_token.value + "'")); + } + + free_node(node_allocator_,expression); + + return error_node(); + } + else + { + if ( + token_is(token_t::e_ternary,prsrhlpr_t::e_hold) && + (precedence == e_level00) + ) + { + expression = parse_ternary_conditional_statement(new_expression); + } + else + expression = new_expression; + + 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 > uvn_t; + + uvn_t* n = dynamic_cast(node); + + if (n) + { + const T& v = n->v(); + expression_node_ptr return_node = error_node(); + + if ( + (0 != (return_node = symtab_store_.get_variable(v))) || + (0 != (return_node = sem_ .get_variable(v))) + ) + { + free_node(node_allocator_,node); + node = return_node; + + return true; + } + else + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR013 - 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&); + }; + + struct scoped_bool_negator + { + scoped_bool_negator(bool& bb) + : b(bb) + { b = !b; } + + ~scoped_bool_negator() + { b = !b; } + + bool& b; + }; + + struct scoped_bool_or_restorer + { + scoped_bool_or_restorer(bool& bb) + : b(bb), + original_value_(bb) + {} + + ~scoped_bool_or_restorer() + { + b = b || original_value_; + } + + bool& b; + bool original_value_; + }; + + 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(), + "ERR014 - 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(), + "ERR015 - 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) + { + #ifdef _MSC_VER + #pragma warning(push) + #pragma warning(disable: 4127) + #endif + if (0 == NumberofParameters) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR016 - Expecting ifunction '" + function_name + "' to have non-zero parameter count")); + + return error_node(); + } + #ifdef _MSC_VER + #pragma warning(pop) + #endif + + expression_node_ptr branch[NumberofParameters]; + expression_node_ptr result = error_node(); + + std::fill_n(branch,NumberofParameters,reinterpret_cast(0)); + scoped_delete sd(*this,branch); + + next_token(); + + if (!token_is(token_t::e_lbracket)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR017 - 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(), + "ERR018 - 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(), + "ERR019 - 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(), + "ERR020 - 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); + + state_.side_effect_present = function->has_side_effects(); + + next_token(); + + if ( + token_is(token_t::e_lbracket) && + !token_is(token_t::e_rbracket) + ) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR021 - 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(), + "ERR022 - 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(), + "ERR023 - 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(), + "ERR024 - No entry found for base operation: " + operation_name)); + + return error_node(); + } + + static const std::size_t MaxNumberofParameters = 4; + 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 <= MaxNumberofParameters) + { + 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) + #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(), + "ERR025 - 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(), + "ERR026 - 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(), + "ERR027 - 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(), + "ERR028 - 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(), + "ERR029 - 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(), + "ERR030 - Expected ')' at the end of if-statement")); + result = false; + } + + #ifndef exprtk_disable_string_capabilities + if (result) + { + const bool consq_is_str = is_generally_string_node( consequent); + const bool alter_is_str = is_generally_string_node(alternative); + + if (consq_is_str || alter_is_str) + { + if (consq_is_str && alter_is_str) + { + return expression_generator_ + .conditional_string(condition,consequent,alternative); + } + + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR031 - Return types of ternary if-statement differ")); + + result = false; + } + } + #endif + + if (!result) + { + free_node(node_allocator_, condition); + free_node(node_allocator_, consequent); + free_node(node_allocator_,alternative); + + return error_node(); + } + else + return expression_generator_ + .conditional(condition,consequent,alternative); + } + + inline expression_node_ptr parse_conditional_statement_02(expression_node_ptr condition) + { + expression_node_ptr consequent = error_node(); + expression_node_ptr alternative = error_node(); + + bool result = true; + + if (token_is(token_t::e_lcrlbracket,prsrhlpr_t::e_hold)) + { + if (0 == (consequent = parse_multi_sequence("if-statement-01"))) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR032 - Failed to parse body of consequent for if-statement")); + result = false; + } + } + else + { + if ( + settings_.commutative_check_enabled() && + token_is(token_t::e_mul,prsrhlpr_t::e_hold) + ) + { + next_token(); + } + + if (0 != (consequent = parse_expression())) + { + if (!token_is(token_t::e_eof)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR033 - Expected ';' at the end of the consequent for if-statement")); + result = false; + } + } + else + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR034 - 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,prsrhlpr_t::e_hold)) + { + if (0 == (alternative = parse_multi_sequence("else-statement-01"))) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR035 - 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(), + "ERR036 - 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(), + "ERR037 - 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(), + "ERR038 - Failed to parse body of the 'else' for if-statement")); + result = false; + } + } + } + + #ifndef exprtk_disable_string_capabilities + if (result) + { + const bool consq_is_str = is_generally_string_node( consequent); + const bool alter_is_str = is_generally_string_node(alternative); + + if (consq_is_str || alter_is_str) + { + if (consq_is_str && alter_is_str) + { + return expression_generator_ + .conditional_string(condition,consequent,alternative); + } + + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR039 - Return types of ternary if-statement differ")); + + result = false; + } + } + #endif + + 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(), + "ERR040 - 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(), + "ERR041 - Failed to parse condition for if-statement")); + + return error_node(); + } + else if (token_is(token_t::e_comma,prsrhlpr_t::e_hold)) + { + // if (x,y,z) + return parse_conditional_statement_01(condition); + } + else if (token_is(token_t::e_rbracket)) + { + // 00. if (x) y; + // 01. if (x) y; else z; + // 02. if (x) y; else {z0; ... zn;} + // 03. if (x) y; else if (z) w; + // 04. if (x) y; else if (z) w; else u; + // 05. if (x) y; else if (z) w; else {u0; ... un;} + // 06. if (x) y; else if (z) {w0; ... wn;} + // 07. if (x) {y0; ... yn;} + // 08. if (x) {y0; ... yn;} else z; + // 09. if (x) {y0; ... yn;} else {z0; ... zn;}; + // 10. if (x) {y0; ... yn;} else if (z) w; + // 11. if (x) {y0; ... yn;} else if (z) w; else u; + // 12. if (x) {y0; ... nex;} else if (z) w; else {u0 ... un;} + // 13. if (x) {y0; ... yn;} else if (z) {w0; ... wn;} + return parse_conditional_statement_02(condition); + } + + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR042 - 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(), + "ERR043 - 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(), + "ERR044 - 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(), + "ERR045 - Failed to parse consequent for ternary if-statement")); + + result = false; + } + else if (!token_is(token_t::e_colon)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR046 - 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(), + "ERR047 - Failed to parse alternative for ternary if-statement")); + + result = false; + } + + #ifndef exprtk_disable_string_capabilities + if (result) + { + const bool consq_is_str = is_generally_string_node( consequent); + const bool alter_is_str = is_generally_string_node(alternative); + + if (consq_is_str || alter_is_str) + { + if (consq_is_str && alter_is_str) + { + return expression_generator_ + .conditional_string(condition,consequent,alternative); + } + + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR048 - Return types of ternary if-statement differ")); + + result = false; + } + } + #endif + + 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(), + "ERR049 - 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(), + "ERR050 - 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(), + "ERR051 - 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(), + "ERR052 - 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(), + "ERR053 - 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; + std::vector side_effect_list; + + scoped_vec_delete sdd(*this,arg_list); + + brkcnt_list_.push_front(false); + + if (details::imatch(current_token().value,"until")) + { + next_token(); + branch = node_allocator_.allocate >(); + } + else + { + token_t::token_type seperator = token_t::e_eof; + + scope_handler sh(*this); + + scoped_bool_or_restorer sbr(state_.side_effect_present); + + for ( ; ; ) + { + state_.side_effect_present = false; + + expression_node_ptr arg = parse_expression(); + + if (0 == arg) + return error_node(); + else + { + arg_list.push_back(arg); + side_effect_list.push_back(state_.side_effect_present); + } + + if (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(), + "ERR054 - Expected '" + token_t::to_str(seperator) + "' in body of repeat until loop")); + + return error_node(); + } + + if (details::imatch(current_token().value,"until")) + { + next_token(); + break; + } + } + + branch = simplify(arg_list,side_effect_list); + + sdd.delete_ptr = (0 == branch); + + if (sdd.delete_ptr) + { + brkcnt_list_.pop_front(); + + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR055 - 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(), + "ERR056 - 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(), + "ERR057 - 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(), + "ERR058 - 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(), + "ERR059 - 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(), + "ERR060 - Expected '(' at start of for-loop")); + + return error_node(); + } + + if (!token_is(token_t::e_eof)) + { + if ( + !token_is(token_t::e_symbol,prsrhlpr_t::e_hold) && + details::imatch(current_token().value,"var") + ) + { + next_token(); + + if (!token_is(token_t::e_symbol,prsrhlpr_t::e_hold)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR061 - 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(), + "ERR062 - 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(), + "ERR063 - For-loop variable '" + loop_counter_symbol+ "' is being shadowed by a previous declaration")); + + return error_node(); + } + else if (!symtab_store_.is_variable(loop_counter_symbol)) + { + if ( + !se->active && + (se->name == loop_counter_symbol) && + (se->type == scope_element::e_variable) + ) + { + se->active = true; + se->ref_count++; + } + else + { + scope_element nse; + nse.name = loop_counter_symbol; + nse.active = true; + nse.ref_count = 1; + nse.type = scope_element::e_variable; + nse.depth = state_.scope_depth; + nse.data = new T(T(0)); + nse.var_node = node_allocator_.allocate(*(T*)(nse.data)); + + if (!sem_.add_element(nse)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR064 - Failed to add new local variable '" + loop_counter_symbol + "' to SEM")); + + sem_.free_element(nse); + + result = false; + } + else + { + exprtk_debug(("parse_for_loop() - INFO - Added new local variable: %s\n",nse.name.c_str())); + + state_.activate_side_effect("parse_for_loop()"); + } + } + } + } + + if (0 == (initialiser = parse_expression())) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR065 - Failed to parse initialiser of for-loop")); + result = false; + } + else if (!token_is(token_t::e_eof)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR066 - 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(), + "ERR067 - 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(), + "ERR068 - 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(), + "ERR069 - 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(), + "ERR070 - 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(), + "ERR071 - 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(), + "ERR072 - 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(), + "ERR073 - 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(), + "ERR074 - 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(), + "ERR075 - 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(), + "ERR076 - Expected ';' at end of case for switch statement")); + + return error_node(); + } + + // Can we optimise away the case statement? + if (is_constant_node(condition) && is_false(condition)) + { + free_node(node_allocator_, condition); + free_node(node_allocator_,consequent); + + 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(), + "ERR077 - Expected ':' for default of switch statement")); + + return error_node(); + } + + expression_node_ptr default_statement = error_node(); + + if (token_is(token_t::e_lcrlbracket,prsrhlpr_t::e_hold)) + default_statement = parse_multi_sequence("switch-default"); + else + default_statement = parse_expression(); + + if (0 == default_statement) + return error_node(); + else if (!token_is(token_t::e_eof)) + { + free_node(node_allocator_,default_statement); + + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR078 - 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(), + "ERR079 - 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(), + "ERR080 - 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(), + "ERR081 - 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(), + "ERR082 - 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(), + "ERR083 - 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(), + "ERR084 - Expected ';' at end of case for [*] statement")); + + return error_node(); + } + + // Can we optimise away the case statement? + if (is_constant_node(condition) && is_false(condition)) + { + free_node(node_allocator_, condition); + free_node(node_allocator_,consequent); + + condition = 0; + consequent = 0; + } + else + { + arg_list.push_back(condition); + arg_list.push_back(consequent); + } + + if (token_is(token_t::e_rcrlbracket,prsrhlpr_t::e_hold)) + { + break; + } + } + + if (!token_is(token_t::e_rcrlbracket)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR085 - 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(), + "ERR086 - Unsupported vararg function: " + symbol)); + + return error_node(); + } + + scoped_vec_delete sdd(*this,arg_list); + + lodge_symbol(symbol,e_st_function); + + next_token(); + + if (!token_is(token_t::e_lbracket)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR087 - 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(), + "ERR088 - 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; + } + + #ifndef exprtk_disable_string_capabilities + inline expression_node_ptr parse_string_range_statement(expression_node_ptr& expression) + { + if (!token_is(token_t::e_lsqrbracket)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR089 - 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(), + "ERR090 - Failed to generate string range node")); + + free_node(node_allocator_,expression); + } + + rp.clear(); + + return result; + } + #else + inline expression_node_ptr parse_string_range_statement(expression_node_ptr&) + { + return error_node(); + } + #endif + + inline void parse_pending_string_rangesize(expression_node_ptr& expression) + { + // Allow no more than 100 range calls, eg: s[][][]...[][] + const std::size_t max_rangesize_parses = 100; + + std::size_t i = 0; + + while + ( + (0 != expression) && + (i++ < max_rangesize_parses) && + error_list_.empty() && + is_generally_string_node(expression) && + token_is(token_t::e_lsqrbracket,prsrhlpr_t::e_hold) + ) + { + expression = parse_string_range_statement(expression); + } + } + + template class Sequence> + inline expression_node_ptr simplify(Sequence& expression_list, + Sequence& side_effect_list, + const bool specialise_on_final_type = false) + { + if (expression_list.empty()) + return error_node(); + else if (1 == expression_list.size()) + return expression_list[0]; + + Sequence tmp_expression_list; + + bool return_node_present = false; + + for (std::size_t i = 0; i < (expression_list.size() - 1); ++i) + { + if (is_variable_node(expression_list[i])) + continue; + else if ( + is_return_node (expression_list[i]) || + is_break_node (expression_list[i]) || + is_continue_node(expression_list[i]) + ) + { + tmp_expression_list.push_back(expression_list[i]); + + // Remove all subexpressions after first short-circuit + // node has been encountered. + + for (std::size_t j = i + 1; j < expression_list.size(); ++j) + { + free_node(node_allocator_,expression_list[j]); + } + + return_node_present = true; + + break; + } + else if ( + is_constant_node(expression_list[i]) || + is_null_node (expression_list[i]) || + !side_effect_list[i] + ) + { + free_node(node_allocator_,expression_list[i]); + continue; + } + else + tmp_expression_list.push_back(expression_list[i]); + } + + if (!return_node_present) + { + tmp_expression_list.push_back(expression_list.back()); + } + + expression_list.swap(tmp_expression_list); + + if (tmp_expression_list.size() > expression_list.size()) + { + exprtk_debug(("simplify() - Reduced subexpressions from %d to %d\n", + static_cast(tmp_expression_list.size()), + static_cast(expression_list .size()))); + } + + if ( + return_node_present || + side_effect_list.back() || + (expression_list.size() > 1) + ) + state_.activate_side_effect("simplify()"); + + if (1 == expression_list.size()) + return expression_list[0]; + else if (specialise_on_final_type && is_generally_string_node(expression_list.back())) + return expression_generator_.vararg_function(details::e_smulti,expression_list); + else + return expression_generator_.vararg_function(details::e_multi,expression_list); + } + + inline expression_node_ptr parse_multi_sequence(const std::string& source = "") + { + token_t::token_type close_bracket = token_t::e_rcrlbracket; + token_t::token_type seperator = token_t::e_eof; + + if (!token_is(token_t::e_lcrlbracket)) + { + if (token_is(token_t::e_lbracket)) + { + close_bracket = token_t::e_rbracket; + seperator = token_t::e_comma; + } + else + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR091 - 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; + std::vector side_effect_list; + + expression_node_ptr result = error_node(); + + scoped_vec_delete sdd(*this,arg_list); + + scope_handler sh(*this); + + scoped_bool_or_restorer sbr(state_.side_effect_present); + + for ( ; ; ) + { + state_.side_effect_present = false; + + expression_node_ptr arg = parse_expression(); + + if (0 == arg) + return error_node(); + else + { + arg_list.push_back(arg); + side_effect_list.push_back(state_.side_effect_present); + } + + if (token_is(close_bracket)) + break; + + 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(), + "ERR092 - 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,side_effect_list,source.empty()); + + sdd.delete_ptr = (0 == result); + return result; + } + + inline bool parse_range(range_t& rp, const bool skip_lsqr = false) + { + // Examples of valid ranges: + // 1. [1:5] -> 1..5 + // 2. [ :5] -> 0..5 + // 3. [1: ] -> 1..end + // 4. [x:y] -> x..y where x <= y + // 5. [x+1:y/2] -> x+1..y/2 where x+1 <= y/2 + // 6. [ :y] -> 0..y where 0 <= y + // 7. [x: ] -> x..end where x <= end + + rp.clear(); + + if (!skip_lsqr && !token_is(token_t::e_lsqrbracket)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR093 - 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(), + "ERR094 - 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(), + "ERR095 - 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(), + "ERR096 - 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(), + "ERR097 - 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(), + "ERR098 - 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(), + "ERR099 - 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(), + "ERR100 - 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); + } + + #ifndef exprtk_disable_string_capabilities + inline expression_node_ptr parse_string() + { + const std::string symbol = current_token().value; + + typedef details::stringvar_node* strvar_node_t; + + expression_node_ptr result = error_node(); + strvar_node_t const_str_node = static_cast(0); + bool is_const_string = false; + + scope_element& se = sem_.get_active_element(symbol); + + if (scope_element::e_string == se.type) + { + se.active = true; + result = se.str_node; + lodge_symbol(symbol,e_st_local_string); + } + else + { + if (!symtab_store_.is_conststr_stringvar(symbol)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR101 - Unknown string symbol")); + + return error_node(); + } + + result = symtab_store_.get_stringvar(symbol); + + is_const_string = symtab_store_.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; + } + #else + inline expression_node_ptr parse_string() + { + return error_node(); + } + #endif + + #ifndef exprtk_disable_string_capabilities + inline expression_node_ptr parse_const_string() + { + const std::string const_str = current_token().value; + expression_node_ptr result = expression_generator_(const_str); + + if (peek_token_is(token_t::e_lsqrbracket)) + { + next_token(); + + if (peek_token_is(token_t::e_rsqrbracket)) + { + next_token(); + next_token(); + + free_node(node_allocator_,result); + + return expression_generator_(T(const_str.size())); + } + + range_t rp; + + if (!parse_range(rp)) + { + free_node(node_allocator_,result); + + 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(), + "ERR102 - Overflow in range for string: '" + const_str + "'[" + + (rp.n0_c.first ? details::to_str(static_cast(rp.n0_c.second)) : "?") + ":" + + (rp.n1_c.first ? details::to_str(static_cast(rp.n1_c.second)) : "?") + "]")); + + return error_node(); + } + + result = expression_generator_(const_str,rp); + + if (result) + rp.clear(); + } + else + next_token(); + + return result; + } + #else + inline expression_node_ptr parse_const_string() + { + return error_node(); + } + #endif + + inline expression_node_ptr parse_vector() + { + const std::string symbol = current_token().value; + + vector_holder_ptr vec = vector_holder_ptr(0); + + const scope_element& se = sem_.get_active_element(symbol); + + if ( + (se.name != symbol) || + (se.depth > state_.scope_depth) || + (scope_element::e_vector != se.type) + ) + { + if (0 == (vec = symtab_store_.get_vector(symbol))) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR103 - 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(), + "ERR104 - 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(), + "ERR105 - 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)) + { + if (!vararg_function->allow_zero_parameters()) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR106 - Zero parameter call to vararg function: " + + vararg_function_name + " not allowed")); + + return error_node(); + } + } + else + { + for ( ; ; ) + { + expression_node_ptr arg = parse_expression(); + + if (0 == arg) + return error_node(); + else + arg_list.push_back(arg); + + if (token_is(token_t::e_rbracket)) + break; + else if (!token_is(token_t::e_comma)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR107 - Expected ',' for call to vararg function: " + + vararg_function_name)); + + return error_node(); + } + } + } + } + else if (!vararg_function->allow_zero_parameters()) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR108 - Zero parameter call to vararg function: " + + vararg_function_name + " not allowed")); + + return error_node(); + } + + if (arg_list.size() < vararg_function->min_num_args()) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR109 - Invalid number of parameters to call to vararg function: " + + vararg_function_name + ", require at least " + + details::to_str(static_cast(vararg_function->min_num_args())) + " parameters")); + + return error_node(); + } + else if (arg_list.size() > vararg_function->max_num_args()) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR110 - Invalid number of parameters to call to vararg function: " + + vararg_function_name + ", require no more than " + + details::to_str(static_cast(vararg_function->max_num_args())) + " parameters")); + + 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) + { + details::char_t diff_value = 0; + std::size_t diff_index = 0; + + bool result = details::sequence_match(param_seq_list_[i], + param_seq, + diff_index,diff_value); + + 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(), + "ERR111 - 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(), + "ERR112 - 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_; + } + + bool allow_zero_parameters() const + { + return + param_seq_list_.end() != std::find(param_seq_list_.begin(), + param_seq_list_.end(), + "Z"); + } + + 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 ("Z" == curr_str) + { + psl.push_back(curr_str); + return true; + } + else if (std::string::npos == curr_str.find_first_not_of("STV*?|")) + { + psl.push_back(curr_str); + return true; + } + } + + return false; + } }; - - struct synthesize_vococ_expression0 - { - typedef typename vococ_t::type0 node_type; - typedef typename vococ_t::sf3_type sf3_type; - - static inline expression_node_ptr process(expression_generator& expr_gen, - const details::operator_type& operation, - expression_node_ptr (&branch)[2]) - { - // (v o0 c0) o1 (c1) - const details::voc_base_node* voc = static_cast*>(branch[0]); - const Type& v = voc->v(); - const Type& c0 = voc->c(); - const Type& c1 = static_cast*>(branch[1])->value(); - const details::operator_type o0 = voc->operation(); - const details::operator_type o1 = operation; - - binary_functor_t f0 = reinterpret_cast(0); - binary_functor_t f1 = reinterpret_cast(0); - - details::free_node(*(expr_gen.node_allocator_),branch[0]); - details::free_node(*(expr_gen.node_allocator_),branch[1]); - - expression_node_ptr result = error_node(); - - if (expr_gen.parser_->settings_.strength_reduction_enabled()) - { - // (v + c0) + c1 --> (voc) v + (c0 + c1) - if ((details::e_add == o0) && (details::e_add == o1)) - { - exprtk_debug(("(v + c0) + c1 --> (voc) v + (c0 + c1)\n")); - - return expr_gen.node_allocator_-> - template allocate_rc > >(v,c0 + c1); - } - // (v + c0) - c1 --> (voc) v + (c0 - c1) - else if ((details::e_add == o0) && (details::e_sub == o1)) - { - exprtk_debug(("(v + c0) - c1 --> (voc) v + (c0 - c1)\n")); - - return expr_gen.node_allocator_-> - template allocate_rc > >(v,c0 - c1); - } - // (v - c0) + c1 --> (voc) v - (c0 + c1) - else if ((details::e_sub == o0) && (details::e_add == o1)) - { - exprtk_debug(("(v - c0) + c1 --> (voc) v - (c0 + c1)\n")); - - return expr_gen.node_allocator_-> - template allocate_rc > >(v,c1 - c0); - } - // (v - c0) - c1 --> (voc) v - (c0 + c1) - else if ((details::e_sub == o0) && (details::e_sub == o1)) - { - exprtk_debug(("(v - c0) - c1 --> (voc) v - (c0 + c1)\n")); - - return expr_gen.node_allocator_-> - template allocate_rc > >(v,c0 + c1); - } - // (v * c0) * c1 --> (voc) v * (c0 * c1) - else if ((details::e_mul == o0) && (details::e_mul == o1)) - { - exprtk_debug(("(v * c0) * c1 --> (voc) v * (c0 * c1)\n")); - - return expr_gen.node_allocator_-> - template allocate_rc > >(v,c0 * c1); - } - // (v * c0) / c1 --> (voc) v * (c0 / c1) - else if ((details::e_mul == o0) && (details::e_div == o1)) - { - exprtk_debug(("(v * c0) / c1 --> (voc) v * (c0 / c1)\n")); - - return expr_gen.node_allocator_-> - template allocate_rc > >(v,c0 / c1); - } - // (v / c0) * c1 --> (voc) v * (c1 / c0) - else if ((details::e_div == o0) && (details::e_mul == o1)) - { - exprtk_debug(("(v / c0) * c1 --> (voc) v * (c1 / c0)\n")); - - return expr_gen.node_allocator_-> - template allocate_rc > >(v,c1 / c0); - } - // (v / c0) / c1 --> (voc) v / (c0 * c1) - else if ((details::e_div == o0) && (details::e_div == o1)) - { - exprtk_debug(("(v / c0) / c1 --> (voc) v / (c0 * c1)\n")); - - return expr_gen.node_allocator_-> - template allocate_rc > >(v,c0 * c1); - } - // (v ^ c0) ^ c1 --> (voc) v ^ (c0 * c1) - else if ((details::e_pow == o0) && (details::e_pow == o1)) - { - exprtk_debug(("(v ^ c0) ^ c1 --> (voc) v ^ (c0 * c1)\n")); - - return expr_gen.node_allocator_-> - template allocate_rc > >(v,c0 * c1); - } - } - - if (synthesize_sf3ext_expression::template compile(expr_gen,id(expr_gen,o0,o1),v,c0,c1,result)) - return result; - else if (!expr_gen.valid_operator(o0,f0)) + + 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(), + "ERR113 - 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(), + "ERR114 - 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(), + "ERR115 - Type checker instantiation failure for generic function: " + function_name)); + + return error_node(); + } + + if ( + !function->parameter_sequence.empty() && + function->allow_zero_parameters () && + !tc .allow_zero_parameters () + ) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR116 - Mismatch in zero parameter condition for generic function: " + + function_name)); + + return error_node(); + } + + if (token_is(token_t::e_lbracket)) + { + if (token_is(token_t::e_rbracket)) + { + if ( + !function->allow_zero_parameters() && + !tc .allow_zero_parameters() + ) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR117 - Zero parameter call to generic function: " + + function_name + " not allowed")); + + return error_node(); + } + } + else + { + for ( ; ; ) + { + expression_node_ptr arg = parse_expression(); + + if (0 == arg) + return error_node(); + + if (is_ivector_node(arg)) + param_type_list += 'V'; + else if (is_generally_string_node(arg)) + param_type_list += 'S'; + else // Everything else is assumed to be a scalar returning expression + param_type_list += 'T'; + + arg_list.push_back(arg); + + if (token_is(token_t::e_rbracket)) + break; + else if (!token_is(token_t::e_comma)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR118 - Expected ',' for call to generic function: " + function_name)); + + return error_node(); + } + } + } + } + else if ( + !function->parameter_sequence.empty() && + function->allow_zero_parameters () && + !tc .allow_zero_parameters () + ) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR119 - Zero parameter call to generic function: " + + function_name + " not allowed")); + + return error_node(); + } + + std::size_t param_seq_index = 0; + + if ( + state_.type_check_enabled && + !tc.verify(param_type_list, param_seq_index) + ) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR120 - 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; + } + + #ifndef exprtk_disable_string_capabilities + 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(), + "ERR121 - 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(), + "ERR122 - 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; + } + #endif + + 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(), + "ERR123 - 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(), + "ERR124 - 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(), + "ERR125 - 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(), + "ERR126 - 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 (state_.parsing_break_stmt) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR127 - Break call within a break call is not allowed")); + + return error_node(); + } + + scoped_bool_negator sbn(state_.parsing_break_stmt); + + if (!brkcnt_list_.empty()) + { + next_token(); + + brkcnt_list_.front() = true; + + expression_node_ptr return_expr = error_node(); + + if (token_is(token_t::e_lsqrbracket)) + { + if (0 == (return_expr = parse_expression())) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR128 - 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(), + "ERR129 - Expected ']' at the completion of break's return expression")); + + free_node(node_allocator_,return_expr); + + return error_node(); + } + } + + state_.activate_side_effect("parse_break_statement()"); + + return node_allocator_.allocate >(return_expr); + } + else + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR130 - 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; + state_.activate_side_effect("parse_continue_statement()"); + + return node_allocator_.allocate >(); + } + else + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR131 - 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(), + "ERR132 - 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(), + "ERR133 - 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(), + "ERR134 - 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(), + "ERR135 - 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; + bool vec_to_vec_initialiser = false; + bool null_initialisation = false; + + if (!token_is(token_t::e_rsqrbracket)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR136 - 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(), + "ERR137 - 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(), + "ERR138 - 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(), + "ERR139 - Expected ']' to close single value vector initialiser")); + + return error_node(); + } + + single_value_initialiser = true; + } + else if (!token_is(token_t::e_lcrlbracket)) + { + expression_node_ptr initialiser = error_node(); + + // Is this a vector to vector assignment and initialisation? + if (token_t::e_symbol == current_token().type) + { + // Is it a locally defined vector? + scope_element& se = sem_.get_active_element(current_token().value); + + if (scope_element::e_vector == se.type) + { + if (0 != (initialiser = parse_expression())) + vec_initilizer_list.push_back(initialiser); + else return error_node(); - else if (!expr_gen.valid_operator(o1,f1)) + } + // Are we dealing with a user defined vector? + else if (symtab_store_.is_vector(current_token().value)) + { + lodge_symbol(current_token().value,e_st_vector); + + if (0 != (initialiser = parse_expression())) + vec_initilizer_list.push_back(initialiser); + else return error_node(); - else - return node_type::allocate(*(expr_gen.node_allocator_),v,c0,c1,f0,f1); - } - - static inline std::string id(expression_generator& expr_gen, - const details::operator_type o0, const details::operator_type o1) - { - return (details::build_string() << "(t" << expr_gen.to_str(o0) << "t)" << expr_gen.to_str(o1) << "t"); - } - }; - - struct synthesize_vococ_expression1 - { - typedef typename vococ_t::type0 node_type; - - static inline expression_node_ptr process(expression_generator&, const details::operator_type&, expression_node_ptr (&)[2]) - { - // (v) o0 (c0 o1 c1) - Not possible. - exprtk_debug(("(v) o0 (c0 o1 c1) - Not possible.\n")); - return error_node(); - } - }; - - struct synthesize_vovovov_expression0 - { - typedef typename vovovov_t::type0 node_type; - typedef typename vovovov_t::sf4_type sf4_type; - typedef typename node_type::T0 T0; - typedef typename node_type::T1 T1; - typedef typename node_type::T2 T2; - typedef typename node_type::T3 T3; - - static inline expression_node_ptr process(expression_generator& expr_gen, - const details::operator_type& operation, - expression_node_ptr (&branch)[2]) - { - // (v0 o0 v1) o1 (v2 o2 v3) - const details::vov_base_node* vov0 = static_cast*>(branch[0]); - const details::vov_base_node* vov1 = static_cast*>(branch[1]); - const Type& v0 = vov0->v0(); - const Type& v1 = vov0->v1(); - const Type& v2 = vov1->v0(); - const Type& v3 = vov1->v1(); - const details::operator_type o0 = vov0->operation(); - const details::operator_type o1 = operation; - const details::operator_type o2 = vov1->operation(); - - binary_functor_t f0 = reinterpret_cast(0); - binary_functor_t f1 = reinterpret_cast(0); - binary_functor_t f2 = reinterpret_cast(0); - - details::free_node(*(expr_gen.node_allocator_),branch[0]); - details::free_node(*(expr_gen.node_allocator_),branch[1]); - - expression_node_ptr result = error_node(); - - if (expr_gen.parser_->settings_.strength_reduction_enabled()) - { - // (v0 / v1) * (v2 / v3) --> (vovovov) (v0 * v2) / (v1 * v3) - if ((details::e_div == o0) && (details::e_mul == o1) && (details::e_div == o2)) - { - const bool synthesis_result = - synthesize_sf4ext_expression:: - template compile(expr_gen,"(t*t)/(t*t)",v0,v2,v1,v3,result); - - exprtk_debug(("(v0 / v1) * (v2 / v3) --> (vovovov) (v0 * v2) / (v1 * v3)\n")); - - return (synthesis_result) ? result : error_node(); - } - // (v0 / v1) / (v2 / v3) --> (vovovov) (v0 * v3) / (v1 * v2) - else if ((details::e_div == o0) && (details::e_div == o1) && (details::e_div == o2)) - { - const bool synthesis_result = - synthesize_sf4ext_expression:: - template compile(expr_gen,"(t*t)/(t*t)",v0,v3,v1,v2,result); - - exprtk_debug(("(v0 / v1) / (v2 / v3) --> (vovovov) (v0 * v3) / (v1 * v2)\n")); - - return (synthesis_result) ? result : error_node(); - } - // (v0 + v1) / (v2 / v3) --> (vovovov) (v0 + v1) * (v3 / v2) - else if ((details::e_add == o0) && (details::e_div == o1) && (details::e_div == o2)) - { - const bool synthesis_result = - synthesize_sf4ext_expression:: - template compile(expr_gen,"(t+t)*(t/t)",v0,v1,v3,v2,result); - - exprtk_debug(("(v0 + v1) / (v2 / v3) --> (vovovov) (v0 + v1) * (v3 / v2)\n")); - - return (synthesis_result) ? result : error_node(); - } - // (v0 - v1) / (v2 / v3) --> (vovovov) (v0 + v1) * (v3 / v2) - else if ((details::e_sub == o0) && (details::e_div == o1) && (details::e_div == o2)) - { - const bool synthesis_result = - synthesize_sf4ext_expression:: - template compile(expr_gen,"(t-t)*(t/t)",v0,v1,v3,v2,result); - - exprtk_debug(("(v0 - v1) / (v2 / v3) --> (vovovov) (v0 - v1) * (v3 / v2)\n")); - - return (synthesis_result) ? result : error_node(); - } - // (v0 * v1) / (v2 / v3) --> (vovovov) ((v0 * v1) * v3) / v2 - else if ((details::e_mul == o0) && (details::e_div == o1) && (details::e_div == o2)) + } + // Are we dealing with a null initialisation vector definition? + else if (token_is(token_t::e_symbol,"null")) + null_initialisation = true; + } + + if (!null_initialisation) + { + if (0 == initialiser) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR140 - Expected '{' as part of vector initialiser list")); + + return error_node(); + } + else + vec_to_vec_initialiser = true; + } + } + else if (!token_is(token_t::e_rcrlbracket)) + { + for ( ; ; ) + { + expression_node_ptr initialiser = parse_expression(); + + if (0 == initialiser) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR141 - 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(), + "ERR142 - Expected ',' between vector initialisers")); + + return error_node(); + } + + if (token_is(token_t::e_rcrlbracket)) + break; + } + } + + if ( + !token_is(token_t::e_rbracket ,prsrhlpr_t::e_hold) && + !token_is(token_t::e_rcrlbracket,prsrhlpr_t::e_hold) && + !token_is(token_t::e_rsqrbracket,prsrhlpr_t::e_hold) + ) + { + if (!token_is(token_t::e_eof)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR143 - 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(), + "ERR144 - 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(), + "ERR145 - 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.depth = state_.scope_depth; + se.ref_count++; + } + } + + if (0 == vec_holder) + { + scope_element nse; + nse.name = vec_name; + nse.active = true; + nse.ref_count = 1; + nse.type = scope_element::e_vector; + nse.depth = state_.scope_depth; + nse.size = vec_size; + nse.data = new T[vec_size]; + nse.vec_node = new typename scope_element::vector_holder_t((T*)(nse.data),nse.size); + + if (!sem_.add_element(nse)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR146 - Failed to add new local vector '" + vec_name + "' to SEM")); + + sem_.free_element(nse); + + return error_node(); + } + + vec_holder = nse.vec_node; + + exprtk_debug(("parse_define_vector_statement() - INFO - Added new local vector: %s[%d]\n", + nse.name.c_str(), + static_cast(nse.size))); + } + + state_.activate_side_effect("parse_define_vector_statement()"); + + lodge_symbol(vec_name,e_st_local_vector); + + expression_node_ptr result = error_node(); + + if (null_initialisation) + result = expression_generator_(T(0.0)); + else if (vec_to_vec_initialiser) + result = expression_generator_( + details::e_assign, + node_allocator_.allocate(vec_holder), + vec_initilizer_list[0]); + else + result = node_allocator_ + .allocate >( + (*vec_holder)[0], + vec_size, + vec_initilizer_list, + single_value_initialiser); + + svd.delete_ptr = (0 == result); + + return result; + } + + #ifndef exprtk_disable_string_capabilities + inline expression_node_ptr parse_define_string_statement(const std::string& str_name, expression_node_ptr initialisation_expression) + { + stringvar_node_t* str_node = reinterpret_cast(0); + + scope_element& se = sem_.get_element(str_name); + + if (se.name == str_name) + { + if (se.active) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR147 - Illegal redefinition of local variable: '" + str_name + "'")); + + free_node(node_allocator_,initialisation_expression); + + return error_node(); + } + else if (scope_element::e_string == se.type) + { + str_node = se.str_node; + se.active = true; + se.depth = state_.scope_depth; + se.ref_count++; + } + } + + if (0 == str_node) + { + scope_element nse; + nse.name = str_name; + nse.active = true; + nse.ref_count = 1; + nse.type = scope_element::e_string; + nse.depth = state_.scope_depth; + nse.data = new std::string; + nse.str_node = new stringvar_node_t(*(std::string*)(nse.data)); + + if (!sem_.add_element(nse)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR148 - Failed to add new local string variable '" + str_name + "' to SEM")); + + free_node(node_allocator_,initialisation_expression); + + sem_.free_element(nse); + + return error_node(); + } + + str_node = nse.str_node; + + exprtk_debug(("parse_define_string_statement() - INFO - Added new local string variable: %s\n",nse.name.c_str())); + } + + lodge_symbol(str_name,e_st_local_string); + + state_.activate_side_effect("parse_define_string_statement()"); + + expression_node_ptr branch[2] = {0}; + + branch[0] = str_node; + branch[1] = initialisation_expression; + + return expression_generator_(details::e_assign,branch); + } + #else + inline expression_node_ptr parse_define_string_statement(const std::string&, expression_node_ptr) + { + return error_node(); + } + #endif + + inline bool local_variable_is_shadowed(const std::string& symbol) + { + const scope_element& se = sem_.get_element(symbol); + return (se.name == symbol) && se.active; + } + + inline expression_node_ptr parse_define_var_statement() + { + if (settings_.vardef_disabled()) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR149 - 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(), + "ERR150 - 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(), + "ERR151 - Illegal redefinition of reserved keyword: '" + var_name + "'")); + + return error_node(); + } + else if (symtab_store_.symbol_exists(var_name)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR152 - 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(), + "ERR153 - Illegal redefinition of local variable: '" + var_name + "'")); + + return error_node(); + } + else if (token_is(token_t::e_lsqrbracket,prsrhlpr_t::e_hold)) + { + return parse_define_vector_statement(var_name); + } + else if (token_is(token_t::e_lcrlbracket,prsrhlpr_t::e_hold)) + { + return parse_uninitialised_var_statement(var_name); + } + else if (token_is(token_t::e_assign)) + { + if (0 == (initialisation_expression = parse_expression())) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR154 - Failed to parse initialisation expression")); + + return error_node(); + } + } + + if ( + !token_is(token_t::e_rbracket ,prsrhlpr_t::e_hold) && + !token_is(token_t::e_rcrlbracket,prsrhlpr_t::e_hold) && + !token_is(token_t::e_rsqrbracket,prsrhlpr_t::e_hold) + ) + { + if (!token_is(token_t::e_eof,prsrhlpr_t::e_hold)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR155 - Expected ';' after variable definition")); + + free_node(node_allocator_,initialisation_expression); + + return error_node(); + } + } + + if ( + (0 != initialisation_expression) && + details::is_generally_string_node(initialisation_expression) + ) + { + return parse_define_string_statement(var_name,initialisation_expression); + } + + expression_node_ptr var_node = reinterpret_cast(0); + + scope_element& se = sem_.get_element(var_name); + + if (se.name == var_name) + { + if (se.active) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR156 - 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.depth = state_.scope_depth; + se.ref_count++; + } + } + + if (0 == var_node) + { + scope_element nse; + nse.name = var_name; + nse.active = true; + nse.ref_count = 1; + nse.type = scope_element::e_variable; + nse.depth = state_.scope_depth; + nse.data = new T(T(0)); + nse.var_node = node_allocator_.allocate(*(T*)(nse.data)); + + if (!sem_.add_element(nse)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR157 - Failed to add new local variable '" + var_name + "' to SEM")); + + free_node(node_allocator_,initialisation_expression); + + sem_.free_element(nse); + + return error_node(); + } + + var_node = nse.var_node; + + exprtk_debug(("parse_define_var_statement() - INFO - Added new local variable: %s\n",nse.name.c_str())); + } + + state_.activate_side_effect("parse_define_var_statement()"); + + lodge_symbol(var_name,e_st_local_variable); + + expression_node_ptr branch[2] = {0}; + + branch[0] = var_node; + branch[1] = initialisation_expression ? initialisation_expression : expression_generator_(T(0)); + + return expression_generator_(details::e_assign,branch); + } + + inline expression_node_ptr parse_uninitialised_var_statement(const std::string& var_name) + { + if ( + !token_is(token_t::e_lcrlbracket) || + !token_is(token_t::e_rcrlbracket) + ) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR158 - Expected a '{}' for uninitialised var definition")); + + return error_node(); + } + else if (!token_is(token_t::e_eof,prsrhlpr_t::e_hold)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR159 - Expected ';' after uninitialised variable definition")); + + return error_node(); + } + + expression_node_ptr var_node = reinterpret_cast(0); + + scope_element& se = sem_.get_element(var_name); + + if (se.name == var_name) + { + if (se.active) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR160 - 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 = state_.scope_depth; + nse.ip_index = sem_.next_ip_index(); + nse.data = new T(T(0)); + nse.var_node = node_allocator_.allocate(*(T*)(nse.data)); + + if (!sem_.add_element(nse)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR161 - Failed to add new local variable '" + var_name + "' to SEM")); + + sem_.free_element(nse); + + return error_node(); + } + + exprtk_debug(("parse_uninitialised_var_statement() - INFO - Added new local variable: %s\n", + nse.name.c_str())); + } + + lodge_symbol(var_name,e_st_local_variable); + + state_.activate_side_effect("parse_uninitialised_var_statement()"); + + return expression_generator_(T(0)); + } + + inline expression_node_ptr parse_swap_statement() + { + if (!details::imatch(current_token().value,"swap")) + { + return error_node(); + } + else + next_token(); + + if (!token_is(token_t::e_lbracket)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR162 - 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,prsrhlpr_t::e_hold)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR163 - 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(), + "ERR164 - First parameter to swap is an invalid vector element: '" + var0_name + "'")); + + return error_node(); + } + + variable0_generated = true; + } + else + { + if (symtab_store_.is_variable(var0_name)) + { + variable0 = symtab_store_.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(), + "ERR165 - 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(), + "ERR166 - 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,prsrhlpr_t::e_hold)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR167 - 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(), + "ERR168 - 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 (symtab_store_.is_variable(var1_name)) + { + variable1 = symtab_store_.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(), + "ERR169 - 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(), + "ERR170 - 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); + + expression_node_ptr result = error_node(); + + if ( + (0 != (v0 = dynamic_cast(variable0))) && + (0 != (v1 = dynamic_cast(variable1))) + ) + { + result = node_allocator_.allocate >(v0,v1); + + if (variable0_generated) + { + free_node(node_allocator_,variable0); + } + + if (variable1_generated) + { + free_node(node_allocator_,variable1); + } + } + else + result = node_allocator_.allocate >(variable0,variable1); + + state_.activate_side_effect("parse_swap_statement()"); + + return result; + } + + #ifndef exprtk_disable_return_statement + inline expression_node_ptr parse_return_statement() + { + if (state_.parsing_return_stmt) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR171 - Return call within a return call is not allowed")); + + return error_node(); + } + + scoped_bool_negator sbn(state_.parsing_return_stmt); + + std::vector arg_list; + + scoped_vec_delete sdd(*this,arg_list); + + if (!details::imatch(current_token().value,"return")) + { + return error_node(); + } + else + next_token(); + + if (!token_is(token_t::e_lsqrbracket)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR172 - Expected '[' at start of return statement")); + + return error_node(); + } + else if (!token_is(token_t::e_rsqrbracket)) + { + for ( ; ; ) + { + expression_node_ptr arg = parse_expression(); + + if (0 == arg) + return error_node(); + + arg_list.push_back(arg); + + if (token_is(token_t::e_rsqrbracket)) + break; + else if (!token_is(token_t::e_comma)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR173 - Expected ',' between values during call to return")); + + return error_node(); + } + } + } + else if (settings_.zero_return_disabled()) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR174 - Zero parameter return statement not allowed")); + + return error_node(); + } + + lexer::token prev_token = current_token(); + + if (token_is(token_t::e_rsqrbracket)) + { + if (!arg_list.empty()) + { + set_error( + make_error(parser_error::e_syntax, + prev_token, + "ERR175 - Invalid ']' found during return call")); + + return error_node(); + } + } + + std::string ret_param_type_list; + + for (std::size_t i = 0; i < arg_list.size(); ++i) + { + if (0 == arg_list[i]) + return error_node(); + else if (is_ivector_node(arg_list[i])) + ret_param_type_list += 'V'; + else if (is_generally_string_node(arg_list[i])) + ret_param_type_list += 'S'; + else + ret_param_type_list += 'T'; + } + + dec_.retparam_list_.push_back(ret_param_type_list); + + expression_node_ptr result = expression_generator_.return_call(arg_list); + + sdd.delete_ptr = (0 == result); + + state_.return_stmt_present = true; + + state_.activate_side_effect("parse_return_statement()"); + + return result; + } + #else + inline expression_node_ptr parse_return_statement() + { + return error_node(); + } + #endif + + inline bool post_variable_process(const std::string& symbol) + { + if ( + peek_token_is(token_t::e_lbracket ) || + peek_token_is(token_t::e_lcrlbracket) || + peek_token_is(token_t::e_lsqrbracket) + ) + { + if (!settings_.commutative_check_enabled()) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR176 - 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; + + const lexer::parser_helper::token_advance_mode hold = prsrhlpr_t::e_hold; + + switch (token) + { + case token_t::e_lcrlbracket : implied_mul = token_is(token_t::e_lbracket ,hold) || + token_is(token_t::e_lcrlbracket,hold) || + token_is(token_t::e_lsqrbracket,hold) ; + break; + + case token_t::e_lbracket : implied_mul = token_is(token_t::e_lbracket ,hold) || + token_is(token_t::e_lcrlbracket,hold) || + token_is(token_t::e_lsqrbracket,hold) ; + break; + + case token_t::e_lsqrbracket : implied_mul = token_is(token_t::e_lbracket ,hold) || + token_is(token_t::e_lcrlbracket,hold) || + token_is(token_t::e_lsqrbracket,hold) ; + break; + + default : return true; + } + + if (implied_mul) + { + if (!settings_.commutative_check_enabled()) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR177 - 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 = symtab_store_.get_variable(symbol); + + if (variable) + { + if (symtab_store_.is_constant_node(symbol)) + { + variable = expression_generator_(variable->value()); + } + + if (!post_variable_process(symbol)) + return error_node(); + + lodge_symbol(symbol,e_st_variable); + next_token(); + + return variable; + } + + // Are we dealing with a locally defined variable, vector or string? + if (!sem_.empty()) + { + scope_element& se = sem_.get_active_element(symbol); + + if (se.active && (se.name == symbol)) + { + if (scope_element::e_variable == se.type) + { + se.active = true; + lodge_symbol(symbol,e_st_local_variable); + + if (!post_variable_process(symbol)) + return error_node(); + + next_token(); + + return se.var_node; + } + else if (scope_element::e_vector == se.type) + { + return parse_vector(); + } + #ifndef exprtk_disable_string_capabilities + else if (scope_element::e_string == se.type) + { + return parse_string(); + } + #endif + } + } + + #ifndef exprtk_disable_string_capabilities + // Are we dealing with a string variable? + if (symtab_store_.is_stringvar(symbol)) + { + return parse_string(); + } + #endif + + { + // Are we dealing with a function? + ifunction* function = symtab_store_.get_function(symbol); + + if (function) + { + lodge_symbol(symbol,e_st_function); + + expression_node_ptr func_node = + parse_function_invocation(function,symbol); + + if (func_node) + return func_node; + else + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR178 - Failed to generate node for function: '" + symbol + "'")); + + return error_node(); + } + } + } + + { + // Are we dealing with a vararg function? + ivararg_function* vararg_function = symtab_store_.get_vararg_function(symbol); + + if (vararg_function) + { + lodge_symbol(symbol,e_st_function); + + expression_node_ptr vararg_func_node = + parse_vararg_function_call(vararg_function,symbol); + + if (vararg_func_node) + return vararg_func_node; + else + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR179 - Failed to generate node for vararg function: '" + symbol + "'")); + + return error_node(); + } + } + } + + { + // Are we dealing with a vararg generic function? + igeneric_function* generic_function = symtab_store_.get_generic_function(symbol); + + if (generic_function) + { + lodge_symbol(symbol,e_st_function); + + expression_node_ptr genericfunc_node = + parse_generic_function_call(generic_function,symbol); + + if (genericfunc_node) + return genericfunc_node; + else + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR180 - Failed to generate node for generic function: '" + symbol + "'")); + + return error_node(); + } + } + } + + #ifndef exprtk_disable_string_capabilities + { + // Are we dealing with a vararg string returning function? + igeneric_function* string_function = symtab_store_.get_string_function(symbol); + + if (string_function) + { + lodge_symbol(symbol,e_st_function); + + expression_node_ptr stringfunc_node = + parse_string_function_call(string_function,symbol); + + if (stringfunc_node) + return stringfunc_node; + else + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR181 - Failed to generate node for string function: '" + symbol + "'")); + + return error_node(); + } + } + } + #endif + + // Are we dealing with a vector? + if (symtab_store_.is_vector(symbol)) + { + lodge_symbol(symbol,e_st_vector); + return parse_vector(); + } + + if (details::is_reserved_symbol(symbol)) + { + if (settings_.function_enabled(symbol) || !details::is_base_function(symbol)) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR182 - Invalid use of reserved symbol '" + symbol + "'")); + + return error_node(); + } + } + + // Should we handle unknown symbols? + if (resolve_unknown_symbol_ && unknown_symbol_resolver_) + { + if (!(settings_.rsrvd_sym_usr_disabled() && details::is_reserved_symbol(symbol))) + { + 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; + + symbol_table_t& symtab = symtab_store_.get_symbol_table(); + + switch (usr_symbol_type) + { + case unknown_symbol_resolver::e_usr_variable_type : create_result = symtab.create_variable(symbol,default_value); + break; + + case unknown_symbol_resolver::e_usr_constant_type : create_result = symtab.add_constant(symbol,default_value); + break; + + default : create_result = false; + } + + if (create_result) + { + expression_node_ptr var = symtab_store_.get_variable(symbol); + + if (var) + { + if (symtab_store_.is_constant_node(symbol)) { - const bool synthesis_result = - synthesize_sf4ext_expression:: - template compile(expr_gen,"((t*t)*t)/t",v0,v1,v3,v2,result); - - exprtk_debug(("(v0 * v1) / (v2 / v3) --> (vovovov) ((v0 * v1) * v3) / v2\n")); - - return (synthesis_result) ? result : error_node(); + var = expression_generator_(var->value()); } - } - - if (synthesize_sf4ext_expression::template compile(expr_gen,id(expr_gen,o0,o1,o2),v0,v1,v2,v3,result)) - return result; - else if (!expr_gen.valid_operator(o0,f0)) - return error_node(); - else if (!expr_gen.valid_operator(o1,f1)) - return error_node(); - else if (!expr_gen.valid_operator(o2,f2)) - return error_node(); - else - return node_type::allocate(*(expr_gen.node_allocator_),v0,v1,v2,v3,f0,f1,f2); - } - - static inline std::string id(expression_generator& expr_gen, - const details::operator_type o0, - const details::operator_type o1, - const details::operator_type o2) - { - return (details::build_string() << "(t" << expr_gen.to_str(o0) << "t)" << expr_gen.to_str(o1) << "(t" << expr_gen.to_str(o2) << "t)"); - } + + 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(), + "ERR183 - Failed to create variable: '" + symbol + "'")); + + return error_node(); + } + } + } + + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR184 - 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" ; + static const std::string symbol_return = "return" ; + + 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) && + settings_.control_struct_enabled(current_token().value) + ) + { + return parse_conditional_statement(); + } + else if ( + details::imatch(current_token().value,symbol_while) && + settings_.control_struct_enabled(current_token().value) + ) + { + return parse_while_loop(); + } + else if ( + details::imatch(current_token().value,symbol_repeat) && + settings_.control_struct_enabled(current_token().value) + ) + { + return parse_repeat_until_loop(); + } + else if ( + details::imatch(current_token().value,symbol_for) && + settings_.control_struct_enabled(current_token().value) + ) + { + return parse_for_loop(); + } + else if ( + details::imatch(current_token().value,symbol_switch) && + settings_.control_struct_enabled(current_token().value) + ) + { + 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(); + } + #ifndef exprtk_disable_return_statement + else if ( + details::imatch(current_token().value,symbol_return) && + settings_.control_struct_enabled(current_token().value) + ) + { + return parse_return_statement(); + } + #endif + else if (symtab_store_.valid() || !sem_.empty()) + { + return parse_symtab_symbol(); + } + else + { + set_error( + make_error(parser_error::e_symtab, + current_token(), + "ERR185 - 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(), + "ERR186 - 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(), + "ERR187 - 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(), + "ERR188 - 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(), + "ERR189 - 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(), + "ERR190 - Premature end of expression[1]")); + + return error_node(); + } + else + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR191 - Premature end of expression[2]")); + + return error_node(); + } + + if ( + branch && + (e_level00 == precedence) && + token_is(token_t::e_ternary,prsrhlpr_t::e_hold) + ) + { + branch = parse_ternary_conditional_statement(branch); + } + + parse_pending_string_rangesize(branch); + + return branch; + } + + template + class expression_generator + { + public: + + typedef details::expression_node* expression_node_ptr; + typedef expression_node_ptr (*synthesize_functor_t)(expression_generator&, const details::operator_type& operation, expression_node_ptr (&branch)[2]); + typedef std::map synthesize_map_t; + typedef typename exprtk::parser parser_t; + typedef const Type& vtype; + typedef const Type ctype; + + inline void init_synthesize_map() + { + #ifndef exprtk_disable_enhanced_features + synthesize_map_["(v)o(v)"] = synthesize_vov_expression::process; + synthesize_map_["(c)o(v)"] = synthesize_cov_expression::process; + synthesize_map_["(v)o(c)"] = synthesize_voc_expression::process; + + #define register_synthezier(S) \ + synthesize_map_[S ::node_type::id()] = S ::process; \ + + register_synthezier(synthesize_vovov_expression0) + register_synthezier(synthesize_vovov_expression1) + register_synthezier(synthesize_vovoc_expression0) + register_synthezier(synthesize_vovoc_expression1) + register_synthezier(synthesize_vocov_expression0) + register_synthezier(synthesize_vocov_expression1) + register_synthezier(synthesize_covov_expression0) + register_synthezier(synthesize_covov_expression1) + register_synthezier(synthesize_covoc_expression0) + register_synthezier(synthesize_covoc_expression1) + register_synthezier(synthesize_cocov_expression1) + register_synthezier(synthesize_vococ_expression0) + + register_synthezier(synthesize_vovovov_expression0) + register_synthezier(synthesize_vovovoc_expression0) + register_synthezier(synthesize_vovocov_expression0) + register_synthezier(synthesize_vocovov_expression0) + register_synthezier(synthesize_covovov_expression0) + register_synthezier(synthesize_covocov_expression0) + register_synthezier(synthesize_vocovoc_expression0) + register_synthezier(synthesize_covovoc_expression0) + register_synthezier(synthesize_vococov_expression0) + + register_synthezier(synthesize_vovovov_expression1) + register_synthezier(synthesize_vovovoc_expression1) + register_synthezier(synthesize_vovocov_expression1) + register_synthezier(synthesize_vocovov_expression1) + register_synthezier(synthesize_covovov_expression1) + register_synthezier(synthesize_covocov_expression1) + register_synthezier(synthesize_vocovoc_expression1) + register_synthezier(synthesize_covovoc_expression1) + register_synthezier(synthesize_vococov_expression1) + + register_synthezier(synthesize_vovovov_expression2) + register_synthezier(synthesize_vovovoc_expression2) + register_synthezier(synthesize_vovocov_expression2) + register_synthezier(synthesize_vocovov_expression2) + register_synthezier(synthesize_covovov_expression2) + register_synthezier(synthesize_covocov_expression2) + register_synthezier(synthesize_vocovoc_expression2) + register_synthezier(synthesize_covovoc_expression2) + + register_synthezier(synthesize_vovovov_expression3) + register_synthezier(synthesize_vovovoc_expression3) + register_synthezier(synthesize_vovocov_expression3) + register_synthezier(synthesize_vocovov_expression3) + register_synthezier(synthesize_covovov_expression3) + register_synthezier(synthesize_covocov_expression3) + register_synthezier(synthesize_vocovoc_expression3) + register_synthezier(synthesize_covovoc_expression3) + register_synthezier(synthesize_vococov_expression3) + + register_synthezier(synthesize_vovovov_expression4) + register_synthezier(synthesize_vovovoc_expression4) + register_synthezier(synthesize_vovocov_expression4) + register_synthezier(synthesize_vocovov_expression4) + register_synthezier(synthesize_covovov_expression4) + register_synthezier(synthesize_covocov_expression4) + register_synthezier(synthesize_vocovoc_expression4) + register_synthezier(synthesize_covovoc_expression4) + #endif + } + + inline void set_parser(parser_t& p) + { + parser_ = &p; + } + + inline void set_uom(unary_op_map_t& unary_op_map) + { + unary_op_map_ = &unary_op_map; + } + + inline void set_bom(binary_op_map_t& binary_op_map) + { + binary_op_map_ = &binary_op_map; + } + + inline void set_ibom(inv_binary_op_map_t& inv_binary_op_map) + { + inv_binary_op_map_ = &inv_binary_op_map; + } + + inline void set_sf3m(sf3_map_t& sf3_map) + { + sf3_map_ = &sf3_map; + } + + inline void set_sf4m(sf4_map_t& sf4_map) + { + sf4_map_ = &sf4_map; + } + + inline void set_allocator(details::node_allocator& na) + { + node_allocator_ = &na; + } + + inline void set_strength_reduction_state(const bool enabled) + { + strength_reduction_enabled_ = enabled; + } + + inline bool strength_reduction_enabled() const + { + return strength_reduction_enabled_; + } + + inline bool valid_operator(const details::operator_type& operation, binary_functor_t& bop) + { + typename binary_op_map_t::iterator bop_itr = binary_op_map_->find(operation); + + if ((*binary_op_map_).end() == bop_itr) + return false; + + bop = bop_itr->second; + + return true; + } + + inline bool valid_operator(const details::operator_type& operation, unary_functor_t& uop) + { + typename unary_op_map_t::iterator uop_itr = unary_op_map_->find(operation); + + if ((*unary_op_map_).end() == uop_itr) + return false; + + uop = uop_itr->second; + + return true; + } + + inline details::operator_type get_operator(const binary_functor_t& bop) + { + return (*inv_binary_op_map_).find(bop)->second; + } + + inline expression_node_ptr operator()(const Type& v) const + { + return node_allocator_->allocate(v); + } + + #ifndef exprtk_disable_string_capabilities + inline expression_node_ptr operator()(const std::string& s) const + { + return node_allocator_->allocate(s); + } + + inline expression_node_ptr operator()(std::string& s, range_t& rp) const + { + return node_allocator_->allocate_rr(s,rp); + } + + inline expression_node_ptr operator()(const std::string& s, range_t& rp) const + { + return node_allocator_->allocate_tt(s,rp); + } + + inline expression_node_ptr operator()(expression_node_ptr branch, range_t& rp) const + { + if (is_generally_string_node(branch)) + return node_allocator_->allocate_tt(branch,rp); + else + return error_node(); + } + #endif + + inline bool unary_optimisable(const details::operator_type& operation) const + { + return (details::e_abs == operation) || (details::e_acos == operation) || + (details::e_acosh == operation) || (details::e_asin == operation) || + (details::e_asinh == operation) || (details::e_atan == operation) || + (details::e_atanh == operation) || (details::e_ceil == operation) || + (details::e_cos == operation) || (details::e_cosh == operation) || + (details::e_exp == operation) || (details::e_expm1 == operation) || + (details::e_floor == operation) || (details::e_log == operation) || + (details::e_log10 == operation) || (details::e_log2 == operation) || + (details::e_log1p == operation) || (details::e_neg == operation) || + (details::e_pos == operation) || (details::e_round == operation) || + (details::e_sin == operation) || (details::e_sinc == operation) || + (details::e_sinh == operation) || (details::e_sqrt == operation) || + (details::e_tan == operation) || (details::e_tanh == operation) || + (details::e_cot == operation) || (details::e_sec == operation) || + (details::e_csc == operation) || (details::e_r2d == operation) || + (details::e_d2r == operation) || (details::e_d2g == operation) || + (details::e_g2d == operation) || (details::e_notl == operation) || + (details::e_sgn == operation) || (details::e_erf == operation) || + (details::e_erfc == operation) || (details::e_ncdf == operation) || + (details::e_frac == operation) || (details::e_trunc == operation) ; + } + + inline bool sf3_optimisable(const std::string& sf3id, trinary_functor_t& tfunc) + { + 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_optimisable(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_optimisable(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_optimisable(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_optimisable(operation) && details::is_variable_node(branch[0])) + return synthesize_uv_expression(operation,branch); + else if (unary_optimisable(operation) && details::is_ivector_node(branch[0])) + return synthesize_uvec_expression(operation,branch); + else + return synthesize_unary_expression(operation,branch); + } + + inline bool is_assignment_operation(const details::operator_type& operation) const + { + return ( + (details::e_addass == operation) || + (details::e_subass == operation) || + (details::e_mulass == operation) || + (details::e_divass == operation) || + (details::e_modass == operation) + ) && + parser_->settings_.assignment_enabled(operation); + } + + #ifndef exprtk_disable_string_capabilities + inline bool valid_string_operation(const details::operator_type& operation) const + { + return (details::e_add == operation) || + (details::e_lt == operation) || + (details::e_lte == operation) || + (details::e_gt == operation) || + (details::e_gte == operation) || + (details::e_eq == operation) || + (details::e_ne == operation) || + (details::e_in == operation) || + (details::e_like == operation) || + (details::e_ilike == operation) || + (details::e_assign == operation) || + (details::e_addass == operation) || + (details::e_swap == operation) ; + } + #else + inline bool valid_string_operation(const details::operator_type&) const + { + return false; + } + #endif + + inline std::string to_str(const details::operator_type& operation) const + { + switch (operation) + { + case details::e_add : return "+"; + case details::e_sub : return "-"; + case details::e_mul : return "*"; + case details::e_div : return "/"; + case details::e_mod : return "%"; + case details::e_pow : return "^"; + case details::e_lt : return "<"; + case details::e_lte : return "<="; + case details::e_gt : return ">"; + case details::e_gte : return ">="; + case details::e_eq : return "=="; + case details::e_ne : return "!="; + case details::e_and : return "and"; + case details::e_nand : return "nand"; + case details::e_or : return "or"; + case details::e_nor : return "nor"; + case details::e_xor : return "xor"; + case details::e_xnor : return "xnor"; + default : return "UNKNOWN"; + } + } + + inline bool operation_optimisable(const details::operator_type& operation) const + { + return (details::e_add == operation) || + (details::e_sub == operation) || + (details::e_mul == operation) || + (details::e_div == operation) || + (details::e_mod == operation) || + (details::e_pow == operation) || + (details::e_lt == operation) || + (details::e_lte == operation) || + (details::e_gt == operation) || + (details::e_gte == operation) || + (details::e_eq == operation) || + (details::e_ne == operation) || + (details::e_and == operation) || + (details::e_nand == operation) || + (details::e_or == operation) || + (details::e_nor == operation) || + (details::e_xor == operation) || + (details::e_xnor == operation) ; + } + + inline std::string branch_to_id(expression_node_ptr branch) + { + 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_optimisable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const + { + if (!operation_optimisable(operation)) + return false; + else + return (details::is_constant_node(branch[0]) && details::is_variable_node(branch[1])); + } + + inline bool voc_optimisable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const + { + if (!operation_optimisable(operation)) + return false; + else + return (details::is_variable_node(branch[0]) && details::is_constant_node(branch[1])); + } + + inline bool vov_optimisable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const + { + if (!operation_optimisable(operation)) + return false; + else + return (details::is_variable_node(branch[0]) && details::is_variable_node(branch[1])); + } + + inline bool cob_optimisable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const + { + if (!operation_optimisable(operation)) + return false; + else + return (details::is_constant_node(branch[0]) && !details::is_constant_node(branch[1])); + } + + inline bool boc_optimisable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const + { + if (!operation_optimisable(operation)) + return false; + else + return (!details::is_constant_node(branch[0]) && details::is_constant_node(branch[1])); + } + + inline bool cocob_optimisable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const + { + if ( + (details::e_add == operation) || + (details::e_sub == operation) || + (details::e_mul == operation) || + (details::e_div == operation) + ) + { + return (details::is_constant_node(branch[0]) && details::is_cob_node(branch[1])) || + (details::is_constant_node(branch[1]) && details::is_cob_node(branch[0])); + } + else + return false; + } + + inline bool coboc_optimisable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const + { + if ( + (details::e_add == operation) || + (details::e_sub == operation) || + (details::e_mul == operation) || + (details::e_div == operation) + ) + { + return (details::is_constant_node(branch[0]) && details::is_boc_node(branch[1])) || + (details::is_constant_node(branch[1]) && details::is_boc_node(branch[0])); + } + else + return false; + } + + inline bool uvouv_optimisable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const + { + if (!operation_optimisable(operation)) + return false; + else + return (details::is_uv_node(branch[0]) && details::is_uv_node(branch[1])); + } + + inline bool vob_optimisable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const + { + if (!operation_optimisable(operation)) + return false; + else + return (details::is_variable_node(branch[0]) && !details::is_variable_node(branch[1])); + } + + inline bool bov_optimisable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const + { + if (!operation_optimisable(operation)) + return false; + else + return (!details::is_variable_node(branch[0]) && details::is_variable_node(branch[1])); + } + + inline bool binext_optimisable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const + { + if (!operation_optimisable(operation)) + return false; + else + return (!details::is_constant_node(branch[0]) || !details::is_constant_node(branch[1])); + } + + inline bool is_invalid_assignment_op(const details::operator_type& operation, expression_node_ptr (&branch)[2]) + { + if (is_assignment_operation(operation)) + { + const bool b1_is_genstring = details::is_generally_string_node(branch[1]); + + if (details::is_string_node(branch[0])) + return !b1_is_genstring; + else + return ( + !details::is_variable_node (branch[0]) && + !details::is_vector_elem_node (branch[0]) && + !details::is_rebasevector_elem_node (branch[0]) && + !details::is_rebasevector_celem_node(branch[0]) && + !details::is_vector_node (branch[0]) + ) + || b1_is_genstring; + } + else + return false; + } + + inline bool is_constpow_operation(const details::operator_type& operation, expression_node_ptr(&branch)[2]) + { + if ( + !is_constant_node(branch[1]) || + is_constant_node(branch[0]) || + is_variable_node(branch[0]) || + is_vector_node (branch[0]) || + is_generally_string_node(branch[0]) + ) + return false; + + const Type c = static_cast*>(branch[1])->value(); + + return cardinal_pow_optimisable(operation, c); + } + + inline bool is_invalid_break_continue_op(expression_node_ptr (&branch)[2]) + { + 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_logic_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) || + (details::e_equal == operation) || + (details::e_and == operation) || + (details::e_nand == operation) || + (details:: e_or == operation) || + (details:: e_nor == operation) || + (details:: e_xor == operation) || + (details::e_xnor == operation) + ); + } + + inline bool is_vector_arithmetic_operation(const details::operator_type& operation, expression_node_ptr (&branch)[2]) + { + if (!is_ivector_node(branch[0]) && !is_ivector_node(branch[1])) + return false; + else + return ( + (details::e_add == operation) || + (details::e_sub == operation) || + (details::e_mul == operation) || + (details::e_div == operation) || + (details::e_pow == operation) + ); + } + + inline expression_node_ptr operator()(const details::operator_type& operation, expression_node_ptr (&branch)[2]) + { + if ((0 == branch[0]) || (0 == branch[1])) + return error_node(); + else if (is_invalid_string_op(operation,branch)) + return error_node(); + else if (is_invalid_assignment_op(operation,branch)) + return error_node(); + else if (is_invalid_break_continue_op(branch)) + return error_node(); + else if (details::e_assign == operation) + return synthesize_assignment_expression(operation,branch); + else if (details::e_swap == operation) + return synthesize_swap_expression(branch); + else if (is_assignment_operation(operation)) + return synthesize_assignment_operation_expression(operation,branch); + else if (is_vector_eqineq_logic_operation(operation,branch)) + return synthesize_veceqineqlogic_operation_expression(operation,branch); + else if (is_vector_arithmetic_operation(operation,branch)) + return synthesize_vecarithmetic_operation_expression(operation,branch); + else if (is_shortcircuit_expression(operation)) + return synthesize_shortcircuit_expression(operation,branch); + else if (is_string_operation(operation,branch)) + return synthesize_string_expression(operation,branch); + else if (is_null_present(branch)) + return synthesize_null_expression(operation, branch); + #ifndef exprtk_disable_cardinal_pow_optimisation + else if (is_constpow_operation(operation, branch)) + return cardinal_pow_optimisation(branch); + #endif + + expression_node_ptr result = error_node(); + + #ifndef exprtk_disable_enhanced_features + if (synthesize_expression(operation,branch,result)) + return result; + else + #endif + + { + /* + Possible reductions: + 1. c o cob -> cob + 2. cob o c -> cob + 3. c o boc -> boc + 4. boc o c -> boc + */ + result = error_node(); + + if (cocob_optimisable(operation,branch)) + result = synthesize_cocob_expression::process(*this,operation,branch); + else if (coboc_optimisable(operation,branch) && (0 == result)) + result = synthesize_coboc_expression::process(*this,operation,branch); + + if (result) + return result; + } + + if (uvouv_optimisable(operation,branch)) + return synthesize_uvouv_expression(operation,branch); + else if (vob_optimisable(operation,branch)) + return synthesize_vob_expression::process(*this,operation,branch); + else if (bov_optimisable(operation,branch)) + return synthesize_bov_expression::process(*this,operation,branch); + else if (cob_optimisable(operation,branch)) + return synthesize_cob_expression::process(*this,operation,branch); + else if (boc_optimisable(operation,branch)) + return synthesize_boc_expression::process(*this,operation,branch); + #ifndef exprtk_disable_enhanced_features + else if (cov_optimisable(operation,branch)) + return synthesize_cov_expression::process(*this,operation,branch); + #endif + else if (binext_optimisable(operation,branch)) + return synthesize_binary_ext_expression::process(*this,operation,branch); + else + return synthesize_expression(operation,branch); + } + + inline expression_node_ptr operator()(const details::operator_type& operation, expression_node_ptr (&branch)[3]) + { + if ( + (0 == branch[0]) || + (0 == branch[1]) || + (0 == branch[2]) + ) + { + details::free_all_nodes(*node_allocator_,branch); + + return error_node(); + } + else if (is_invalid_string_op(operation,branch)) + return error_node(); + else if (is_string_operation(operation,branch)) + return synthesize_string_expression(operation,branch); + else + return synthesize_expression(operation,branch); + } + + inline expression_node_ptr operator()(const details::operator_type& operation, expression_node_ptr (&branch)[4]) + { + return synthesize_expression(operation,branch); + } + + inline expression_node_ptr operator()(const details::operator_type& operation, expression_node_ptr b0) + { + expression_node_ptr branch[1] = { b0 }; + return (*this)(operation,branch); + } + + inline expression_node_ptr operator()(const details::operator_type& operation, expression_node_ptr b0, expression_node_ptr b1) + { + 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 optimise. + 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); + } + + #ifndef exprtk_disable_string_capabilities + inline expression_node_ptr conditional_string(expression_node_ptr condition, + expression_node_ptr consequent, + expression_node_ptr alternative) const + { + if ((0 == condition) || (0 == consequent)) + { + 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 optimise. + 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_c >(""); + } + } + else if ((0 != consequent) && (0 != alternative)) + return node_allocator_-> + allocate(condition,consequent,alternative); + else + return error_node(); + } + #else + inline expression_node_ptr conditional_string(expression_node_ptr, + expression_node_ptr, + expression_node_ptr) const + { + return error_node(); + } + #endif + + inline expression_node_ptr 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_optimise_switch(Sequence& arg_list) + { + expression_node_ptr result = error_node(); + + for (std::size_t i = 0; i < (arg_list.size() / 2); ++i) + { + expression_node_ptr condition = arg_list[(2 * i) ]; + expression_node_ptr consequent = arg_list[(2 * i) + 1]; + + if ((0 == result) && details::is_true(condition)) + { + result = consequent; + break; + } + } + + if (0 == result) + { + result = arg_list.back(); + } + + for (std::size_t i = 0; i < arg_list.size(); ++i) + { + expression_node_ptr current_expr = arg_list[i]; + + if (current_expr && (current_expr != result)) + { + free_node(*node_allocator_,current_expr); + } + } + + return result; + } + + template class Sequence> + inline expression_node_ptr const_optimise_mswitch(Sequence& arg_list) + { + expression_node_ptr result = error_node(); + + for (std::size_t i = 0; i < (arg_list.size() / 2); ++i) + { + expression_node_ptr condition = arg_list[(2 * i) ]; + expression_node_ptr consequent = arg_list[(2 * i) + 1]; + + if (details::is_true(condition)) + { + result = consequent; + } + } + + if (0 == result) + { + T zero = T(0); + result = node_allocator_->allocate(zero); + } + + for (std::size_t i = 0; i < arg_list.size(); ++i) + { + expression_node_ptr& current_expr = arg_list[i]; + + if (current_expr && (current_expr != result)) + { + free_node(*node_allocator_,current_expr); + } + } + + return result; + } + + struct switch_nodes + { + typedef std::vector arg_list_t; + + #define case_stmt(N) \ + if (is_true(arg[(2 * N)])) { return arg[(2 * N) + 1]->value(); } \ + + struct switch_1 + { + static inline T process(const arg_list_t& arg) + { + case_stmt(0) + return arg.back()->value(); + } }; - - struct synthesize_vovovoc_expression0 - { - typedef typename vovovoc_t::type0 node_type; - typedef typename vovovoc_t::sf4_type sf4_type; - typedef typename node_type::T0 T0; - typedef typename node_type::T1 T1; - typedef typename node_type::T2 T2; - typedef typename node_type::T3 T3; - - static inline expression_node_ptr process(expression_generator& expr_gen, - const details::operator_type& operation, - expression_node_ptr (&branch)[2]) - { - // (v0 o0 v1) o1 (v2 o2 c) - const details::vov_base_node* vov = static_cast*>(branch[0]); - const details::voc_base_node* voc = static_cast*>(branch[1]); - const Type& v0 = vov->v0(); - const Type& v1 = vov->v1(); - const Type& v2 = voc->v (); - const Type c = voc->c (); - const details::operator_type o0 = vov->operation(); - const details::operator_type o1 = operation; - const details::operator_type o2 = voc->operation(); - - binary_functor_t f0 = reinterpret_cast(0); - binary_functor_t f1 = reinterpret_cast(0); - binary_functor_t f2 = reinterpret_cast(0); - - details::free_node(*(expr_gen.node_allocator_),branch[0]); - details::free_node(*(expr_gen.node_allocator_),branch[1]); - - expression_node_ptr result = error_node(); - - if (expr_gen.parser_->settings_.strength_reduction_enabled()) - { - // (v0 / v1) * (v2 / c) --> (vovovoc) (v0 * v2) / (v1 * c) - if ((details::e_div == o0) && (details::e_mul == o1) && (details::e_div == o2)) - { - const bool synthesis_result = - synthesize_sf4ext_expression:: - template compile(expr_gen,"(t*t)/(t*t)",v0,v2,v1,c,result); - - exprtk_debug(("(v0 / v1) * (v2 / c) --> (vovovoc) (v0 * v2) / (v1 * c)\n")); - - return (synthesis_result) ? result : error_node(); - } - // (v0 / v1) / (v2 / c) --> (vocovov) (v0 * c) / (v1 * v2) - if ((details::e_div == o0) && (details::e_div == o1) && (details::e_div == o2)) - { - const bool synthesis_result = - synthesize_sf4ext_expression:: - template compile(expr_gen,"(t*t)/(t*t)",v0,c,v1,v2,result); - - exprtk_debug(("(v0 / v1) / (v2 / c) --> (vocovov) (v0 * c) / (v1 * v2)\n")); - - return (synthesis_result) ? result : error_node(); - } - } - - if (synthesize_sf4ext_expression::template compile(expr_gen,id(expr_gen,o0,o1,o2),v0,v1,v2,c,result)) - return result; - else if (!expr_gen.valid_operator(o0,f0)) - return error_node(); - else if (!expr_gen.valid_operator(o1,f1)) - return error_node(); - else if (!expr_gen.valid_operator(o2,f2)) - return error_node(); - else - return node_type::allocate(*(expr_gen.node_allocator_),v0,v1,v2,c,f0,f1,f2); - } - - static inline std::string id(expression_generator& expr_gen, - const details::operator_type o0, - const details::operator_type o1, - const details::operator_type o2) - { - return (details::build_string() << "(t" << expr_gen.to_str(o0) << "t)" << expr_gen.to_str(o1) << "(t" << expr_gen.to_str(o2) << "t)"); - } + + struct switch_2 + { + static inline T process(const arg_list_t& arg) + { + case_stmt(0) case_stmt(1) + return arg.back()->value(); + } }; - - struct synthesize_vovocov_expression0 - { - typedef typename vovocov_t::type0 node_type; - typedef typename vovocov_t::sf4_type sf4_type; - typedef typename node_type::T0 T0; - typedef typename node_type::T1 T1; - typedef typename node_type::T2 T2; - typedef typename node_type::T3 T3; - - static inline expression_node_ptr process(expression_generator& expr_gen, - const details::operator_type& operation, - expression_node_ptr (&branch)[2]) - { - // (v0 o0 v1) o1 (c o2 v2) - const details::vov_base_node* vov = static_cast*>(branch[0]); - const details::cov_base_node* cov = static_cast*>(branch[1]); - const Type& v0 = vov->v0(); - const Type& v1 = vov->v1(); - const Type& v2 = cov->v (); - const Type c = cov->c (); - const details::operator_type o0 = vov->operation(); - const details::operator_type o1 = operation; - const details::operator_type o2 = cov->operation(); - - binary_functor_t f0 = reinterpret_cast(0); - binary_functor_t f1 = reinterpret_cast(0); - binary_functor_t f2 = reinterpret_cast(0); - - details::free_node(*(expr_gen.node_allocator_),branch[0]); - details::free_node(*(expr_gen.node_allocator_),branch[1]); - - expression_node_ptr result = error_node(); - - if (expr_gen.parser_->settings_.strength_reduction_enabled()) - { - // (v0 / v1) * (c / v2) --> (vocovov) (v0 * c) / (v1 * v2) - if ((details::e_div == o0) && (details::e_mul == o1) && (details::e_div == o2)) - { - const bool synthesis_result = - synthesize_sf4ext_expression:: - template compile(expr_gen,"(t*t)/(t*t)",v0,c,v1,v2,result); - - exprtk_debug(("(v0 / v1) * (c / v2) --> (vocovov) (v0 * c) / (v1 * v2)\n")); - - return (synthesis_result) ? result : error_node(); - } - // (v0 / v1) / (c / v2) --> (vovovoc) (v0 * v2) / (v1 * c) - if ((details::e_div == o0) && (details::e_div == o1) && (details::e_div == o2)) - { - const bool synthesis_result = - synthesize_sf4ext_expression:: - template compile(expr_gen,"(t*t)/(t*t)",v0,v2,v1,c,result); - - exprtk_debug(("(v0 / v1) / (c / v2) --> (vovovoc) (v0 * v2) / (v1 * c)\n")); - - return (synthesis_result) ? result : error_node(); - } - } - - if (synthesize_sf4ext_expression::template compile(expr_gen,id(expr_gen,o0,o1,o2),v0,v1,c,v2,result)) - return result; - else if (!expr_gen.valid_operator(o0,f0)) - return error_node(); - else if (!expr_gen.valid_operator(o1,f1)) - return error_node(); - else if (!expr_gen.valid_operator(o2,f2)) - return error_node(); - else - return node_type::allocate(*(expr_gen.node_allocator_),v0,v1,c,v2,f0,f1,f2); - } - - static inline std::string id(expression_generator& expr_gen, - const details::operator_type o0, - const details::operator_type o1, - const details::operator_type o2) - { - return (details::build_string() << "(t" << expr_gen.to_str(o0) << "t)" << expr_gen.to_str(o1) << "(t" << expr_gen.to_str(o2) << "t)"); - } + + struct switch_3 + { + static inline T process(const arg_list_t& arg) + { + case_stmt(0) case_stmt(1) + case_stmt(2) + return arg.back()->value(); + } }; - - struct synthesize_vocovov_expression0 - { - typedef typename vocovov_t::type0 node_type; - typedef typename vocovov_t::sf4_type sf4_type; - typedef typename node_type::T0 T0; - typedef typename node_type::T1 T1; - typedef typename node_type::T2 T2; - typedef typename node_type::T3 T3; - - static inline expression_node_ptr process(expression_generator& expr_gen, - const details::operator_type& operation, - expression_node_ptr (&branch)[2]) - { - // (v0 o0 c) o1 (v1 o2 v2) - const details::voc_base_node* voc = static_cast*>(branch[0]); - const details::vov_base_node* vov = static_cast*>(branch[1]); - const Type c = voc->c (); - const Type& v0 = voc->v (); - const Type& v1 = vov->v0(); - const Type& v2 = vov->v1(); - const details::operator_type o0 = voc->operation(); - const details::operator_type o1 = operation; - const details::operator_type o2 = vov->operation(); - - binary_functor_t f0 = reinterpret_cast(0); - binary_functor_t f1 = reinterpret_cast(0); - binary_functor_t f2 = reinterpret_cast(0); - - details::free_node(*(expr_gen.node_allocator_),branch[0]); - details::free_node(*(expr_gen.node_allocator_),branch[1]); - - expression_node_ptr result = error_node(); - - if (expr_gen.parser_->settings_.strength_reduction_enabled()) - { - // (v0 / c) * (v1 / v2) --> (vovocov) (v0 * v1) / (c * v2) - if ((details::e_div == o0) && (details::e_mul == o1) && (details::e_div == o2)) - { - const bool synthesis_result = - synthesize_sf4ext_expression:: - template compile(expr_gen,"(t*t)/(t*t)",v0,v1,c,v2,result); - - exprtk_debug(("(v0 / c) * (v1 / v2) --> (vovocov) (v0 * v1) / (c * v2)\n")); - - return (synthesis_result) ? result : error_node(); - } - // (v0 / c) / (v1 / v2) --> (vovocov) (v0 * v2) / (c * v1) - if ((details::e_div == o0) && (details::e_div == o1) && (details::e_div == o2)) - { - const bool synthesis_result = - synthesize_sf4ext_expression:: - template compile(expr_gen,"(t*t)/(t*t)",v0,v2,c,v1,result); - - exprtk_debug(("(v0 / c) / (v1 / v2) --> (vovocov) (v0 * v2) / (c * v1)\n")); - - return (synthesis_result) ? result : error_node(); - } - } - - if (synthesize_sf4ext_expression::template compile(expr_gen,id(expr_gen,o0,o1,o2),v0,c,v1,v2,result)) - return result; - else if (!expr_gen.valid_operator(o0,f0)) - return error_node(); - else if (!expr_gen.valid_operator(o1,f1)) - return error_node(); - else if (!expr_gen.valid_operator(o2,f2)) - return error_node(); - else - return node_type::allocate(*(expr_gen.node_allocator_),v0,c,v1,v2,f0,f1,f2); - } - - static inline std::string id(expression_generator& expr_gen, - const details::operator_type o0, - const details::operator_type o1, - const details::operator_type o2) - { - return (details::build_string() << "(t" << expr_gen.to_str(o0) << "t)" << expr_gen.to_str(o1) << "(t" << expr_gen.to_str(o2) << "t)"); - } + + struct switch_4 + { + static inline T process(const arg_list_t& arg) + { + case_stmt(0) case_stmt(1) + case_stmt(2) case_stmt(3) + return arg.back()->value(); + } }; - - struct synthesize_covovov_expression0 - { - typedef typename covovov_t::type0 node_type; - typedef typename covovov_t::sf4_type sf4_type; - typedef typename node_type::T0 T0; - typedef typename node_type::T1 T1; - typedef typename node_type::T2 T2; - typedef typename node_type::T3 T3; - - static inline expression_node_ptr process(expression_generator& expr_gen, - const details::operator_type& operation, - expression_node_ptr (&branch)[2]) - { - // (c o0 v0) o1 (v1 o2 v2) - const details::cov_base_node* cov = static_cast*>(branch[0]); - const details::vov_base_node* vov = static_cast*>(branch[1]); - const Type c = cov->c (); - const Type& v0 = cov->v (); - const Type& v1 = vov->v0(); - const Type& v2 = vov->v1(); - const details::operator_type o0 = cov->operation(); - const details::operator_type o1 = operation; - const details::operator_type o2 = vov->operation(); - - binary_functor_t f0 = reinterpret_cast(0); - binary_functor_t f1 = reinterpret_cast(0); - binary_functor_t f2 = reinterpret_cast(0); - - details::free_node(*(expr_gen.node_allocator_),branch[0]); - details::free_node(*(expr_gen.node_allocator_),branch[1]); - - expression_node_ptr result = error_node(); - - if (expr_gen.parser_->settings_.strength_reduction_enabled()) - { - // (c / v0) * (v1 / v2) --> (covovov) (c * v1) / (v0 * v2) - if ((details::e_div == o0) && (details::e_mul == o1) && (details::e_div == o2)) - { - const bool synthesis_result = - synthesize_sf4ext_expression:: - template compile(expr_gen,"(t*t)/(t*t)",c,v1,v0,v2,result); - - exprtk_debug(("(c / v0) * (v1 / v2) --> (covovov) (c * v1) / (v0 * v2)\n")); - - return (synthesis_result) ? result : error_node(); - } - // (c / v0) / (v1 / v2) --> (covovov) (c * v2) / (v0 * v1) - if ((details::e_div == o0) && (details::e_div == o1) && (details::e_div == o2)) - { - const bool synthesis_result = - synthesize_sf4ext_expression:: - template compile(expr_gen,"(t*t)/(t*t)",c,v2,v0,v1,result); - - exprtk_debug(("(c / v0) / (v1 / v2) --> (covovov) (c * v2) / (v0 * v1)\n")); - - return (synthesis_result) ? result : error_node(); - } - } - - if (synthesize_sf4ext_expression::template compile(expr_gen,id(expr_gen,o0,o1,o2),c,v0,v1,v2,result)) - return result; - else if (!expr_gen.valid_operator(o0,f0)) - return error_node(); - else if (!expr_gen.valid_operator(o1,f1)) - return error_node(); - else if (!expr_gen.valid_operator(o2,f2)) - return error_node(); - else - return node_type::allocate(*(expr_gen.node_allocator_),c,v0,v1,v2,f0,f1,f2); - } - - static inline std::string id(expression_generator& expr_gen, - const details::operator_type o0, - const details::operator_type o1, - const details::operator_type o2) - { - return (details::build_string() << "(t" << expr_gen.to_str(o0) << "t)" << expr_gen.to_str(o1) << "(t" << expr_gen.to_str(o2) << "t)"); - } + + struct switch_5 + { + static inline T process(const arg_list_t& arg) + { + case_stmt(0) case_stmt(1) + case_stmt(2) case_stmt(3) + case_stmt(4) + return arg.back()->value(); + } }; - - struct synthesize_covocov_expression0 - { - typedef typename covocov_t::type0 node_type; - typedef typename covocov_t::sf4_type sf4_type; - typedef typename node_type::T0 T0; - typedef typename node_type::T1 T1; - typedef typename node_type::T2 T2; - typedef typename node_type::T3 T3; - - static inline expression_node_ptr process(expression_generator& expr_gen, - const details::operator_type& operation, - expression_node_ptr (&branch)[2]) - { - // (c0 o0 v0) o1 (c1 o2 v1) - const details::cov_base_node* cov0 = static_cast*>(branch[0]); - const details::cov_base_node* cov1 = static_cast*>(branch[1]); - const Type c0 = cov0->c(); - const Type& v0 = cov0->v(); - const Type c1 = cov1->c(); - const Type& v1 = cov1->v(); - const details::operator_type o0 = cov0->operation(); - const details::operator_type o1 = operation; - const details::operator_type o2 = cov1->operation(); - - binary_functor_t f0 = reinterpret_cast(0); - binary_functor_t f1 = reinterpret_cast(0); - binary_functor_t f2 = reinterpret_cast(0); - - details::free_node(*(expr_gen.node_allocator_),branch[0]); - details::free_node(*(expr_gen.node_allocator_),branch[1]); - - expression_node_ptr result = error_node(); - - if (expr_gen.parser_->settings_.strength_reduction_enabled()) - { - // (c0 + v0) + (c1 + v1) --> (covov) (c0 + c1) + v0 + v1 - if ((details::e_add == o0) && (details::e_add == o1) && (details::e_add == o2)) - { - const bool synthesis_result = - synthesize_sf3ext_expression:: - template compile(expr_gen,"(t+t)+t",(c0 + c1),v0,v1,result); - - exprtk_debug(("(c0 + v0) + (c1 + v1) --> (covov) (c0 + c1) + v0 + v1\n")); - - return (synthesis_result) ? result : error_node(); - } - // (c0 + v0) - (c1 + v1) --> (covov) (c0 - c1) + v0 - v1 - else if ((details::e_add == o0) && (details::e_sub == o1) && (details::e_add == o2)) - { - const bool synthesis_result = - synthesize_sf3ext_expression:: - template compile(expr_gen,"(t+t)-t",(c0 - c1),v0,v1,result); - - exprtk_debug(("(c0 + v0) - (c1 + v1) --> (covov) (c0 - c1) + v0 - v1\n")); - - return (synthesis_result) ? result : error_node(); - } - // (c0 - v0) - (c1 - v1) --> (covov) (c0 - c1) - v0 + v1 - else if ((details::e_sub == o0) && (details::e_sub == o1) && (details::e_sub == o2)) - { - const bool synthesis_result = - synthesize_sf3ext_expression:: - template compile(expr_gen,"(t-t)+t",(c0 - c1),v0,v1,result); - - exprtk_debug(("(c0 - v0) - (c1 - v1) --> (covov) (c0 - c1) - v0 + v1\n")); - - return (synthesis_result) ? result : error_node(); - } - // (c0 * v0) * (c1 * v1) --> (covov) (c0 * c1) * v0 * v1 - else if ((details::e_mul == o0) && (details::e_mul == o1) && (details::e_mul == o2)) - { - const bool synthesis_result = - synthesize_sf3ext_expression:: - template compile(expr_gen,"(t*t)*t",(c0 * c1),v0,v1,result); - - exprtk_debug(("(c0 * v0) * (c1 * v1) --> (covov) (c0 * c1) * v0 * v1\n")); - - return (synthesis_result) ? result : error_node(); - } - // (c0 * v0) / (c1 * v1) --> (covov) (c0 / c1) * (v0 / v1) - else if ((details::e_mul == o0) && (details::e_div == o1) && (details::e_mul == o2)) - { - const bool synthesis_result = - synthesize_sf3ext_expression:: - template compile(expr_gen,"(t*t)/t",(c0 / c1),v0,v1,result); - - exprtk_debug(("(c0 * v0) / (c1 * v1) --> (covov) (c0 / c1) * (v0 / v1)\n")); - - return (synthesis_result) ? result : error_node(); - } - // (c0 / v0) * (c1 / v1) --> (covov) (c0 * c1) / (v0 * v1) - else if ((details::e_div == o0) && (details::e_mul == o1) && (details::e_div == o2)) - { - const bool synthesis_result = - synthesize_sf3ext_expression:: - template compile(expr_gen,"t/(t*t)",(c0 * c1),v0,v1,result); - - exprtk_debug(("(c0 / v0) * (c1 / v1) --> (covov) (c0 * c1) / (v0 * v1)\n")); - - return (synthesis_result) ? result : error_node(); - } - // (c0 / v0) / (c1 / v1) --> (covov) ((c0 / c1) * v1) / v0 - else if ((details::e_div == o0) && (details::e_div == o1) && (details::e_div == o2)) - { - const bool synthesis_result = - synthesize_sf3ext_expression:: - template compile(expr_gen,"(t*t)/t",(c0 / c1),v1,v0,result); - - exprtk_debug(("(c0 / v0) / (c1 / v1) --> (covov) ((c0 / c1) * v1) / v0\n")); - - return (synthesis_result) ? result : error_node(); - } - // (c0 * v0) / (c1 / v1) --> (covov) (c0 / c1) * (v0 * v1) - else if ((details::e_mul == o0) && (details::e_div == o1) && (details::e_div == o2)) - { - const bool synthesis_result = - synthesize_sf3ext_expression:: - template compile(expr_gen,"t*(t*t)",(c0 / c1),v0,v1,result); - - exprtk_debug(("(c0 * v0) / (c1 / v1) --> (covov) (c0 / c1) * (v0 * v1)\n")); - - return (synthesis_result) ? result : error_node(); - } - // (c0 / v0) / (c1 * v1) --> (covov) (c0 / c1) / (v0 * v1) - else if ((details::e_div == o0) && (details::e_div == o1) && (details::e_mul == o2)) - { - const bool synthesis_result = - synthesize_sf3ext_expression:: - template compile(expr_gen,"t/(t*t)",(c0 / c1),v0,v1,result); - - exprtk_debug(("(c0 / v0) / (c1 * v1) --> (covov) (c0 / c1) / (v0 * v1)\n")); - - return (synthesis_result) ? result : error_node(); - } - // (c * v0) +/- (c * v1) --> (covov) c * (v0 +/- v1) - else if ( - (std::equal_to()(c0,c1)) && - (details::e_mul == o0) && - (details::e_mul == o2) && - ( - (details::e_add == o1) || - (details::e_sub == o1) - ) - ) - { - std::string specfunc; - - switch (o1) - { - case details::e_add : specfunc = "t*(t+t)"; break; - case details::e_sub : specfunc = "t*(t-t)"; break; - default : return error_node(); - } - - const bool synthesis_result = - synthesize_sf3ext_expression:: - template compile(expr_gen,specfunc,c0,v0,v1,result); - - exprtk_debug(("(c * v0) +/- (c * v1) --> (covov) c * (v0 +/- v1)\n")); - - return (synthesis_result) ? result : error_node(); - } - } - - if (synthesize_sf4ext_expression::template compile(expr_gen,id(expr_gen,o0,o1,o2),c0,v0,c1,v1,result)) - return result; - else if (!expr_gen.valid_operator(o0,f0)) - return error_node(); - else if (!expr_gen.valid_operator(o1,f1)) - return error_node(); - else if (!expr_gen.valid_operator(o2,f2)) - return error_node(); - else - return node_type::allocate(*(expr_gen.node_allocator_),c0,v0,c1,v1,f0,f1,f2); - } - - static inline std::string id(expression_generator& expr_gen, - const details::operator_type o0, - const details::operator_type o1, - const details::operator_type o2) - { - return (details::build_string() << "(t" << expr_gen.to_str(o0) << "t)" << expr_gen.to_str(o1) << "(t" << expr_gen.to_str(o2) << "t)"); - } + + struct switch_6 + { + static inline T process(const arg_list_t& arg) + { + case_stmt(0) case_stmt(1) + case_stmt(2) case_stmt(3) + case_stmt(4) case_stmt(5) + return arg.back()->value(); + } }; - - struct synthesize_vocovoc_expression0 - { - typedef typename vocovoc_t::type0 node_type; - typedef typename vocovoc_t::sf4_type sf4_type; - typedef typename node_type::T0 T0; - typedef typename node_type::T1 T1; - typedef typename node_type::T2 T2; - typedef typename node_type::T3 T3; - - static inline expression_node_ptr process(expression_generator& expr_gen, - const details::operator_type& operation, - expression_node_ptr (&branch)[2]) - { - // (v0 o0 c0) o1 (v1 o2 c1) - const details::voc_base_node* voc0 = static_cast*>(branch[0]); - const details::voc_base_node* voc1 = static_cast*>(branch[1]); - const Type c0 = voc0->c(); - const Type& v0 = voc0->v(); - const Type c1 = voc1->c(); - const Type& v1 = voc1->v(); - const details::operator_type o0 = voc0->operation(); - const details::operator_type o1 = operation; - const details::operator_type o2 = voc1->operation(); - - binary_functor_t f0 = reinterpret_cast(0); - binary_functor_t f1 = reinterpret_cast(0); - binary_functor_t f2 = reinterpret_cast(0); - - details::free_node(*(expr_gen.node_allocator_),branch[0]); - details::free_node(*(expr_gen.node_allocator_),branch[1]); - - expression_node_ptr result = error_node(); - - if (expr_gen.parser_->settings_.strength_reduction_enabled()) - { - // (v0 + c0) + (v1 + c1) --> (covov) (c0 + c1) + v0 + v1 - if ((details::e_add == o0) && (details::e_add == o1) && (details::e_add == o2)) - { - const bool synthesis_result = - synthesize_sf3ext_expression:: - template compile(expr_gen,"(t+t)+t",(c0 + c1),v0,v1,result); - - exprtk_debug(("(v0 + c0) + (v1 + c1) --> (covov) (c0 + c1) + v0 + v1\n")); - - return (synthesis_result) ? result : error_node(); - } - // (v0 + c0) - (v1 + c1) --> (covov) (c0 - c1) + v0 - v1 - else if ((details::e_add == o0) && (details::e_sub == o1) && (details::e_add == o2)) - { - const bool synthesis_result = - synthesize_sf3ext_expression:: - template compile(expr_gen,"(t+t)-t",(c0 - c1),v0,v1,result); - - exprtk_debug(("(v0 + c0) - (v1 + c1) --> (covov) (c0 - c1) + v0 - v1\n")); - - return (synthesis_result) ? result : error_node(); - } - // (v0 - c0) - (v1 - c1) --> (covov) (c1 - c0) + v0 - v1 - else if ((details::e_sub == o0) && (details::e_sub == o1) && (details::e_sub == o2)) - { - const bool synthesis_result = - synthesize_sf3ext_expression:: - template compile(expr_gen,"(t+t)-t",(c1 - c0),v0,v1,result); - - exprtk_debug(("(v0 - c0) - (v1 - c1) --> (covov) (c1 - c0) + v0 - v1\n")); - - return (synthesis_result) ? result : error_node(); - } - // (v0 * c0) * (v1 * c1) --> (covov) (c0 * c1) * v0 * v1 - else if ((details::e_mul == o0) && (details::e_mul == o1) && (details::e_mul == o2)) - { - const bool synthesis_result = - synthesize_sf3ext_expression:: - template compile(expr_gen,"(t*t)*t",(c0 * c1),v0,v1,result); - - exprtk_debug(("(v0 * c0) * (v1 * c1) --> (covov) (c0 * c1) * v0 * v1\n")); - - return (synthesis_result) ? result : error_node(); - } - // (v0 * c0) / (v1 * c1) --> (covov) (c0 / c1) * (v0 / v1) - else if ((details::e_mul == o0) && (details::e_div == o1) && (details::e_mul == o2)) - { - const bool synthesis_result = - synthesize_sf3ext_expression:: - template compile(expr_gen,"(t*t)/t",(c0 / c1),v0,v1,result); - - exprtk_debug(("(v0 * c0) / (v1 * c1) --> (covov) (c0 / c1) * (v0 / v1)\n")); - - return (synthesis_result) ? result : error_node(); - } - // (v0 / c0) * (v1 / c1) --> (covov) (1 / (c0 * c1)) * v0 * v1 - else if ((details::e_div == o0) && (details::e_mul == o1) && (details::e_div == o2)) - { - const bool synthesis_result = - synthesize_sf3ext_expression:: - template compile(expr_gen,"(t*t)*t",Type(1) / (c0 * c1),v0,v1,result); - - exprtk_debug(("(v0 / c0) * (v1 / c1) --> (covov) (1 / (c0 * c1)) * v0 * v1\n")); - - return (synthesis_result) ? result : error_node(); - } - // (v0 / c0) / (v1 / c1) --> (covov) ((c1 / c0) * v0) / v1 - else if ((details::e_div == o0) && (details::e_div == o1) && (details::e_div == o2)) - { - const bool synthesis_result = - synthesize_sf3ext_expression:: - template compile(expr_gen,"(t*t)/t",(c1 / c0),v0,v1,result); - - exprtk_debug(("(v0 / c0) / (v1 / c1) --> (covov) ((c1 / c0) * v0) / v1\n")); - - return (synthesis_result) ? result : error_node(); - } - // (v0 * c0) / (v1 / c1) --> (covov) (c0 * c1) * (v0 / v1) - else if ((details::e_mul == o0) && (details::e_div == o1) && (details::e_div == o2)) - { - const bool synthesis_result = - synthesize_sf3ext_expression:: - template compile(expr_gen,"t*(t/t)",(c0 * c1),v0,v1,result); - - exprtk_debug(("(v0 * c0) / (v1 / c1) --> (covov) (c0 * c1) * (v0 / v1)\n")); - - return (synthesis_result) ? result : error_node(); - } - // (v0 / c0) / (v1 * c1) --> (covov) (1 / (c0 * c1)) * v0 / v1 - else if ((details::e_div == o0) && (details::e_div == o1) && (details::e_mul == o2)) - { - const bool synthesis_result = - synthesize_sf3ext_expression:: - template compile(expr_gen,"t*(t/t)",Type(1) / (c0 * c1),v0,v1,result); - - exprtk_debug(("(v0 / c0) / (v1 * c1) --> (covov) (1 / (c0 * c1)) * v0 / v1\n")); - - return (synthesis_result) ? result : error_node(); - } - // (v0 / c0) * (v1 + c1) --> (vocovoc) (v0 * (1 / c0)) * (v1 + c1) - else if ((details::e_div == o0) && (details::e_mul == o1) && (details::e_add == o2)) - { - const bool synthesis_result = - synthesize_sf4ext_expression:: - template compile(expr_gen,"(t*t)*(t+t)",v0,T(1) / c0,v1,c1,result); - - exprtk_debug(("(v0 / c0) * (v1 + c1) --> (vocovoc) (v0 * (1 / c0)) * (v1 + c1)\n")); - - return (synthesis_result) ? result : error_node(); - } - // (v0 / c0) * (v1 - c1) --> (vocovoc) (v0 * (1 / c0)) * (v1 - c1) - else if ((details::e_div == o0) && (details::e_mul == o1) && (details::e_sub == o2)) - { - const bool synthesis_result = - synthesize_sf4ext_expression:: - template compile(expr_gen,"(t*t)*(t-t)",v0,T(1) / c0,v1,c1,result); - - exprtk_debug(("(v0 / c0) * (v1 - c1) --> (vocovoc) (v0 * (1 / c0)) * (v1 - c1)\n")); - - return (synthesis_result) ? result : error_node(); - } - // (v0 * c) +/- (v1 * c) --> (covov) c * (v0 +/- v1) - else if ( - (std::equal_to()(c0,c1)) && - (details::e_mul == o0) && - (details::e_mul == o2) && - ( - (details::e_add == o1) || - (details::e_sub == o1) - ) - ) - { - std::string specfunc; - - switch (o1) - { - case details::e_add : specfunc = "t*(t+t)"; break; - case details::e_sub : specfunc = "t*(t-t)"; break; - default : return error_node(); - } - - const bool synthesis_result = - synthesize_sf3ext_expression:: - template compile(expr_gen,specfunc,c0,v0,v1,result); - - exprtk_debug(("(v0 * c) +/- (v1 * c) --> (covov) c * (v0 +/- v1)\n")); - - return (synthesis_result) ? result : error_node(); - } - // (v0 / c) +/- (v1 / c) --> (vovoc) (v0 +/- v1) / c - else if ( - (std::equal_to()(c0,c1)) && - (details::e_div == o0) && - (details::e_div == o2) && - ( - (details::e_add == o1) || - (details::e_sub == o1) - ) - ) - { - std::string specfunc; - - switch (o1) - { - case details::e_add : specfunc = "(t+t)/t"; break; - case details::e_sub : specfunc = "(t-t)/t"; break; - default : return error_node(); - } - - const bool synthesis_result = - synthesize_sf3ext_expression:: - template compile(expr_gen,specfunc,v0,v1,c0,result); - - exprtk_debug(("(v0 / c) +/- (v1 / c) --> (vovoc) (v0 +/- v1) / c\n")); - - return (synthesis_result) ? result : error_node(); - } - } - - if (synthesize_sf4ext_expression::template compile(expr_gen,id(expr_gen,o0,o1,o2),v0,c0,v1,c1,result)) - return result; - else if (!expr_gen.valid_operator(o0,f0)) - return error_node(); - else if (!expr_gen.valid_operator(o1,f1)) - return error_node(); - else if (!expr_gen.valid_operator(o2,f2)) - return error_node(); - else - return node_type::allocate(*(expr_gen.node_allocator_),v0,c0,v1,c1,f0,f1,f2); - } - - static inline std::string id(expression_generator& expr_gen, - const details::operator_type o0, - const details::operator_type o1, - const details::operator_type o2) - { - return (details::build_string() << "(t" << expr_gen.to_str(o0) << "t)" << expr_gen.to_str(o1) << "(t" << expr_gen.to_str(o2) << "t)"); - } + + struct switch_7 + { + static inline T process(const arg_list_t& arg) + { + case_stmt(0) case_stmt(1) + case_stmt(2) case_stmt(3) + case_stmt(4) case_stmt(5) + case_stmt(6) + return arg.back()->value(); + } }; - - struct synthesize_covovoc_expression0 - { - typedef typename covovoc_t::type0 node_type; - typedef typename covovoc_t::sf4_type sf4_type; - typedef typename node_type::T0 T0; - typedef typename node_type::T1 T1; - typedef typename node_type::T2 T2; - typedef typename node_type::T3 T3; - - static inline expression_node_ptr process(expression_generator& expr_gen, - const details::operator_type& operation, - expression_node_ptr (&branch)[2]) - { - // (c0 o0 v0) o1 (v1 o2 c1) - const details::cov_base_node* cov = static_cast*>(branch[0]); - const details::voc_base_node* voc = static_cast*>(branch[1]); - const Type c0 = cov->c(); - const Type& v0 = cov->v(); - const Type c1 = voc->c(); - const Type& v1 = voc->v(); - const details::operator_type o0 = cov->operation(); - const details::operator_type o1 = operation; - const details::operator_type o2 = voc->operation(); - - binary_functor_t f0 = reinterpret_cast(0); - binary_functor_t f1 = reinterpret_cast(0); - binary_functor_t f2 = reinterpret_cast(0); - - details::free_node(*(expr_gen.node_allocator_),branch[0]); - details::free_node(*(expr_gen.node_allocator_),branch[1]); - - expression_node_ptr result = error_node(); - - if (expr_gen.parser_->settings_.strength_reduction_enabled()) - { - // (c0 + v0) + (v1 + c1) --> (covov) (c0 + c1) + v0 + v1 - if ((details::e_add == o0) && (details::e_add == o1) && (details::e_add == o2)) - { - const bool synthesis_result = - synthesize_sf3ext_expression:: - template compile(expr_gen,"(t+t)+t",(c0 + c1),v0,v1,result); - - exprtk_debug(("(c0 + v0) + (v1 + c1) --> (covov) (c0 + c1) + v0 + v1\n")); - - return (synthesis_result) ? result : error_node(); - } - // (c0 + v0) - (v1 + c1) --> (covov) (c0 - c1) + v0 - v1 - else if ((details::e_add == o0) && (details::e_sub == o1) && (details::e_add == o2)) - { - const bool synthesis_result = - synthesize_sf3ext_expression:: - template compile(expr_gen,"(t+t)-t",(c0 - c1),v0,v1,result); - - exprtk_debug(("(c0 + v0) - (v1 + c1) --> (covov) (c0 - c1) + v0 - v1\n")); - - return (synthesis_result) ? result : error_node(); - } - // (c0 - v0) - (v1 - c1) --> (covov) (c0 + c1) - v0 - v1 - else if ((details::e_sub == o0) && (details::e_sub == o1) && (details::e_sub == o2)) - { - const bool synthesis_result = - synthesize_sf3ext_expression:: - template compile(expr_gen,"t-(t+t)",(c0 + c1),v0,v1,result); - - exprtk_debug(("(c0 - v0) - (v1 - c1) --> (covov) (c0 + c1) - v0 - v1\n")); - - return (synthesis_result) ? result : error_node(); - } - // (c0 * v0) * (v1 * c1) --> (covov) (c0 * c1) * v0 * v1 - else if ((details::e_mul == o0) && (details::e_mul == o1) && (details::e_mul == o2)) - { - const bool synthesis_result = - synthesize_sf3ext_expression:: - template compile(expr_gen,"(t*t)*t",(c0 * c1),v0,v1,result); - - exprtk_debug(("(c0 * v0) * (v1 * c1) --> (covov) (c0 * c1) * v0 * v1\n")); - - return (synthesis_result) ? result : error_node(); - } - // (c0 * v0) / (v1 * c1) --> (covov) (c0 / c1) * (v0 / v1) - else if ((details::e_mul == o0) && (details::e_div == o1) && (details::e_mul == o2)) - { - const bool synthesis_result = - synthesize_sf3ext_expression:: - template compile(expr_gen,"(t*t)/t",(c0 / c1),v0,v1,result); - - exprtk_debug(("(c0 * v0) / (v1 * c1) --> (covov) (c0 / c1) * (v0 / v1)\n")); - - return (synthesis_result) ? result : error_node(); - } - // (c0 / v0) * (v1 / c1) --> (covov) (c0 / c1) * (v1 / v0) - else if ((details::e_div == o0) && (details::e_mul == o1) && (details::e_div == o2)) - { - const bool synthesis_result = - synthesize_sf3ext_expression:: - template compile(expr_gen,"t*(t/t)",(c0 / c1),v1,v0,result); - - exprtk_debug(("(c0 / v0) * (v1 / c1) --> (covov) (c0 / c1) * (v1 / v0)\n")); - - return (synthesis_result) ? result : error_node(); - } - // (c0 / v0) / (v1 / c1) --> (covov) (c0 * c1) / (v0 * v1) - else if ((details::e_div == o0) && (details::e_div == o1) && (details::e_div == o2)) - { - const bool synthesis_result = - synthesize_sf3ext_expression:: - template compile(expr_gen,"t/(t*t)",(c0 * c1),v0,v1,result); - - exprtk_debug(("(c0 / v0) / (v1 / c1) --> (covov) (c0 * c1) / (v0 * v1)\n")); - - return (synthesis_result) ? result : error_node(); - } - // (c0 * v0) / (v1 / c1) --> (covov) (c0 * c1) * (v0 / v1) - else if ((details::e_mul == o0) && (details::e_div == o1) && (details::e_div == o2)) - { - const bool synthesis_result = - synthesize_sf3ext_expression:: - template compile(expr_gen,"(t*t)/t",(c0 * c1),v0,v1,result); - - exprtk_debug(("(c0 * v0) / (v1 / c1) --> (covov) (c0 * c1) * (v0 / v1)\n")); - - return (synthesis_result) ? result : error_node(); - } - // (c0 / v0) / (v1 * c1) --> (covov) (c0 / c1) / (v0 * v1) - else if ((details::e_div == o0) && (details::e_div == o1) && (details::e_mul == o2)) - { - const bool synthesis_result = - synthesize_sf3ext_expression:: - template compile(expr_gen,"t/(t*t)",(c0 / c1),v0,v1,result); - - exprtk_debug(("(c0 / v0) / (v1 * c1) --> (covov) (c0 / c1) / (v0 * v1)\n")); - - return (synthesis_result) ? result : error_node(); - } - // (c * v0) +/- (v1 * c) --> (covov) c * (v0 +/- v1) - else if ( - (std::equal_to()(c0,c1)) && - (details::e_mul == o0) && - (details::e_mul == o2) && - ( - (details::e_add == o1) || - (details::e_sub == o1) - ) - ) - { - std::string specfunc; - - switch (o1) - { - case details::e_add : specfunc = "t*(t+t)"; break; - case details::e_sub : specfunc = "t*(t-t)"; break; - default : return error_node(); - } - - const bool synthesis_result = - synthesize_sf3ext_expression:: - template compile(expr_gen,specfunc,c0,v0,v1,result); - - exprtk_debug(("(c * v0) +/- (v1 * c) --> (covov) c * (v0 +/- v1)\n")); - - return (synthesis_result) ? result : error_node(); - } - } - - if (synthesize_sf4ext_expression::template compile(expr_gen,id(expr_gen,o0,o1,o2),c0,v0,v1,c1,result)) - return result; - else if (!expr_gen.valid_operator(o0,f0)) + + #undef case_stmt + }; + + template class Sequence> + inline expression_node_ptr switch_statement(Sequence& arg_list) + { + if (arg_list.empty()) + return error_node(); + else if ( + !all_nodes_valid(arg_list) || + (arg_list.size() < 3) || + ((arg_list.size() % 2) != 1) + ) + { + details::free_all_nodes(*node_allocator_,arg_list); + + return error_node(); + } + else if (is_constant_foldable(arg_list)) + return const_optimise_switch(arg_list); + + switch ((arg_list.size() - 1) / 2) + { + #define case_stmt(N) \ + case N : \ + return node_allocator_-> \ + allocate >(arg_list); \ + + case_stmt(1) + case_stmt(2) + case_stmt(3) + case_stmt(4) + case_stmt(5) + case_stmt(6) + case_stmt(7) + #undef case_stmt + + default : return node_allocator_->allocate >(arg_list); + } + } + + template class Sequence> + inline expression_node_ptr multi_switch_statement(Sequence& arg_list) + { + if (!all_nodes_valid(arg_list)) + { + details::free_all_nodes(*node_allocator_,arg_list); + + return error_node(); + } + else if (is_constant_foldable(arg_list)) + return const_optimise_mswitch(arg_list); + else + return node_allocator_->allocate >(arg_list); + } + + #define unary_opr_switch_statements \ + case_stmt(details:: e_abs,details:: abs_op) \ + case_stmt(details:: e_acos,details:: acos_op) \ + case_stmt(details::e_acosh,details::acosh_op) \ + case_stmt(details:: e_asin,details:: asin_op) \ + case_stmt(details::e_asinh,details::asinh_op) \ + case_stmt(details:: e_atan,details:: atan_op) \ + case_stmt(details::e_atanh,details::atanh_op) \ + case_stmt(details:: e_ceil,details:: ceil_op) \ + case_stmt(details:: e_cos,details:: cos_op) \ + case_stmt(details:: e_cosh,details:: cosh_op) \ + case_stmt(details:: e_exp,details:: exp_op) \ + case_stmt(details::e_expm1,details::expm1_op) \ + case_stmt(details::e_floor,details::floor_op) \ + case_stmt(details:: e_log,details:: log_op) \ + case_stmt(details::e_log10,details::log10_op) \ + case_stmt(details:: e_log2,details:: log2_op) \ + case_stmt(details::e_log1p,details::log1p_op) \ + case_stmt(details:: e_neg,details:: neg_op) \ + case_stmt(details:: e_pos,details:: pos_op) \ + case_stmt(details::e_round,details::round_op) \ + case_stmt(details:: e_sin,details:: sin_op) \ + case_stmt(details:: e_sinc,details:: sinc_op) \ + case_stmt(details:: e_sinh,details:: sinh_op) \ + case_stmt(details:: e_sqrt,details:: sqrt_op) \ + case_stmt(details:: e_tan,details:: tan_op) \ + case_stmt(details:: e_tanh,details:: tanh_op) \ + case_stmt(details:: e_cot,details:: cot_op) \ + case_stmt(details:: e_sec,details:: sec_op) \ + case_stmt(details:: e_csc,details:: csc_op) \ + case_stmt(details:: e_r2d,details:: r2d_op) \ + case_stmt(details:: e_d2r,details:: d2r_op) \ + case_stmt(details:: e_d2g,details:: d2g_op) \ + case_stmt(details:: e_g2d,details:: g2d_op) \ + case_stmt(details:: e_notl,details:: notl_op) \ + case_stmt(details:: e_sgn,details:: sgn_op) \ + case_stmt(details:: e_erf,details:: erf_op) \ + case_stmt(details:: e_erfc,details:: erfc_op) \ + case_stmt(details:: e_ncdf,details:: ncdf_op) \ + case_stmt(details:: e_frac,details:: frac_op) \ + case_stmt(details::e_trunc,details::trunc_op) \ + + inline expression_node_ptr synthesize_uv_expression(const details::operator_type& operation, + expression_node_ptr (&branch)[1]) + { + T& v = static_cast*>(branch[0])->ref(); + + switch (operation) + { + #define case_stmt(op0,op1) \ + case op0 : return node_allocator_-> \ + allocate > >(v); \ + + unary_opr_switch_statements + #undef case_stmt + default : return error_node(); + } + } + + inline expression_node_ptr synthesize_uvec_expression(const details::operator_type& operation, + expression_node_ptr (&branch)[1]) + { + switch (operation) + { + #define case_stmt(op0,op1) \ + case op0 : return node_allocator_-> \ + allocate > > \ + (operation,branch[0]); \ + + unary_opr_switch_statements + #undef case_stmt + default : return error_node(); + } + } + + inline expression_node_ptr synthesize_unary_expression(const details::operator_type& operation, + expression_node_ptr (&branch)[1]) + { + switch (operation) + { + #define case_stmt(op0,op1) \ + case op0 : return node_allocator_-> \ + allocate > >(branch[0]); \ + + unary_opr_switch_statements + #undef case_stmt + default : return error_node(); + } + } + + inline expression_node_ptr const_optimise_sf3(const details::operator_type& operation, + expression_node_ptr (&branch)[3]) + { + expression_node_ptr temp_node = error_node(); + + switch (operation) + { + #define case_stmt(op) \ + case details::e_sf##op : temp_node = node_allocator_-> \ + allocate > > \ + (operation,branch); \ + break; \ + + case_stmt(00) case_stmt(01) case_stmt(02) case_stmt(03) + case_stmt(04) case_stmt(05) case_stmt(06) case_stmt(07) + case_stmt(08) case_stmt(09) case_stmt(10) case_stmt(11) + case_stmt(12) case_stmt(13) case_stmt(14) case_stmt(15) + case_stmt(16) case_stmt(17) case_stmt(18) case_stmt(19) + case_stmt(20) case_stmt(21) case_stmt(22) case_stmt(23) + case_stmt(24) case_stmt(25) case_stmt(26) case_stmt(27) + case_stmt(28) case_stmt(29) case_stmt(30) case_stmt(31) + case_stmt(32) case_stmt(33) case_stmt(34) case_stmt(35) + case_stmt(36) case_stmt(37) case_stmt(38) case_stmt(39) + case_stmt(40) case_stmt(41) case_stmt(42) case_stmt(43) + case_stmt(44) case_stmt(45) case_stmt(46) case_stmt(47) + #undef case_stmt + default : return error_node(); + } + + T v = temp_node->value(); + + details::free_node(*node_allocator_,temp_node); + + return node_allocator_->allocate(v); + } + + inline expression_node_ptr varnode_optimise_sf3(const details::operator_type& operation, expression_node_ptr (&branch)[3]) + { + typedef details::variable_node* variable_ptr; + + const Type& v0 = static_cast(branch[0])->ref(); + const Type& v1 = static_cast(branch[1])->ref(); + const Type& v2 = static_cast(branch[2])->ref(); + + switch (operation) + { + #define case_stmt(op) \ + case details::e_sf##op : return node_allocator_-> \ + allocate_rrr > > \ + (v0,v1,v2); \ + + case_stmt(00) case_stmt(01) case_stmt(02) case_stmt(03) + case_stmt(04) case_stmt(05) case_stmt(06) case_stmt(07) + case_stmt(08) case_stmt(09) case_stmt(10) case_stmt(11) + case_stmt(12) case_stmt(13) case_stmt(14) case_stmt(15) + case_stmt(16) case_stmt(17) case_stmt(18) case_stmt(19) + case_stmt(20) case_stmt(21) case_stmt(22) case_stmt(23) + case_stmt(24) case_stmt(25) case_stmt(26) case_stmt(27) + case_stmt(28) case_stmt(29) case_stmt(30) case_stmt(31) + case_stmt(32) case_stmt(33) case_stmt(34) case_stmt(35) + case_stmt(36) case_stmt(37) case_stmt(38) case_stmt(39) + case_stmt(40) case_stmt(41) case_stmt(42) case_stmt(43) + case_stmt(44) case_stmt(45) case_stmt(46) case_stmt(47) + #undef case_stmt + default : return error_node(); + } + } + + inline expression_node_ptr special_function(const details::operator_type& operation, expression_node_ptr (&branch)[3]) + { + if (!all_nodes_valid(branch)) + return error_node(); + else if (is_constant_foldable(branch)) + return const_optimise_sf3(operation,branch); + else if (all_nodes_variables(branch)) + return varnode_optimise_sf3(operation,branch); + else + { + switch (operation) + { + #define case_stmt(op) \ + case details::e_sf##op : return node_allocator_-> \ + allocate > > \ + (operation,branch); \ + + case_stmt(00) case_stmt(01) case_stmt(02) case_stmt(03) + case_stmt(04) case_stmt(05) case_stmt(06) case_stmt(07) + case_stmt(08) case_stmt(09) case_stmt(10) case_stmt(11) + case_stmt(12) case_stmt(13) case_stmt(14) case_stmt(15) + case_stmt(16) case_stmt(17) case_stmt(18) case_stmt(19) + case_stmt(20) case_stmt(21) case_stmt(22) case_stmt(23) + case_stmt(24) case_stmt(25) case_stmt(26) case_stmt(27) + case_stmt(28) case_stmt(29) case_stmt(30) case_stmt(31) + case_stmt(32) case_stmt(33) case_stmt(34) case_stmt(35) + case_stmt(36) case_stmt(37) case_stmt(38) case_stmt(39) + case_stmt(40) case_stmt(41) case_stmt(42) case_stmt(43) + case_stmt(44) case_stmt(45) case_stmt(46) case_stmt(47) + #undef case_stmt + default : return error_node(); + } + } + } + + inline expression_node_ptr const_optimise_sf4(const details::operator_type& operation, expression_node_ptr (&branch)[4]) + { + expression_node_ptr temp_node = error_node(); + + switch (operation) + { + #define case_stmt(op) \ + case details::e_sf##op : temp_node = node_allocator_-> \ + allocate > > \ + (operation,branch); \ + break; \ + + case_stmt(48) case_stmt(49) case_stmt(50) case_stmt(51) + case_stmt(52) case_stmt(53) case_stmt(54) case_stmt(55) + case_stmt(56) case_stmt(57) case_stmt(58) case_stmt(59) + case_stmt(60) case_stmt(61) case_stmt(62) case_stmt(63) + case_stmt(64) case_stmt(65) case_stmt(66) case_stmt(67) + case_stmt(68) case_stmt(69) case_stmt(70) case_stmt(71) + case_stmt(72) case_stmt(73) case_stmt(74) case_stmt(75) + case_stmt(76) case_stmt(77) case_stmt(78) case_stmt(79) + case_stmt(80) case_stmt(81) case_stmt(82) case_stmt(83) + case_stmt(84) case_stmt(85) case_stmt(86) case_stmt(87) + case_stmt(88) case_stmt(89) case_stmt(90) case_stmt(91) + case_stmt(92) case_stmt(93) case_stmt(94) case_stmt(95) + case_stmt(96) case_stmt(97) case_stmt(98) case_stmt(99) + #undef case_stmt + default : return error_node(); + } + + T v = temp_node->value(); + details::free_node(*node_allocator_,temp_node); + + return node_allocator_->allocate(v); + } + + inline expression_node_ptr varnode_optimise_sf4(const details::operator_type& operation, expression_node_ptr (&branch)[4]) + { + typedef details::variable_node* variable_ptr; + + const Type& v0 = static_cast(branch[0])->ref(); + const Type& v1 = static_cast(branch[1])->ref(); + const Type& v2 = static_cast(branch[2])->ref(); + const Type& v3 = static_cast(branch[3])->ref(); + + switch (operation) + { + #define case_stmt(op) \ + case details::e_sf##op : return node_allocator_-> \ + allocate_rrrr > > \ + (v0,v1,v2,v3); \ + + case_stmt(48) case_stmt(49) case_stmt(50) case_stmt(51) + case_stmt(52) case_stmt(53) case_stmt(54) case_stmt(55) + case_stmt(56) case_stmt(57) case_stmt(58) case_stmt(59) + case_stmt(60) case_stmt(61) case_stmt(62) case_stmt(63) + case_stmt(64) case_stmt(65) case_stmt(66) case_stmt(67) + case_stmt(68) case_stmt(69) case_stmt(70) case_stmt(71) + case_stmt(72) case_stmt(73) case_stmt(74) case_stmt(75) + case_stmt(76) case_stmt(77) case_stmt(78) case_stmt(79) + case_stmt(80) case_stmt(81) case_stmt(82) case_stmt(83) + case_stmt(84) case_stmt(85) case_stmt(86) case_stmt(87) + case_stmt(88) case_stmt(89) case_stmt(90) case_stmt(91) + case_stmt(92) case_stmt(93) case_stmt(94) case_stmt(95) + case_stmt(96) case_stmt(97) case_stmt(98) case_stmt(99) + #undef case_stmt + default : return error_node(); + } + } + + inline expression_node_ptr special_function(const details::operator_type& operation, expression_node_ptr (&branch)[4]) + { + if (!all_nodes_valid(branch)) + return error_node(); + else if (is_constant_foldable(branch)) + return const_optimise_sf4(operation,branch); + else if (all_nodes_variables(branch)) + return varnode_optimise_sf4(operation,branch); + switch (operation) + { + #define case_stmt(op) \ + case details::e_sf##op : return node_allocator_-> \ + allocate > > \ + (operation,branch); \ + + case_stmt(48) case_stmt(49) case_stmt(50) case_stmt(51) + case_stmt(52) case_stmt(53) case_stmt(54) case_stmt(55) + case_stmt(56) case_stmt(57) case_stmt(58) case_stmt(59) + case_stmt(60) case_stmt(61) case_stmt(62) case_stmt(63) + case_stmt(64) case_stmt(65) case_stmt(66) case_stmt(67) + case_stmt(68) case_stmt(69) case_stmt(70) case_stmt(71) + case_stmt(72) case_stmt(73) case_stmt(74) case_stmt(75) + case_stmt(76) case_stmt(77) case_stmt(78) case_stmt(79) + case_stmt(80) case_stmt(81) case_stmt(82) case_stmt(83) + case_stmt(84) case_stmt(85) case_stmt(86) case_stmt(87) + case_stmt(88) case_stmt(89) case_stmt(90) case_stmt(91) + case_stmt(92) case_stmt(93) case_stmt(94) case_stmt(95) + case_stmt(96) case_stmt(97) case_stmt(98) case_stmt(99) + #undef case_stmt + default : return error_node(); + } + } + + template class Sequence> + inline expression_node_ptr const_optimise_varargfunc(const details::operator_type& operation, Sequence& arg_list) + { + expression_node_ptr temp_node = error_node(); + + switch (operation) + { + #define case_stmt(op0,op1) \ + case op0 : temp_node = node_allocator_-> \ + allocate > > \ + (arg_list); \ + break; \ + + case_stmt(details::e_sum, details::vararg_add_op ) + case_stmt(details::e_prod, details::vararg_mul_op ) + case_stmt(details::e_avg, details::vararg_avg_op ) + case_stmt(details::e_min, details::vararg_min_op ) + case_stmt(details::e_max, details::vararg_max_op ) + case_stmt(details::e_mand, details::vararg_mand_op ) + case_stmt(details::e_mor, details::vararg_mor_op ) + case_stmt(details::e_multi,details::vararg_multi_op) + #undef case_stmt + default : return error_node(); + } + + 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_optimise_varargfunc(const details::operator_type& operation, Sequence& arg_list) + { + switch (operation) + { + #define case_stmt(op0,op1) \ + case op0 : return node_allocator_-> \ + allocate > >(arg_list); \ + + case_stmt(details::e_sum, details::vararg_add_op ) + case_stmt(details::e_prod, details::vararg_mul_op ) + case_stmt(details::e_avg, details::vararg_avg_op ) + case_stmt(details::e_min, details::vararg_min_op ) + case_stmt(details::e_max, details::vararg_max_op ) + case_stmt(details::e_mand, details::vararg_mand_op ) + case_stmt(details::e_mor, details::vararg_mor_op ) + case_stmt(details::e_multi,details::vararg_multi_op) + #undef case_stmt + default : return error_node(); + } + } + + template class Sequence> + inline expression_node_ptr vectorize_func(const details::operator_type& operation, Sequence& arg_list) + { + if (1 == arg_list.size()) + { + switch (operation) + { + #define case_stmt(op0,op1) \ + case op0 : return node_allocator_-> \ + allocate > >(arg_list[0]); \ + + case_stmt(details::e_sum, details::vec_add_op) + case_stmt(details::e_prod, details::vec_mul_op) + case_stmt(details::e_avg, details::vec_avg_op) + case_stmt(details::e_min, details::vec_min_op) + case_stmt(details::e_max, details::vec_max_op) + #undef case_stmt + default : return error_node(); + } + } + else + return error_node(); + } + + template class Sequence> + inline expression_node_ptr vararg_function(const details::operator_type& operation, Sequence& arg_list) + { + if (!all_nodes_valid(arg_list)) + { + details::free_all_nodes(*node_allocator_,arg_list); + + return error_node(); + } + else if (is_constant_foldable(arg_list)) + return const_optimise_varargfunc(operation,arg_list); + else if ((arg_list.size() == 1) && details::is_ivector_node(arg_list[0])) + return vectorize_func(operation,arg_list); + else if ((arg_list.size() == 1) && special_one_parameter_vararg(operation)) + return arg_list[0]; + else if (all_nodes_variables(arg_list)) + return varnode_optimise_varargfunc(operation,arg_list); + + if (details::e_smulti == operation) + { + return node_allocator_-> + allocate > >(arg_list); + } + else + { + switch (operation) + { + #define case_stmt(op0,op1) \ + case op0 : return node_allocator_-> \ + allocate > >(arg_list); \ + + case_stmt(details::e_sum, details::vararg_add_op ) + case_stmt(details::e_prod, details::vararg_mul_op ) + case_stmt(details::e_avg, details::vararg_avg_op ) + case_stmt(details::e_min, details::vararg_min_op ) + case_stmt(details::e_max, details::vararg_max_op ) + case_stmt(details::e_mand, details::vararg_mand_op ) + case_stmt(details::e_mor, details::vararg_mor_op ) + case_stmt(details::e_multi,details::vararg_multi_op) + #undef case_stmt + default : return error_node(); + } + } + } + + template + inline expression_node_ptr function(ifunction_t* f, expression_node_ptr (&b)[N]) + { + typedef typename details::function_N_node function_N_node_t; + expression_node_ptr result = synthesize_expression(f,b); + + if (0 == result) + return error_node(); + else + { + // Can the function call be completely optimised? + if (details::is_constant_node(result)) + return result; + else if (!all_nodes_valid(b)) + 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); + } + + parser_->state_.activate_side_effect("vararg_function_call()"); + + return result; + } + + inline expression_node_ptr generic_function_call(igeneric_function_t* gf, + std::vector& arg_list, + const std::size_t& param_seq_index = std::numeric_limits::max()) + { + if (!all_nodes_valid(arg_list)) + { + details::free_all_nodes(*node_allocator_,arg_list); + return error_node(); + } + + typedef details::generic_function_node alloc_type1; + typedef details::multimode_genfunction_node alloc_type2; + + const std::size_t no_psi = std::numeric_limits::max(); + + expression_node_ptr result = error_node(); + + if (no_psi == param_seq_index) + result = node_allocator_->allocate(arg_list,gf); + else + result = node_allocator_->allocate(gf,param_seq_index,arg_list); + + alloc_type1* genfunc_node_ptr = static_cast(result); + + if ( + !arg_list.empty() && + !gf->has_side_effects() && + parser_->state_.type_check_enabled && + is_constant_foldable(arg_list) + ) + { + genfunc_node_ptr->init_branches(); + Type v = result->value(); + details::free_node(*node_allocator_,result); + return node_allocator_->allocate(v); + } + else if (genfunc_node_ptr->init_branches()) + { + parser_->state_.activate_side_effect("generic_function_call()"); + return result; + } + else + { + details::free_node(*node_allocator_,result); + details::free_all_nodes(*node_allocator_,arg_list); + return error_node(); + } + } + + #ifndef exprtk_disable_string_capabilities + inline expression_node_ptr string_function_call(igeneric_function_t* gf, + std::vector& arg_list, + const std::size_t& param_seq_index = std::numeric_limits::max()) + { + if (!all_nodes_valid(arg_list)) + { + details::free_all_nodes(*node_allocator_,arg_list); + return error_node(); + } + + typedef details::string_function_node alloc_type1; + typedef details::multimode_strfunction_node alloc_type2; + + const std::size_t no_psi = std::numeric_limits::max(); + + expression_node_ptr result = error_node(); + + if (no_psi == param_seq_index) + result = node_allocator_->allocate(gf,arg_list); + else + result = node_allocator_->allocate(gf,param_seq_index,arg_list); + + alloc_type1* strfunc_node_ptr = static_cast(result); + + if ( + !arg_list.empty() && + !gf->has_side_effects() && + is_constant_foldable(arg_list) + ) + { + strfunc_node_ptr->init_branches(); + + Type v = result->value(); + + details::free_node(*node_allocator_,result); + + return node_allocator_->allocate(v); + } + else if (strfunc_node_ptr->init_branches()) + { + parser_->state_.activate_side_effect("string_function_call()"); + + return result; + } + else + { + details::free_node(*node_allocator_,result); + details::free_all_nodes(*node_allocator_,arg_list); + + return error_node(); + } + } + #endif + + #ifndef exprtk_disable_return_statement + inline expression_node_ptr return_call(std::vector& arg_list) + { + if (!all_nodes_valid(arg_list)) + { + details::free_all_nodes(*node_allocator_,arg_list); + return error_node(); + } + + typedef details::return_node alloc_type; + + expression_node_ptr result = node_allocator_-> + allocate_rr(arg_list,parser_->results_ctx()); + + alloc_type* return_node_ptr = static_cast(result); + + if (return_node_ptr->init_branches()) + { + parser_->state_.activate_side_effect("return_call()"); + + return result; + } + else + { + details::free_node(*node_allocator_,result); + details::free_all_nodes(*node_allocator_,arg_list); + + return error_node(); + } + } + + inline expression_node_ptr return_envelope(expression_node_ptr body, + results_context_t* rc, + bool*& return_invoked) + { + typedef details::return_envelope_node alloc_type; + + expression_node_ptr result = node_allocator_-> + allocate_cr(body,(*rc)); + + return_invoked = static_cast(result)->retinvk_ptr(); + + return result; + } + #else + inline expression_node_ptr return_call(std::vector&) + { + return error_node(); + } + + inline expression_node_ptr return_envelope(expression_node_ptr, + results_context_t*, + bool*&) + { + return error_node(); + } + #endif + + inline expression_node_ptr vector_element(const std::string& symbol, + vector_holder_ptr vector_base, + expression_node_ptr index) + { + expression_node_ptr result = error_node(); + + if (details::is_constant_node(index)) + { + std::size_t i = static_cast(details::numeric::to_int64(index->value())); + + details::free_node(*node_allocator_,index); + + if (vector_base->rebaseable()) + { + return node_allocator_->allocate(i,vector_base); + } + + scope_element& se = parser_->sem_.get_element(symbol,i); + + if (se.index == i) + { + result = se.var_node; + } + else + { + scope_element nse; + nse.name = symbol; + nse.active = true; + nse.ref_count = 1; + nse.type = scope_element::e_vecelem; + nse.index = i; + nse.depth = parser_->state_.scope_depth; + nse.data = 0; + nse.var_node = node_allocator_->allocate((*(*vector_base)[i])); + + if (!parser_->sem_.add_element(nse)) + { + parser_->set_synthesis_error("Failed to add new local vector element to SEM [1]"); + + parser_->sem_.free_element(nse); + + result = error_node(); + } + + exprtk_debug(("vector_element() - INFO - Added new local vector element: %s\n",nse.name.c_str())); + + parser_->state_.activate_side_effect("vector_element()"); + + result = nse.var_node; + } + } + else if (vector_base->rebaseable()) + result = node_allocator_->allocate(index,vector_base); + else + result = node_allocator_->allocate(index,vector_base); + + return result; + } + + private: + + template + inline bool is_constant_foldable(NodePtr (&b)[N]) const + { + for (std::size_t i = 0; i < N; ++i) + { + if (0 == b[i]) + return false; + else if (!details::is_constant_node(b[i])) + return false; + } + + return true; + } + + template class Sequence> + inline bool is_constant_foldable(const Sequence& b) const + { + for (std::size_t i = 0; i < b.size(); ++i) + { + if (0 == b[i]) + return false; + else if (!details::is_constant_node(b[i])) + return false; + } + + return true; + } + + void lodge_assignment(symbol_type cst, expression_node_ptr node) + { + parser_->state_.activate_side_effect("lodge_assignment()"); + + if (!parser_->dec_.collect_assignments()) + return; + + std::string symbol_name; + + switch (cst) + { + case e_st_variable : symbol_name = parser_->symtab_store_ + .get_variable_name(node); + break; + + #ifndef exprtk_disable_string_capabilities + case e_st_string : symbol_name = parser_->symtab_store_ + .get_stringvar_name(node); + break; + #endif + + case e_st_vector : { + typedef details::vector_holder vector_holder_t; + + vector_holder_t& vh = static_cast(node)->vec_holder(); + + symbol_name = parser_->symtab_store_.get_vector_name(&vh); + } + break; + + case e_st_vecelem : { + typedef details::vector_holder vector_holder_t; + + vector_holder_t& vh = static_cast(node)->vec_holder(); + + symbol_name = parser_->symtab_store_.get_vector_name(&vh); + + cst = e_st_vector; + } + break; + + default : return; + } + + if (!symbol_name.empty()) + { + parser_->dec_.add_assignment(symbol_name,cst); + } + } + + inline expression_node_ptr synthesize_assignment_expression(const details::operator_type& operation, expression_node_ptr (&branch)[2]) + { + if (details::is_variable_node(branch[0])) + { + lodge_assignment(e_st_variable,branch[0]); + + return synthesize_expression(operation,branch); + } + else if (details::is_vector_elem_node(branch[0])) + { + lodge_assignment(e_st_vecelem,branch[0]); + + return synthesize_expression(operation, branch); + } + else if (details::is_rebasevector_elem_node(branch[0])) + { + lodge_assignment(e_st_vecelem,branch[0]); + + return synthesize_expression(operation, branch); + } + else if (details::is_rebasevector_celem_node(branch[0])) + { + lodge_assignment(e_st_vecelem,branch[0]); + + return synthesize_expression(operation, branch); + } + #ifndef exprtk_disable_string_capabilities + else if (details::is_string_node(branch[0])) + { + lodge_assignment(e_st_string,branch[0]); + + return synthesize_expression(operation,branch); + } + else if (details::is_string_range_node(branch[0])) + { + lodge_assignment(e_st_string,branch[0]); + + return synthesize_expression(operation,branch); + } + #endif + else if (details::is_vector_node(branch[0])) + { + lodge_assignment(e_st_vector,branch[0]); + + if (details::is_ivector_node(branch[1])) + return synthesize_expression(operation,branch); + else + return synthesize_expression(operation,branch); + } + else + { + parser_->set_synthesis_error("Invalid assignment operation.[1]"); + + return error_node(); + } + } + + inline expression_node_ptr synthesize_assignment_operation_expression(const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + if (details::is_variable_node(branch[0])) + { + lodge_assignment(e_st_variable,branch[0]); + + switch (operation) + { + #define case_stmt(op0,op1) \ + case op0 : return node_allocator_-> \ + template allocate_rrr > > \ + (operation,branch[0],branch[1]); \ + + case_stmt(details::e_addass,details::add_op) + case_stmt(details::e_subass,details::sub_op) + case_stmt(details::e_mulass,details::mul_op) + case_stmt(details::e_divass,details::div_op) + case_stmt(details::e_modass,details::mod_op) + #undef case_stmt + default : return error_node(); + } + } + else if (details::is_vector_elem_node(branch[0])) + { + switch (operation) + { + #define case_stmt(op0,op1) \ + case op0 : return node_allocator_-> \ + template allocate_rrr > > \ + (operation,branch[0],branch[1]); \ + + case_stmt(details::e_addass,details::add_op) + case_stmt(details::e_subass,details::sub_op) + case_stmt(details::e_mulass,details::mul_op) + case_stmt(details::e_divass,details::div_op) + case_stmt(details::e_modass,details::mod_op) + #undef case_stmt + default : return error_node(); + } + } + else if (details::is_rebasevector_elem_node(branch[0])) + { + switch (operation) + { + #define case_stmt(op0,op1) \ + case op0 : return node_allocator_-> \ + template allocate_rrr > > \ + (operation,branch[0],branch[1]); \ + + case_stmt(details::e_addass,details::add_op) + case_stmt(details::e_subass,details::sub_op) + case_stmt(details::e_mulass,details::mul_op) + case_stmt(details::e_divass,details::div_op) + case_stmt(details::e_modass,details::mod_op) + #undef case_stmt + default : return error_node(); + } + } + else if (details::is_rebasevector_celem_node(branch[0])) + { + switch (operation) + { + #define case_stmt(op0,op1) \ + case op0 : return node_allocator_-> \ + template allocate_rrr > > \ + (operation,branch[0],branch[1]); \ + + case_stmt(details::e_addass,details::add_op) + case_stmt(details::e_subass,details::sub_op) + case_stmt(details::e_mulass,details::mul_op) + case_stmt(details::e_divass,details::div_op) + case_stmt(details::e_modass,details::mod_op) + #undef case_stmt + default : return error_node(); + } + } + else if (details::is_vector_node(branch[0])) + { + lodge_assignment(e_st_vector,branch[0]); + + if (details::is_ivector_node(branch[1])) + { + switch (operation) + { + #define case_stmt(op0,op1) \ + case op0 : return node_allocator_-> \ + template allocate_rrr > > \ + (operation,branch[0],branch[1]); \ + + case_stmt(details::e_addass,details::add_op) + case_stmt(details::e_subass,details::sub_op) + case_stmt(details::e_mulass,details::mul_op) + case_stmt(details::e_divass,details::div_op) + case_stmt(details::e_modass,details::mod_op) + #undef case_stmt + default : return error_node(); + } + } + else + { + switch (operation) + { + #define case_stmt(op0,op1) \ + case op0 : return node_allocator_-> \ + template allocate_rrr > > \ + (operation,branch[0],branch[1]); \ + + case_stmt(details::e_addass,details::add_op) + case_stmt(details::e_subass,details::sub_op) + case_stmt(details::e_mulass,details::mul_op) + case_stmt(details::e_divass,details::div_op) + case_stmt(details::e_modass,details::mod_op) + #undef case_stmt + default : return error_node(); + } + } + } + #ifndef exprtk_disable_string_capabilities + else if ( + (details::e_addass == operation) && + details::is_string_node(branch[0]) + ) + { + typedef details::assignment_string_node addass_t; + + lodge_assignment(e_st_string,branch[0]); + + return synthesize_expression(operation,branch); + } + #endif + else + { + parser_->set_synthesis_error("Invalid assignment operation[2]"); + + return error_node(); + } + } + + inline expression_node_ptr synthesize_veceqineqlogic_operation_expression(const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + const bool is_b0_ivec = details::is_ivector_node(branch[0]); + const bool is_b1_ivec = details::is_ivector_node(branch[1]); + + #define batch_eqineq_logic_case \ + case_stmt(details:: e_lt,details:: lt_op) \ + case_stmt(details:: e_lte,details:: lte_op) \ + case_stmt(details:: e_gt,details:: gt_op) \ + case_stmt(details:: e_gte,details:: gte_op) \ + case_stmt(details:: e_eq,details:: eq_op) \ + case_stmt(details:: e_ne,details:: ne_op) \ + case_stmt(details::e_equal,details::equal_op) \ + case_stmt(details:: e_and, details::and_op) \ + case_stmt(details:: e_nand, details::nand_op) \ + case_stmt(details:: e_or, details:: or_op) \ + case_stmt(details:: e_nor, details:: nor_op) \ + case_stmt(details:: e_xor, details:: xor_op) \ + case_stmt(details:: e_xnor, details::xnor_op) \ + + if (is_b0_ivec && is_b1_ivec) + { + switch (operation) + { + #define case_stmt(op0,op1) \ + case op0 : return node_allocator_-> \ + template allocate_rrr > > \ + (operation,branch[0],branch[1]); \ + + batch_eqineq_logic_case + #undef case_stmt + default : return error_node(); + } + } + else if (is_b0_ivec && !is_b1_ivec) + { + switch (operation) + { + #define case_stmt(op0,op1) \ + case op0 : return node_allocator_-> \ + template allocate_rrr > > \ + (operation,branch[0],branch[1]); \ + + batch_eqineq_logic_case + #undef case_stmt + default : return error_node(); + } + } + else if (!is_b0_ivec && is_b1_ivec) + { + switch (operation) + { + #define case_stmt(op0,op1) \ + case op0 : return node_allocator_-> \ + template allocate_rrr > > \ + (operation,branch[0],branch[1]); \ + + batch_eqineq_logic_case + #undef case_stmt + default : return error_node(); + } + } + else + return error_node(); + + #undef batch_eqineq_logic_case + } + + inline expression_node_ptr synthesize_vecarithmetic_operation_expression(const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + const bool is_b0_ivec = details::is_ivector_node(branch[0]); + const bool is_b1_ivec = details::is_ivector_node(branch[1]); + + #define vector_ops \ + case_stmt(details::e_add,details::add_op) \ + case_stmt(details::e_sub,details::sub_op) \ + case_stmt(details::e_mul,details::mul_op) \ + case_stmt(details::e_div,details::div_op) \ + case_stmt(details::e_mod,details::mod_op) \ + + if (is_b0_ivec && is_b1_ivec) + { + switch (operation) + { + #define case_stmt(op0,op1) \ + case op0 : return node_allocator_-> \ + template allocate_rrr > > \ + (operation,branch[0],branch[1]); \ + + vector_ops + case_stmt(details::e_pow,details:: pow_op) + #undef case_stmt + default : return error_node(); + } + } + else if (is_b0_ivec && !is_b1_ivec) + { + switch (operation) + { + #define case_stmt(op0,op1) \ + case op0 : return node_allocator_-> \ + template allocate_rrr > > \ + (operation,branch[0],branch[1]); \ + + vector_ops + case_stmt(details::e_pow,details:: pow_op) + #undef case_stmt + default : return error_node(); + } + } + else if (!is_b0_ivec && is_b1_ivec) + { + switch (operation) + { + #define case_stmt(op0,op1) \ + case op0 : return node_allocator_-> \ + template allocate_rrr > > \ + (operation,branch[0],branch[1]); \ + + vector_ops + #undef case_stmt + default : return error_node(); + } + } + else + return error_node(); + + #undef vector_ops + } + + inline expression_node_ptr synthesize_swap_expression(expression_node_ptr (&branch)[2]) + { + const bool v0_is_ivar = details::is_ivariable_node(branch[0]); + const bool v1_is_ivar = details::is_ivariable_node(branch[1]); + + const bool v0_is_ivec = details::is_ivector_node(branch[0]); + const bool v1_is_ivec = details::is_ivector_node(branch[1]); + + #ifndef exprtk_disable_string_capabilities + const bool v0_is_str = details::is_generally_string_node(branch[0]); + const bool v1_is_str = details::is_generally_string_node(branch[1]); + #endif + + expression_node_ptr result = error_node(); + + if (v0_is_ivar && v1_is_ivar) + { + typedef details::variable_node* variable_node_ptr; + + variable_node_ptr v0 = variable_node_ptr(0); + variable_node_ptr v1 = variable_node_ptr(0); + + if ( + (0 != (v0 = dynamic_cast(branch[0]))) && + (0 != (v1 = dynamic_cast(branch[1]))) + ) + { + result = node_allocator_->allocate >(v0,v1); + } + else + result = node_allocator_->allocate >(branch[0],branch[1]); + } + else if (v0_is_ivec && v1_is_ivec) + { + result = node_allocator_->allocate >(branch[0],branch[1]); + } + #ifndef exprtk_disable_string_capabilities + else if (v0_is_str && v1_is_str) + { + if (is_string_node(branch[0]) && is_string_node(branch[1])) + result = node_allocator_->allocate >(branch[0],branch[1]); + else + result = node_allocator_->allocate >(branch[0],branch[1]); + } + #endif + else + { + parser_->set_synthesis_error("Only variables, strings, vectors or vector elements can be swapped"); + + return error_node(); + } + + parser_->state_.activate_side_effect("synthesize_swap_expression()"); + + return result; + } + + #ifndef exprtk_disable_sc_andor + inline expression_node_ptr synthesize_shortcircuit_expression(const details::operator_type& operation, expression_node_ptr (&branch)[2]) + { + expression_node_ptr result = error_node(); + + if (details::is_constant_node(branch[0])) + { + if ( + (details::e_scand == operation) && + std::equal_to()(T(0),branch[0]->value()) + ) + result = node_allocator_->allocate_c(T(0)); + else if ( + (details::e_scor == operation) && + std::not_equal_to()(T(0),branch[0]->value()) + ) + result = node_allocator_->allocate_c(T(1)); + } + + if (details::is_constant_node(branch[1]) && (0 == result)) + { + if ( + (details::e_scand == operation) && + std::equal_to()(T(0),branch[1]->value()) + ) + result = node_allocator_->allocate_c(T(0)); + else if ( + (details::e_scor == operation) && + std::not_equal_to()(T(0),branch[1]->value()) + ) + result = node_allocator_->allocate_c(T(1)); + } + + if (result) + { + 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 class IPowNode> + inline expression_node_ptr cardinal_pow_optimisation_impl(const TType& v, const unsigned int& p) + { + switch (p) + { + #define case_stmt(cp) \ + case cp : return node_allocator_-> \ + allocate > >(v); \ + + case_stmt( 1) case_stmt( 2) case_stmt( 3) case_stmt( 4) + case_stmt( 5) case_stmt( 6) case_stmt( 7) case_stmt( 8) + case_stmt( 9) case_stmt(10) case_stmt(11) case_stmt(12) + case_stmt(13) case_stmt(14) case_stmt(15) case_stmt(16) + case_stmt(17) case_stmt(18) case_stmt(19) case_stmt(20) + case_stmt(21) case_stmt(22) case_stmt(23) case_stmt(24) + case_stmt(25) case_stmt(26) case_stmt(27) case_stmt(28) + case_stmt(29) case_stmt(30) case_stmt(31) case_stmt(32) + case_stmt(33) case_stmt(34) case_stmt(35) case_stmt(36) + case_stmt(37) case_stmt(38) case_stmt(39) case_stmt(40) + case_stmt(41) case_stmt(42) case_stmt(43) case_stmt(44) + case_stmt(45) case_stmt(46) case_stmt(47) case_stmt(48) + case_stmt(49) case_stmt(50) case_stmt(51) case_stmt(52) + case_stmt(53) case_stmt(54) case_stmt(55) case_stmt(56) + case_stmt(57) case_stmt(58) case_stmt(59) case_stmt(60) + #undef case_stmt + default : return error_node(); + } + } + + inline expression_node_ptr cardinal_pow_optimisation(const T& v, const T& c) + { + const bool not_recipricol = (c >= T(0)); + const int p = details::numeric::to_int32(details::numeric::abs(c)); + + if (0 == p) + return node_allocator_->allocate_c(T(1)); + else if (std::equal_to()(T(2),c)) + { + return node_allocator_-> + template allocate_rr > >(v,v); + } + else + { + if (not_recipricol) + return cardinal_pow_optimisation_impl(v,p); + else + return cardinal_pow_optimisation_impl(v,p); + } + } + + inline bool cardinal_pow_optimisable(const details::operator_type& operation, const T& c) + { + return (details::e_pow == operation) && (details::numeric::abs(c) <= T(60)) && details::numeric::is_integer(c); + } + + inline expression_node_ptr cardinal_pow_optimisation(expression_node_ptr (&branch)[2]) + { + const Type c = static_cast*>(branch[1])->value(); + const bool not_recipricol = (c >= T(0)); + const int p = details::numeric::to_int32(details::numeric::abs(c)); + + node_allocator_->free(branch[1]); + + if (0 == p) + { + details::free_all_nodes(*node_allocator_, branch); + return node_allocator_->allocate_c(T(1)); + } + else if (not_recipricol) + return cardinal_pow_optimisation_impl(branch[0],p); + else + return cardinal_pow_optimisation_impl(branch[0],p); + } + #else + inline expression_node_ptr cardinal_pow_optimisation(T&, const T&) + { + return error_node(); + } + + inline bool cardinal_pow_optimisable(const details::operator_type&, const T&) + { + return false; + } + + inline expression_node_ptr cardinal_pow_optimisation(expression_node_ptr(&)[2]) + { + return error_node(); + } + #endif + + struct synthesize_binary_ext_expression + { + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + const bool left_neg = is_neg_unary_node(branch[0]); + const bool right_neg = is_neg_unary_node(branch[1]); + + if (left_neg && right_neg) + { + if ( + (details::e_add == operation) || + (details::e_sub == operation) || + (details::e_mul == operation) || + (details::e_div == operation) + ) + { + if ( + !expr_gen.parser_->simplify_unary_negation_branch(branch[0]) || + !expr_gen.parser_->simplify_unary_negation_branch(branch[1]) + ) + { + details::free_all_nodes(*expr_gen.node_allocator_,branch); + return error_node(); - else if (!expr_gen.valid_operator(o1,f1)) + } + } + + switch (operation) + { + // -f(x + 1) + -g(y + 1) --> -(f(x + 1) + g(y + 1)) + case details::e_add : return expr_gen(details::e_neg, + expr_gen.node_allocator_-> + template allocate > > + (branch[0],branch[1])); + + // -f(x + 1) - -g(y + 1) --> g(y + 1) - f(x + 1) + case details::e_sub : return expr_gen.node_allocator_-> + template allocate > > + (branch[1],branch[0]); + + default : break; + } + } + else if (left_neg && !right_neg) + { + if ( + (details::e_add == operation) || + (details::e_sub == operation) || + (details::e_mul == operation) || + (details::e_div == operation) + ) + { + if (!expr_gen.parser_->simplify_unary_negation_branch(branch[0])) + { + details::free_all_nodes(*expr_gen.node_allocator_,branch); + return error_node(); - else if (!expr_gen.valid_operator(o2,f2)) + } + + switch (operation) + { + // -f(x + 1) + g(y + 1) --> g(y + 1) - f(x + 1) + case details::e_add : return expr_gen.node_allocator_-> + template allocate > > + (branch[1],branch[0]); + + // -f(x + 1) - g(y + 1) --> -(f(x + 1) + g(y + 1)) + case details::e_sub : return expr_gen(details::e_neg, + expr_gen.node_allocator_-> + template allocate > > + (branch[0],branch[1])); + + // -f(x + 1) * g(y + 1) --> -(f(x + 1) * g(y + 1)) + case details::e_mul : return expr_gen(details::e_neg, + expr_gen.node_allocator_-> + template allocate > > + (branch[0],branch[1])); + + // -f(x + 1) / g(y + 1) --> -(f(x + 1) / g(y + 1)) + case details::e_div : return expr_gen(details::e_neg, + expr_gen.node_allocator_-> + template allocate > > + (branch[0],branch[1])); + + default : return error_node(); + } + } + } + else if (!left_neg && right_neg) + { + if ( + (details::e_add == operation) || + (details::e_sub == operation) || + (details::e_mul == operation) || + (details::e_div == operation) + ) + { + if (!expr_gen.parser_->simplify_unary_negation_branch(branch[1])) + { + details::free_all_nodes(*expr_gen.node_allocator_,branch); + return error_node(); - else - return node_type::allocate(*(expr_gen.node_allocator_),c0,v0,v1,c1,f0,f1,f2); - } - - static inline std::string id(expression_generator& expr_gen, - const details::operator_type o0, - const details::operator_type o1, - const details::operator_type o2) - { - return (details::build_string() << "(t" << expr_gen.to_str(o0) << "t)" << expr_gen.to_str(o1) << "(t" << expr_gen.to_str(o2) << "t)"); - } - }; - - struct synthesize_vococov_expression0 - { - typedef typename vococov_t::type0 node_type; - typedef typename vococov_t::sf4_type sf4_type; - typedef typename node_type::T0 T0; - typedef typename node_type::T1 T1; - typedef typename node_type::T2 T2; - typedef typename node_type::T3 T3; - - static inline expression_node_ptr process(expression_generator& expr_gen, - const details::operator_type& operation, - expression_node_ptr (&branch)[2]) - { - // (v0 o0 c0) o1 (c1 o2 v1) - const details::voc_base_node* voc = static_cast*>(branch[0]); - const details::cov_base_node* cov = static_cast*>(branch[1]); - const Type c0 = voc->c(); - const Type& v0 = voc->v(); - const Type c1 = cov->c(); - const Type& v1 = cov->v(); - const details::operator_type o0 = voc->operation(); - const details::operator_type o1 = operation; - const details::operator_type o2 = cov->operation(); - - binary_functor_t f0 = reinterpret_cast(0); - binary_functor_t f1 = reinterpret_cast(0); - binary_functor_t f2 = reinterpret_cast(0); - - details::free_node(*(expr_gen.node_allocator_),branch[0]); - details::free_node(*(expr_gen.node_allocator_),branch[1]); - - expression_node_ptr result = error_node(); - - if (expr_gen.parser_->settings_.strength_reduction_enabled()) - { - // (v0 + c0) + (c1 + v1) --> (covov) (c0 + c1) + v0 + v1 - if ((details::e_add == o0) && (details::e_add == o1) && (details::e_add == o2)) - { - const bool synthesis_result = - synthesize_sf3ext_expression:: - template compile(expr_gen,"(t+t)+t",(c0 + c1),v0,v1,result); - - exprtk_debug(("(v0 + c0) + (c1 + v1) --> (covov) (c0 + c1) + v0 + v1\n")); - - return (synthesis_result) ? result : error_node(); - } - // (v0 + c0) - (c1 + v1) --> (covov) (c0 - c1) + v0 - v1 - else if ((details::e_add == o0) && (details::e_sub == o1) && (details::e_add == o2)) - { - const bool synthesis_result = - synthesize_sf3ext_expression:: - template compile(expr_gen,"(t+t)-t",(c0 - c1),v0,v1,result); - - exprtk_debug(("(v0 + c0) - (c1 + v1) --> (covov) (c0 - c1) + v0 - v1\n")); - - return (synthesis_result) ? result : error_node(); - } - // (v0 - c0) - (c1 - v1) --> (vovoc) v0 + v1 - (c1 + c0) - else if ((details::e_sub == o0) && (details::e_sub == o1) && (details::e_sub == o2)) - { - const bool synthesis_result = - synthesize_sf3ext_expression:: - template compile(expr_gen,"(t+t)-t",v0,v1,(c1 + c0),result); - - exprtk_debug(("(v0 - c0) - (c1 - v1) --> (vovoc) v0 + v1 - (c1 + c0)\n")); - - return (synthesis_result) ? result : error_node(); - } - // (v0 * c0) * (c1 * v1) --> (covov) (c0 * c1) * v0 * v1 - else if ((details::e_mul == o0) && (details::e_mul == o1) && (details::e_mul == o2)) + } + + switch (operation) + { + // f(x + 1) + -g(y + 1) --> f(x + 1) - g(y + 1) + case details::e_add : return expr_gen.node_allocator_-> + template allocate > > + (branch[0],branch[1]); + + // f(x + 1) - - g(y + 1) --> f(x + 1) + g(y + 1) + case details::e_sub : return expr_gen.node_allocator_-> + template allocate > > + (branch[0],branch[1]); + + // f(x + 1) * -g(y + 1) --> -(f(x + 1) * g(y + 1)) + case details::e_mul : return expr_gen(details::e_neg, + expr_gen.node_allocator_-> + template allocate > > + (branch[0],branch[1])); + + // f(x + 1) / -g(y + 1) --> -(f(x + 1) / g(y + 1)) + case details::e_div : return expr_gen(details::e_neg, + expr_gen.node_allocator_-> + template allocate > > + (branch[0],branch[1])); + + default : return error_node(); + } + } + } + + switch (operation) + { + #define case_stmt(op0,op1) \ + case op0 : return expr_gen.node_allocator_-> \ + template allocate > > \ + (branch[0],branch[1]); \ + + basic_opr_switch_statements + extended_opr_switch_statements + #undef case_stmt + default : return error_node(); + } + } + }; + + struct synthesize_vob_expression + { + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + const Type& v = static_cast*>(branch[0])->ref(); + + #ifndef exprtk_disable_enhanced_features + if (details::is_sf3ext_node(branch[1])) + { + expression_node_ptr result = error_node(); + + if (synthesize_sf4ext_expression::template compile_right(expr_gen,v,operation,branch[1],result)) + { + free_node(*expr_gen.node_allocator_,branch[1]); + return result; + } + } + #endif + + if ( + (details::e_mul == operation) || + (details::e_div == operation) + ) + { + if (details::is_uv_node(branch[1])) + { + typedef details::uv_base_node* uvbn_ptr_t; + + details::operator_type o = static_cast(branch[1])->operation(); + + if (details::e_neg == o) + { + const Type& v1 = static_cast(branch[1])->v(); + + free_node(*expr_gen.node_allocator_,branch[1]); + + switch (operation) { - const bool synthesis_result = - synthesize_sf3ext_expression:: - template compile(expr_gen,"(t*t)*t",(c0 * c1),v0,v1,result); - - exprtk_debug(("(v0 * c0) * (c1 * v1) --> (covov) (c0 * c1) * v0 * v1\n")); - - return (synthesis_result) ? result : error_node(); + case details::e_mul : return expr_gen(details::e_neg, + expr_gen.node_allocator_-> + template allocate_rr > >(v,v1)); + + case details::e_div : return expr_gen(details::e_neg, + expr_gen.node_allocator_-> + template allocate_rr > >(v,v1)); + + default : break; } - // (v0 * c0) / (c1 * v1) --> (covov) (c0 / c1) * (v0 * v1) - else if ((details::e_mul == o0) && (details::e_div == o1) && (details::e_mul == o2)) + } + } + } + + switch (operation) + { + #define case_stmt(op0,op1) \ + case op0 : return expr_gen.node_allocator_-> \ + template allocate_rc > > \ + (v,branch[1]); \ + + basic_opr_switch_statements + extended_opr_switch_statements + #undef case_stmt + default : return error_node(); + } + } + }; + + struct synthesize_bov_expression + { + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + const Type& v = static_cast*>(branch[1])->ref(); + + #ifndef exprtk_disable_enhanced_features + if (details::is_sf3ext_node(branch[0])) + { + expression_node_ptr result = error_node(); + + if (synthesize_sf4ext_expression::template compile_left(expr_gen,v,operation,branch[0],result)) + { + free_node(*expr_gen.node_allocator_,branch[0]); + + return result; + } + } + #endif + + if ( + (details::e_add == operation) || + (details::e_sub == operation) || + (details::e_mul == operation) || + (details::e_div == operation) + ) + { + if (details::is_uv_node(branch[0])) + { + typedef details::uv_base_node* uvbn_ptr_t; + + details::operator_type o = static_cast(branch[0])->operation(); + + if (details::e_neg == o) + { + const Type& v0 = static_cast(branch[0])->v(); + + free_node(*expr_gen.node_allocator_,branch[0]); + + switch (operation) { - const bool synthesis_result = - synthesize_sf3ext_expression:: - template compile(expr_gen,"(t*t)/t",(c0 / c1),v0,v1,result); - - exprtk_debug(("(v0 * c0) / (c1 * v1) --> (covov) (c0 / c1) * (v0 * v1)\n")); - - return (synthesis_result) ? result : error_node(); + case details::e_add : return expr_gen.node_allocator_-> + template allocate_rr > >(v,v0); + + case details::e_sub : return expr_gen(details::e_neg, + expr_gen.node_allocator_-> + template allocate_rr > >(v0,v)); + + case details::e_mul : return expr_gen(details::e_neg, + expr_gen.node_allocator_-> + template allocate_rr > >(v0,v)); + + case details::e_div : return expr_gen(details::e_neg, + expr_gen.node_allocator_-> + template allocate_rr > >(v0,v)); + default : break; } - // (v0 / c0) * (c1 / v1) --> (covov) (c1 / c0) * (v0 / v1) - else if ((details::e_div == o0) && (details::e_mul == o1) && (details::e_div == o2)) + } + } + } + + switch (operation) + { + #define case_stmt(op0,op1) \ + case op0 : return expr_gen.node_allocator_-> \ + template allocate_cr > > \ + (branch[0],v); \ + + basic_opr_switch_statements + extended_opr_switch_statements + #undef case_stmt + default : return error_node(); + } + } + }; + + struct synthesize_cob_expression + { + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + const Type c = static_cast*>(branch[0])->value(); + + free_node(*expr_gen.node_allocator_,branch[0]); + + if ((T(0) == c) && (details::e_mul == operation)) + { + free_node(*expr_gen.node_allocator_,branch[1]); + + return expr_gen(T(0)); + } + else if ((T(0) == c) && (details::e_div == operation)) + { + free_node(*expr_gen.node_allocator_, branch[1]); + + return expr_gen(T(0)); + } + else if ((T(0) == c) && (details::e_add == operation)) + return branch[1]; + else if ((T(1) == c) && (details::e_mul == operation)) + return branch[1]; + + if (details::is_cob_node(branch[1])) + { + // Simplify expressions of the form: + // 1. (1 * (2 * (3 * (4 * (5 * (6 * (7 * (8 * (9 + x))))))))) --> 40320 * (9 + x) + // 2. (1 + (2 + (3 + (4 + (5 + (6 + (7 + (8 + (9 + x))))))))) --> 45 + x + if ( + (operation == details::e_mul) || + (operation == details::e_add) + ) + { + details::cob_base_node* cobnode = static_cast*>(branch[1]); + + if (operation == cobnode->operation()) + { + switch (operation) { - const bool synthesis_result = - synthesize_sf3ext_expression:: - template compile(expr_gen,"(t*t)/t",(c1 / c0),v0,v1,result); - - exprtk_debug(("(v0 / c0) * (c1 / v1) --> (covov) (c1 / c0) * (v0 / v1)\n")); - - return (synthesis_result) ? result : error_node(); + case details::e_add : cobnode->set_c(c + cobnode->c()); break; + case details::e_mul : cobnode->set_c(c * cobnode->c()); break; + default : return error_node(); } - // (v0 * c0) / (c1 / v1) --> (covov) (c0 / c1) * (v0 * v1) - else if ((details::e_mul == o0) && (details::e_div == o1) && (details::e_div == o2)) + + return cobnode; + } + } + + if (operation == details::e_mul) + { + details::cob_base_node* cobnode = static_cast*>(branch[1]); + details::operator_type cob_opr = cobnode->operation(); + + if ( + (details::e_div == cob_opr) || + (details::e_mul == cob_opr) + ) + { + switch (cob_opr) { - const bool synthesis_result = - synthesize_sf3ext_expression:: - template compile(expr_gen,"(t*t)*t",(c0 / c1),v0,v1,result); - - exprtk_debug(("(v0 * c0) / (c1 / v1) --> (covov) (c0 / c1) * (v0 * v1)\n")); - - return (synthesis_result) ? result : error_node(); + case details::e_div : cobnode->set_c(c * cobnode->c()); break; + case details::e_mul : cobnode->set_c(cobnode->c() / c); break; + default : return error_node(); } - // (v0 / c0) / (c1 * v1) --> (covov) (1 / (c0 * c1)) * (v0 / v1) - else if ((details::e_div == o0) && (details::e_div == o1) && (details::e_mul == o2)) + + return cobnode; + } + } + else if (operation == details::e_div) + { + details::cob_base_node* cobnode = static_cast*>(branch[1]); + details::operator_type cob_opr = cobnode->operation(); + + if ( + (details::e_div == cob_opr) || + (details::e_mul == cob_opr) + ) + { + details::expression_node* new_cobnode = error_node(); + + switch (cob_opr) { - const bool synthesis_result = - synthesize_sf3ext_expression:: - template compile(expr_gen,"(t*t)/t",Type(1) / (c0 * c1),v0,v1,result); - - exprtk_debug(("(v0 / c0) / (c1 * v1) --> (covov) (1 / (c0 * c1)) * (v0 / v1)\n")); - - return (synthesis_result) ? result : error_node(); + case details::e_div : new_cobnode = expr_gen.node_allocator_-> + template allocate_tt > > + (c / cobnode->c(),cobnode->move_branch(0)); + break; + + case details::e_mul : new_cobnode = expr_gen.node_allocator_-> + template allocate_tt > > + (c / cobnode->c(),cobnode->move_branch(0)); + break; + + default : return error_node(); } - // (v0 / c0) / (c1 / v1) --> (vovoc) (v0 * v1) * (1 / (c0 * c1)) - else if ((details::e_div == o0) && (details::e_div == o1) && (details::e_div == o2)) + + free_node(*expr_gen.node_allocator_,branch[1]); + + return new_cobnode; + } + } + } + #ifndef exprtk_disable_enhanced_features + else if (details::is_sf3ext_node(branch[1])) + { + expression_node_ptr result = error_node(); + + if (synthesize_sf4ext_expression::template compile_right(expr_gen,c,operation,branch[1],result)) + { + free_node(*expr_gen.node_allocator_,branch[1]); + + return result; + } + } + #endif + + switch (operation) + { + #define case_stmt(op0,op1) \ + case op0 : return expr_gen.node_allocator_-> \ + template allocate_tt > > \ + (c,branch[1]); \ + + basic_opr_switch_statements + extended_opr_switch_statements + #undef case_stmt + default : return error_node(); + } + } + }; + + struct synthesize_boc_expression + { + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + const Type c = static_cast*>(branch[1])->value(); + + details::free_node(*(expr_gen.node_allocator_),branch[1]); + + if ((T(0) == c) && (details::e_mul == operation)) + { + free_node(*expr_gen.node_allocator_,branch[0]); + + return expr_gen(T(0)); + } + else if ((T(0) == c) && (details::e_div == operation)) + { + free_node(*expr_gen.node_allocator_, branch[0]); + + return expr_gen(std::numeric_limits::quiet_NaN()); + } + else if ((T(0) == c) && (details::e_add == operation)) + return branch[0]; + else if ((T(1) == c) && (details::e_mul == operation)) + return branch[0]; + + if (details::is_boc_node(branch[0])) + { + // Simplify expressions of the form: + // 1. (((((((((x + 9) * 8) * 7) * 6) * 5) * 4) * 3) * 2) * 1) --> (x + 9) * 40320 + // 2. (((((((((x + 9) + 8) + 7) + 6) + 5) + 4) + 3) + 2) + 1) --> x + 45 + if ( + (operation == details::e_mul) || + (operation == details::e_add) + ) + { + details::boc_base_node* bocnode = static_cast*>(branch[0]); + + if (operation == bocnode->operation()) + { + switch (operation) { - const bool synthesis_result = - synthesize_sf3ext_expression:: - template compile(expr_gen,"(t*t)*t",v0,v1,Type(1) / (c0 * c1),result); - - exprtk_debug(("(v0 / c0) / (c1 / v1) --> (vovoc) (v0 * v1) * (1 / (c0 * c1))\n")); - - return (synthesis_result) ? result : error_node(); + case details::e_add : bocnode->set_c(c + bocnode->c()); break; + case details::e_mul : bocnode->set_c(c * bocnode->c()); break; + default : return error_node(); } - // (v0 * c) +/- (c * v1) --> (covov) c * (v0 +/- v1) - else if ( - (std::equal_to()(c0,c1)) && - (details::e_mul == o0) && - (details::e_mul == o2) && - ( - (details::e_add == o1) || (details::e_sub == o1) - ) - ) + + return bocnode; + } + } + else if (operation == details::e_div) + { + details::boc_base_node* bocnode = static_cast*>(branch[0]); + details::operator_type boc_opr = bocnode->operation(); + + if ( + (details::e_div == boc_opr) || + (details::e_mul == boc_opr) + ) + { + switch (boc_opr) { - std::string specfunc; - - switch (o1) - { - case details::e_add : specfunc = "t*(t+t)"; break; - case details::e_sub : specfunc = "t*(t-t)"; break; - default : return error_node(); - } - - const bool synthesis_result = - synthesize_sf3ext_expression:: - template compile(expr_gen,specfunc,c0,v0,v1,result); - - exprtk_debug(("(v0 * c) +/- (c * v1) --> (covov) c * (v0 +/- v1)\n")); - - return (synthesis_result) ? result : error_node(); + case details::e_div : bocnode->set_c(c * bocnode->c()); break; + case details::e_mul : bocnode->set_c(bocnode->c() / c); break; + default : return error_node(); } - } - - if (synthesize_sf4ext_expression::template compile(expr_gen,id(expr_gen,o0,o1,o2),v0,c0,c1,v1,result)) - return result; - else if (!expr_gen.valid_operator(o0,f0)) - return error_node(); - else if (!expr_gen.valid_operator(o1,f1)) - return error_node(); - else if (!expr_gen.valid_operator(o2,f2)) - return error_node(); - else - return node_type::allocate(*(expr_gen.node_allocator_),v0,c0,c1,v1,f0,f1,f2); - } - - static inline std::string id(expression_generator& expr_gen, - const details::operator_type o0, - const details::operator_type o1, - const details::operator_type o2) - { - return (details::build_string() << "(t" << expr_gen.to_str(o0) << "t)" << expr_gen.to_str(o1) << "(t" << expr_gen.to_str(o2) << "t)"); - } - }; - - struct synthesize_vovovov_expression1 - { - typedef typename vovovov_t::type1 node_type; - typedef typename vovovov_t::sf4_type sf4_type; - typedef typename node_type::T0 T0; - typedef typename node_type::T1 T1; - typedef typename node_type::T2 T2; - typedef typename node_type::T3 T3; - - static inline expression_node_ptr process(expression_generator& expr_gen, - const details::operator_type& operation, - expression_node_ptr (&branch)[2]) - { - // v0 o0 (v1 o1 (v2 o2 v3)) - typedef typename synthesize_vovov_expression1::node_type lcl_vovov_t; - - const lcl_vovov_t* vovov = static_cast(branch[1]); - const Type& v0 = static_cast*>(branch[0])->ref(); - const Type& v1 = vovov->t0(); - const Type& v2 = vovov->t1(); - const Type& v3 = vovov->t2(); - const details::operator_type o0 = operation; - const details::operator_type o1 = expr_gen.get_operator(vovov->f0()); - const details::operator_type o2 = expr_gen.get_operator(vovov->f1()); - - binary_functor_t f0 = reinterpret_cast(0); - binary_functor_t f1 = vovov->f0(); - binary_functor_t f2 = vovov->f1(); - - details::free_node(*(expr_gen.node_allocator_),branch[1]); - - expression_node_ptr result = error_node(); - - if (synthesize_sf4ext_expression::template compile(expr_gen,id(expr_gen,o0,o1,o2),v0,v1,v2,v3,result)) - return result; - else if (!expr_gen.valid_operator(o0,f0)) - return error_node(); - - exprtk_debug(("v0 o0 (v1 o1 (v2 o2 v3))\n")); - - return node_type::allocate(*(expr_gen.node_allocator_),v0,v1,v2,v3,f0,f1,f2); - } - - static inline std::string id(expression_generator& expr_gen, - const details::operator_type o0, - const details::operator_type o1, - const details::operator_type o2) - { - return (details::build_string() << "t" << expr_gen.to_str(o0) << "(t" << expr_gen.to_str(o1) << "(t" << expr_gen.to_str(o2) << "t))"); - } - }; - - struct synthesize_vovovoc_expression1 - { - typedef typename vovovoc_t::type1 node_type; - typedef typename vovovoc_t::sf4_type sf4_type; - typedef typename node_type::T0 T0; - typedef typename node_type::T1 T1; - typedef typename node_type::T2 T2; - typedef typename node_type::T3 T3; - - static inline expression_node_ptr process(expression_generator& expr_gen, - const details::operator_type& operation, - expression_node_ptr (&branch)[2]) - { - // v0 o0 (v1 o1 (v2 o2 c)) - typedef typename synthesize_vovoc_expression1::node_type lcl_vovoc_t; - - const lcl_vovoc_t* vovoc = static_cast(branch[1]); - const Type& v0 = static_cast*>(branch[0])->ref(); - const Type& v1 = vovoc->t0(); - const Type& v2 = vovoc->t1(); - const Type c = vovoc->t2(); - const details::operator_type o0 = operation; - const details::operator_type o1 = expr_gen.get_operator(vovoc->f0()); - const details::operator_type o2 = expr_gen.get_operator(vovoc->f1()); - - binary_functor_t f0 = reinterpret_cast(0); - binary_functor_t f1 = vovoc->f0(); - binary_functor_t f2 = vovoc->f1(); - - details::free_node(*(expr_gen.node_allocator_),branch[1]); - - expression_node_ptr result = error_node(); - - if (synthesize_sf4ext_expression::template compile(expr_gen,id(expr_gen,o0,o1,o2),v0,v1,v2,c,result)) - return result; - else if (!expr_gen.valid_operator(o0,f0)) - return error_node(); - - exprtk_debug(("v0 o0 (v1 o1 (v2 o2 c))\n")); - - return node_type::allocate(*(expr_gen.node_allocator_),v0,v1,v2,c,f0,f1,f2); - } - - static inline std::string id(expression_generator& expr_gen, - const details::operator_type o0, - const details::operator_type o1, - const details::operator_type o2) - { - return (details::build_string() << "t" << expr_gen.to_str(o0) << "(t" << expr_gen.to_str(o1) << "(t" << expr_gen.to_str(o2) << "t))"); - } - }; - - struct synthesize_vovocov_expression1 - { - typedef typename vovocov_t::type1 node_type; - typedef typename vovocov_t::sf4_type sf4_type; - typedef typename node_type::T0 T0; - typedef typename node_type::T1 T1; - typedef typename node_type::T2 T2; - typedef typename node_type::T3 T3; - - static inline expression_node_ptr process(expression_generator& expr_gen, - const details::operator_type& operation, - expression_node_ptr (&branch)[2]) - { - // v0 o0 (v1 o1 (c o2 v2)) - typedef typename synthesize_vocov_expression1::node_type lcl_vocov_t; - - const lcl_vocov_t* vocov = static_cast(branch[1]); - const Type& v0 = static_cast*>(branch[0])->ref(); - const Type& v1 = vocov->t0(); - const Type c = vocov->t1(); - const Type& v2 = vocov->t2(); - const details::operator_type o0 = operation; - const details::operator_type o1 = expr_gen.get_operator(vocov->f0()); - const details::operator_type o2 = expr_gen.get_operator(vocov->f1()); - - binary_functor_t f0 = reinterpret_cast(0); - binary_functor_t f1 = vocov->f0(); - binary_functor_t f2 = vocov->f1(); - - details::free_node(*(expr_gen.node_allocator_),branch[1]); - - expression_node_ptr result = error_node(); - - if (synthesize_sf4ext_expression::template compile(expr_gen,id(expr_gen,o0,o1,o2),v0,v1,c,v2,result)) - return result; - if (!expr_gen.valid_operator(o0,f0)) - return error_node(); - - exprtk_debug(("v0 o0 (v1 o1 (c o2 v2))\n")); - - return node_type::allocate(*(expr_gen.node_allocator_),v0,v1,c,v2,f0,f1,f2); - } - - static inline std::string id(expression_generator& expr_gen, - const details::operator_type o0, - const details::operator_type o1, - const details::operator_type o2) - { - return (details::build_string() << "t" << expr_gen.to_str(o0) << "(t" << expr_gen.to_str(o1) << "(t" << expr_gen.to_str(o2) << "t))"); - } - }; - - struct synthesize_vocovov_expression1 - { - typedef typename vocovov_t::type1 node_type; - typedef typename vocovov_t::sf4_type sf4_type; - typedef typename node_type::T0 T0; - typedef typename node_type::T1 T1; - typedef typename node_type::T2 T2; - typedef typename node_type::T3 T3; - - static inline expression_node_ptr process(expression_generator& expr_gen, - const details::operator_type& operation, - expression_node_ptr (&branch)[2]) - { - // v0 o0 (c o1 (v1 o2 v2)) - typedef typename synthesize_covov_expression1::node_type lcl_covov_t; - - const lcl_covov_t* covov = static_cast(branch[1]); - const Type& v0 = static_cast*>(branch[0])->ref(); - const Type c = covov->t0(); - const Type& v1 = covov->t1(); - const Type& v2 = covov->t2(); - const details::operator_type o0 = operation; - const details::operator_type o1 = expr_gen.get_operator(covov->f0()); - const details::operator_type o2 = expr_gen.get_operator(covov->f1()); - - binary_functor_t f0 = reinterpret_cast(0); - binary_functor_t f1 = covov->f0(); - binary_functor_t f2 = covov->f1(); - - details::free_node(*(expr_gen.node_allocator_),branch[1]); - - expression_node_ptr result = error_node(); - - if (synthesize_sf4ext_expression::template compile(expr_gen,id(expr_gen,o0,o1,o2),v0,c,v1,v2,result)) - return result; - else if (!expr_gen.valid_operator(o0,f0)) - return error_node(); - - exprtk_debug(("v0 o0 (c o1 (v1 o2 v2))\n")); - - return node_type::allocate(*(expr_gen.node_allocator_),v0,c,v1,v2,f0,f1,f2); - } - - static inline std::string id(expression_generator& expr_gen, - const details::operator_type o0, - const details::operator_type o1, - const details::operator_type o2) - { - return (details::build_string() << "t" << expr_gen.to_str(o0) << "(t" << expr_gen.to_str(o1) << "(t" << expr_gen.to_str(o2) << "t))"); - } - }; - - struct synthesize_covovov_expression1 - { - typedef typename covovov_t::type1 node_type; - typedef typename covovov_t::sf4_type sf4_type; - typedef typename node_type::T0 T0; - typedef typename node_type::T1 T1; - typedef typename node_type::T2 T2; - typedef typename node_type::T3 T3; - - static inline expression_node_ptr process(expression_generator& expr_gen, - const details::operator_type& operation, - expression_node_ptr (&branch)[2]) - { - // c o0 (v0 o1 (v1 o2 v2)) - typedef typename synthesize_vovov_expression1::node_type lcl_vovov_t; - - const lcl_vovov_t* vovov = static_cast(branch[1]); - const Type c = static_cast*>(branch[0])->value(); - const Type& v0 = vovov->t0(); - const Type& v1 = vovov->t1(); - const Type& v2 = vovov->t2(); - const details::operator_type o0 = operation; - const details::operator_type o1 = expr_gen.get_operator(vovov->f0()); - const details::operator_type o2 = expr_gen.get_operator(vovov->f1()); - - binary_functor_t f0 = reinterpret_cast(0); - binary_functor_t f1 = vovov->f0(); - binary_functor_t f2 = vovov->f1(); - - details::free_node(*(expr_gen.node_allocator_),branch[0]); - details::free_node(*(expr_gen.node_allocator_),branch[1]); - - expression_node_ptr result = error_node(); - - if (synthesize_sf4ext_expression::template compile(expr_gen,id(expr_gen,o0,o1,o2),c,v0,v1,v2,result)) - return result; - if (!expr_gen.valid_operator(o0,f0)) - return error_node(); - - exprtk_debug(("c o0 (v0 o1 (v1 o2 v2))\n")); - - return node_type::allocate(*(expr_gen.node_allocator_),c,v0,v1,v2,f0,f1,f2); - } - - static inline std::string id(expression_generator& expr_gen, - const details::operator_type o0, - const details::operator_type o1, - const details::operator_type o2) - { - return (details::build_string() << "t" << expr_gen.to_str(o0) << "(t" << expr_gen.to_str(o1) << "(t" << expr_gen.to_str(o2) << "t))"); - } - }; - - struct synthesize_covocov_expression1 - { - typedef typename covocov_t::type1 node_type; - typedef typename covocov_t::sf4_type sf4_type; - typedef typename node_type::T0 T0; - typedef typename node_type::T1 T1; - typedef typename node_type::T2 T2; - typedef typename node_type::T3 T3; - - static inline expression_node_ptr process(expression_generator& expr_gen, - const details::operator_type& operation, - expression_node_ptr (&branch)[2]) - { - // c0 o0 (v0 o1 (c1 o2 v1)) - typedef typename synthesize_vocov_expression1::node_type lcl_vocov_t; - - const lcl_vocov_t* vocov = static_cast(branch[1]); - const Type c0 = static_cast*>(branch[0])->value(); - const Type& v0 = vocov->t0(); - const Type c1 = vocov->t1(); - const Type& v1 = vocov->t2(); - const details::operator_type o0 = operation; - const details::operator_type o1 = expr_gen.get_operator(vocov->f0()); - const details::operator_type o2 = expr_gen.get_operator(vocov->f1()); - - binary_functor_t f0 = reinterpret_cast(0); - binary_functor_t f1 = vocov->f0(); - binary_functor_t f2 = vocov->f1(); - - details::free_node(*(expr_gen.node_allocator_),branch[0]); - details::free_node(*(expr_gen.node_allocator_),branch[1]); - - expression_node_ptr result = error_node(); - - if (synthesize_sf4ext_expression::template compile(expr_gen,id(expr_gen,o0,o1,o2),c0,v0,c1,v1,result)) - return result; - else if (!expr_gen.valid_operator(o0,f0)) - return error_node(); - - exprtk_debug(("c0 o0 (v0 o1 (c1 o2 v1))\n")); - - return node_type::allocate(*(expr_gen.node_allocator_),c0,v0,c1,v1,f0,f1,f2); - } - - static inline std::string id(expression_generator& expr_gen, - const details::operator_type o0, - const details::operator_type o1, - const details::operator_type o2) - { - return (details::build_string() << "t" << expr_gen.to_str(o0) << "(t" << expr_gen.to_str(o1) << "(t" << expr_gen.to_str(o2) << "t))"); - } - }; - - struct synthesize_vocovoc_expression1 - { - typedef typename vocovoc_t::type1 node_type; - typedef typename vocovoc_t::sf4_type sf4_type; - typedef typename node_type::T0 T0; - typedef typename node_type::T1 T1; - typedef typename node_type::T2 T2; - typedef typename node_type::T3 T3; - - static inline expression_node_ptr process(expression_generator& expr_gen, - const details::operator_type& operation, - expression_node_ptr (&branch)[2]) - { - // v0 o0 (c0 o1 (v1 o2 c2)) - typedef typename synthesize_covoc_expression1::node_type lcl_covoc_t; - - const lcl_covoc_t* covoc = static_cast(branch[1]); - const Type& v0 = static_cast*>(branch[0])->ref(); - const Type c0 = covoc->t0(); - const Type& v1 = covoc->t1(); - const Type c1 = covoc->t2(); - const details::operator_type o0 = operation; - const details::operator_type o1 = expr_gen.get_operator(covoc->f0()); - const details::operator_type o2 = expr_gen.get_operator(covoc->f1()); - - binary_functor_t f0 = reinterpret_cast(0); - binary_functor_t f1 = covoc->f0(); - binary_functor_t f2 = covoc->f1(); - - details::free_node(*(expr_gen.node_allocator_),branch[1]); - - expression_node_ptr result = error_node(); - - if (synthesize_sf4ext_expression::template compile(expr_gen,id(expr_gen,o0,o1,o2),v0,c0,v1,c1,result)) - return result; - else if (!expr_gen.valid_operator(o0,f0)) - return error_node(); - - exprtk_debug(("v0 o0 (c0 o1 (v1 o2 c2))\n")); - - return node_type::allocate(*(expr_gen.node_allocator_),v0,c0,v1,c1,f0,f1,f2); - } - - static inline std::string id(expression_generator& expr_gen, - const details::operator_type o0, - const details::operator_type o1, - const details::operator_type o2) - { - return (details::build_string() << "t" << expr_gen.to_str(o0) << "(t" << expr_gen.to_str(o1) << "(t" << expr_gen.to_str(o2) << "t))"); - } - }; - - struct synthesize_covovoc_expression1 - { - typedef typename covovoc_t::type1 node_type; - typedef typename covovoc_t::sf4_type sf4_type; - typedef typename node_type::T0 T0; - typedef typename node_type::T1 T1; - typedef typename node_type::T2 T2; - typedef typename node_type::T3 T3; - static inline expression_node_ptr process(expression_generator& expr_gen, - const details::operator_type& operation, - expression_node_ptr (&branch)[2]) - { - // c0 o0 (v0 o1 (v1 o2 c1)) - typedef typename synthesize_vovoc_expression1::node_type lcl_vovoc_t; - - const lcl_vovoc_t* vovoc = static_cast(branch[1]); - const Type c0 = static_cast*>(branch[0])->value(); - const Type& v0 = vovoc->t0(); - const Type& v1 = vovoc->t1(); - const Type c1 = vovoc->t2(); - const details::operator_type o0 = operation; - const details::operator_type o1 = expr_gen.get_operator(vovoc->f0()); - const details::operator_type o2 = expr_gen.get_operator(vovoc->f1()); - - binary_functor_t f0 = reinterpret_cast(0); - binary_functor_t f1 = vovoc->f0(); - binary_functor_t f2 = vovoc->f1(); - - details::free_node(*(expr_gen.node_allocator_),branch[0]); - details::free_node(*(expr_gen.node_allocator_),branch[1]); - - expression_node_ptr result = error_node(); - - if (synthesize_sf4ext_expression::template compile(expr_gen,id(expr_gen,o0,o1,o2),c0,v0,v1,c1,result)) - return result; - else if (!expr_gen.valid_operator(o0,f0)) - return error_node(); - - exprtk_debug(("c0 o0 (v0 o1 (v1 o2 c1))\n")); - - return node_type::allocate(*(expr_gen.node_allocator_),c0,v0,v1,c1,f0,f1,f2); - } - - static inline std::string id(expression_generator& expr_gen, - const details::operator_type o0, - const details::operator_type o1, - const details::operator_type o2) - { - return (details::build_string() << "t" << expr_gen.to_str(o0) << "(t" << expr_gen.to_str(o1) << "(t" << expr_gen.to_str(o2) << "t))"); - } - }; - - struct synthesize_vococov_expression1 - { - typedef typename vococov_t::type1 node_type; - typedef typename vococov_t::sf4_type sf4_type; - typedef typename node_type::T0 T0; - typedef typename node_type::T1 T1; - typedef typename node_type::T2 T2; - typedef typename node_type::T3 T3; - - static inline expression_node_ptr process(expression_generator& expr_gen, - const details::operator_type& operation, - expression_node_ptr (&branch)[2]) - { - // v0 o0 (c0 o1 (c1 o2 v1)) - typedef typename synthesize_cocov_expression1::node_type lcl_cocov_t; - - const lcl_cocov_t* cocov = static_cast(branch[1]); - const Type& v0 = static_cast*>(branch[0])->ref(); - const Type c0 = cocov->t0(); - const Type c1 = cocov->t1(); - const Type& v1 = cocov->t2(); - const details::operator_type o0 = operation; - const details::operator_type o1 = expr_gen.get_operator(cocov->f0()); - const details::operator_type o2 = expr_gen.get_operator(cocov->f1()); - - binary_functor_t f0 = reinterpret_cast(0); - binary_functor_t f1 = cocov->f0(); - binary_functor_t f2 = cocov->f1(); - - details::free_node(*(expr_gen.node_allocator_),branch[1]); - - expression_node_ptr result = error_node(); - - if (synthesize_sf4ext_expression::template compile(expr_gen,id(expr_gen,o0,o1,o2),v0,c0,c1,v1,result)) - return result; - else if (!expr_gen.valid_operator(o0,f0)) - return error_node(); - - exprtk_debug(("v0 o0 (c0 o1 (c1 o2 v1))\n")); - - return node_type::allocate(*(expr_gen.node_allocator_),v0,c0,c1,v1,f0,f1,f2); - } - - static inline std::string id(expression_generator& expr_gen, - const details::operator_type o0, - const details::operator_type o1, - const details::operator_type o2) - { - return (details::build_string() << "t" << expr_gen.to_str(o0) << "(t" << expr_gen.to_str(o1) << "(t" << expr_gen.to_str(o2) << "t))"); - } - }; - - struct synthesize_vovovov_expression2 - { - typedef typename vovovov_t::type2 node_type; - typedef typename vovovov_t::sf4_type sf4_type; - typedef typename node_type::T0 T0; - typedef typename node_type::T1 T1; - typedef typename node_type::T2 T2; - typedef typename node_type::T3 T3; - - static inline expression_node_ptr process(expression_generator& expr_gen, - const details::operator_type& operation, - expression_node_ptr (&branch)[2]) - { - // v0 o0 ((v1 o1 v2) o2 v3) - typedef typename synthesize_vovov_expression0::node_type lcl_vovov_t; - - const lcl_vovov_t* vovov = static_cast(branch[1]); - const Type& v0 = static_cast*>(branch[0])->ref(); - const Type& v1 = vovov->t0(); - const Type& v2 = vovov->t1(); - const Type& v3 = vovov->t2(); - const details::operator_type o0 = operation; - const details::operator_type o1 = expr_gen.get_operator(vovov->f0()); - const details::operator_type o2 = expr_gen.get_operator(vovov->f1()); - - binary_functor_t f0 = reinterpret_cast(0); - binary_functor_t f1 = vovov->f0(); - binary_functor_t f2 = vovov->f1(); - - details::free_node(*(expr_gen.node_allocator_),branch[1]); - - expression_node_ptr result = error_node(); - - if (synthesize_sf4ext_expression::template compile(expr_gen,id(expr_gen,o0,o1,o2),v0,v1,v2,v3,result)) - return result; - else if (!expr_gen.valid_operator(o0,f0)) - return error_node(); - - exprtk_debug(("v0 o0 ((v1 o1 v2) o2 v3)\n")); - - return node_type::allocate(*(expr_gen.node_allocator_),v0,v1,v2,v3,f0,f1,f2); - } - - static inline std::string id(expression_generator& expr_gen, - const details::operator_type o0, - const details::operator_type o1, - const details::operator_type o2) - { - return (details::build_string() << "t" << expr_gen.to_str(o0) << "((t" << expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t)"); - } - }; - - struct synthesize_vovovoc_expression2 - { - typedef typename vovovoc_t::type2 node_type; - typedef typename vovovoc_t::sf4_type sf4_type; - typedef typename node_type::T0 T0; - typedef typename node_type::T1 T1; - typedef typename node_type::T2 T2; - typedef typename node_type::T3 T3; - - static inline expression_node_ptr process(expression_generator& expr_gen, - const details::operator_type& operation, - expression_node_ptr (&branch)[2]) - { - // v0 o0 ((v1 o1 v2) o2 c) - typedef typename synthesize_vovoc_expression0::node_type lcl_vovoc_t; - - const lcl_vovoc_t* vovoc = static_cast(branch[1]); - const Type& v0 = static_cast*>(branch[0])->ref(); - const Type& v1 = vovoc->t0(); - const Type& v2 = vovoc->t1(); - const Type c = vovoc->t2(); - const details::operator_type o0 = operation; - const details::operator_type o1 = expr_gen.get_operator(vovoc->f0()); - const details::operator_type o2 = expr_gen.get_operator(vovoc->f1()); - - binary_functor_t f0 = reinterpret_cast(0); - binary_functor_t f1 = vovoc->f0(); - binary_functor_t f2 = vovoc->f1(); - - details::free_node(*(expr_gen.node_allocator_),branch[1]); - - expression_node_ptr result = error_node(); - - if (synthesize_sf4ext_expression::template compile(expr_gen,id(expr_gen,o0,o1,o2),v0,v1,v2,c,result)) - return result; - else if (!expr_gen.valid_operator(o0,f0)) - return error_node(); - - exprtk_debug(("v0 o0 ((v1 o1 v2) o2 c)\n")); - - return node_type::allocate(*(expr_gen.node_allocator_),v0,v1,v2,c,f0,f1,f2); - } - - static inline std::string id(expression_generator& expr_gen, - const details::operator_type o0, - const details::operator_type o1, - const details::operator_type o2) - { - return (details::build_string() << "t" << expr_gen.to_str(o0) << "((t" << expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t)"); - } - }; - - struct synthesize_vovocov_expression2 - { - typedef typename vovocov_t::type2 node_type; - typedef typename vovocov_t::sf4_type sf4_type; - typedef typename node_type::T0 T0; - typedef typename node_type::T1 T1; - typedef typename node_type::T2 T2; - typedef typename node_type::T3 T3; - - static inline expression_node_ptr process(expression_generator& expr_gen, - const details::operator_type& operation, - expression_node_ptr (&branch)[2]) - { - // v0 o0 ((v1 o1 c) o2 v2) - typedef typename synthesize_vocov_expression0::node_type lcl_vocov_t; - - const lcl_vocov_t* vocov = static_cast(branch[1]); - const Type& v0 = static_cast*>(branch[0])->ref(); - const Type& v1 = vocov->t0(); - const Type c = vocov->t1(); - const Type& v2 = vocov->t2(); - const details::operator_type o0 = operation; - const details::operator_type o1 = expr_gen.get_operator(vocov->f0()); - const details::operator_type o2 = expr_gen.get_operator(vocov->f1()); - - binary_functor_t f0 = reinterpret_cast(0); - binary_functor_t f1 = vocov->f0(); - binary_functor_t f2 = vocov->f1(); - - details::free_node(*(expr_gen.node_allocator_),branch[1]); - - expression_node_ptr result = error_node(); - - if (synthesize_sf4ext_expression::template compile(expr_gen,id(expr_gen,o0,o1,o2),v0,v1,c,v2,result)) - return result; - else if (!expr_gen.valid_operator(o0,f0)) - return error_node(); - - exprtk_debug(("v0 o0 ((v1 o1 c) o2 v2)\n")); - - return node_type::allocate(*(expr_gen.node_allocator_),v0,v1,c,v2,f0,f1,f2); - } - - static inline std::string id(expression_generator& expr_gen, - const details::operator_type o0, - const details::operator_type o1, - const details::operator_type o2) - { - return (details::build_string() << "t" << expr_gen.to_str(o0) << "((t" << expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t)"); - } - }; - - struct synthesize_vocovov_expression2 - { - typedef typename vocovov_t::type2 node_type; - typedef typename vocovov_t::sf4_type sf4_type; - typedef typename node_type::T0 T0; - typedef typename node_type::T1 T1; - typedef typename node_type::T2 T2; - typedef typename node_type::T3 T3; - - static inline expression_node_ptr process(expression_generator& expr_gen, - const details::operator_type& operation, - expression_node_ptr (&branch)[2]) - { - // v0 o0 ((c o1 v1) o2 v2) - typedef typename synthesize_covov_expression0::node_type lcl_covov_t; - - const lcl_covov_t* covov = static_cast(branch[1]); - const Type& v0 = static_cast*>(branch[0])->ref(); - const Type c = covov->t0(); - const Type& v1 = covov->t1(); - const Type& v2 = covov->t2(); - const details::operator_type o0 = operation; - const details::operator_type o1 = expr_gen.get_operator(covov->f0()); - const details::operator_type o2 = expr_gen.get_operator(covov->f1()); - - binary_functor_t f0 = reinterpret_cast(0); - binary_functor_t f1 = covov->f0(); - binary_functor_t f2 = covov->f1(); - - details::free_node(*(expr_gen.node_allocator_),branch[1]); - - expression_node_ptr result = error_node(); - - if (synthesize_sf4ext_expression::template compile(expr_gen,id(expr_gen,o0,o1,o2),v0,c,v1,v2,result)) - return result; - else if (!expr_gen.valid_operator(o0,f0)) - return error_node(); - - exprtk_debug(("v0 o0 ((c o1 v1) o2 v2)\n")); - - return node_type::allocate(*(expr_gen.node_allocator_),v0,c,v1,v2,f0,f1,f2); - } - - static inline std::string id(expression_generator& expr_gen, - const details::operator_type o0, - const details::operator_type o1, - const details::operator_type o2) - { - return (details::build_string() << "t" << expr_gen.to_str(o0) << "((t" << expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t)"); - } - }; - - struct synthesize_covovov_expression2 - { - typedef typename covovov_t::type2 node_type; - typedef typename covovov_t::sf4_type sf4_type; - typedef typename node_type::T0 T0; - typedef typename node_type::T1 T1; - typedef typename node_type::T2 T2; - typedef typename node_type::T3 T3; - - static inline expression_node_ptr process(expression_generator& expr_gen, - const details::operator_type& operation, - expression_node_ptr (&branch)[2]) - { - // c o0 ((v1 o1 v2) o2 v3) - typedef typename synthesize_vovov_expression0::node_type lcl_vovov_t; - - const lcl_vovov_t* vovov = static_cast(branch[1]); - const Type c = static_cast*>(branch[0])->value(); - const Type& v0 = vovov->t0(); - const Type& v1 = vovov->t1(); - const Type& v2 = vovov->t2(); - const details::operator_type o0 = operation; - const details::operator_type o1 = expr_gen.get_operator(vovov->f0()); - const details::operator_type o2 = expr_gen.get_operator(vovov->f1()); - - binary_functor_t f0 = reinterpret_cast(0); - binary_functor_t f1 = vovov->f0(); - binary_functor_t f2 = vovov->f1(); - - details::free_node(*(expr_gen.node_allocator_),branch[0]); - details::free_node(*(expr_gen.node_allocator_),branch[1]); - - expression_node_ptr result = error_node(); - - if (synthesize_sf4ext_expression::template compile(expr_gen,id(expr_gen,o0,o1,o2),c,v0,v1,v2,result)) - return result; - else if (!expr_gen.valid_operator(o0,f0)) - return error_node(); - - exprtk_debug(("c o0 ((v1 o1 v2) o2 v3)\n")); - - return node_type::allocate(*(expr_gen.node_allocator_),c,v0,v1,v2,f0,f1,f2); - } - - static inline std::string id(expression_generator& expr_gen, - const details::operator_type o0, - const details::operator_type o1, - const details::operator_type o2) - { - return (details::build_string() << "t" << expr_gen.to_str(o0) << "((t" << expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t)"); - } - }; - - struct synthesize_covocov_expression2 - { - typedef typename covocov_t::type2 node_type; - typedef typename covocov_t::sf4_type sf4_type; - typedef typename node_type::T0 T0; - typedef typename node_type::T1 T1; - typedef typename node_type::T2 T2; - typedef typename node_type::T3 T3; - - static inline expression_node_ptr process(expression_generator& expr_gen, - const details::operator_type& operation, - expression_node_ptr (&branch)[2]) - { - // c0 o0 ((v0 o1 c1) o2 v1) - typedef typename synthesize_vocov_expression0::node_type lcl_vocov_t; - - const lcl_vocov_t* vocov = static_cast(branch[1]); - const Type c0 = static_cast*>(branch[0])->value(); - const Type& v0 = vocov->t0(); - const Type c1 = vocov->t1(); - const Type& v1 = vocov->t2(); - const details::operator_type o0 = operation; - const details::operator_type o1 = expr_gen.get_operator(vocov->f0()); - const details::operator_type o2 = expr_gen.get_operator(vocov->f1()); - - binary_functor_t f0 = reinterpret_cast(0); - binary_functor_t f1 = vocov->f0(); - binary_functor_t f2 = vocov->f1(); - - details::free_node(*(expr_gen.node_allocator_),branch[0]); - details::free_node(*(expr_gen.node_allocator_),branch[1]); - - expression_node_ptr result = error_node(); - - if (synthesize_sf4ext_expression::template compile(expr_gen,id(expr_gen,o0,o1,o2),c0,v0,c1,v1,result)) - return result; - else if (!expr_gen.valid_operator(o0,f0)) - return error_node(); - - exprtk_debug(("c0 o0 ((v0 o1 c1) o2 v1)\n")); - - return node_type::allocate(*(expr_gen.node_allocator_),c0,v0,c1,v1,f0,f1,f2); - } - - static inline std::string id(expression_generator& expr_gen, - const details::operator_type o0, - const details::operator_type o1, - const details::operator_type o2) - { - return (details::build_string() << "t" << expr_gen.to_str(o0) << "((t" << expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t)"); - } - }; - - struct synthesize_vocovoc_expression2 - { - typedef typename vocovoc_t::type2 node_type; - typedef typename vocovoc_t::sf4_type sf4_type; - typedef typename node_type::T0 T0; - typedef typename node_type::T1 T1; - typedef typename node_type::T2 T2; - typedef typename node_type::T3 T3; - - static inline expression_node_ptr process(expression_generator& expr_gen, - const details::operator_type& operation, - expression_node_ptr (&branch)[2]) - { - // v0 o0 ((c0 o1 v1) o2 c1) - typedef typename synthesize_covoc_expression0::node_type lcl_covoc_t; - - const lcl_covoc_t* covoc = static_cast(branch[1]); - const Type& v0 = static_cast*>(branch[0])->ref(); - const Type c0 = covoc->t0(); - const Type& v1 = covoc->t1(); - const Type c1 = covoc->t2(); - const details::operator_type o0 = operation; - const details::operator_type o1 = expr_gen.get_operator(covoc->f0()); - const details::operator_type o2 = expr_gen.get_operator(covoc->f1()); - - binary_functor_t f0 = reinterpret_cast(0); - binary_functor_t f1 = covoc->f0(); - binary_functor_t f2 = covoc->f1(); - - details::free_node(*(expr_gen.node_allocator_),branch[1]); - - expression_node_ptr result = error_node(); - - if (synthesize_sf4ext_expression::template compile(expr_gen,id(expr_gen,o0,o1,o2),v0,c0,v1,c1,result)) - return result; - else if (!expr_gen.valid_operator(o0,f0)) - return error_node(); - - exprtk_debug(("v0 o0 ((c0 o1 v1) o2 c1)\n")); - - return node_type::allocate(*(expr_gen.node_allocator_),v0,c0,v1,c1,f0,f1,f2); - } - - static inline std::string id(expression_generator& expr_gen, - const details::operator_type o0, - const details::operator_type o1, - const details::operator_type o2) - { - return (details::build_string() << "t" << expr_gen.to_str(o0) << "((t" << expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t)"); - } - }; - - struct synthesize_covovoc_expression2 - { - typedef typename covovoc_t::type2 node_type; - typedef typename covovoc_t::sf4_type sf4_type; - typedef typename node_type::T0 T0; - typedef typename node_type::T1 T1; - typedef typename node_type::T2 T2; - typedef typename node_type::T3 T3; - - static inline expression_node_ptr process(expression_generator& expr_gen, - const details::operator_type& operation, - expression_node_ptr (&branch)[2]) - { - // c0 o0 ((v0 o1 v1) o2 c1) - typedef typename synthesize_vovoc_expression0::node_type lcl_vovoc_t; - - const lcl_vovoc_t* vovoc = static_cast(branch[1]); - const Type c0 = static_cast*>(branch[0])->value(); - const Type& v0 = vovoc->t0(); - const Type& v1 = vovoc->t1(); - const Type c1 = vovoc->t2(); - const details::operator_type o0 = operation; - const details::operator_type o1 = expr_gen.get_operator(vovoc->f0()); - const details::operator_type o2 = expr_gen.get_operator(vovoc->f1()); - - binary_functor_t f0 = reinterpret_cast(0); - binary_functor_t f1 = vovoc->f0(); - binary_functor_t f2 = vovoc->f1(); - - details::free_node(*(expr_gen.node_allocator_),branch[0]); - details::free_node(*(expr_gen.node_allocator_),branch[1]); - - expression_node_ptr result = error_node(); - - if (synthesize_sf4ext_expression::template compile(expr_gen,id(expr_gen,o0,o1,o2),c0,v0,v1,c1,result)) - return result; - else if (!expr_gen.valid_operator(o0,f0)) - return error_node(); - - exprtk_debug(("c0 o0 ((v0 o1 v1) o2 c1)\n")); - - return node_type::allocate(*(expr_gen.node_allocator_),c0,v0,v1,c1,f0,f1,f2); - } - - static inline std::string id(expression_generator& expr_gen, - const details::operator_type o0, - const details::operator_type o1, - const details::operator_type o2) - { - return (details::build_string() << "t" << expr_gen.to_str(o0) << "((t" << expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t)"); - } - }; - - struct synthesize_vococov_expression2 - { - typedef typename vococov_t::type2 node_type; - static inline expression_node_ptr process(expression_generator&, const details::operator_type&, expression_node_ptr (&)[2]) - { - // v0 o0 ((c0 o1 c1) o2 v1) - Not possible - exprtk_debug(("v0 o0 ((c0 o1 c1) o2 v1) - Not possible\n")); - return error_node(); - } - - static inline std::string id(expression_generator&, - const details::operator_type, const details::operator_type, const details::operator_type) - { - return "INVALID"; - } - }; - - struct synthesize_vovovov_expression3 - { - typedef typename vovovov_t::type3 node_type; - typedef typename vovovov_t::sf4_type sf4_type; - typedef typename node_type::T0 T0; - typedef typename node_type::T1 T1; - typedef typename node_type::T2 T2; - typedef typename node_type::T3 T3; - - static inline expression_node_ptr process(expression_generator& expr_gen, - const details::operator_type& operation, - expression_node_ptr (&branch)[2]) - { - // ((v0 o0 v1) o1 v2) o2 v3 - typedef typename synthesize_vovov_expression0::node_type lcl_vovov_t; - - const lcl_vovov_t* vovov = static_cast(branch[0]); - const Type& v0 = vovov->t0(); - const Type& v1 = vovov->t1(); - const Type& v2 = vovov->t2(); - const Type& v3 = static_cast*>(branch[1])->ref(); - const details::operator_type o0 = expr_gen.get_operator(vovov->f0()); - const details::operator_type o1 = expr_gen.get_operator(vovov->f1()); - const details::operator_type o2 = operation; - - binary_functor_t f0 = vovov->f0(); - binary_functor_t f1 = vovov->f1(); - binary_functor_t f2 = reinterpret_cast(0); - - details::free_node(*(expr_gen.node_allocator_),branch[0]); - - expression_node_ptr result = error_node(); - - if (synthesize_sf4ext_expression::template compile(expr_gen,id(expr_gen,o0,o1,o2),v0,v1,v2,v3,result)) - return result; - else if (!expr_gen.valid_operator(o2,f2)) - return error_node(); - - exprtk_debug(("((v0 o0 v1) o1 v2) o2 v3\n")); - - return node_type::allocate(*(expr_gen.node_allocator_),v0,v1,v2,v3,f0,f1,f2); - } - - static inline std::string id(expression_generator& expr_gen, - const details::operator_type o0, - const details::operator_type o1, - const details::operator_type o2) - { - return (details::build_string() << "((t" << expr_gen.to_str(o0) << "t)" << expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t"); - } - }; - - struct synthesize_vovovoc_expression3 - { - typedef typename vovovoc_t::type3 node_type; - typedef typename vovovoc_t::sf4_type sf4_type; - typedef typename node_type::T0 T0; - typedef typename node_type::T1 T1; - typedef typename node_type::T2 T2; - typedef typename node_type::T3 T3; - - static inline expression_node_ptr process(expression_generator& expr_gen, - const details::operator_type& operation, - expression_node_ptr (&branch)[2]) - { - // ((v0 o0 v1) o1 v2) o2 c - typedef typename synthesize_vovov_expression0::node_type lcl_vovov_t; - - const lcl_vovov_t* vovov = static_cast(branch[0]); - const Type& v0 = vovov->t0(); - const Type& v1 = vovov->t1(); - const Type& v2 = vovov->t2(); - const Type c = static_cast*>(branch[1])->value(); - const details::operator_type o0 = expr_gen.get_operator(vovov->f0()); - const details::operator_type o1 = expr_gen.get_operator(vovov->f1()); - const details::operator_type o2 = operation; - - binary_functor_t f0 = vovov->f0(); - binary_functor_t f1 = vovov->f1(); - binary_functor_t f2 = reinterpret_cast(0); - - details::free_node(*(expr_gen.node_allocator_),branch[0]); - details::free_node(*(expr_gen.node_allocator_),branch[1]); - - expression_node_ptr result = error_node(); - - if (synthesize_sf4ext_expression::template compile(expr_gen,id(expr_gen,o0,o1,o2),v0,v1,v2,c,result)) - return result; - else if (!expr_gen.valid_operator(o2,f2)) - return error_node(); - - exprtk_debug(("((v0 o0 v1) o1 v2) o2 c\n")); - - return node_type::allocate(*(expr_gen.node_allocator_),v0,v1,v2,c,f0,f1,f2); - } - - static inline std::string id(expression_generator& expr_gen, - const details::operator_type o0, - const details::operator_type o1, - const details::operator_type o2) - { - return (details::build_string() << "((t" << expr_gen.to_str(o0) << "t)" << expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t"); - } - }; - - struct synthesize_vovocov_expression3 - { - typedef typename vovocov_t::type3 node_type; - typedef typename vovocov_t::sf4_type sf4_type; - typedef typename node_type::T0 T0; - typedef typename node_type::T1 T1; - typedef typename node_type::T2 T2; - typedef typename node_type::T3 T3; - - static inline expression_node_ptr process(expression_generator& expr_gen, - const details::operator_type& operation, - expression_node_ptr (&branch)[2]) - { - // ((v0 o0 v1) o1 c) o2 v2 - typedef typename synthesize_vovoc_expression0::node_type lcl_vovoc_t; - - const lcl_vovoc_t* vovoc = static_cast(branch[0]); - const Type& v0 = vovoc->t0(); - const Type& v1 = vovoc->t1(); - const Type c = vovoc->t2(); - const Type& v2 = static_cast*>(branch[1])->ref(); - const details::operator_type o0 = expr_gen.get_operator(vovoc->f0()); - const details::operator_type o1 = expr_gen.get_operator(vovoc->f1()); - const details::operator_type o2 = operation; - - binary_functor_t f0 = vovoc->f0(); - binary_functor_t f1 = vovoc->f1(); - binary_functor_t f2 = reinterpret_cast(0); - - details::free_node(*(expr_gen.node_allocator_),branch[0]); - - expression_node_ptr result = error_node(); - - if (synthesize_sf4ext_expression::template compile(expr_gen,id(expr_gen,o0,o1,o2),v0,v1,c,v2,result)) - return result; - else if (!expr_gen.valid_operator(o2,f2)) - return error_node(); - - exprtk_debug(("((v0 o0 v1) o1 c) o2 v2\n")); - - return node_type::allocate(*(expr_gen.node_allocator_),v0,v1,c,v2,f0,f1,f2); - } - - static inline std::string id(expression_generator& expr_gen, - const details::operator_type o0, - const details::operator_type o1, - const details::operator_type o2) - { - return (details::build_string() << "((t" << expr_gen.to_str(o0) << "t)" << expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t"); - } - }; - - struct synthesize_vocovov_expression3 - { - typedef typename vocovov_t::type3 node_type; - typedef typename vocovov_t::sf4_type sf4_type; - typedef typename node_type::T0 T0; - typedef typename node_type::T1 T1; - typedef typename node_type::T2 T2; - typedef typename node_type::T3 T3; - - static inline expression_node_ptr process(expression_generator& expr_gen, - const details::operator_type& operation, - expression_node_ptr (&branch)[2]) - { - // ((v0 o0 c) o1 v1) o2 v2 - typedef typename synthesize_vocov_expression0::node_type lcl_vocov_t; - - const lcl_vocov_t* vocov = static_cast(branch[0]); - const Type& v0 = vocov->t0(); - const Type c = vocov->t1(); - const Type& v1 = vocov->t2(); - const Type& v2 = static_cast*>(branch[1])->ref(); - const details::operator_type o0 = expr_gen.get_operator(vocov->f0()); - const details::operator_type o1 = expr_gen.get_operator(vocov->f1()); - const details::operator_type o2 = operation; - - binary_functor_t f0 = vocov->f0(); - binary_functor_t f1 = vocov->f1(); - binary_functor_t f2 = reinterpret_cast(0); - - details::free_node(*(expr_gen.node_allocator_),branch[0]); - - expression_node_ptr result = error_node(); - - if (synthesize_sf4ext_expression::template compile(expr_gen,id(expr_gen,o0,o1,o2),v0,c,v1,v2,result)) - return result; - else if (!expr_gen.valid_operator(o2,f2)) - return error_node(); - - exprtk_debug(("((v0 o0 c) o1 v1) o2 v2\n")); - - return node_type::allocate(*(expr_gen.node_allocator_),v0,c,v1,v2,f0,f1,f2); - } - - static inline std::string id(expression_generator& expr_gen, - const details::operator_type o0, - const details::operator_type o1, - const details::operator_type o2) - { - return (details::build_string() << "((t" << expr_gen.to_str(o0) << "t)" << expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t"); - } - }; - - struct synthesize_covovov_expression3 - { - typedef typename covovov_t::type3 node_type; - typedef typename covovov_t::sf4_type sf4_type; - typedef typename node_type::T0 T0; - typedef typename node_type::T1 T1; - typedef typename node_type::T2 T2; - typedef typename node_type::T3 T3; - - static inline expression_node_ptr process(expression_generator& expr_gen, - const details::operator_type& operation, - expression_node_ptr (&branch)[2]) - { - // ((c o0 v0) o1 v1) o2 v2 - typedef typename synthesize_covov_expression0::node_type lcl_covov_t; - - const lcl_covov_t* covov = static_cast(branch[0]); - const Type c = covov->t0(); - const Type& v0 = covov->t1(); - const Type& v1 = covov->t2(); - const Type& v2 = static_cast*>(branch[1])->ref(); - const details::operator_type o0 = expr_gen.get_operator(covov->f0()); - const details::operator_type o1 = expr_gen.get_operator(covov->f1()); - const details::operator_type o2 = operation; - - binary_functor_t f0 = covov->f0(); - binary_functor_t f1 = covov->f1(); - binary_functor_t f2 = reinterpret_cast(0); - - details::free_node(*(expr_gen.node_allocator_),branch[0]); - - expression_node_ptr result = error_node(); - - if (synthesize_sf4ext_expression::template compile(expr_gen,id(expr_gen,o0,o1,o2),c,v0,v1,v2,result)) - return result; - else if (!expr_gen.valid_operator(o2,f2)) - return error_node(); - - exprtk_debug(("((c o0 v0) o1 v1) o2 v2\n")); - - return node_type::allocate(*(expr_gen.node_allocator_),c,v0,v1,v2,f0,f1,f2); - } - - static inline std::string id(expression_generator& expr_gen, - const details::operator_type o0, - const details::operator_type o1, - const details::operator_type o2) - { - return (details::build_string() << "((t" << expr_gen.to_str(o0) << "t)" << expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t"); - } - }; - - struct synthesize_covocov_expression3 - { - typedef typename covocov_t::type3 node_type; - typedef typename covocov_t::sf4_type sf4_type; - typedef typename node_type::T0 T0; - typedef typename node_type::T1 T1; - typedef typename node_type::T2 T2; - typedef typename node_type::T3 T3; - - static inline expression_node_ptr process(expression_generator& expr_gen, - const details::operator_type& operation, - expression_node_ptr (&branch)[2]) - { - // ((c0 o0 v0) o1 c1) o2 v1 - typedef typename synthesize_covoc_expression0::node_type lcl_covoc_t; - - const lcl_covoc_t* covoc = static_cast(branch[0]); - const Type c0 = covoc->t0(); - const Type& v0 = covoc->t1(); - const Type c1 = covoc->t2(); - const Type& v1 = static_cast*>(branch[1])->ref(); - const details::operator_type o0 = expr_gen.get_operator(covoc->f0()); - const details::operator_type o1 = expr_gen.get_operator(covoc->f1()); - const details::operator_type o2 = operation; - - binary_functor_t f0 = covoc->f0(); - binary_functor_t f1 = covoc->f1(); - binary_functor_t f2 = reinterpret_cast(0); - - details::free_node(*(expr_gen.node_allocator_),branch[0]); - - expression_node_ptr result = error_node(); - - if (synthesize_sf4ext_expression::template compile(expr_gen,id(expr_gen,o0,o1,o2),c0,v0,c1,v1,result)) - return result; - else if (!expr_gen.valid_operator(o2,f2)) - return error_node(); - - exprtk_debug(("((c0 o0 v0) o1 c1) o2 v1\n")); - - return node_type::allocate(*(expr_gen.node_allocator_),c0,v0,c1,v1,f0,f1,f2); - } - - static inline std::string id(expression_generator& expr_gen, - const details::operator_type o0, - const details::operator_type o1, - const details::operator_type o2) - { - return (details::build_string() << "((t" << expr_gen.to_str(o0) << "t)" << expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t"); - } - }; - - struct synthesize_vocovoc_expression3 - { - typedef typename vocovoc_t::type3 node_type; - typedef typename vocovoc_t::sf4_type sf4_type; - typedef typename node_type::T0 T0; - typedef typename node_type::T1 T1; - typedef typename node_type::T2 T2; - typedef typename node_type::T3 T3; - - static inline expression_node_ptr process(expression_generator& expr_gen, - const details::operator_type& operation, - expression_node_ptr (&branch)[2]) - { - // ((v0 o0 c0) o1 v1) o2 c1 - typedef typename synthesize_vocov_expression0::node_type lcl_vocov_t; - - const lcl_vocov_t* vocov = static_cast(branch[0]); - const Type& v0 = vocov->t0(); - const Type c0 = vocov->t1(); - const Type& v1 = vocov->t2(); - const Type c1 = static_cast*>(branch[1])->value(); - const details::operator_type o0 = expr_gen.get_operator(vocov->f0()); - const details::operator_type o1 = expr_gen.get_operator(vocov->f1()); - const details::operator_type o2 = operation; - - binary_functor_t f0 = vocov->f0(); - binary_functor_t f1 = vocov->f1(); - binary_functor_t f2 = reinterpret_cast(0); - - details::free_node(*(expr_gen.node_allocator_),branch[0]); - details::free_node(*(expr_gen.node_allocator_),branch[1]); - - expression_node_ptr result = error_node(); - - if (synthesize_sf4ext_expression::template compile(expr_gen,id(expr_gen,o0,o1,o2),v0,c0,v1,c1,result)) - return result; - else if (!expr_gen.valid_operator(o2,f2)) - return error_node(); - - exprtk_debug(("((v0 o0 c0) o1 v1) o2 c1\n")); - - return node_type::allocate(*(expr_gen.node_allocator_),v0,c0,v1,c1,f0,f1,f2); - } - - static inline std::string id(expression_generator& expr_gen, - const details::operator_type o0, - const details::operator_type o1, - const details::operator_type o2) - { - return (details::build_string() << "((t" << expr_gen.to_str(o0) << "t)" << expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t"); - } - }; - - struct synthesize_covovoc_expression3 - { - typedef typename covovoc_t::type3 node_type; - typedef typename covovoc_t::sf4_type sf4_type; - typedef typename node_type::T0 T0; - typedef typename node_type::T1 T1; - typedef typename node_type::T2 T2; - typedef typename node_type::T3 T3; - - static inline expression_node_ptr process(expression_generator& expr_gen, - const details::operator_type& operation, - expression_node_ptr (&branch)[2]) - { - // ((c0 o0 v0) o1 v1) o2 c1 - typedef typename synthesize_covov_expression0::node_type lcl_covov_t; - - const lcl_covov_t* covov = static_cast(branch[0]); - const Type c0 = covov->t0(); - const Type& v0 = covov->t1(); - const Type& v1 = covov->t2(); - const Type c1 = static_cast*>(branch[1])->value(); - const details::operator_type o0 = expr_gen.get_operator(covov->f0()); - const details::operator_type o1 = expr_gen.get_operator(covov->f1()); - const details::operator_type o2 = operation; - - binary_functor_t f0 = covov->f0(); - binary_functor_t f1 = covov->f1(); - binary_functor_t f2 = reinterpret_cast(0); - - details::free_node(*(expr_gen.node_allocator_),branch[0]); - details::free_node(*(expr_gen.node_allocator_),branch[1]); - - expression_node_ptr result = error_node(); - - if (synthesize_sf4ext_expression::template compile(expr_gen,id(expr_gen,o0,o1,o2),c0,v0,v1,c1,result)) - return result; - else if (!expr_gen.valid_operator(o2,f2)) - return error_node(); - - exprtk_debug(("((c0 o0 v0) o1 v1) o2 c1\n")); - - return node_type::allocate(*(expr_gen.node_allocator_),c0,v0,v1,c1,f0,f1,f2); - } - - static inline std::string id(expression_generator& expr_gen, - const details::operator_type o0, - const details::operator_type o1, - const details::operator_type o2) - { - return (details::build_string() << "((t" << expr_gen.to_str(o0) << "t)" << expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t"); - } - }; - - struct synthesize_vococov_expression3 - { - typedef typename vococov_t::type3 node_type; - typedef typename vococov_t::sf4_type sf4_type; - typedef typename node_type::T0 T0; - typedef typename node_type::T1 T1; - typedef typename node_type::T2 T2; - typedef typename node_type::T3 T3; - - static inline expression_node_ptr process(expression_generator& expr_gen, - const details::operator_type& operation, - expression_node_ptr (&branch)[2]) - { - // ((v0 o0 c0) o1 c1) o2 v1 - typedef typename synthesize_vococ_expression0::node_type lcl_vococ_t; - - const lcl_vococ_t* vococ = static_cast(branch[0]); - const Type& v0 = vococ->t0(); - const Type c0 = vococ->t1(); - const Type c1 = vococ->t2(); - const Type& v1 = static_cast*>(branch[1])->ref(); - const details::operator_type o0 = expr_gen.get_operator(vococ->f0()); - const details::operator_type o1 = expr_gen.get_operator(vococ->f1()); - const details::operator_type o2 = operation; - - binary_functor_t f0 = vococ->f0(); - binary_functor_t f1 = vococ->f1(); - binary_functor_t f2 = reinterpret_cast(0); - - details::free_node(*(expr_gen.node_allocator_),branch[0]); - - expression_node_ptr result = error_node(); - - if (synthesize_sf4ext_expression::template compile(expr_gen,id(expr_gen,o0,o1,o2),v0,c0,c1,v1,result)) - return result; - else if (!expr_gen.valid_operator(o2,f2)) - return error_node(); - - exprtk_debug(("((v0 o0 c0) o1 c1) o2 v1\n")); - - return node_type::allocate(*(expr_gen.node_allocator_),v0,c0,c1,v1,f0,f1,f2); - } - - static inline std::string id(expression_generator& expr_gen, - const details::operator_type o0, - const details::operator_type o1, - const details::operator_type o2) - { - return (details::build_string() << "((t" << expr_gen.to_str(o0) << "t)" << expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t"); - } - }; - - struct synthesize_vovovov_expression4 - { - typedef typename vovovov_t::type4 node_type; - typedef typename vovovov_t::sf4_type sf4_type; - typedef typename node_type::T0 T0; - typedef typename node_type::T1 T1; - typedef typename node_type::T2 T2; - typedef typename node_type::T3 T3; - - static inline expression_node_ptr process(expression_generator& expr_gen, - const details::operator_type& operation, - expression_node_ptr (&branch)[2]) - { - // (v0 o0 (v1 o1 v2)) o2 v3 - typedef typename synthesize_vovov_expression1::node_type lcl_vovov_t; - - const lcl_vovov_t* vovov = static_cast(branch[0]); - const Type& v0 = vovov->t0(); - const Type& v1 = vovov->t1(); - const Type& v2 = vovov->t2(); - const Type& v3 = static_cast*>(branch[1])->ref(); - const details::operator_type o0 = expr_gen.get_operator(vovov->f0()); - const details::operator_type o1 = expr_gen.get_operator(vovov->f1()); - const details::operator_type o2 = operation; - - binary_functor_t f0 = vovov->f0(); - binary_functor_t f1 = vovov->f1(); - binary_functor_t f2 = reinterpret_cast(0); - - details::free_node(*(expr_gen.node_allocator_),branch[0]); - - expression_node_ptr result = error_node(); - - if (synthesize_sf4ext_expression::template compile(expr_gen,id(expr_gen,o0,o1,o2),v0,v1,v2,v3,result)) - return result; - else if (!expr_gen.valid_operator(o2,f2)) - return error_node(); - - exprtk_debug(("(v0 o0 (v1 o1 v2)) o2 v3\n")); - - return node_type::allocate(*(expr_gen.node_allocator_),v0,v1,v2,v3,f0,f1,f2); - } - - static inline std::string id(expression_generator& expr_gen, - const details::operator_type o0, - const details::operator_type o1, - const details::operator_type o2) - { - return (details::build_string() << "(t" << expr_gen.to_str(o0) << "(t" << expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t"); - } - }; - - struct synthesize_vovovoc_expression4 - { - typedef typename vovovoc_t::type4 node_type; - typedef typename vovovoc_t::sf4_type sf4_type; - typedef typename node_type::T0 T0; - typedef typename node_type::T1 T1; - typedef typename node_type::T2 T2; - typedef typename node_type::T3 T3; - - static inline expression_node_ptr process(expression_generator& expr_gen, - const details::operator_type& operation, - expression_node_ptr (&branch)[2]) - { - // ((v0 o0 (v1 o1 v2)) o2 c) - typedef typename synthesize_vovov_expression1::node_type lcl_vovov_t; - - const lcl_vovov_t* vovov = static_cast(branch[0]); - const Type& v0 = vovov->t0(); - const Type& v1 = vovov->t1(); - const Type& v2 = vovov->t2(); - const Type c = static_cast*>(branch[1])->value(); - const details::operator_type o0 = expr_gen.get_operator(vovov->f0()); - const details::operator_type o1 = expr_gen.get_operator(vovov->f1()); - const details::operator_type o2 = operation; - - binary_functor_t f0 = vovov->f0(); - binary_functor_t f1 = vovov->f1(); - binary_functor_t f2 = reinterpret_cast(0); - - details::free_node(*(expr_gen.node_allocator_),branch[0]); - details::free_node(*(expr_gen.node_allocator_),branch[1]); - - expression_node_ptr result = error_node(); - - if (synthesize_sf4ext_expression::template compile(expr_gen,id(expr_gen,o0,o1,o2),v0,v1,v2,c,result)) - return result; - else if (!expr_gen.valid_operator(o2,f2)) - return error_node(); - - exprtk_debug(("((v0 o0 (v1 o1 v2)) o2 c)\n")); - - return node_type::allocate(*(expr_gen.node_allocator_),v0,v1,v2,c,f0,f1,f2); - } - - static inline std::string id(expression_generator& expr_gen, - const details::operator_type o0, - const details::operator_type o1, - const details::operator_type o2) - { - return (details::build_string() << "(t" << expr_gen.to_str(o0) << "(t" << expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t"); - } - }; - - struct synthesize_vovocov_expression4 - { - typedef typename vovocov_t::type4 node_type; - typedef typename vovocov_t::sf4_type sf4_type; - typedef typename node_type::T0 T0; - typedef typename node_type::T1 T1; - typedef typename node_type::T2 T2; - typedef typename node_type::T3 T3; - - static inline expression_node_ptr process(expression_generator& expr_gen, - const details::operator_type& operation, - expression_node_ptr (&branch)[2]) - { - // ((v0 o0 (v1 o1 c)) o2 v1) - typedef typename synthesize_vovoc_expression1::node_type lcl_vovoc_t; - - const lcl_vovoc_t* vovoc = static_cast(branch[0]); - const Type& v0 = vovoc->t0(); - const Type& v1 = vovoc->t1(); - const Type c = vovoc->t2(); - const Type& v2 = static_cast*>(branch[1])->ref(); - const details::operator_type o0 = expr_gen.get_operator(vovoc->f0()); - const details::operator_type o1 = expr_gen.get_operator(vovoc->f1()); - const details::operator_type o2 = operation; - - binary_functor_t f0 = vovoc->f0(); - binary_functor_t f1 = vovoc->f1(); - binary_functor_t f2 = reinterpret_cast(0); - - details::free_node(*(expr_gen.node_allocator_),branch[0]); - - expression_node_ptr result = error_node(); - - if (synthesize_sf4ext_expression::template compile(expr_gen,id(expr_gen,o0,o1,o2),v0,v1,c,v2,result)) - return result; - else if (!expr_gen.valid_operator(o2,f2)) - return error_node(); - - exprtk_debug(("((v0 o0 (v1 o1 c)) o2 v1)\n")); - - return node_type::allocate(*(expr_gen.node_allocator_),v0,v1,c,v2,f0,f1,f2); - } - - static inline std::string id(expression_generator& expr_gen, - const details::operator_type o0, - const details::operator_type o1, - const details::operator_type o2) - { - return (details::build_string() << "(t" << expr_gen.to_str(o0) << "(t" << expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t"); - } - }; - - struct synthesize_vocovov_expression4 - { - typedef typename vocovov_t::type4 node_type; - typedef typename vocovov_t::sf4_type sf4_type; - typedef typename node_type::T0 T0; - typedef typename node_type::T1 T1; - typedef typename node_type::T2 T2; - typedef typename node_type::T3 T3; - - static inline expression_node_ptr process(expression_generator& expr_gen, - const details::operator_type& operation, - expression_node_ptr (&branch)[2]) - { - // ((v0 o0 (c o1 v1)) o2 v2) - typedef typename synthesize_vocov_expression1::node_type lcl_vocov_t; - - const lcl_vocov_t* vocov = static_cast(branch[0]); - const Type& v0 = vocov->t0(); - const Type c = vocov->t1(); - const Type& v1 = vocov->t2(); - const Type& v2 = static_cast*>(branch[1])->ref(); - const details::operator_type o0 = expr_gen.get_operator(vocov->f0()); - const details::operator_type o1 = expr_gen.get_operator(vocov->f1()); - const details::operator_type o2 = operation; - - binary_functor_t f0 = vocov->f0(); - binary_functor_t f1 = vocov->f1(); - binary_functor_t f2 = reinterpret_cast(0); - - details::free_node(*(expr_gen.node_allocator_),branch[0]); - expression_node_ptr result = error_node(); - - if (synthesize_sf4ext_expression::template compile(expr_gen,id(expr_gen,o0,o1,o2),v0,c,v1,v2,result)) - return result; - else if (!expr_gen.valid_operator(o2,f2)) - return error_node(); - - exprtk_debug(("((v0 o0 (c o1 v1)) o2 v2)\n")); - - return node_type::allocate(*(expr_gen.node_allocator_),v0,c,v1,v2,f0,f1,f2); - } - - static inline std::string id(expression_generator& expr_gen, - const details::operator_type o0, - const details::operator_type o1, - const details::operator_type o2) - { - return (details::build_string() << "(t" << expr_gen.to_str(o0) << "(t" << expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t"); - } - }; - - struct synthesize_covovov_expression4 - { - typedef typename covovov_t::type4 node_type; - typedef typename covovov_t::sf4_type sf4_type; - typedef typename node_type::T0 T0; - typedef typename node_type::T1 T1; - typedef typename node_type::T2 T2; - typedef typename node_type::T3 T3; - - static inline expression_node_ptr process(expression_generator& expr_gen, - const details::operator_type& operation, - expression_node_ptr (&branch)[2]) - { - // ((c o0 (v0 o1 v1)) o2 v2) - typedef typename synthesize_covov_expression1::node_type lcl_covov_t; - - const lcl_covov_t* covov = static_cast(branch[0]); - const Type c = covov->t0(); - const Type& v0 = covov->t1(); - const Type& v1 = covov->t2(); - const Type& v2 = static_cast*>(branch[1])->ref(); - const details::operator_type o0 = expr_gen.get_operator(covov->f0()); - const details::operator_type o1 = expr_gen.get_operator(covov->f1()); - const details::operator_type o2 = operation; - - binary_functor_t f0 = covov->f0(); - binary_functor_t f1 = covov->f1(); - binary_functor_t f2 = reinterpret_cast(0); - - details::free_node(*(expr_gen.node_allocator_),branch[0]); - - expression_node_ptr result = error_node(); - - if (synthesize_sf4ext_expression::template compile(expr_gen,id(expr_gen,o0,o1,o2),c,v0,v1,v2,result)) - return result; - else if (!expr_gen.valid_operator(o2,f2)) - return error_node(); - - exprtk_debug(("((c o0 (v0 o1 v1)) o2 v2)\n")); - - return node_type::allocate(*(expr_gen.node_allocator_),c,v0,v1,v2,f0,f1,f2); - } - - static inline std::string id(expression_generator& expr_gen, - const details::operator_type o0, - const details::operator_type o1, - const details::operator_type o2) - { - return (details::build_string() << "(t" << expr_gen.to_str(o0) << "(t" << expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t"); - } - }; - - struct synthesize_covocov_expression4 - { - typedef typename covocov_t::type4 node_type; - typedef typename covocov_t::sf4_type sf4_type; - typedef typename node_type::T0 T0; - typedef typename node_type::T1 T1; - typedef typename node_type::T2 T2; - typedef typename node_type::T3 T3; - - static inline expression_node_ptr process(expression_generator& expr_gen, - const details::operator_type& operation, - expression_node_ptr (&branch)[2]) - { - // ((c0 o0 (v0 o1 c1)) o2 v1) - typedef typename synthesize_covoc_expression1::node_type lcl_covoc_t; - - const lcl_covoc_t* covoc = static_cast(branch[0]); - const Type c0 = covoc->t0(); - const Type& v0 = covoc->t1(); - const Type c1 = covoc->t2(); - const Type& v1 = static_cast*>(branch[1])->ref(); - const details::operator_type o0 = expr_gen.get_operator(covoc->f0()); - const details::operator_type o1 = expr_gen.get_operator(covoc->f1()); - const details::operator_type o2 = operation; - - binary_functor_t f0 = covoc->f0(); - binary_functor_t f1 = covoc->f1(); - binary_functor_t f2 = reinterpret_cast(0); - - details::free_node(*(expr_gen.node_allocator_),branch[0]); - - expression_node_ptr result = error_node(); - - if (synthesize_sf4ext_expression::template compile(expr_gen,id(expr_gen,o0,o1,o2),c0,v0,c1,v1,result)) - return result; - else if (!expr_gen.valid_operator(o2,f2)) - return error_node(); - - exprtk_debug(("((c0 o0 (v0 o1 c1)) o2 v1)\n")); - - return node_type::allocate(*(expr_gen.node_allocator_),c0,v0,c1,v1,f0,f1,f2); - } - - static inline std::string id(expression_generator& expr_gen, - const details::operator_type o0, - const details::operator_type o1, - const details::operator_type o2) - { - return (details::build_string() << "(t" << expr_gen.to_str(o0) << "(t" << expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t"); - } - }; - - struct synthesize_vocovoc_expression4 - { - typedef typename vocovoc_t::type4 node_type; - typedef typename vocovoc_t::sf4_type sf4_type; - typedef typename node_type::T0 T0; - typedef typename node_type::T1 T1; - typedef typename node_type::T2 T2; - typedef typename node_type::T3 T3; - - static inline expression_node_ptr process(expression_generator& expr_gen, - const details::operator_type& operation, - expression_node_ptr (&branch)[2]) - { - // ((v0 o0 (c0 o1 v1)) o2 c1) - typedef typename synthesize_vocov_expression1::node_type lcl_vocov_t; - - const lcl_vocov_t* vocov = static_cast(branch[0]); - const Type& v0 = vocov->t0(); - const Type c0 = vocov->t1(); - const Type& v1 = vocov->t2(); - const Type c1 = static_cast*>(branch[1])->value(); - const details::operator_type o0 = expr_gen.get_operator(vocov->f0()); - const details::operator_type o1 = expr_gen.get_operator(vocov->f1()); - const details::operator_type o2 = operation; - - binary_functor_t f0 = vocov->f0(); - binary_functor_t f1 = vocov->f1(); - binary_functor_t f2 = reinterpret_cast(0); - - details::free_node(*(expr_gen.node_allocator_),branch[0]); - details::free_node(*(expr_gen.node_allocator_),branch[1]); - - expression_node_ptr result = error_node(); - - if (synthesize_sf4ext_expression::template compile(expr_gen,id(expr_gen,o0,o1,o2),v0,c0,v1,c1,result)) - return result; - else if (!expr_gen.valid_operator(o2,f2)) - return error_node(); - - exprtk_debug(("((v0 o0 (c0 o1 v1)) o2 c1)\n")); - - return node_type::allocate(*(expr_gen.node_allocator_),v0,c0,v1,c1,f0,f1,f2); - } - - static inline std::string id(expression_generator& expr_gen, - const details::operator_type o0, - const details::operator_type o1, - const details::operator_type o2) - { - return (details::build_string() << "(t" << expr_gen.to_str(o0) << "(t" << expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t"); - } - }; - - struct synthesize_covovoc_expression4 - { - typedef typename covovoc_t::type4 node_type; - typedef typename covovoc_t::sf4_type sf4_type; - typedef typename node_type::T0 T0; - typedef typename node_type::T1 T1; - typedef typename node_type::T2 T2; - typedef typename node_type::T3 T3; - - static inline expression_node_ptr process(expression_generator& expr_gen, - const details::operator_type& operation, - expression_node_ptr (&branch)[2]) - { - // ((c0 o0 (v0 o1 v1)) o2 c1) - typedef typename synthesize_covov_expression1::node_type lcl_covov_t; - - const lcl_covov_t* covov = static_cast(branch[0]); - const Type c0 = covov->t0(); - const Type& v0 = covov->t1(); - const Type& v1 = covov->t2(); - const Type c1 = static_cast*>(branch[1])->value(); - const details::operator_type o0 = expr_gen.get_operator(covov->f0()); - const details::operator_type o1 = expr_gen.get_operator(covov->f1()); - const details::operator_type o2 = operation; - - binary_functor_t f0 = covov->f0(); - binary_functor_t f1 = covov->f1(); - binary_functor_t f2 = reinterpret_cast(0); - - details::free_node(*(expr_gen.node_allocator_),branch[0]); - details::free_node(*(expr_gen.node_allocator_),branch[1]); - - expression_node_ptr result = error_node(); - - if (synthesize_sf4ext_expression::template compile(expr_gen,id(expr_gen,o0,o1,o2),c0,v0,v1,c1,result)) - return result; - else if (!expr_gen.valid_operator(o2,f2)) - return error_node(); - - exprtk_debug(("((c0 o0 (v0 o1 v1)) o2 c1)\n")); - - return node_type::allocate(*(expr_gen.node_allocator_),c0,v0,v1,c1,f0,f1,f2); - } - - static inline std::string id(expression_generator& expr_gen, - const details::operator_type o0, - const details::operator_type o1, - const details::operator_type o2) - { - return (details::build_string() << "(t" << expr_gen.to_str(o0) << "(t" << expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t"); - } - }; - - struct synthesize_vococov_expression4 - { - typedef typename vococov_t::type4 node_type; - static inline expression_node_ptr process(expression_generator&, const details::operator_type&, expression_node_ptr (&)[2]) - { - // ((v0 o0 (c0 o1 c1)) o2 v1) - Not possible - exprtk_debug(("((v0 o0 (c0 o1 c1)) o2 v1) - Not possible\n")); - return error_node(); - } - - static inline std::string id(expression_generator&, - const details::operator_type, const details::operator_type, const details::operator_type) - { - return "INVALID"; - } - }; + + return bocnode; + } + } + else if (operation == details::e_pow) + { + // (v ^ c0) ^ c1 --> v ^(c0 * c1) + details::boc_base_node* bocnode = static_cast*>(branch[0]); + details::operator_type boc_opr = bocnode->operation(); + + if (details::e_pow == boc_opr) + { + bocnode->set_c(bocnode->c() * c); + + return bocnode; + } + } + } + + #ifndef exprtk_disable_enhanced_features + if (details::is_sf3ext_node(branch[0])) + { + expression_node_ptr result = error_node(); + + if (synthesize_sf4ext_expression::template compile_left(expr_gen,c,operation,branch[0],result)) + { + free_node(*expr_gen.node_allocator_,branch[0]); + + return result; + } + } + #endif + + switch (operation) + { + #define case_stmt(op0,op1) \ + case op0 : return expr_gen.node_allocator_-> \ + template allocate_cr > > \ + (branch[0],c); \ + + basic_opr_switch_statements + extended_opr_switch_statements + #undef case_stmt + default : return error_node(); + } + } + }; + + struct synthesize_cocob_expression + { + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + expression_node_ptr result = error_node(); + + // (cob) o c --> cob + if (details::is_cob_node(branch[0])) + { + details::cob_base_node* cobnode = static_cast*>(branch[0]); + const Type c = static_cast*>(branch[1])->value(); + + if ((T(0) == c) && (details::e_mul == operation)) + { + free_node(*expr_gen.node_allocator_,branch[0]); + free_node(*expr_gen.node_allocator_,branch[1]); + + return expr_gen(T(0)); + } + else if ((T(0) == c) && (details::e_div == operation)) + { + free_node(*expr_gen.node_allocator_,branch[0]); + free_node(*expr_gen.node_allocator_,branch[1]); + + return expr_gen(T(std::numeric_limits::quiet_NaN())); + } + else if ((T(0) == c) && (details::e_add == operation)) + { + free_node(*expr_gen.node_allocator_, branch[1]); + return branch[0]; + } + else if ((T(1) == c) && (details::e_mul == operation)) + { + free_node(*expr_gen.node_allocator_, branch[1]); + return branch[0]; + } + else if ((T(1) == c) && (details::e_div == operation)) + { + free_node(*expr_gen.node_allocator_, branch[1]); + return branch[0]; + } + + bool op_addsub = (details::e_add == cobnode->operation()) || + (details::e_sub == cobnode->operation()); + + if (op_addsub) + { + switch (operation) + { + case details::e_add : cobnode->set_c(cobnode->c() + c); break; + case details::e_sub : cobnode->set_c(cobnode->c() - c); break; + default : return error_node(); + } + + result = cobnode; + } + else if (details::e_mul == cobnode->operation()) + { + switch (operation) + { + case details::e_mul : cobnode->set_c(cobnode->c() * c); break; + case details::e_div : cobnode->set_c(cobnode->c() / c); break; + default : return error_node(); + } + + result = cobnode; + } + else if (details::e_div == cobnode->operation()) + { + if (details::e_mul == operation) + { + cobnode->set_c(cobnode->c() * c); + result = cobnode; + } + else if (details::e_div == operation) + { + result = expr_gen.node_allocator_-> + template allocate_tt > > + (cobnode->c() / c,cobnode->move_branch(0)); + + free_node(*expr_gen.node_allocator_,branch[0]); + } + } + + if (result) + { + free_node(*expr_gen.node_allocator_,branch[1]); + } + } + + // c o (cob) --> cob + else if (details::is_cob_node(branch[1])) + { + details::cob_base_node* cobnode = static_cast*>(branch[1]); + const Type c = static_cast*>(branch[0])->value(); + + if ((T(0) == c) && (details::e_mul == operation)) + { + free_node(*expr_gen.node_allocator_,branch[0]); + free_node(*expr_gen.node_allocator_,branch[1]); + + return expr_gen(T(0)); + } + else if ((T(0) == c) && (details::e_div == operation)) + { + free_node(*expr_gen.node_allocator_,branch[0]); + free_node(*expr_gen.node_allocator_,branch[1]); + + return expr_gen(T(0)); + } + else if ((T(0) == c) && (details::e_add == operation)) + { + free_node(*expr_gen.node_allocator_, branch[0]); + return branch[1]; + } + else if ((T(1) == c) && (details::e_mul == operation)) + { + free_node(*expr_gen.node_allocator_, branch[0]); + return branch[1]; + } + + if (details::e_add == cobnode->operation()) + { + if (details::e_add == operation) + { + cobnode->set_c(c + cobnode->c()); + result = cobnode; + } + else if (details::e_sub == operation) + { + result = expr_gen.node_allocator_-> + template allocate_tt > > + (c - cobnode->c(),cobnode->move_branch(0)); + + free_node(*expr_gen.node_allocator_,branch[1]); + } + } + else if (details::e_sub == cobnode->operation()) + { + if (details::e_add == operation) + { + cobnode->set_c(c + cobnode->c()); + result = cobnode; + } + else if (details::e_sub == operation) + { + result = expr_gen.node_allocator_-> + template allocate_tt > > + (c - cobnode->c(),cobnode->move_branch(0)); + + free_node(*expr_gen.node_allocator_,branch[1]); + } + } + else if (details::e_mul == cobnode->operation()) + { + if (details::e_mul == operation) + { + cobnode->set_c(c * cobnode->c()); + result = cobnode; + } + else if (details::e_div == operation) + { + result = expr_gen.node_allocator_-> + template allocate_tt > > + (c / cobnode->c(),cobnode->move_branch(0)); + + free_node(*expr_gen.node_allocator_,branch[1]); + } + } + else if (details::e_div == cobnode->operation()) + { + if (details::e_mul == operation) + { + cobnode->set_c(c * cobnode->c()); + result = cobnode; + } + else if (details::e_div == operation) + { + result = expr_gen.node_allocator_-> + template allocate_tt > > + (c / cobnode->c(),cobnode->move_branch(0)); + + free_node(*expr_gen.node_allocator_,branch[1]); + } + } + + if (result) + { + free_node(*expr_gen.node_allocator_,branch[0]); + } + } + + return result; + } + }; + + struct synthesize_coboc_expression + { + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + expression_node_ptr result = error_node(); + + // (boc) o c --> boc + if (details::is_boc_node(branch[0])) + { + details::boc_base_node* bocnode = static_cast*>(branch[0]); + const Type c = static_cast*>(branch[1])->value(); + + if (details::e_add == bocnode->operation()) + { + switch (operation) + { + case details::e_add : bocnode->set_c(bocnode->c() + c); break; + case details::e_sub : bocnode->set_c(bocnode->c() - c); break; + default : return error_node(); + } + + result = bocnode; + } + else if (details::e_mul == bocnode->operation()) + { + switch (operation) + { + case details::e_mul : bocnode->set_c(bocnode->c() * c); break; + case details::e_div : bocnode->set_c(bocnode->c() / c); break; + default : return error_node(); + } + + result = bocnode; + } + else if (details::e_sub == bocnode->operation()) + { + if (details::e_add == operation) + { + result = expr_gen.node_allocator_-> + template allocate_tt > > + (bocnode->move_branch(0),c - bocnode->c()); + + free_node(*expr_gen.node_allocator_,branch[0]); + } + else if (details::e_sub == operation) + { + bocnode->set_c(bocnode->c() + c); + result = bocnode; + } + } + else if (details::e_div == bocnode->operation()) + { + switch (operation) + { + case details::e_div : bocnode->set_c(bocnode->c() * c); break; + case details::e_mul : bocnode->set_c(bocnode->c() / c); break; + default : return error_node(); + } + + result = bocnode; + } + + if (result) + { + free_node(*expr_gen.node_allocator_,branch[1]); + } + } + + // c o (boc) --> boc + else if (details::is_boc_node(branch[1])) + { + details::boc_base_node* bocnode = static_cast*>(branch[1]); + const Type c = static_cast*>(branch[0])->value(); + + if (details::e_add == bocnode->operation()) + { + if (details::e_add == operation) + { + bocnode->set_c(c + bocnode->c()); + result = bocnode; + } + else if (details::e_sub == operation) + { + result = expr_gen.node_allocator_-> + template allocate_tt > > + (c - bocnode->c(),bocnode->move_branch(0)); + + free_node(*expr_gen.node_allocator_,branch[1]); + } + } + else if (details::e_sub == bocnode->operation()) + { + if (details::e_add == operation) + { + result = expr_gen.node_allocator_-> + template allocate_tt > > + (bocnode->move_branch(0),c - bocnode->c()); + + free_node(*expr_gen.node_allocator_,branch[1]); + } + else if (details::e_sub == operation) + { + result = expr_gen.node_allocator_-> + template allocate_tt > > + (c + bocnode->c(),bocnode->move_branch(0)); + + free_node(*expr_gen.node_allocator_,branch[1]); + } + } + else if (details::e_mul == bocnode->operation()) + { + if (details::e_mul == operation) + { + bocnode->set_c(c * bocnode->c()); + result = bocnode; + } + else if (details::e_div == operation) + { + result = expr_gen.node_allocator_-> + template allocate_tt > > + (c / bocnode->c(),bocnode->move_branch(0)); + + free_node(*expr_gen.node_allocator_,branch[1]); + } + } + else if (details::e_div == bocnode->operation()) + { + if (details::e_mul == operation) + { + bocnode->set_c(bocnode->c() / c); + result = bocnode; + } + else if (details::e_div == operation) + { + result = expr_gen.node_allocator_-> + template allocate_tt > > + (c * bocnode->c(),bocnode->move_branch(0)); + + free_node(*expr_gen.node_allocator_,branch[1]); + } + } + + if (result) + { + free_node(*expr_gen.node_allocator_,branch[0]); + } + } + + return result; + } + }; + + #ifndef exprtk_disable_enhanced_features + inline bool synthesize_expression(const details::operator_type& operation, + expression_node_ptr (&branch)[2], + expression_node_ptr& result) + { + result = error_node(); + + if (!operation_optimisable(operation)) + return false; + + const std::string node_id = branch_to_id(branch); + + typename synthesize_map_t::iterator itr = synthesize_map_.find(node_id); + + if (synthesize_map_.end() != itr) + { + result = itr->second(*this,operation,branch); + + return true; + } + else + return false; + } + + struct synthesize_vov_expression + { + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + const Type& v1 = static_cast*>(branch[0])->ref(); + const Type& v2 = static_cast*>(branch[1])->ref(); + + switch (operation) + { + #define case_stmt(op0,op1) \ + case op0 : return expr_gen.node_allocator_-> \ + template allocate_rr > > \ + (v1,v2); \ + + basic_opr_switch_statements + extended_opr_switch_statements + #undef case_stmt + default : return error_node(); + } + } + }; + + struct synthesize_cov_expression + { + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + const Type c = static_cast*> (branch[0])->value(); + const Type& v = static_cast*>(branch[1])->ref(); + + details::free_node(*(expr_gen.node_allocator_),branch[0]); + + if ((T(0) == c) && (details::e_mul == operation)) + return expr_gen(T(0)); + else if ((T(0) == c) && (details::e_div == operation)) + return expr_gen(T(0)); + else if ((T(0) == c) && (details::e_add == operation)) + return static_cast*>(branch[1]); + else if ((T(1) == c) && (details::e_mul == operation)) + return static_cast*>(branch[1]); + + switch (operation) + { + #define case_stmt(op0,op1) \ + case op0 : return expr_gen.node_allocator_-> \ + template allocate_cr > > \ + (c,v); \ + + basic_opr_switch_statements + extended_opr_switch_statements + #undef case_stmt + default : return error_node(); + } + } + }; + + struct synthesize_voc_expression + { + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + const Type& v = static_cast*>(branch[0])->ref(); + const Type c = static_cast*> (branch[1])->value(); + + details::free_node(*(expr_gen.node_allocator_),branch[1]); + + if (expr_gen.cardinal_pow_optimisable(operation,c)) + { + if (std::equal_to()(T(1),c)) + return branch[0]; + else + return expr_gen.cardinal_pow_optimisation(v,c); + } + else if ((T(0) == c) && (details::e_mul == operation)) + return expr_gen(T(0)); + else if ((T(0) == c) && (details::e_div == operation)) + return expr_gen(std::numeric_limits::quiet_NaN()); + else if ((T(0) == c) && (details::e_add == operation)) + return static_cast*>(branch[0]); + else if ((T(1) == c) && (details::e_mul == operation)) + return static_cast*>(branch[0]); + else if ((T(1) == c) && (details::e_div == operation)) + return static_cast*>(branch[0]); + + switch (operation) + { + #define case_stmt(op0,op1) \ + case op0 : return expr_gen.node_allocator_-> \ + template allocate_rc > > \ + (v,c); \ + + basic_opr_switch_statements + extended_opr_switch_statements + #undef case_stmt + default : return error_node(); + } + } + }; + + struct synthesize_sf3ext_expression + { + template + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& sf3opr, + T0 t0, T1 t1, T2 t2) + { + switch (sf3opr) + { + #define case_stmt(op) \ + case details::e_sf##op : return details::T0oT1oT2_sf3ext >:: \ + allocate(*(expr_gen.node_allocator_),t0,t1,t2); \ + + case_stmt(00) case_stmt(01) case_stmt(02) case_stmt(03) + case_stmt(04) case_stmt(05) case_stmt(06) case_stmt(07) + case_stmt(08) case_stmt(09) case_stmt(10) case_stmt(11) + case_stmt(12) case_stmt(13) case_stmt(14) case_stmt(15) + case_stmt(16) case_stmt(17) case_stmt(18) case_stmt(19) + case_stmt(20) case_stmt(21) case_stmt(22) case_stmt(23) + case_stmt(24) case_stmt(25) case_stmt(26) case_stmt(27) + case_stmt(28) case_stmt(29) case_stmt(30) + #undef case_stmt + default : return error_node(); + } + } + + template + static inline bool compile(expression_generator& expr_gen, const std::string& id, + T0 t0, T1 t1, T2 t2, + expression_node_ptr& result) + { + details::operator_type sf3opr; + + if (!expr_gen.sf3_optimisable(id,sf3opr)) + return false; + else + result = synthesize_sf3ext_expression::template process(expr_gen,sf3opr,t0,t1,t2); + + return true; + } + }; + + struct synthesize_sf4ext_expression + { + template + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& sf4opr, + T0 t0, T1 t1, T2 t2, T3 t3) + { + switch (sf4opr) + { + #define case_stmt0(op) \ + case details::e_sf##op : return details::T0oT1oT2oT3_sf4ext >:: \ + allocate(*(expr_gen.node_allocator_),t0,t1,t2,t3); \ + + + #define case_stmt1(op) \ + case details::e_sf4ext##op : return details::T0oT1oT2oT3_sf4ext >:: \ + allocate(*(expr_gen.node_allocator_),t0,t1,t2,t3); \ + + case_stmt0(48) case_stmt0(49) case_stmt0(50) case_stmt0(51) + case_stmt0(52) case_stmt0(53) case_stmt0(54) case_stmt0(55) + case_stmt0(56) case_stmt0(57) case_stmt0(58) case_stmt0(59) + case_stmt0(60) case_stmt0(61) case_stmt0(62) case_stmt0(63) + case_stmt0(64) case_stmt0(65) case_stmt0(66) case_stmt0(67) + case_stmt0(68) case_stmt0(69) case_stmt0(70) case_stmt0(71) + case_stmt0(72) case_stmt0(73) case_stmt0(74) case_stmt0(75) + case_stmt0(76) case_stmt0(77) case_stmt0(78) case_stmt0(79) + case_stmt0(80) case_stmt0(81) case_stmt0(82) case_stmt0(83) + + case_stmt1(00) case_stmt1(01) case_stmt1(02) case_stmt1(03) + case_stmt1(04) case_stmt1(05) case_stmt1(06) case_stmt1(07) + case_stmt1(08) case_stmt1(09) case_stmt1(10) case_stmt1(11) + case_stmt1(12) case_stmt1(13) case_stmt1(14) case_stmt1(15) + case_stmt1(16) case_stmt1(17) case_stmt1(18) case_stmt1(19) + case_stmt1(20) case_stmt1(21) case_stmt1(22) case_stmt1(23) + case_stmt1(24) case_stmt1(25) case_stmt1(26) case_stmt1(27) + case_stmt1(28) case_stmt1(29) case_stmt1(30) case_stmt1(31) + case_stmt1(32) case_stmt1(33) case_stmt1(34) case_stmt1(35) + case_stmt1(36) case_stmt1(37) case_stmt1(38) case_stmt1(39) + case_stmt1(40) case_stmt1(41) case_stmt1(42) case_stmt1(43) + case_stmt1(44) case_stmt1(45) case_stmt1(46) case_stmt1(47) + case_stmt1(48) case_stmt1(49) case_stmt1(50) case_stmt1(51) + case_stmt1(52) case_stmt1(53) case_stmt1(54) case_stmt1(55) + case_stmt1(56) case_stmt1(57) case_stmt1(58) case_stmt1(59) + case_stmt1(60) case_stmt1(61) + + #undef case_stmt0 + #undef case_stmt1 + default : return error_node(); + } + } + + template + static inline bool compile(expression_generator& expr_gen, const std::string& id, + T0 t0, T1 t1, T2 t2, T3 t3, + expression_node_ptr& result) + { + details::operator_type sf4opr; + + if (!expr_gen.sf4_optimisable(id,sf4opr)) + return false; + else + result = synthesize_sf4ext_expression::template process(expr_gen,sf4opr,t0,t1,t2,t3); + + return true; + } + + // T o (sf3ext) + template + static inline bool compile_right(expression_generator& expr_gen, + ExternalType t, + const details::operator_type& operation, + expression_node_ptr& sf3node, + expression_node_ptr& result) + { + if (!details::is_sf3ext_node(sf3node)) + return false; + + typedef details::T0oT1oT2_base_node* sf3ext_base_ptr; + + sf3ext_base_ptr n = static_cast(sf3node); + std::string id = "t" + expr_gen.to_str(operation) + "(" + n->type_id() + ")"; + + switch (n->type()) + { + case details::expression_node::e_covoc : return compile_right_impl + + (expr_gen,id,t,sf3node,result); + + case details::expression_node::e_covov : return compile_right_impl + + (expr_gen,id,t,sf3node,result); + + case details::expression_node::e_vocov : return compile_right_impl + + (expr_gen,id,t,sf3node,result); + + case details::expression_node::e_vovoc : return compile_right_impl + + (expr_gen,id,t,sf3node,result); + + case details::expression_node::e_vovov : return compile_right_impl + + (expr_gen,id,t,sf3node,result); + + default : return false; + } + } + + // (sf3ext) o T + template + static inline bool compile_left(expression_generator& expr_gen, + ExternalType t, + const details::operator_type& operation, + expression_node_ptr& sf3node, + expression_node_ptr& result) + { + if (!details::is_sf3ext_node(sf3node)) + return false; + + typedef details::T0oT1oT2_base_node* sf3ext_base_ptr; + + sf3ext_base_ptr n = static_cast(sf3node); + + std::string id = "(" + n->type_id() + ")" + expr_gen.to_str(operation) + "t"; + + switch (n->type()) + { + case details::expression_node::e_covoc : return compile_left_impl + + (expr_gen,id,t,sf3node,result); + + case details::expression_node::e_covov : return compile_left_impl + + (expr_gen,id,t,sf3node,result); + + case details::expression_node::e_vocov : return compile_left_impl + + (expr_gen,id,t,sf3node,result); + + case details::expression_node::e_vovoc : return compile_left_impl + + (expr_gen,id,t,sf3node,result); + + case details::expression_node::e_vovov : return compile_left_impl + + (expr_gen,id,t,sf3node,result); + + default : return false; + } + } + + template + static inline bool compile_right_impl(expression_generator& expr_gen, + const std::string& id, + ExternalType t, + expression_node_ptr& node, + expression_node_ptr& result) + { + SF3TypeNode* n = dynamic_cast(node); + + if (n) + { + T0 t0 = n->t0(); + T1 t1 = n->t1(); + T2 t2 = n->t2(); + + return synthesize_sf4ext_expression:: + template compile(expr_gen,id,t,t0,t1,t2,result); + } + else + return false; + } + + template + static inline bool compile_left_impl(expression_generator& expr_gen, + const std::string& id, + ExternalType t, + expression_node_ptr& node, + expression_node_ptr& result) + { + SF3TypeNode* n = dynamic_cast(node); + + if (n) + { + T0 t0 = n->t0(); + T1 t1 = n->t1(); + T2 t2 = n->t2(); + + return synthesize_sf4ext_expression:: + template compile(expr_gen,id,t0,t1,t2,t,result); + } + else + return false; + } + }; + + struct synthesize_vovov_expression0 + { + typedef typename vovov_t::type0 node_type; + typedef typename vovov_t::sf3_type sf3_type; + + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + // (v0 o0 v1) o1 (v2) + const details::vov_base_node* vov = static_cast*>(branch[0]); + const Type& v0 = vov->v0(); + const Type& v1 = vov->v1(); + const Type& v2 = static_cast*>(branch[1])->ref(); + const details::operator_type o0 = vov->operation(); + const details::operator_type o1 = operation; + + binary_functor_t f0 = reinterpret_cast(0); + binary_functor_t f1 = reinterpret_cast(0); + + details::free_node(*(expr_gen.node_allocator_),branch[0]); + + expression_node_ptr result = error_node(); + + if (expr_gen.parser_->settings_.strength_reduction_enabled()) + { + // (v0 / v1) / v2 --> (vovov) v0 / (v1 * v2) + if ((details::e_div == o0) && (details::e_div == o1)) + { + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen,"t/(t*t)",v0,v1,v2,result); + + exprtk_debug(("(v0 / v1) / v2 --> (vovov) v0 / (v1 * v2)\n")); + + return (synthesis_result) ? result : error_node(); + } + } + + if (synthesize_sf3ext_expression::template compile(expr_gen,id(expr_gen,o0,o1),v0,v1,v2,result)) + return result; + else if (!expr_gen.valid_operator(o0,f0)) + return error_node(); + else if (!expr_gen.valid_operator(o1,f1)) + return error_node(); + else + return node_type::allocate(*(expr_gen.node_allocator_),v0,v1,v2,f0,f1); + } + + static inline std::string id(expression_generator& expr_gen, + const details::operator_type o0, const details::operator_type o1) + { + return (details::build_string() << "(t" << expr_gen.to_str(o0) << "t)" << expr_gen.to_str(o1) << "t"); + } + }; + + struct synthesize_vovov_expression1 + { + typedef typename vovov_t::type1 node_type; + typedef typename vovov_t::sf3_type sf3_type; + + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + // (v0) o0 (v1 o1 v2) + const details::vov_base_node* vov = static_cast*>(branch[1]); + const Type& v0 = static_cast*>(branch[0])->ref(); + const Type& v1 = vov->v0(); + const Type& v2 = vov->v1(); + const details::operator_type o0 = operation; + const details::operator_type o1 = vov->operation(); + + binary_functor_t f0 = reinterpret_cast(0); + binary_functor_t f1 = reinterpret_cast(0); + + details::free_node(*(expr_gen.node_allocator_),branch[1]); + + expression_node_ptr result = error_node(); + + if (expr_gen.parser_->settings_.strength_reduction_enabled()) + { + // v0 / (v1 / v2) --> (vovov) (v0 * v2) / v1 + if ((details::e_div == o0) && (details::e_div == o1)) + { + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen,"(t*t)/t",v0,v2,v1,result); + + exprtk_debug(("v0 / (v1 / v2) --> (vovov) (v0 * v2) / v1\n")); + + return (synthesis_result) ? result : error_node(); + } + } + + if (synthesize_sf3ext_expression::template compile(expr_gen,id(expr_gen,o0,o1),v0,v1,v2,result)) + return result; + else if (!expr_gen.valid_operator(o0,f0)) + return error_node(); + else if (!expr_gen.valid_operator(o1,f1)) + return error_node(); + else + return node_type::allocate(*(expr_gen.node_allocator_),v0,v1,v2,f0,f1); + } + + static inline std::string id(expression_generator& expr_gen, + const details::operator_type o0, const details::operator_type o1) + { + return (details::build_string() << "t" << expr_gen.to_str(o0) << "(t" << expr_gen.to_str(o1) << "t)"); + } + }; + + struct synthesize_vovoc_expression0 + { + typedef typename vovoc_t::type0 node_type; + typedef typename vovoc_t::sf3_type sf3_type; + + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + // (v0 o0 v1) o1 (c) + const details::vov_base_node* vov = static_cast*>(branch[0]); + const Type& v0 = vov->v0(); + const Type& v1 = vov->v1(); + const Type c = static_cast*>(branch[1])->value(); + const details::operator_type o0 = vov->operation(); + const details::operator_type o1 = operation; + + binary_functor_t f0 = reinterpret_cast(0); + binary_functor_t f1 = reinterpret_cast(0); + + details::free_node(*(expr_gen.node_allocator_),branch[0]); + details::free_node(*(expr_gen.node_allocator_),branch[1]); + + expression_node_ptr result = error_node(); + + if (expr_gen.parser_->settings_.strength_reduction_enabled()) + { + // (v0 / v1) / c --> (vovoc) v0 / (v1 * c) + if ((details::e_div == o0) && (details::e_div == o1)) + { + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen,"t/(t*t)",v0,v1,c,result); + + exprtk_debug(("(v0 / v1) / c --> (vovoc) v0 / (v1 * c)\n")); + + return (synthesis_result) ? result : error_node(); + } + } + + if (synthesize_sf3ext_expression::template compile(expr_gen,id(expr_gen,o0,o1),v0,v1,c,result)) + return result; + else if (!expr_gen.valid_operator(o0,f0)) + return error_node(); + else if (!expr_gen.valid_operator(o1,f1)) + return error_node(); + else + return node_type::allocate(*(expr_gen.node_allocator_),v0,v1,c,f0,f1); + } + + static inline std::string id(expression_generator& expr_gen, + const details::operator_type o0, const details::operator_type o1) + { + return (details::build_string() << "(t" << expr_gen.to_str(o0) << "t)" << expr_gen.to_str(o1) << "t"); + } + }; + + struct synthesize_vovoc_expression1 + { + typedef typename vovoc_t::type1 node_type; + typedef typename vovoc_t::sf3_type sf3_type; + + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + // (v0) o0 (v1 o1 c) + const details::voc_base_node* voc = static_cast*>(branch[1]); + const Type& v0 = static_cast*>(branch[0])->ref(); + const Type& v1 = voc->v(); + const Type c = voc->c(); + const details::operator_type o0 = operation; + const details::operator_type o1 = voc->operation(); + + binary_functor_t f0 = reinterpret_cast(0); + binary_functor_t f1 = reinterpret_cast(0); + + details::free_node(*(expr_gen.node_allocator_),branch[1]); + + expression_node_ptr result = error_node(); + + if (expr_gen.parser_->settings_.strength_reduction_enabled()) + { + // v0 / (v1 / c) --> (vocov) (v0 * c) / v1 + if ((details::e_div == o0) && (details::e_div == o1)) + { + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen,"(t*t)/t",v0,c,v1,result); + + exprtk_debug(("v0 / (v1 / c) --> (vocov) (v0 * c) / v1\n")); + + return (synthesis_result) ? result : error_node(); + } + } + + if (synthesize_sf3ext_expression::template compile(expr_gen,id(expr_gen,o0,o1),v0,v1,c,result)) + return result; + else if (!expr_gen.valid_operator(o0,f0)) + return error_node(); + else if (!expr_gen.valid_operator(o1,f1)) + return error_node(); + else + return node_type::allocate(*(expr_gen.node_allocator_),v0,v1,c,f0,f1); + } + + static inline std::string id(expression_generator& expr_gen, + const details::operator_type o0, const details::operator_type o1) + { + return (details::build_string() << "t" << expr_gen.to_str(o0) << "(t" << expr_gen.to_str(o1) << "t)"); + } + }; + + struct synthesize_vocov_expression0 + { + typedef typename vocov_t::type0 node_type; + typedef typename vocov_t::sf3_type sf3_type; + + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + // (v0 o0 c) o1 (v1) + const details::voc_base_node* voc = static_cast*>(branch[0]); + const Type& v0 = voc->v(); + const Type c = voc->c(); + const Type& v1 = static_cast*>(branch[1])->ref(); + const details::operator_type o0 = voc->operation(); + const details::operator_type o1 = operation; + + binary_functor_t f0 = reinterpret_cast(0); + binary_functor_t f1 = reinterpret_cast(0); + + details::free_node(*(expr_gen.node_allocator_),branch[0]); + + expression_node_ptr result = error_node(); + + if (expr_gen.parser_->settings_.strength_reduction_enabled()) + { + // (v0 / c) / v1 --> (vovoc) v0 / (v1 * c) + if ((details::e_div == o0) && (details::e_div == o1)) + { + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen,"t/(t*t)",v0,v1,c,result); + + exprtk_debug(("(v0 / c) / v1 --> (vovoc) v0 / (v1 * c)\n")); + + return (synthesis_result) ? result : error_node(); + } + } + + if (synthesize_sf3ext_expression::template compile(expr_gen,id(expr_gen,o0,o1),v0,c,v1,result)) + return result; + else if (!expr_gen.valid_operator(o0,f0)) + return error_node(); + else if (!expr_gen.valid_operator(o1,f1)) + return error_node(); + else + return node_type::allocate(*(expr_gen.node_allocator_),v0,c,v1,f0,f1); + } + + static inline std::string id(expression_generator& expr_gen, + const details::operator_type o0, const details::operator_type o1) + { + return (details::build_string() << "(t" << expr_gen.to_str(o0) << "t)" << expr_gen.to_str(o1) << "t"); + } + }; + + struct synthesize_vocov_expression1 + { + typedef typename vocov_t::type1 node_type; + typedef typename vocov_t::sf3_type sf3_type; + + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + // (v0) o0 (c o1 v1) + const details::cov_base_node* cov = static_cast*>(branch[1]); + const Type& v0 = static_cast*>(branch[0])->ref(); + const Type c = cov->c(); + const Type& v1 = cov->v(); + const details::operator_type o0 = operation; + const details::operator_type o1 = cov->operation(); + + binary_functor_t f0 = reinterpret_cast(0); + binary_functor_t f1 = reinterpret_cast(0); + + details::free_node(*(expr_gen.node_allocator_),branch[1]); + + expression_node_ptr result = error_node(); + + if (expr_gen.parser_->settings_.strength_reduction_enabled()) + { + // v0 / (c / v1) --> (vovoc) (v0 * v1) / c + if ((details::e_div == o0) && (details::e_div == o1)) + { + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen,"(t*t)/t",v0,v1,c,result); + + exprtk_debug(("v0 / (c / v1) --> (vovoc) (v0 * v1) / c\n")); + + return (synthesis_result) ? result : error_node(); + } + } + + if (synthesize_sf3ext_expression::template compile(expr_gen,id(expr_gen,o0,o1),v0,c,v1,result)) + return result; + else if (!expr_gen.valid_operator(o0,f0)) + return error_node(); + else if (!expr_gen.valid_operator(o1,f1)) + return error_node(); + else + return node_type::allocate(*(expr_gen.node_allocator_),v0,c,v1,f0,f1); + } + + static inline std::string id(expression_generator& expr_gen, + const details::operator_type o0, const details::operator_type o1) + { + return (details::build_string() << "t" << expr_gen.to_str(o0) << "(t" << expr_gen.to_str(o1) << "t)"); + } + }; + + struct synthesize_covov_expression0 + { + typedef typename covov_t::type0 node_type; + typedef typename covov_t::sf3_type sf3_type; + + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + // (c o0 v0) o1 (v1) + const details::cov_base_node* cov = static_cast*>(branch[0]); + const Type c = cov->c(); + const Type& v0 = cov->v(); + const Type& v1 = static_cast*>(branch[1])->ref(); + const details::operator_type o0 = cov->operation(); + const details::operator_type o1 = operation; + + binary_functor_t f0 = reinterpret_cast(0); + binary_functor_t f1 = reinterpret_cast(0); + + details::free_node(*(expr_gen.node_allocator_),branch[0]); + + expression_node_ptr result = error_node(); + + if (expr_gen.parser_->settings_.strength_reduction_enabled()) + { + // (c / v0) / v1 --> (covov) c / (v0 * v1) + if ((details::e_div == o0) && (details::e_div == o1)) + { + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen,"t/(t*t)",c,v0,v1,result); + + exprtk_debug(("(c / v0) / v1 --> (covov) c / (v0 * v1)\n")); + + return (synthesis_result) ? result : error_node(); + } + } + + if (synthesize_sf3ext_expression::template compile(expr_gen,id(expr_gen,o0,o1),c,v0,v1,result)) + return result; + else if (!expr_gen.valid_operator(o0,f0)) + return error_node(); + else if (!expr_gen.valid_operator(o1,f1)) + return error_node(); + else + return node_type::allocate(*(expr_gen.node_allocator_),c,v0,v1,f0,f1); + } + + static inline std::string id(expression_generator& expr_gen, + const details::operator_type o0, const details::operator_type o1) + { + return (details::build_string() << "(t" << expr_gen.to_str(o0) << "t)" << expr_gen.to_str(o1) << "t"); + } + }; + + struct synthesize_covov_expression1 + { + typedef typename covov_t::type1 node_type; + typedef typename covov_t::sf3_type sf3_type; + + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + // (c) o0 (v0 o1 v1) + const details::vov_base_node* vov = static_cast*>(branch[1]); + const Type c = static_cast*>(branch[0])->value(); + const Type& v0 = vov->v0(); + const Type& v1 = vov->v1(); + const details::operator_type o0 = operation; + const details::operator_type o1 = vov->operation(); + + binary_functor_t f0 = reinterpret_cast(0); + binary_functor_t f1 = reinterpret_cast(0); + + details::free_node(*(expr_gen.node_allocator_),branch[0]); + details::free_node(*(expr_gen.node_allocator_),branch[1]); + + expression_node_ptr result = error_node(); + + if (expr_gen.parser_->settings_.strength_reduction_enabled()) + { + // c / (v0 / v1) --> (covov) (c * v1) / v0 + if ((details::e_div == o0) && (details::e_div == o1)) + { + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen,"(t*t)/t",c,v1,v0,result); + + exprtk_debug(("c / (v0 / v1) --> (covov) (c * v1) / v0\n")); + + return (synthesis_result) ? result : error_node(); + } + } + + if (synthesize_sf3ext_expression::template compile(expr_gen,id(expr_gen,o0,o1),c,v0,v1,result)) + return result; + else if (!expr_gen.valid_operator(o0,f0)) + return error_node(); + else if (!expr_gen.valid_operator(o1,f1)) + return error_node(); + else + return node_type::allocate(*(expr_gen.node_allocator_),c,v0,v1,f0,f1); + } + + static inline std::string id(expression_generator& expr_gen, const details::operator_type o0, const details::operator_type o1) + { + return (details::build_string() << "t" << expr_gen.to_str(o0) << "(t" << expr_gen.to_str(o1) << "t)"); + } + }; + + struct synthesize_covoc_expression0 + { + typedef typename covoc_t::type0 node_type; + typedef typename covoc_t::sf3_type sf3_type; + + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + // (c0 o0 v) o1 (c1) + const details::cov_base_node* cov = static_cast*>(branch[0]); + const Type c0 = cov->c(); + const Type& v = cov->v(); + const Type c1 = static_cast*>(branch[1])->value(); + const details::operator_type o0 = cov->operation(); + const details::operator_type o1 = operation; + + binary_functor_t f0 = reinterpret_cast(0); + binary_functor_t f1 = reinterpret_cast(0); + + details::free_node(*(expr_gen.node_allocator_),branch[0]); + details::free_node(*(expr_gen.node_allocator_),branch[1]); + + expression_node_ptr result = error_node(); + + if (expr_gen.parser_->settings_.strength_reduction_enabled()) + { + // (c0 + v) + c1 --> (cov) (c0 + c1) + v + if ((details::e_add == o0) && (details::e_add == o1)) + { + exprtk_debug(("(c0 + v) + c1 --> (cov) (c0 + c1) + v\n")); + + return expr_gen.node_allocator_-> + template allocate_cr > >(c0 + c1,v); + } + // (c0 + v) - c1 --> (cov) (c0 - c1) + v + else if ((details::e_add == o0) && (details::e_sub == o1)) + { + exprtk_debug(("(c0 + v) - c1 --> (cov) (c0 - c1) + v\n")); + + return expr_gen.node_allocator_-> + template allocate_cr > >(c0 - c1,v); + } + // (c0 - v) + c1 --> (cov) (c0 + c1) - v + else if ((details::e_sub == o0) && (details::e_add == o1)) + { + exprtk_debug(("(c0 - v) + c1 --> (cov) (c0 + c1) - v\n")); + + return expr_gen.node_allocator_-> + template allocate_cr > >(c0 + c1,v); + } + // (c0 - v) - c1 --> (cov) (c0 - c1) - v + else if ((details::e_sub == o0) && (details::e_sub == o1)) + { + exprtk_debug(("(c0 - v) - c1 --> (cov) (c0 - c1) - v\n")); + + return expr_gen.node_allocator_-> + template allocate_cr > >(c0 - c1,v); + } + // (c0 * v) * c1 --> (cov) (c0 * c1) * v + else if ((details::e_mul == o0) && (details::e_mul == o1)) + { + exprtk_debug(("(c0 * v) * c1 --> (cov) (c0 * c1) * v\n")); + + return expr_gen.node_allocator_-> + template allocate_cr > >(c0 * c1,v); + } + // (c0 * v) / c1 --> (cov) (c0 / c1) * v + else if ((details::e_mul == o0) && (details::e_div == o1)) + { + exprtk_debug(("(c0 * v) / c1 --> (cov) (c0 / c1) * v\n")); + + return expr_gen.node_allocator_-> + template allocate_cr > >(c0 / c1,v); + } + // (c0 / v) * c1 --> (cov) (c0 * c1) / v + else if ((details::e_div == o0) && (details::e_mul == o1)) + { + exprtk_debug(("(c0 / v) * c1 --> (cov) (c0 * c1) / v\n")); + + return expr_gen.node_allocator_-> + template allocate_cr > >(c0 * c1,v); + } + // (c0 / v) / c1 --> (cov) (c0 / c1) / v + else if ((details::e_div == o0) && (details::e_div == o1)) + { + exprtk_debug(("(c0 / v) / c1 --> (cov) (c0 / c1) / v\n")); + + return expr_gen.node_allocator_-> + template allocate_cr > >(c0 / c1,v); + } + } + + if (synthesize_sf3ext_expression::template compile(expr_gen,id(expr_gen,o0,o1),c0,v,c1,result)) + return result; + else if (!expr_gen.valid_operator(o0,f0)) + return error_node(); + else if (!expr_gen.valid_operator(o1,f1)) + return error_node(); + else + return node_type::allocate(*(expr_gen.node_allocator_),c0,v,c1,f0,f1); + } + + static inline std::string id(expression_generator& expr_gen, + const details::operator_type o0, const details::operator_type o1) + { + return (details::build_string() << "(t" << expr_gen.to_str(o0) << "t)" << expr_gen.to_str(o1) << "t"); + } + }; + + struct synthesize_covoc_expression1 + { + typedef typename covoc_t::type1 node_type; + typedef typename covoc_t::sf3_type sf3_type; + + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + // (c0) o0 (v o1 c1) + const details::voc_base_node* voc = static_cast*>(branch[1]); + const Type c0 = static_cast*>(branch[0])->value(); + const Type& v = voc->v(); + const Type c1 = voc->c(); + const details::operator_type o0 = operation; + const details::operator_type o1 = voc->operation(); + + binary_functor_t f0 = reinterpret_cast(0); + binary_functor_t f1 = reinterpret_cast(0); + + details::free_node(*(expr_gen.node_allocator_),branch[0]); + details::free_node(*(expr_gen.node_allocator_),branch[1]); + + expression_node_ptr result = error_node(); + + if (expr_gen.parser_->settings_.strength_reduction_enabled()) + { + // (c0) + (v + c1) --> (cov) (c0 + c1) + v + if ((details::e_add == o0) && (details::e_add == o1)) + { + exprtk_debug(("(c0) + (v + c1) --> (cov) (c0 + c1) + v\n")); + + return expr_gen.node_allocator_-> + template allocate_cr > >(c0 + c1,v); + } + // (c0) + (v - c1) --> (cov) (c0 - c1) + v + else if ((details::e_add == o0) && (details::e_sub == o1)) + { + exprtk_debug(("(c0) + (v - c1) --> (cov) (c0 - c1) + v\n")); + + return expr_gen.node_allocator_-> + template allocate_cr > >(c0 - c1,v); + } + // (c0) - (v + c1) --> (cov) (c0 - c1) - v + else if ((details::e_sub == o0) && (details::e_add == o1)) + { + exprtk_debug(("(c0) - (v + c1) --> (cov) (c0 - c1) - v\n")); + + return expr_gen.node_allocator_-> + template allocate_cr > >(c0 - c1,v); + } + // (c0) - (v - c1) --> (cov) (c0 + c1) - v + else if ((details::e_sub == o0) && (details::e_sub == o1)) + { + exprtk_debug(("(c0) - (v - c1) --> (cov) (c0 + c1) - v\n")); + + return expr_gen.node_allocator_-> + template allocate_cr > >(c0 + c1,v); + } + // (c0) * (v * c1) --> (voc) v * (c0 * c1) + else if ((details::e_mul == o0) && (details::e_mul == o1)) + { + exprtk_debug(("(c0) * (v * c1) --> (voc) v * (c0 * c1)\n")); + + return expr_gen.node_allocator_-> + template allocate_cr > >(c0 * c1,v); + } + // (c0) * (v / c1) --> (cov) (c0 / c1) * v + else if ((details::e_mul == o0) && (details::e_div == o1)) + { + exprtk_debug(("(c0) * (v / c1) --> (cov) (c0 / c1) * v\n")); + + return expr_gen.node_allocator_-> + template allocate_cr > >(c0 / c1,v); + } + // (c0) / (v * c1) --> (cov) (c0 / c1) / v + else if ((details::e_div == o0) && (details::e_mul == o1)) + { + exprtk_debug(("(c0) / (v * c1) --> (cov) (c0 / c1) / v\n")); + + return expr_gen.node_allocator_-> + template allocate_cr > >(c0 / c1,v); + } + // (c0) / (v / c1) --> (cov) (c0 * c1) / v + else if ((details::e_div == o0) && (details::e_div == o1)) + { + exprtk_debug(("(c0) / (v / c1) --> (cov) (c0 * c1) / v\n")); + + return expr_gen.node_allocator_-> + template allocate_cr > >(c0 * c1,v); + } + } + + if (synthesize_sf3ext_expression::template compile(expr_gen,id(expr_gen,o0,o1),c0,v,c1,result)) + return result; + else if (!expr_gen.valid_operator(o0,f0)) + return error_node(); + else if (!expr_gen.valid_operator(o1,f1)) + return error_node(); + else + return node_type::allocate(*(expr_gen.node_allocator_),c0,v,c1,f0,f1); + } + + static inline std::string id(expression_generator& expr_gen, + const details::operator_type o0, const details::operator_type o1) + { + return (details::build_string() << "t" << expr_gen.to_str(o0) << "(t" << expr_gen.to_str(o1) << "t)"); + } + }; + + struct synthesize_cocov_expression0 + { + typedef typename cocov_t::type0 node_type; + static inline expression_node_ptr process(expression_generator&, const details::operator_type&, expression_node_ptr (&)[2]) + { + // (c0 o0 c1) o1 (v) - Not possible. + return error_node(); + } + }; + + struct synthesize_cocov_expression1 + { + typedef typename cocov_t::type1 node_type; + typedef typename cocov_t::sf3_type sf3_type; + + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + // (c0) o0 (c1 o1 v) + const details::cov_base_node* cov = static_cast*>(branch[1]); + const Type c0 = static_cast*>(branch[0])->value(); + const Type c1 = cov->c(); + const Type& v = cov->v(); + const details::operator_type o0 = operation; + const details::operator_type o1 = cov->operation(); + + binary_functor_t f0 = reinterpret_cast(0); + binary_functor_t f1 = reinterpret_cast(0); + + details::free_node(*(expr_gen.node_allocator_),branch[0]); + details::free_node(*(expr_gen.node_allocator_),branch[1]); + + expression_node_ptr result = error_node(); + + if (expr_gen.parser_->settings_.strength_reduction_enabled()) + { + // (c0) + (c1 + v) --> (cov) (c0 + c1) + v + if ((details::e_add == o0) && (details::e_add == o1)) + { + exprtk_debug(("(c0) + (c1 + v) --> (cov) (c0 + c1) + v\n")); + + return expr_gen.node_allocator_-> + template allocate_cr > >(c0 + c1,v); + } + // (c0) + (c1 - v) --> (cov) (c0 + c1) - v + else if ((details::e_add == o0) && (details::e_sub == o1)) + { + exprtk_debug(("(c0) + (c1 - v) --> (cov) (c0 + c1) - v\n")); + + return expr_gen.node_allocator_-> + template allocate_cr > >(c0 + c1,v); + } + // (c0) - (c1 + v) --> (cov) (c0 - c1) - v + else if ((details::e_sub == o0) && (details::e_add == o1)) + { + exprtk_debug(("(c0) - (c1 + v) --> (cov) (c0 - c1) - v\n")); + + return expr_gen.node_allocator_-> + template allocate_cr > >(c0 - c1,v); + } + // (c0) - (c1 - v) --> (cov) (c0 - c1) + v + else if ((details::e_sub == o0) && (details::e_sub == o1)) + { + exprtk_debug(("(c0) - (c1 - v) --> (cov) (c0 - c1) + v\n")); + + return expr_gen.node_allocator_-> + template allocate_cr > >(c0 - c1,v); + } + // (c0) * (c1 * v) --> (cov) (c0 * c1) * v + else if ((details::e_mul == o0) && (details::e_mul == o1)) + { + exprtk_debug(("(c0) * (c1 * v) --> (cov) (c0 * c1) * v\n")); + + return expr_gen.node_allocator_-> + template allocate_cr > >(c0 * c1,v); + } + // (c0) * (c1 / v) --> (cov) (c0 * c1) / v + else if ((details::e_mul == o0) && (details::e_div == o1)) + { + exprtk_debug(("(c0) * (c1 / v) --> (cov) (c0 * c1) / v\n")); + + return expr_gen.node_allocator_-> + template allocate_cr > >(c0 * c1,v); + } + // (c0) / (c1 * v) --> (cov) (c0 / c1) / v + else if ((details::e_div == o0) && (details::e_mul == o1)) + { + exprtk_debug(("(c0) / (c1 * v) --> (cov) (c0 / c1) / v\n")); + + return expr_gen.node_allocator_-> + template allocate_cr > >(c0 / c1,v); + } + // (c0) / (c1 / v) --> (cov) (c0 / c1) * v + else if ((details::e_div == o0) && (details::e_div == o1)) + { + exprtk_debug(("(c0) / (c1 / v) --> (cov) (c0 / c1) * v\n")); + + return expr_gen.node_allocator_-> + template allocate_cr > >(c0 / c1,v); + } + } + + if (synthesize_sf3ext_expression::template compile(expr_gen,id(expr_gen,o0,o1),c0,c1,v,result)) + return result; + else if (!expr_gen.valid_operator(o0,f0)) + return error_node(); + else if (!expr_gen.valid_operator(o1,f1)) + return error_node(); + else + return node_type::allocate(*(expr_gen.node_allocator_),c0,c1,v,f0,f1); + } + + static inline std::string id(expression_generator& expr_gen, const details::operator_type o0, const details::operator_type o1) + { + return (details::build_string() << "t" << expr_gen.to_str(o0) << "(t" << expr_gen.to_str(o1) << "t)"); + } + }; + + struct synthesize_vococ_expression0 + { + typedef typename vococ_t::type0 node_type; + typedef typename vococ_t::sf3_type sf3_type; + + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + // (v o0 c0) o1 (c1) + const details::voc_base_node* voc = static_cast*>(branch[0]); + const Type& v = voc->v(); + const Type& c0 = voc->c(); + const Type& c1 = static_cast*>(branch[1])->value(); + const details::operator_type o0 = voc->operation(); + const details::operator_type o1 = operation; + + binary_functor_t f0 = reinterpret_cast(0); + binary_functor_t f1 = reinterpret_cast(0); + + details::free_node(*(expr_gen.node_allocator_),branch[0]); + details::free_node(*(expr_gen.node_allocator_),branch[1]); + + expression_node_ptr result = error_node(); + + if (expr_gen.parser_->settings_.strength_reduction_enabled()) + { + // (v + c0) + c1 --> (voc) v + (c0 + c1) + if ((details::e_add == o0) && (details::e_add == o1)) + { + exprtk_debug(("(v + c0) + c1 --> (voc) v + (c0 + c1)\n")); + + return expr_gen.node_allocator_-> + template allocate_rc > >(v,c0 + c1); + } + // (v + c0) - c1 --> (voc) v + (c0 - c1) + else if ((details::e_add == o0) && (details::e_sub == o1)) + { + exprtk_debug(("(v + c0) - c1 --> (voc) v + (c0 - c1)\n")); + + return expr_gen.node_allocator_-> + template allocate_rc > >(v,c0 - c1); + } + // (v - c0) + c1 --> (voc) v - (c0 + c1) + else if ((details::e_sub == o0) && (details::e_add == o1)) + { + exprtk_debug(("(v - c0) + c1 --> (voc) v - (c0 + c1)\n")); + + return expr_gen.node_allocator_-> + template allocate_rc > >(v,c1 - c0); + } + // (v - c0) - c1 --> (voc) v - (c0 + c1) + else if ((details::e_sub == o0) && (details::e_sub == o1)) + { + exprtk_debug(("(v - c0) - c1 --> (voc) v - (c0 + c1)\n")); + + return expr_gen.node_allocator_-> + template allocate_rc > >(v,c0 + c1); + } + // (v * c0) * c1 --> (voc) v * (c0 * c1) + else if ((details::e_mul == o0) && (details::e_mul == o1)) + { + exprtk_debug(("(v * c0) * c1 --> (voc) v * (c0 * c1)\n")); + + return expr_gen.node_allocator_-> + template allocate_rc > >(v,c0 * c1); + } + // (v * c0) / c1 --> (voc) v * (c0 / c1) + else if ((details::e_mul == o0) && (details::e_div == o1)) + { + exprtk_debug(("(v * c0) / c1 --> (voc) v * (c0 / c1)\n")); + + return expr_gen.node_allocator_-> + template allocate_rc > >(v,c0 / c1); + } + // (v / c0) * c1 --> (voc) v * (c1 / c0) + else if ((details::e_div == o0) && (details::e_mul == o1)) + { + exprtk_debug(("(v / c0) * c1 --> (voc) v * (c1 / c0)\n")); + + return expr_gen.node_allocator_-> + template allocate_rc > >(v,c1 / c0); + } + // (v / c0) / c1 --> (voc) v / (c0 * c1) + else if ((details::e_div == o0) && (details::e_div == o1)) + { + exprtk_debug(("(v / c0) / c1 --> (voc) v / (c0 * c1)\n")); + + return expr_gen.node_allocator_-> + template allocate_rc > >(v,c0 * c1); + } + // (v ^ c0) ^ c1 --> (voc) v ^ (c0 * c1) + else if ((details::e_pow == o0) && (details::e_pow == o1)) + { + exprtk_debug(("(v ^ c0) ^ c1 --> (voc) v ^ (c0 * c1)\n")); + + return expr_gen.node_allocator_-> + template allocate_rc > >(v,c0 * c1); + } + } + + if (synthesize_sf3ext_expression::template compile(expr_gen,id(expr_gen,o0,o1),v,c0,c1,result)) + return result; + else if (!expr_gen.valid_operator(o0,f0)) + return error_node(); + else if (!expr_gen.valid_operator(o1,f1)) + return error_node(); + else + return node_type::allocate(*(expr_gen.node_allocator_),v,c0,c1,f0,f1); + } + + static inline std::string id(expression_generator& expr_gen, + const details::operator_type o0, const details::operator_type o1) + { + return (details::build_string() << "(t" << expr_gen.to_str(o0) << "t)" << expr_gen.to_str(o1) << "t"); + } + }; + + struct synthesize_vococ_expression1 + { + typedef typename vococ_t::type0 node_type; + + static inline expression_node_ptr process(expression_generator&, const details::operator_type&, expression_node_ptr (&)[2]) + { + // (v) o0 (c0 o1 c1) - Not possible. + exprtk_debug(("(v) o0 (c0 o1 c1) - Not possible.\n")); + return error_node(); + } + }; + + struct synthesize_vovovov_expression0 + { + typedef typename vovovov_t::type0 node_type; + typedef typename vovovov_t::sf4_type sf4_type; + typedef typename node_type::T0 T0; + typedef typename node_type::T1 T1; + typedef typename node_type::T2 T2; + typedef typename node_type::T3 T3; + + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + // (v0 o0 v1) o1 (v2 o2 v3) + const details::vov_base_node* vov0 = static_cast*>(branch[0]); + const details::vov_base_node* vov1 = static_cast*>(branch[1]); + const Type& v0 = vov0->v0(); + const Type& v1 = vov0->v1(); + const Type& v2 = vov1->v0(); + const Type& v3 = vov1->v1(); + const details::operator_type o0 = vov0->operation(); + const details::operator_type o1 = operation; + const details::operator_type o2 = vov1->operation(); + + binary_functor_t f0 = reinterpret_cast(0); + binary_functor_t f1 = reinterpret_cast(0); + binary_functor_t f2 = reinterpret_cast(0); + + details::free_node(*(expr_gen.node_allocator_),branch[0]); + details::free_node(*(expr_gen.node_allocator_),branch[1]); + + expression_node_ptr result = error_node(); + + if (expr_gen.parser_->settings_.strength_reduction_enabled()) + { + // (v0 / v1) * (v2 / v3) --> (vovovov) (v0 * v2) / (v1 * v3) + if ((details::e_div == o0) && (details::e_mul == o1) && (details::e_div == o2)) + { + const bool synthesis_result = + synthesize_sf4ext_expression:: + template compile(expr_gen,"(t*t)/(t*t)",v0,v2,v1,v3,result); + + exprtk_debug(("(v0 / v1) * (v2 / v3) --> (vovovov) (v0 * v2) / (v1 * v3)\n")); + + return (synthesis_result) ? result : error_node(); + } + // (v0 / v1) / (v2 / v3) --> (vovovov) (v0 * v3) / (v1 * v2) + else if ((details::e_div == o0) && (details::e_div == o1) && (details::e_div == o2)) + { + const bool synthesis_result = + synthesize_sf4ext_expression:: + template compile(expr_gen,"(t*t)/(t*t)",v0,v3,v1,v2,result); + + exprtk_debug(("(v0 / v1) / (v2 / v3) --> (vovovov) (v0 * v3) / (v1 * v2)\n")); + + return (synthesis_result) ? result : error_node(); + } + // (v0 + v1) / (v2 / v3) --> (vovovov) (v0 + v1) * (v3 / v2) + else if ((details::e_add == o0) && (details::e_div == o1) && (details::e_div == o2)) + { + const bool synthesis_result = + synthesize_sf4ext_expression:: + template compile(expr_gen,"(t+t)*(t/t)",v0,v1,v3,v2,result); + + exprtk_debug(("(v0 + v1) / (v2 / v3) --> (vovovov) (v0 + v1) * (v3 / v2)\n")); + + return (synthesis_result) ? result : error_node(); + } + // (v0 - v1) / (v2 / v3) --> (vovovov) (v0 + v1) * (v3 / v2) + else if ((details::e_sub == o0) && (details::e_div == o1) && (details::e_div == o2)) + { + const bool synthesis_result = + synthesize_sf4ext_expression:: + template compile(expr_gen,"(t-t)*(t/t)",v0,v1,v3,v2,result); + + exprtk_debug(("(v0 - v1) / (v2 / v3) --> (vovovov) (v0 - v1) * (v3 / v2)\n")); + + return (synthesis_result) ? result : error_node(); + } + // (v0 * v1) / (v2 / v3) --> (vovovov) ((v0 * v1) * v3) / v2 + else if ((details::e_mul == o0) && (details::e_div == o1) && (details::e_div == o2)) + { + const bool synthesis_result = + synthesize_sf4ext_expression:: + template compile(expr_gen,"((t*t)*t)/t",v0,v1,v3,v2,result); + + exprtk_debug(("(v0 * v1) / (v2 / v3) --> (vovovov) ((v0 * v1) * v3) / v2\n")); + + return (synthesis_result) ? result : error_node(); + } + } + + if (synthesize_sf4ext_expression::template compile(expr_gen,id(expr_gen,o0,o1,o2),v0,v1,v2,v3,result)) + return result; + else if (!expr_gen.valid_operator(o0,f0)) + return error_node(); + else if (!expr_gen.valid_operator(o1,f1)) + return error_node(); + else if (!expr_gen.valid_operator(o2,f2)) + return error_node(); + else + return node_type::allocate(*(expr_gen.node_allocator_),v0,v1,v2,v3,f0,f1,f2); + } + + static inline std::string id(expression_generator& expr_gen, + const details::operator_type o0, + const details::operator_type o1, + const details::operator_type o2) + { + return (details::build_string() << "(t" << expr_gen.to_str(o0) << "t)" << expr_gen.to_str(o1) << "(t" << expr_gen.to_str(o2) << "t)"); + } + }; + + struct synthesize_vovovoc_expression0 + { + typedef typename vovovoc_t::type0 node_type; + typedef typename vovovoc_t::sf4_type sf4_type; + typedef typename node_type::T0 T0; + typedef typename node_type::T1 T1; + typedef typename node_type::T2 T2; + typedef typename node_type::T3 T3; + + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + // (v0 o0 v1) o1 (v2 o2 c) + const details::vov_base_node* vov = static_cast*>(branch[0]); + const details::voc_base_node* voc = static_cast*>(branch[1]); + const Type& v0 = vov->v0(); + const Type& v1 = vov->v1(); + const Type& v2 = voc->v (); + const Type c = voc->c (); + const details::operator_type o0 = vov->operation(); + const details::operator_type o1 = operation; + const details::operator_type o2 = voc->operation(); + + binary_functor_t f0 = reinterpret_cast(0); + binary_functor_t f1 = reinterpret_cast(0); + binary_functor_t f2 = reinterpret_cast(0); + + details::free_node(*(expr_gen.node_allocator_),branch[0]); + details::free_node(*(expr_gen.node_allocator_),branch[1]); + + expression_node_ptr result = error_node(); + + if (expr_gen.parser_->settings_.strength_reduction_enabled()) + { + // (v0 / v1) * (v2 / c) --> (vovovoc) (v0 * v2) / (v1 * c) + if ((details::e_div == o0) && (details::e_mul == o1) && (details::e_div == o2)) + { + const bool synthesis_result = + synthesize_sf4ext_expression:: + template compile(expr_gen,"(t*t)/(t*t)",v0,v2,v1,c,result); + + exprtk_debug(("(v0 / v1) * (v2 / c) --> (vovovoc) (v0 * v2) / (v1 * c)\n")); + + return (synthesis_result) ? result : error_node(); + } + // (v0 / v1) / (v2 / c) --> (vocovov) (v0 * c) / (v1 * v2) + if ((details::e_div == o0) && (details::e_div == o1) && (details::e_div == o2)) + { + const bool synthesis_result = + synthesize_sf4ext_expression:: + template compile(expr_gen,"(t*t)/(t*t)",v0,c,v1,v2,result); + + exprtk_debug(("(v0 / v1) / (v2 / c) --> (vocovov) (v0 * c) / (v1 * v2)\n")); + + return (synthesis_result) ? result : error_node(); + } + } + + if (synthesize_sf4ext_expression::template compile(expr_gen,id(expr_gen,o0,o1,o2),v0,v1,v2,c,result)) + return result; + else if (!expr_gen.valid_operator(o0,f0)) + return error_node(); + else if (!expr_gen.valid_operator(o1,f1)) + return error_node(); + else if (!expr_gen.valid_operator(o2,f2)) + return error_node(); + else + return node_type::allocate(*(expr_gen.node_allocator_),v0,v1,v2,c,f0,f1,f2); + } + + static inline std::string id(expression_generator& expr_gen, + const details::operator_type o0, + const details::operator_type o1, + const details::operator_type o2) + { + return (details::build_string() << "(t" << expr_gen.to_str(o0) << "t)" << expr_gen.to_str(o1) << "(t" << expr_gen.to_str(o2) << "t)"); + } + }; + + struct synthesize_vovocov_expression0 + { + typedef typename vovocov_t::type0 node_type; + typedef typename vovocov_t::sf4_type sf4_type; + typedef typename node_type::T0 T0; + typedef typename node_type::T1 T1; + typedef typename node_type::T2 T2; + typedef typename node_type::T3 T3; + + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + // (v0 o0 v1) o1 (c o2 v2) + const details::vov_base_node* vov = static_cast*>(branch[0]); + const details::cov_base_node* cov = static_cast*>(branch[1]); + const Type& v0 = vov->v0(); + const Type& v1 = vov->v1(); + const Type& v2 = cov->v (); + const Type c = cov->c (); + const details::operator_type o0 = vov->operation(); + const details::operator_type o1 = operation; + const details::operator_type o2 = cov->operation(); + + binary_functor_t f0 = reinterpret_cast(0); + binary_functor_t f1 = reinterpret_cast(0); + binary_functor_t f2 = reinterpret_cast(0); + + details::free_node(*(expr_gen.node_allocator_),branch[0]); + details::free_node(*(expr_gen.node_allocator_),branch[1]); + + expression_node_ptr result = error_node(); + + if (expr_gen.parser_->settings_.strength_reduction_enabled()) + { + // (v0 / v1) * (c / v2) --> (vocovov) (v0 * c) / (v1 * v2) + if ((details::e_div == o0) && (details::e_mul == o1) && (details::e_div == o2)) + { + const bool synthesis_result = + synthesize_sf4ext_expression:: + template compile(expr_gen,"(t*t)/(t*t)",v0,c,v1,v2,result); + + exprtk_debug(("(v0 / v1) * (c / v2) --> (vocovov) (v0 * c) / (v1 * v2)\n")); + + return (synthesis_result) ? result : error_node(); + } + // (v0 / v1) / (c / v2) --> (vovovoc) (v0 * v2) / (v1 * c) + if ((details::e_div == o0) && (details::e_div == o1) && (details::e_div == o2)) + { + const bool synthesis_result = + synthesize_sf4ext_expression:: + template compile(expr_gen,"(t*t)/(t*t)",v0,v2,v1,c,result); + + exprtk_debug(("(v0 / v1) / (c / v2) --> (vovovoc) (v0 * v2) / (v1 * c)\n")); + + return (synthesis_result) ? result : error_node(); + } + } + + if (synthesize_sf4ext_expression::template compile(expr_gen,id(expr_gen,o0,o1,o2),v0,v1,c,v2,result)) + return result; + else if (!expr_gen.valid_operator(o0,f0)) + return error_node(); + else if (!expr_gen.valid_operator(o1,f1)) + return error_node(); + else if (!expr_gen.valid_operator(o2,f2)) + return error_node(); + else + return node_type::allocate(*(expr_gen.node_allocator_),v0,v1,c,v2,f0,f1,f2); + } + + static inline std::string id(expression_generator& expr_gen, + const details::operator_type o0, + const details::operator_type o1, + const details::operator_type o2) + { + return (details::build_string() << "(t" << expr_gen.to_str(o0) << "t)" << expr_gen.to_str(o1) << "(t" << expr_gen.to_str(o2) << "t)"); + } + }; + + struct synthesize_vocovov_expression0 + { + typedef typename vocovov_t::type0 node_type; + typedef typename vocovov_t::sf4_type sf4_type; + typedef typename node_type::T0 T0; + typedef typename node_type::T1 T1; + typedef typename node_type::T2 T2; + typedef typename node_type::T3 T3; + + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + // (v0 o0 c) o1 (v1 o2 v2) + const details::voc_base_node* voc = static_cast*>(branch[0]); + const details::vov_base_node* vov = static_cast*>(branch[1]); + const Type c = voc->c (); + const Type& v0 = voc->v (); + const Type& v1 = vov->v0(); + const Type& v2 = vov->v1(); + const details::operator_type o0 = voc->operation(); + const details::operator_type o1 = operation; + const details::operator_type o2 = vov->operation(); + + binary_functor_t f0 = reinterpret_cast(0); + binary_functor_t f1 = reinterpret_cast(0); + binary_functor_t f2 = reinterpret_cast(0); + + details::free_node(*(expr_gen.node_allocator_),branch[0]); + details::free_node(*(expr_gen.node_allocator_),branch[1]); + + expression_node_ptr result = error_node(); + + if (expr_gen.parser_->settings_.strength_reduction_enabled()) + { + // (v0 / c) * (v1 / v2) --> (vovocov) (v0 * v1) / (c * v2) + if ((details::e_div == o0) && (details::e_mul == o1) && (details::e_div == o2)) + { + const bool synthesis_result = + synthesize_sf4ext_expression:: + template compile(expr_gen,"(t*t)/(t*t)",v0,v1,c,v2,result); + + exprtk_debug(("(v0 / c) * (v1 / v2) --> (vovocov) (v0 * v1) / (c * v2)\n")); + + return (synthesis_result) ? result : error_node(); + } + // (v0 / c) / (v1 / v2) --> (vovocov) (v0 * v2) / (c * v1) + if ((details::e_div == o0) && (details::e_div == o1) && (details::e_div == o2)) + { + const bool synthesis_result = + synthesize_sf4ext_expression:: + template compile(expr_gen,"(t*t)/(t*t)",v0,v2,c,v1,result); + + exprtk_debug(("(v0 / c) / (v1 / v2) --> (vovocov) (v0 * v2) / (c * v1)\n")); + + return (synthesis_result) ? result : error_node(); + } + } + + if (synthesize_sf4ext_expression::template compile(expr_gen,id(expr_gen,o0,o1,o2),v0,c,v1,v2,result)) + return result; + else if (!expr_gen.valid_operator(o0,f0)) + return error_node(); + else if (!expr_gen.valid_operator(o1,f1)) + return error_node(); + else if (!expr_gen.valid_operator(o2,f2)) + return error_node(); + else + return node_type::allocate(*(expr_gen.node_allocator_),v0,c,v1,v2,f0,f1,f2); + } + + static inline std::string id(expression_generator& expr_gen, + const details::operator_type o0, + const details::operator_type o1, + const details::operator_type o2) + { + return (details::build_string() << "(t" << expr_gen.to_str(o0) << "t)" << expr_gen.to_str(o1) << "(t" << expr_gen.to_str(o2) << "t)"); + } + }; + + struct synthesize_covovov_expression0 + { + typedef typename covovov_t::type0 node_type; + typedef typename covovov_t::sf4_type sf4_type; + typedef typename node_type::T0 T0; + typedef typename node_type::T1 T1; + typedef typename node_type::T2 T2; + typedef typename node_type::T3 T3; + + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + // (c o0 v0) o1 (v1 o2 v2) + const details::cov_base_node* cov = static_cast*>(branch[0]); + const details::vov_base_node* vov = static_cast*>(branch[1]); + const Type c = cov->c (); + const Type& v0 = cov->v (); + const Type& v1 = vov->v0(); + const Type& v2 = vov->v1(); + const details::operator_type o0 = cov->operation(); + const details::operator_type o1 = operation; + const details::operator_type o2 = vov->operation(); + + binary_functor_t f0 = reinterpret_cast(0); + binary_functor_t f1 = reinterpret_cast(0); + binary_functor_t f2 = reinterpret_cast(0); + + details::free_node(*(expr_gen.node_allocator_),branch[0]); + details::free_node(*(expr_gen.node_allocator_),branch[1]); + + expression_node_ptr result = error_node(); + + if (expr_gen.parser_->settings_.strength_reduction_enabled()) + { + // (c / v0) * (v1 / v2) --> (covovov) (c * v1) / (v0 * v2) + if ((details::e_div == o0) && (details::e_mul == o1) && (details::e_div == o2)) + { + const bool synthesis_result = + synthesize_sf4ext_expression:: + template compile(expr_gen,"(t*t)/(t*t)",c,v1,v0,v2,result); + + exprtk_debug(("(c / v0) * (v1 / v2) --> (covovov) (c * v1) / (v0 * v2)\n")); + + return (synthesis_result) ? result : error_node(); + } + // (c / v0) / (v1 / v2) --> (covovov) (c * v2) / (v0 * v1) + if ((details::e_div == o0) && (details::e_div == o1) && (details::e_div == o2)) + { + const bool synthesis_result = + synthesize_sf4ext_expression:: + template compile(expr_gen,"(t*t)/(t*t)",c,v2,v0,v1,result); + + exprtk_debug(("(c / v0) / (v1 / v2) --> (covovov) (c * v2) / (v0 * v1)\n")); + + return (synthesis_result) ? result : error_node(); + } + } + + if (synthesize_sf4ext_expression::template compile(expr_gen,id(expr_gen,o0,o1,o2),c,v0,v1,v2,result)) + return result; + else if (!expr_gen.valid_operator(o0,f0)) + return error_node(); + else if (!expr_gen.valid_operator(o1,f1)) + return error_node(); + else if (!expr_gen.valid_operator(o2,f2)) + return error_node(); + else + return node_type::allocate(*(expr_gen.node_allocator_),c,v0,v1,v2,f0,f1,f2); + } + + static inline std::string id(expression_generator& expr_gen, + const details::operator_type o0, + const details::operator_type o1, + const details::operator_type o2) + { + return (details::build_string() << "(t" << expr_gen.to_str(o0) << "t)" << expr_gen.to_str(o1) << "(t" << expr_gen.to_str(o2) << "t)"); + } + }; + + struct synthesize_covocov_expression0 + { + typedef typename covocov_t::type0 node_type; + typedef typename covocov_t::sf4_type sf4_type; + typedef typename node_type::T0 T0; + typedef typename node_type::T1 T1; + typedef typename node_type::T2 T2; + typedef typename node_type::T3 T3; + + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + // (c0 o0 v0) o1 (c1 o2 v1) + const details::cov_base_node* cov0 = static_cast*>(branch[0]); + const details::cov_base_node* cov1 = static_cast*>(branch[1]); + const Type c0 = cov0->c(); + const Type& v0 = cov0->v(); + const Type c1 = cov1->c(); + const Type& v1 = cov1->v(); + const details::operator_type o0 = cov0->operation(); + const details::operator_type o1 = operation; + const details::operator_type o2 = cov1->operation(); + + binary_functor_t f0 = reinterpret_cast(0); + binary_functor_t f1 = reinterpret_cast(0); + binary_functor_t f2 = reinterpret_cast(0); + + details::free_node(*(expr_gen.node_allocator_),branch[0]); + details::free_node(*(expr_gen.node_allocator_),branch[1]); + + expression_node_ptr result = error_node(); + + if (expr_gen.parser_->settings_.strength_reduction_enabled()) + { + // (c0 + v0) + (c1 + v1) --> (covov) (c0 + c1) + v0 + v1 + if ((details::e_add == o0) && (details::e_add == o1) && (details::e_add == o2)) + { + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen,"(t+t)+t",(c0 + c1),v0,v1,result); + + exprtk_debug(("(c0 + v0) + (c1 + v1) --> (covov) (c0 + c1) + v0 + v1\n")); + + return (synthesis_result) ? result : error_node(); + } + // (c0 + v0) - (c1 + v1) --> (covov) (c0 - c1) + v0 - v1 + else if ((details::e_add == o0) && (details::e_sub == o1) && (details::e_add == o2)) + { + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen,"(t+t)-t",(c0 - c1),v0,v1,result); + + exprtk_debug(("(c0 + v0) - (c1 + v1) --> (covov) (c0 - c1) + v0 - v1\n")); + + return (synthesis_result) ? result : error_node(); + } + // (c0 - v0) - (c1 - v1) --> (covov) (c0 - c1) - v0 + v1 + else if ((details::e_sub == o0) && (details::e_sub == o1) && (details::e_sub == o2)) + { + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen,"(t-t)+t",(c0 - c1),v0,v1,result); + + exprtk_debug(("(c0 - v0) - (c1 - v1) --> (covov) (c0 - c1) - v0 + v1\n")); + + return (synthesis_result) ? result : error_node(); + } + // (c0 * v0) * (c1 * v1) --> (covov) (c0 * c1) * v0 * v1 + else if ((details::e_mul == o0) && (details::e_mul == o1) && (details::e_mul == o2)) + { + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen,"(t*t)*t",(c0 * c1),v0,v1,result); + + exprtk_debug(("(c0 * v0) * (c1 * v1) --> (covov) (c0 * c1) * v0 * v1\n")); + + return (synthesis_result) ? result : error_node(); + } + // (c0 * v0) / (c1 * v1) --> (covov) (c0 / c1) * (v0 / v1) + else if ((details::e_mul == o0) && (details::e_div == o1) && (details::e_mul == o2)) + { + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen,"(t*t)/t",(c0 / c1),v0,v1,result); + + exprtk_debug(("(c0 * v0) / (c1 * v1) --> (covov) (c0 / c1) * (v0 / v1)\n")); + + return (synthesis_result) ? result : error_node(); + } + // (c0 / v0) * (c1 / v1) --> (covov) (c0 * c1) / (v0 * v1) + else if ((details::e_div == o0) && (details::e_mul == o1) && (details::e_div == o2)) + { + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen,"t/(t*t)",(c0 * c1),v0,v1,result); + + exprtk_debug(("(c0 / v0) * (c1 / v1) --> (covov) (c0 * c1) / (v0 * v1)\n")); + + return (synthesis_result) ? result : error_node(); + } + // (c0 / v0) / (c1 / v1) --> (covov) ((c0 / c1) * v1) / v0 + else if ((details::e_div == o0) && (details::e_div == o1) && (details::e_div == o2)) + { + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen,"(t*t)/t",(c0 / c1),v1,v0,result); + + exprtk_debug(("(c0 / v0) / (c1 / v1) --> (covov) ((c0 / c1) * v1) / v0\n")); + + return (synthesis_result) ? result : error_node(); + } + // (c0 * v0) / (c1 / v1) --> (covov) (c0 / c1) * (v0 * v1) + else if ((details::e_mul == o0) && (details::e_div == o1) && (details::e_div == o2)) + { + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen,"t*(t*t)",(c0 / c1),v0,v1,result); + + exprtk_debug(("(c0 * v0) / (c1 / v1) --> (covov) (c0 / c1) * (v0 * v1)\n")); + + return (synthesis_result) ? result : error_node(); + } + // (c0 / v0) / (c1 * v1) --> (covov) (c0 / c1) / (v0 * v1) + else if ((details::e_div == o0) && (details::e_div == o1) && (details::e_mul == o2)) + { + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen,"t/(t*t)",(c0 / c1),v0,v1,result); + + exprtk_debug(("(c0 / v0) / (c1 * v1) --> (covov) (c0 / c1) / (v0 * v1)\n")); + + return (synthesis_result) ? result : error_node(); + } + // (c * v0) +/- (c * v1) --> (covov) c * (v0 +/- v1) + else if ( + (std::equal_to()(c0,c1)) && + (details::e_mul == o0) && + (details::e_mul == o2) && + ( + (details::e_add == o1) || + (details::e_sub == o1) + ) + ) + { + std::string specfunc; + + switch (o1) + { + case details::e_add : specfunc = "t*(t+t)"; break; + case details::e_sub : specfunc = "t*(t-t)"; break; + default : return error_node(); + } + + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen,specfunc,c0,v0,v1,result); + + exprtk_debug(("(c * v0) +/- (c * v1) --> (covov) c * (v0 +/- v1)\n")); + + return (synthesis_result) ? result : error_node(); + } + } + + if (synthesize_sf4ext_expression::template compile(expr_gen,id(expr_gen,o0,o1,o2),c0,v0,c1,v1,result)) + return result; + else if (!expr_gen.valid_operator(o0,f0)) + return error_node(); + else if (!expr_gen.valid_operator(o1,f1)) + return error_node(); + else if (!expr_gen.valid_operator(o2,f2)) + return error_node(); + else + return node_type::allocate(*(expr_gen.node_allocator_),c0,v0,c1,v1,f0,f1,f2); + } + + static inline std::string id(expression_generator& expr_gen, + const details::operator_type o0, + const details::operator_type o1, + const details::operator_type o2) + { + return (details::build_string() << "(t" << expr_gen.to_str(o0) << "t)" << expr_gen.to_str(o1) << "(t" << expr_gen.to_str(o2) << "t)"); + } + }; + + struct synthesize_vocovoc_expression0 + { + typedef typename vocovoc_t::type0 node_type; + typedef typename vocovoc_t::sf4_type sf4_type; + typedef typename node_type::T0 T0; + typedef typename node_type::T1 T1; + typedef typename node_type::T2 T2; + typedef typename node_type::T3 T3; + + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + // (v0 o0 c0) o1 (v1 o2 c1) + const details::voc_base_node* voc0 = static_cast*>(branch[0]); + const details::voc_base_node* voc1 = static_cast*>(branch[1]); + const Type c0 = voc0->c(); + const Type& v0 = voc0->v(); + const Type c1 = voc1->c(); + const Type& v1 = voc1->v(); + const details::operator_type o0 = voc0->operation(); + const details::operator_type o1 = operation; + const details::operator_type o2 = voc1->operation(); + + binary_functor_t f0 = reinterpret_cast(0); + binary_functor_t f1 = reinterpret_cast(0); + binary_functor_t f2 = reinterpret_cast(0); + + details::free_node(*(expr_gen.node_allocator_),branch[0]); + details::free_node(*(expr_gen.node_allocator_),branch[1]); + + expression_node_ptr result = error_node(); + + if (expr_gen.parser_->settings_.strength_reduction_enabled()) + { + // (v0 + c0) + (v1 + c1) --> (covov) (c0 + c1) + v0 + v1 + if ((details::e_add == o0) && (details::e_add == o1) && (details::e_add == o2)) + { + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen,"(t+t)+t",(c0 + c1),v0,v1,result); + + exprtk_debug(("(v0 + c0) + (v1 + c1) --> (covov) (c0 + c1) + v0 + v1\n")); + + return (synthesis_result) ? result : error_node(); + } + // (v0 + c0) - (v1 + c1) --> (covov) (c0 - c1) + v0 - v1 + else if ((details::e_add == o0) && (details::e_sub == o1) && (details::e_add == o2)) + { + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen,"(t+t)-t",(c0 - c1),v0,v1,result); + + exprtk_debug(("(v0 + c0) - (v1 + c1) --> (covov) (c0 - c1) + v0 - v1\n")); + + return (synthesis_result) ? result : error_node(); + } + // (v0 - c0) - (v1 - c1) --> (covov) (c1 - c0) + v0 - v1 + else if ((details::e_sub == o0) && (details::e_sub == o1) && (details::e_sub == o2)) + { + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen,"(t+t)-t",(c1 - c0),v0,v1,result); + + exprtk_debug(("(v0 - c0) - (v1 - c1) --> (covov) (c1 - c0) + v0 - v1\n")); + + return (synthesis_result) ? result : error_node(); + } + // (v0 * c0) * (v1 * c1) --> (covov) (c0 * c1) * v0 * v1 + else if ((details::e_mul == o0) && (details::e_mul == o1) && (details::e_mul == o2)) + { + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen,"(t*t)*t",(c0 * c1),v0,v1,result); + + exprtk_debug(("(v0 * c0) * (v1 * c1) --> (covov) (c0 * c1) * v0 * v1\n")); + + return (synthesis_result) ? result : error_node(); + } + // (v0 * c0) / (v1 * c1) --> (covov) (c0 / c1) * (v0 / v1) + else if ((details::e_mul == o0) && (details::e_div == o1) && (details::e_mul == o2)) + { + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen,"(t*t)/t",(c0 / c1),v0,v1,result); + + exprtk_debug(("(v0 * c0) / (v1 * c1) --> (covov) (c0 / c1) * (v0 / v1)\n")); + + return (synthesis_result) ? result : error_node(); + } + // (v0 / c0) * (v1 / c1) --> (covov) (1 / (c0 * c1)) * v0 * v1 + else if ((details::e_div == o0) && (details::e_mul == o1) && (details::e_div == o2)) + { + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen,"(t*t)*t",Type(1) / (c0 * c1),v0,v1,result); + + exprtk_debug(("(v0 / c0) * (v1 / c1) --> (covov) (1 / (c0 * c1)) * v0 * v1\n")); + + return (synthesis_result) ? result : error_node(); + } + // (v0 / c0) / (v1 / c1) --> (covov) ((c1 / c0) * v0) / v1 + else if ((details::e_div == o0) && (details::e_div == o1) && (details::e_div == o2)) + { + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen,"(t*t)/t",(c1 / c0),v0,v1,result); + + exprtk_debug(("(v0 / c0) / (v1 / c1) --> (covov) ((c1 / c0) * v0) / v1\n")); + + return (synthesis_result) ? result : error_node(); + } + // (v0 * c0) / (v1 / c1) --> (covov) (c0 * c1) * (v0 / v1) + else if ((details::e_mul == o0) && (details::e_div == o1) && (details::e_div == o2)) + { + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen,"t*(t/t)",(c0 * c1),v0,v1,result); + + exprtk_debug(("(v0 * c0) / (v1 / c1) --> (covov) (c0 * c1) * (v0 / v1)\n")); + + return (synthesis_result) ? result : error_node(); + } + // (v0 / c0) / (v1 * c1) --> (covov) (1 / (c0 * c1)) * v0 / v1 + else if ((details::e_div == o0) && (details::e_div == o1) && (details::e_mul == o2)) + { + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen,"t*(t/t)",Type(1) / (c0 * c1),v0,v1,result); + + exprtk_debug(("(v0 / c0) / (v1 * c1) --> (covov) (1 / (c0 * c1)) * v0 / v1\n")); + + return (synthesis_result) ? result : error_node(); + } + // (v0 / c0) * (v1 + c1) --> (vocovoc) (v0 * (1 / c0)) * (v1 + c1) + else if ((details::e_div == o0) && (details::e_mul == o1) && (details::e_add == o2)) + { + const bool synthesis_result = + synthesize_sf4ext_expression:: + template compile(expr_gen,"(t*t)*(t+t)",v0,T(1) / c0,v1,c1,result); + + exprtk_debug(("(v0 / c0) * (v1 + c1) --> (vocovoc) (v0 * (1 / c0)) * (v1 + c1)\n")); + + return (synthesis_result) ? result : error_node(); + } + // (v0 / c0) * (v1 - c1) --> (vocovoc) (v0 * (1 / c0)) * (v1 - c1) + else if ((details::e_div == o0) && (details::e_mul == o1) && (details::e_sub == o2)) + { + const bool synthesis_result = + synthesize_sf4ext_expression:: + template compile(expr_gen,"(t*t)*(t-t)",v0,T(1) / c0,v1,c1,result); + + exprtk_debug(("(v0 / c0) * (v1 - c1) --> (vocovoc) (v0 * (1 / c0)) * (v1 - c1)\n")); + + return (synthesis_result) ? result : error_node(); + } + // (v0 * c) +/- (v1 * c) --> (covov) c * (v0 +/- v1) + else if ( + (std::equal_to()(c0,c1)) && + (details::e_mul == o0) && + (details::e_mul == o2) && + ( + (details::e_add == o1) || + (details::e_sub == o1) + ) + ) + { + std::string specfunc; + + switch (o1) + { + case details::e_add : specfunc = "t*(t+t)"; break; + case details::e_sub : specfunc = "t*(t-t)"; break; + default : return error_node(); + } + + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen,specfunc,c0,v0,v1,result); + + exprtk_debug(("(v0 * c) +/- (v1 * c) --> (covov) c * (v0 +/- v1)\n")); + + return (synthesis_result) ? result : error_node(); + } + // (v0 / c) +/- (v1 / c) --> (vovoc) (v0 +/- v1) / c + else if ( + (std::equal_to()(c0,c1)) && + (details::e_div == o0) && + (details::e_div == o2) && + ( + (details::e_add == o1) || + (details::e_sub == o1) + ) + ) + { + std::string specfunc; + + switch (o1) + { + case details::e_add : specfunc = "(t+t)/t"; break; + case details::e_sub : specfunc = "(t-t)/t"; break; + default : return error_node(); + } + + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen,specfunc,v0,v1,c0,result); + + exprtk_debug(("(v0 / c) +/- (v1 / c) --> (vovoc) (v0 +/- v1) / c\n")); + + return (synthesis_result) ? result : error_node(); + } + } + + if (synthesize_sf4ext_expression::template compile(expr_gen,id(expr_gen,o0,o1,o2),v0,c0,v1,c1,result)) + return result; + else if (!expr_gen.valid_operator(o0,f0)) + return error_node(); + else if (!expr_gen.valid_operator(o1,f1)) + return error_node(); + else if (!expr_gen.valid_operator(o2,f2)) + return error_node(); + else + return node_type::allocate(*(expr_gen.node_allocator_),v0,c0,v1,c1,f0,f1,f2); + } + + static inline std::string id(expression_generator& expr_gen, + const details::operator_type o0, + const details::operator_type o1, + const details::operator_type o2) + { + return (details::build_string() << "(t" << expr_gen.to_str(o0) << "t)" << expr_gen.to_str(o1) << "(t" << expr_gen.to_str(o2) << "t)"); + } + }; + + struct synthesize_covovoc_expression0 + { + typedef typename covovoc_t::type0 node_type; + typedef typename covovoc_t::sf4_type sf4_type; + typedef typename node_type::T0 T0; + typedef typename node_type::T1 T1; + typedef typename node_type::T2 T2; + typedef typename node_type::T3 T3; + + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + // (c0 o0 v0) o1 (v1 o2 c1) + const details::cov_base_node* cov = static_cast*>(branch[0]); + const details::voc_base_node* voc = static_cast*>(branch[1]); + const Type c0 = cov->c(); + const Type& v0 = cov->v(); + const Type c1 = voc->c(); + const Type& v1 = voc->v(); + const details::operator_type o0 = cov->operation(); + const details::operator_type o1 = operation; + const details::operator_type o2 = voc->operation(); + + binary_functor_t f0 = reinterpret_cast(0); + binary_functor_t f1 = reinterpret_cast(0); + binary_functor_t f2 = reinterpret_cast(0); + + details::free_node(*(expr_gen.node_allocator_),branch[0]); + details::free_node(*(expr_gen.node_allocator_),branch[1]); + + expression_node_ptr result = error_node(); + + if (expr_gen.parser_->settings_.strength_reduction_enabled()) + { + // (c0 + v0) + (v1 + c1) --> (covov) (c0 + c1) + v0 + v1 + if ((details::e_add == o0) && (details::e_add == o1) && (details::e_add == o2)) + { + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen,"(t+t)+t",(c0 + c1),v0,v1,result); + + exprtk_debug(("(c0 + v0) + (v1 + c1) --> (covov) (c0 + c1) + v0 + v1\n")); + + return (synthesis_result) ? result : error_node(); + } + // (c0 + v0) - (v1 + c1) --> (covov) (c0 - c1) + v0 - v1 + else if ((details::e_add == o0) && (details::e_sub == o1) && (details::e_add == o2)) + { + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen,"(t+t)-t",(c0 - c1),v0,v1,result); + + exprtk_debug(("(c0 + v0) - (v1 + c1) --> (covov) (c0 - c1) + v0 - v1\n")); + + return (synthesis_result) ? result : error_node(); + } + // (c0 - v0) - (v1 - c1) --> (covov) (c0 + c1) - v0 - v1 + else if ((details::e_sub == o0) && (details::e_sub == o1) && (details::e_sub == o2)) + { + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen,"t-(t+t)",(c0 + c1),v0,v1,result); + + exprtk_debug(("(c0 - v0) - (v1 - c1) --> (covov) (c0 + c1) - v0 - v1\n")); + + return (synthesis_result) ? result : error_node(); + } + // (c0 * v0) * (v1 * c1) --> (covov) (c0 * c1) * v0 * v1 + else if ((details::e_mul == o0) && (details::e_mul == o1) && (details::e_mul == o2)) + { + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen,"(t*t)*t",(c0 * c1),v0,v1,result); + + exprtk_debug(("(c0 * v0) * (v1 * c1) --> (covov) (c0 * c1) * v0 * v1\n")); + + return (synthesis_result) ? result : error_node(); + } + // (c0 * v0) / (v1 * c1) --> (covov) (c0 / c1) * (v0 / v1) + else if ((details::e_mul == o0) && (details::e_div == o1) && (details::e_mul == o2)) + { + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen,"(t*t)/t",(c0 / c1),v0,v1,result); + + exprtk_debug(("(c0 * v0) / (v1 * c1) --> (covov) (c0 / c1) * (v0 / v1)\n")); + + return (synthesis_result) ? result : error_node(); + } + // (c0 / v0) * (v1 / c1) --> (covov) (c0 / c1) * (v1 / v0) + else if ((details::e_div == o0) && (details::e_mul == o1) && (details::e_div == o2)) + { + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen,"t*(t/t)",(c0 / c1),v1,v0,result); + + exprtk_debug(("(c0 / v0) * (v1 / c1) --> (covov) (c0 / c1) * (v1 / v0)\n")); + + return (synthesis_result) ? result : error_node(); + } + // (c0 / v0) / (v1 / c1) --> (covov) (c0 * c1) / (v0 * v1) + else if ((details::e_div == o0) && (details::e_div == o1) && (details::e_div == o2)) + { + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen,"t/(t*t)",(c0 * c1),v0,v1,result); + + exprtk_debug(("(c0 / v0) / (v1 / c1) --> (covov) (c0 * c1) / (v0 * v1)\n")); + + return (synthesis_result) ? result : error_node(); + } + // (c0 * v0) / (v1 / c1) --> (covov) (c0 * c1) * (v0 / v1) + else if ((details::e_mul == o0) && (details::e_div == o1) && (details::e_div == o2)) + { + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen,"(t*t)/t",(c0 * c1),v0,v1,result); + + exprtk_debug(("(c0 * v0) / (v1 / c1) --> (covov) (c0 * c1) * (v0 / v1)\n")); + + return (synthesis_result) ? result : error_node(); + } + // (c0 / v0) / (v1 * c1) --> (covov) (c0 / c1) / (v0 * v1) + else if ((details::e_div == o0) && (details::e_div == o1) && (details::e_mul == o2)) + { + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen,"t/(t*t)",(c0 / c1),v0,v1,result); + + exprtk_debug(("(c0 / v0) / (v1 * c1) --> (covov) (c0 / c1) / (v0 * v1)\n")); + + return (synthesis_result) ? result : error_node(); + } + // (c * v0) +/- (v1 * c) --> (covov) c * (v0 +/- v1) + else if ( + (std::equal_to()(c0,c1)) && + (details::e_mul == o0) && + (details::e_mul == o2) && + ( + (details::e_add == o1) || + (details::e_sub == o1) + ) + ) + { + std::string specfunc; + + switch (o1) + { + case details::e_add : specfunc = "t*(t+t)"; break; + case details::e_sub : specfunc = "t*(t-t)"; break; + default : return error_node(); + } + + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen,specfunc,c0,v0,v1,result); + + exprtk_debug(("(c * v0) +/- (v1 * c) --> (covov) c * (v0 +/- v1)\n")); + + return (synthesis_result) ? result : error_node(); + } + } + + if (synthesize_sf4ext_expression::template compile(expr_gen,id(expr_gen,o0,o1,o2),c0,v0,v1,c1,result)) + return result; + else if (!expr_gen.valid_operator(o0,f0)) + return error_node(); + else if (!expr_gen.valid_operator(o1,f1)) + return error_node(); + else if (!expr_gen.valid_operator(o2,f2)) + return error_node(); + else + return node_type::allocate(*(expr_gen.node_allocator_),c0,v0,v1,c1,f0,f1,f2); + } + + static inline std::string id(expression_generator& expr_gen, + const details::operator_type o0, + const details::operator_type o1, + const details::operator_type o2) + { + return (details::build_string() << "(t" << expr_gen.to_str(o0) << "t)" << expr_gen.to_str(o1) << "(t" << expr_gen.to_str(o2) << "t)"); + } + }; + + struct synthesize_vococov_expression0 + { + typedef typename vococov_t::type0 node_type; + typedef typename vococov_t::sf4_type sf4_type; + typedef typename node_type::T0 T0; + typedef typename node_type::T1 T1; + typedef typename node_type::T2 T2; + typedef typename node_type::T3 T3; + + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + // (v0 o0 c0) o1 (c1 o2 v1) + const details::voc_base_node* voc = static_cast*>(branch[0]); + const details::cov_base_node* cov = static_cast*>(branch[1]); + const Type c0 = voc->c(); + const Type& v0 = voc->v(); + const Type c1 = cov->c(); + const Type& v1 = cov->v(); + const details::operator_type o0 = voc->operation(); + const details::operator_type o1 = operation; + const details::operator_type o2 = cov->operation(); + + binary_functor_t f0 = reinterpret_cast(0); + binary_functor_t f1 = reinterpret_cast(0); + binary_functor_t f2 = reinterpret_cast(0); + + details::free_node(*(expr_gen.node_allocator_),branch[0]); + details::free_node(*(expr_gen.node_allocator_),branch[1]); + + expression_node_ptr result = error_node(); + + if (expr_gen.parser_->settings_.strength_reduction_enabled()) + { + // (v0 + c0) + (c1 + v1) --> (covov) (c0 + c1) + v0 + v1 + if ((details::e_add == o0) && (details::e_add == o1) && (details::e_add == o2)) + { + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen,"(t+t)+t",(c0 + c1),v0,v1,result); + + exprtk_debug(("(v0 + c0) + (c1 + v1) --> (covov) (c0 + c1) + v0 + v1\n")); + + return (synthesis_result) ? result : error_node(); + } + // (v0 + c0) - (c1 + v1) --> (covov) (c0 - c1) + v0 - v1 + else if ((details::e_add == o0) && (details::e_sub == o1) && (details::e_add == o2)) + { + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen,"(t+t)-t",(c0 - c1),v0,v1,result); + + exprtk_debug(("(v0 + c0) - (c1 + v1) --> (covov) (c0 - c1) + v0 - v1\n")); + + return (synthesis_result) ? result : error_node(); + } + // (v0 - c0) - (c1 - v1) --> (vovoc) v0 + v1 - (c1 + c0) + else if ((details::e_sub == o0) && (details::e_sub == o1) && (details::e_sub == o2)) + { + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen,"(t+t)-t",v0,v1,(c1 + c0),result); + + exprtk_debug(("(v0 - c0) - (c1 - v1) --> (vovoc) v0 + v1 - (c1 + c0)\n")); + + return (synthesis_result) ? result : error_node(); + } + // (v0 * c0) * (c1 * v1) --> (covov) (c0 * c1) * v0 * v1 + else if ((details::e_mul == o0) && (details::e_mul == o1) && (details::e_mul == o2)) + { + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen,"(t*t)*t",(c0 * c1),v0,v1,result); + + exprtk_debug(("(v0 * c0) * (c1 * v1) --> (covov) (c0 * c1) * v0 * v1\n")); + + return (synthesis_result) ? result : error_node(); + } + // (v0 * c0) / (c1 * v1) --> (covov) (c0 / c1) * (v0 * v1) + else if ((details::e_mul == o0) && (details::e_div == o1) && (details::e_mul == o2)) + { + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen,"(t*t)/t",(c0 / c1),v0,v1,result); + + exprtk_debug(("(v0 * c0) / (c1 * v1) --> (covov) (c0 / c1) * (v0 * v1)\n")); + + return (synthesis_result) ? result : error_node(); + } + // (v0 / c0) * (c1 / v1) --> (covov) (c1 / c0) * (v0 / v1) + else if ((details::e_div == o0) && (details::e_mul == o1) && (details::e_div == o2)) + { + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen,"(t*t)/t",(c1 / c0),v0,v1,result); + + exprtk_debug(("(v0 / c0) * (c1 / v1) --> (covov) (c1 / c0) * (v0 / v1)\n")); + + return (synthesis_result) ? result : error_node(); + } + // (v0 * c0) / (c1 / v1) --> (covov) (c0 / c1) * (v0 * v1) + else if ((details::e_mul == o0) && (details::e_div == o1) && (details::e_div == o2)) + { + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen,"(t*t)*t",(c0 / c1),v0,v1,result); + + exprtk_debug(("(v0 * c0) / (c1 / v1) --> (covov) (c0 / c1) * (v0 * v1)\n")); + + return (synthesis_result) ? result : error_node(); + } + // (v0 / c0) / (c1 * v1) --> (covov) (1 / (c0 * c1)) * (v0 / v1) + else if ((details::e_div == o0) && (details::e_div == o1) && (details::e_mul == o2)) + { + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen,"(t*t)/t",Type(1) / (c0 * c1),v0,v1,result); + + exprtk_debug(("(v0 / c0) / (c1 * v1) --> (covov) (1 / (c0 * c1)) * (v0 / v1)\n")); + + return (synthesis_result) ? result : error_node(); + } + // (v0 / c0) / (c1 / v1) --> (vovoc) (v0 * v1) * (1 / (c0 * c1)) + else if ((details::e_div == o0) && (details::e_div == o1) && (details::e_div == o2)) + { + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen,"(t*t)*t",v0,v1,Type(1) / (c0 * c1),result); + + exprtk_debug(("(v0 / c0) / (c1 / v1) --> (vovoc) (v0 * v1) * (1 / (c0 * c1))\n")); + + return (synthesis_result) ? result : error_node(); + } + // (v0 * c) +/- (c * v1) --> (covov) c * (v0 +/- v1) + else if ( + (std::equal_to()(c0,c1)) && + (details::e_mul == o0) && + (details::e_mul == o2) && + ( + (details::e_add == o1) || (details::e_sub == o1) + ) + ) + { + std::string specfunc; + + switch (o1) + { + case details::e_add : specfunc = "t*(t+t)"; break; + case details::e_sub : specfunc = "t*(t-t)"; break; + default : return error_node(); + } + + const bool synthesis_result = + synthesize_sf3ext_expression:: + template compile(expr_gen,specfunc,c0,v0,v1,result); + + exprtk_debug(("(v0 * c) +/- (c * v1) --> (covov) c * (v0 +/- v1)\n")); + + return (synthesis_result) ? result : error_node(); + } + } + + if (synthesize_sf4ext_expression::template compile(expr_gen,id(expr_gen,o0,o1,o2),v0,c0,c1,v1,result)) + return result; + else if (!expr_gen.valid_operator(o0,f0)) + return error_node(); + else if (!expr_gen.valid_operator(o1,f1)) + return error_node(); + else if (!expr_gen.valid_operator(o2,f2)) + return error_node(); + else + return node_type::allocate(*(expr_gen.node_allocator_),v0,c0,c1,v1,f0,f1,f2); + } + + static inline std::string id(expression_generator& expr_gen, + const details::operator_type o0, + const details::operator_type o1, + const details::operator_type o2) + { + return (details::build_string() << "(t" << expr_gen.to_str(o0) << "t)" << expr_gen.to_str(o1) << "(t" << expr_gen.to_str(o2) << "t)"); + } + }; + + struct synthesize_vovovov_expression1 + { + typedef typename vovovov_t::type1 node_type; + typedef typename vovovov_t::sf4_type sf4_type; + typedef typename node_type::T0 T0; + typedef typename node_type::T1 T1; + typedef typename node_type::T2 T2; + typedef typename node_type::T3 T3; + + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + // v0 o0 (v1 o1 (v2 o2 v3)) + typedef typename synthesize_vovov_expression1::node_type lcl_vovov_t; + + const lcl_vovov_t* vovov = static_cast(branch[1]); + const Type& v0 = static_cast*>(branch[0])->ref(); + const Type& v1 = vovov->t0(); + const Type& v2 = vovov->t1(); + const Type& v3 = vovov->t2(); + const details::operator_type o0 = operation; + const details::operator_type o1 = expr_gen.get_operator(vovov->f0()); + const details::operator_type o2 = expr_gen.get_operator(vovov->f1()); + + binary_functor_t f0 = reinterpret_cast(0); + binary_functor_t f1 = vovov->f0(); + binary_functor_t f2 = vovov->f1(); + + details::free_node(*(expr_gen.node_allocator_),branch[1]); + + expression_node_ptr result = error_node(); + + if (synthesize_sf4ext_expression::template compile(expr_gen,id(expr_gen,o0,o1,o2),v0,v1,v2,v3,result)) + return result; + else if (!expr_gen.valid_operator(o0,f0)) + return error_node(); + + exprtk_debug(("v0 o0 (v1 o1 (v2 o2 v3))\n")); + + return node_type::allocate(*(expr_gen.node_allocator_),v0,v1,v2,v3,f0,f1,f2); + } + + static inline std::string id(expression_generator& expr_gen, + const details::operator_type o0, + const details::operator_type o1, + const details::operator_type o2) + { + return (details::build_string() << "t" << expr_gen.to_str(o0) << "(t" << expr_gen.to_str(o1) << "(t" << expr_gen.to_str(o2) << "t))"); + } + }; + + struct synthesize_vovovoc_expression1 + { + typedef typename vovovoc_t::type1 node_type; + typedef typename vovovoc_t::sf4_type sf4_type; + typedef typename node_type::T0 T0; + typedef typename node_type::T1 T1; + typedef typename node_type::T2 T2; + typedef typename node_type::T3 T3; + + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + // v0 o0 (v1 o1 (v2 o2 c)) + typedef typename synthesize_vovoc_expression1::node_type lcl_vovoc_t; + + const lcl_vovoc_t* vovoc = static_cast(branch[1]); + const Type& v0 = static_cast*>(branch[0])->ref(); + const Type& v1 = vovoc->t0(); + const Type& v2 = vovoc->t1(); + const Type c = vovoc->t2(); + const details::operator_type o0 = operation; + const details::operator_type o1 = expr_gen.get_operator(vovoc->f0()); + const details::operator_type o2 = expr_gen.get_operator(vovoc->f1()); + + binary_functor_t f0 = reinterpret_cast(0); + binary_functor_t f1 = vovoc->f0(); + binary_functor_t f2 = vovoc->f1(); + + details::free_node(*(expr_gen.node_allocator_),branch[1]); + + expression_node_ptr result = error_node(); + + if (synthesize_sf4ext_expression::template compile(expr_gen,id(expr_gen,o0,o1,o2),v0,v1,v2,c,result)) + return result; + else if (!expr_gen.valid_operator(o0,f0)) + return error_node(); + + exprtk_debug(("v0 o0 (v1 o1 (v2 o2 c))\n")); + + return node_type::allocate(*(expr_gen.node_allocator_),v0,v1,v2,c,f0,f1,f2); + } + + static inline std::string id(expression_generator& expr_gen, + const details::operator_type o0, + const details::operator_type o1, + const details::operator_type o2) + { + return (details::build_string() << "t" << expr_gen.to_str(o0) << "(t" << expr_gen.to_str(o1) << "(t" << expr_gen.to_str(o2) << "t))"); + } + }; + + struct synthesize_vovocov_expression1 + { + typedef typename vovocov_t::type1 node_type; + typedef typename vovocov_t::sf4_type sf4_type; + typedef typename node_type::T0 T0; + typedef typename node_type::T1 T1; + typedef typename node_type::T2 T2; + typedef typename node_type::T3 T3; + + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + // v0 o0 (v1 o1 (c o2 v2)) + typedef typename synthesize_vocov_expression1::node_type lcl_vocov_t; + + const lcl_vocov_t* vocov = static_cast(branch[1]); + const Type& v0 = static_cast*>(branch[0])->ref(); + const Type& v1 = vocov->t0(); + const Type c = vocov->t1(); + const Type& v2 = vocov->t2(); + const details::operator_type o0 = operation; + const details::operator_type o1 = expr_gen.get_operator(vocov->f0()); + const details::operator_type o2 = expr_gen.get_operator(vocov->f1()); + + binary_functor_t f0 = reinterpret_cast(0); + binary_functor_t f1 = vocov->f0(); + binary_functor_t f2 = vocov->f1(); + + details::free_node(*(expr_gen.node_allocator_),branch[1]); + + expression_node_ptr result = error_node(); + + if (synthesize_sf4ext_expression::template compile(expr_gen,id(expr_gen,o0,o1,o2),v0,v1,c,v2,result)) + return result; + if (!expr_gen.valid_operator(o0,f0)) + return error_node(); + + exprtk_debug(("v0 o0 (v1 o1 (c o2 v2))\n")); + + return node_type::allocate(*(expr_gen.node_allocator_),v0,v1,c,v2,f0,f1,f2); + } + + static inline std::string id(expression_generator& expr_gen, + const details::operator_type o0, + const details::operator_type o1, + const details::operator_type o2) + { + return (details::build_string() << "t" << expr_gen.to_str(o0) << "(t" << expr_gen.to_str(o1) << "(t" << expr_gen.to_str(o2) << "t))"); + } + }; + + struct synthesize_vocovov_expression1 + { + typedef typename vocovov_t::type1 node_type; + typedef typename vocovov_t::sf4_type sf4_type; + typedef typename node_type::T0 T0; + typedef typename node_type::T1 T1; + typedef typename node_type::T2 T2; + typedef typename node_type::T3 T3; + + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + // v0 o0 (c o1 (v1 o2 v2)) + typedef typename synthesize_covov_expression1::node_type lcl_covov_t; + + const lcl_covov_t* covov = static_cast(branch[1]); + const Type& v0 = static_cast*>(branch[0])->ref(); + const Type c = covov->t0(); + const Type& v1 = covov->t1(); + const Type& v2 = covov->t2(); + const details::operator_type o0 = operation; + const details::operator_type o1 = expr_gen.get_operator(covov->f0()); + const details::operator_type o2 = expr_gen.get_operator(covov->f1()); + + binary_functor_t f0 = reinterpret_cast(0); + binary_functor_t f1 = covov->f0(); + binary_functor_t f2 = covov->f1(); + + details::free_node(*(expr_gen.node_allocator_),branch[1]); + + expression_node_ptr result = error_node(); + + if (synthesize_sf4ext_expression::template compile(expr_gen,id(expr_gen,o0,o1,o2),v0,c,v1,v2,result)) + return result; + else if (!expr_gen.valid_operator(o0,f0)) + return error_node(); + + exprtk_debug(("v0 o0 (c o1 (v1 o2 v2))\n")); + + return node_type::allocate(*(expr_gen.node_allocator_),v0,c,v1,v2,f0,f1,f2); + } + + static inline std::string id(expression_generator& expr_gen, + const details::operator_type o0, + const details::operator_type o1, + const details::operator_type o2) + { + return (details::build_string() << "t" << expr_gen.to_str(o0) << "(t" << expr_gen.to_str(o1) << "(t" << expr_gen.to_str(o2) << "t))"); + } + }; + + struct synthesize_covovov_expression1 + { + typedef typename covovov_t::type1 node_type; + typedef typename covovov_t::sf4_type sf4_type; + typedef typename node_type::T0 T0; + typedef typename node_type::T1 T1; + typedef typename node_type::T2 T2; + typedef typename node_type::T3 T3; + + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + // c o0 (v0 o1 (v1 o2 v2)) + typedef typename synthesize_vovov_expression1::node_type lcl_vovov_t; + + const lcl_vovov_t* vovov = static_cast(branch[1]); + const Type c = static_cast*>(branch[0])->value(); + const Type& v0 = vovov->t0(); + const Type& v1 = vovov->t1(); + const Type& v2 = vovov->t2(); + const details::operator_type o0 = operation; + const details::operator_type o1 = expr_gen.get_operator(vovov->f0()); + const details::operator_type o2 = expr_gen.get_operator(vovov->f1()); + + binary_functor_t f0 = reinterpret_cast(0); + binary_functor_t f1 = vovov->f0(); + binary_functor_t f2 = vovov->f1(); + + details::free_node(*(expr_gen.node_allocator_),branch[0]); + details::free_node(*(expr_gen.node_allocator_),branch[1]); + + expression_node_ptr result = error_node(); + + if (synthesize_sf4ext_expression::template compile(expr_gen,id(expr_gen,o0,o1,o2),c,v0,v1,v2,result)) + return result; + if (!expr_gen.valid_operator(o0,f0)) + return error_node(); + + exprtk_debug(("c o0 (v0 o1 (v1 o2 v2))\n")); + + return node_type::allocate(*(expr_gen.node_allocator_),c,v0,v1,v2,f0,f1,f2); + } + + static inline std::string id(expression_generator& expr_gen, + const details::operator_type o0, + const details::operator_type o1, + const details::operator_type o2) + { + return (details::build_string() << "t" << expr_gen.to_str(o0) << "(t" << expr_gen.to_str(o1) << "(t" << expr_gen.to_str(o2) << "t))"); + } + }; + + struct synthesize_covocov_expression1 + { + typedef typename covocov_t::type1 node_type; + typedef typename covocov_t::sf4_type sf4_type; + typedef typename node_type::T0 T0; + typedef typename node_type::T1 T1; + typedef typename node_type::T2 T2; + typedef typename node_type::T3 T3; + + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + // c0 o0 (v0 o1 (c1 o2 v1)) + typedef typename synthesize_vocov_expression1::node_type lcl_vocov_t; + + const lcl_vocov_t* vocov = static_cast(branch[1]); + const Type c0 = static_cast*>(branch[0])->value(); + const Type& v0 = vocov->t0(); + const Type c1 = vocov->t1(); + const Type& v1 = vocov->t2(); + const details::operator_type o0 = operation; + const details::operator_type o1 = expr_gen.get_operator(vocov->f0()); + const details::operator_type o2 = expr_gen.get_operator(vocov->f1()); + + binary_functor_t f0 = reinterpret_cast(0); + binary_functor_t f1 = vocov->f0(); + binary_functor_t f2 = vocov->f1(); + + details::free_node(*(expr_gen.node_allocator_),branch[0]); + details::free_node(*(expr_gen.node_allocator_),branch[1]); + + expression_node_ptr result = error_node(); + + if (synthesize_sf4ext_expression::template compile(expr_gen,id(expr_gen,o0,o1,o2),c0,v0,c1,v1,result)) + return result; + else if (!expr_gen.valid_operator(o0,f0)) + return error_node(); + + exprtk_debug(("c0 o0 (v0 o1 (c1 o2 v1))\n")); + + return node_type::allocate(*(expr_gen.node_allocator_),c0,v0,c1,v1,f0,f1,f2); + } + + static inline std::string id(expression_generator& expr_gen, + const details::operator_type o0, + const details::operator_type o1, + const details::operator_type o2) + { + return (details::build_string() << "t" << expr_gen.to_str(o0) << "(t" << expr_gen.to_str(o1) << "(t" << expr_gen.to_str(o2) << "t))"); + } + }; + + struct synthesize_vocovoc_expression1 + { + typedef typename vocovoc_t::type1 node_type; + typedef typename vocovoc_t::sf4_type sf4_type; + typedef typename node_type::T0 T0; + typedef typename node_type::T1 T1; + typedef typename node_type::T2 T2; + typedef typename node_type::T3 T3; + + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + // v0 o0 (c0 o1 (v1 o2 c2)) + typedef typename synthesize_covoc_expression1::node_type lcl_covoc_t; + + const lcl_covoc_t* covoc = static_cast(branch[1]); + const Type& v0 = static_cast*>(branch[0])->ref(); + const Type c0 = covoc->t0(); + const Type& v1 = covoc->t1(); + const Type c1 = covoc->t2(); + const details::operator_type o0 = operation; + const details::operator_type o1 = expr_gen.get_operator(covoc->f0()); + const details::operator_type o2 = expr_gen.get_operator(covoc->f1()); + + binary_functor_t f0 = reinterpret_cast(0); + binary_functor_t f1 = covoc->f0(); + binary_functor_t f2 = covoc->f1(); + + details::free_node(*(expr_gen.node_allocator_),branch[1]); + + expression_node_ptr result = error_node(); + + if (synthesize_sf4ext_expression::template compile(expr_gen,id(expr_gen,o0,o1,o2),v0,c0,v1,c1,result)) + return result; + else if (!expr_gen.valid_operator(o0,f0)) + return error_node(); + + exprtk_debug(("v0 o0 (c0 o1 (v1 o2 c2))\n")); + + return node_type::allocate(*(expr_gen.node_allocator_),v0,c0,v1,c1,f0,f1,f2); + } + + static inline std::string id(expression_generator& expr_gen, + const details::operator_type o0, + const details::operator_type o1, + const details::operator_type o2) + { + return (details::build_string() << "t" << expr_gen.to_str(o0) << "(t" << expr_gen.to_str(o1) << "(t" << expr_gen.to_str(o2) << "t))"); + } + }; + + struct synthesize_covovoc_expression1 + { + typedef typename covovoc_t::type1 node_type; + typedef typename covovoc_t::sf4_type sf4_type; + typedef typename node_type::T0 T0; + typedef typename node_type::T1 T1; + typedef typename node_type::T2 T2; + typedef typename node_type::T3 T3; + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + // c0 o0 (v0 o1 (v1 o2 c1)) + typedef typename synthesize_vovoc_expression1::node_type lcl_vovoc_t; + + const lcl_vovoc_t* vovoc = static_cast(branch[1]); + const Type c0 = static_cast*>(branch[0])->value(); + const Type& v0 = vovoc->t0(); + const Type& v1 = vovoc->t1(); + const Type c1 = vovoc->t2(); + const details::operator_type o0 = operation; + const details::operator_type o1 = expr_gen.get_operator(vovoc->f0()); + const details::operator_type o2 = expr_gen.get_operator(vovoc->f1()); + + binary_functor_t f0 = reinterpret_cast(0); + binary_functor_t f1 = vovoc->f0(); + binary_functor_t f2 = vovoc->f1(); + + details::free_node(*(expr_gen.node_allocator_),branch[0]); + details::free_node(*(expr_gen.node_allocator_),branch[1]); + + expression_node_ptr result = error_node(); + + if (synthesize_sf4ext_expression::template compile(expr_gen,id(expr_gen,o0,o1,o2),c0,v0,v1,c1,result)) + return result; + else if (!expr_gen.valid_operator(o0,f0)) + return error_node(); + + exprtk_debug(("c0 o0 (v0 o1 (v1 o2 c1))\n")); + + return node_type::allocate(*(expr_gen.node_allocator_),c0,v0,v1,c1,f0,f1,f2); + } + + static inline std::string id(expression_generator& expr_gen, + const details::operator_type o0, + const details::operator_type o1, + const details::operator_type o2) + { + return (details::build_string() << "t" << expr_gen.to_str(o0) << "(t" << expr_gen.to_str(o1) << "(t" << expr_gen.to_str(o2) << "t))"); + } + }; + + struct synthesize_vococov_expression1 + { + typedef typename vococov_t::type1 node_type; + typedef typename vococov_t::sf4_type sf4_type; + typedef typename node_type::T0 T0; + typedef typename node_type::T1 T1; + typedef typename node_type::T2 T2; + typedef typename node_type::T3 T3; + + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + // v0 o0 (c0 o1 (c1 o2 v1)) + typedef typename synthesize_cocov_expression1::node_type lcl_cocov_t; + + const lcl_cocov_t* cocov = static_cast(branch[1]); + const Type& v0 = static_cast*>(branch[0])->ref(); + const Type c0 = cocov->t0(); + const Type c1 = cocov->t1(); + const Type& v1 = cocov->t2(); + const details::operator_type o0 = operation; + const details::operator_type o1 = expr_gen.get_operator(cocov->f0()); + const details::operator_type o2 = expr_gen.get_operator(cocov->f1()); + + binary_functor_t f0 = reinterpret_cast(0); + binary_functor_t f1 = cocov->f0(); + binary_functor_t f2 = cocov->f1(); + + details::free_node(*(expr_gen.node_allocator_),branch[1]); + + expression_node_ptr result = error_node(); + + if (synthesize_sf4ext_expression::template compile(expr_gen,id(expr_gen,o0,o1,o2),v0,c0,c1,v1,result)) + return result; + else if (!expr_gen.valid_operator(o0,f0)) + return error_node(); + + exprtk_debug(("v0 o0 (c0 o1 (c1 o2 v1))\n")); + + return node_type::allocate(*(expr_gen.node_allocator_),v0,c0,c1,v1,f0,f1,f2); + } + + static inline std::string id(expression_generator& expr_gen, + const details::operator_type o0, + const details::operator_type o1, + const details::operator_type o2) + { + return (details::build_string() << "t" << expr_gen.to_str(o0) << "(t" << expr_gen.to_str(o1) << "(t" << expr_gen.to_str(o2) << "t))"); + } + }; + + struct synthesize_vovovov_expression2 + { + typedef typename vovovov_t::type2 node_type; + typedef typename vovovov_t::sf4_type sf4_type; + typedef typename node_type::T0 T0; + typedef typename node_type::T1 T1; + typedef typename node_type::T2 T2; + typedef typename node_type::T3 T3; + + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + // v0 o0 ((v1 o1 v2) o2 v3) + typedef typename synthesize_vovov_expression0::node_type lcl_vovov_t; + + const lcl_vovov_t* vovov = static_cast(branch[1]); + const Type& v0 = static_cast*>(branch[0])->ref(); + const Type& v1 = vovov->t0(); + const Type& v2 = vovov->t1(); + const Type& v3 = vovov->t2(); + const details::operator_type o0 = operation; + const details::operator_type o1 = expr_gen.get_operator(vovov->f0()); + const details::operator_type o2 = expr_gen.get_operator(vovov->f1()); + + binary_functor_t f0 = reinterpret_cast(0); + binary_functor_t f1 = vovov->f0(); + binary_functor_t f2 = vovov->f1(); + + details::free_node(*(expr_gen.node_allocator_),branch[1]); + + expression_node_ptr result = error_node(); + + if (synthesize_sf4ext_expression::template compile(expr_gen,id(expr_gen,o0,o1,o2),v0,v1,v2,v3,result)) + return result; + else if (!expr_gen.valid_operator(o0,f0)) + return error_node(); + + exprtk_debug(("v0 o0 ((v1 o1 v2) o2 v3)\n")); + + return node_type::allocate(*(expr_gen.node_allocator_),v0,v1,v2,v3,f0,f1,f2); + } + + static inline std::string id(expression_generator& expr_gen, + const details::operator_type o0, + const details::operator_type o1, + const details::operator_type o2) + { + return (details::build_string() << "t" << expr_gen.to_str(o0) << "((t" << expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t)"); + } + }; + + struct synthesize_vovovoc_expression2 + { + typedef typename vovovoc_t::type2 node_type; + typedef typename vovovoc_t::sf4_type sf4_type; + typedef typename node_type::T0 T0; + typedef typename node_type::T1 T1; + typedef typename node_type::T2 T2; + typedef typename node_type::T3 T3; + + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + // v0 o0 ((v1 o1 v2) o2 c) + typedef typename synthesize_vovoc_expression0::node_type lcl_vovoc_t; + + const lcl_vovoc_t* vovoc = static_cast(branch[1]); + const Type& v0 = static_cast*>(branch[0])->ref(); + const Type& v1 = vovoc->t0(); + const Type& v2 = vovoc->t1(); + const Type c = vovoc->t2(); + const details::operator_type o0 = operation; + const details::operator_type o1 = expr_gen.get_operator(vovoc->f0()); + const details::operator_type o2 = expr_gen.get_operator(vovoc->f1()); + + binary_functor_t f0 = reinterpret_cast(0); + binary_functor_t f1 = vovoc->f0(); + binary_functor_t f2 = vovoc->f1(); + + details::free_node(*(expr_gen.node_allocator_),branch[1]); + + expression_node_ptr result = error_node(); + + if (synthesize_sf4ext_expression::template compile(expr_gen,id(expr_gen,o0,o1,o2),v0,v1,v2,c,result)) + return result; + else if (!expr_gen.valid_operator(o0,f0)) + return error_node(); + + exprtk_debug(("v0 o0 ((v1 o1 v2) o2 c)\n")); + + return node_type::allocate(*(expr_gen.node_allocator_),v0,v1,v2,c,f0,f1,f2); + } + + static inline std::string id(expression_generator& expr_gen, + const details::operator_type o0, + const details::operator_type o1, + const details::operator_type o2) + { + return (details::build_string() << "t" << expr_gen.to_str(o0) << "((t" << expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t)"); + } + }; + + struct synthesize_vovocov_expression2 + { + typedef typename vovocov_t::type2 node_type; + typedef typename vovocov_t::sf4_type sf4_type; + typedef typename node_type::T0 T0; + typedef typename node_type::T1 T1; + typedef typename node_type::T2 T2; + typedef typename node_type::T3 T3; + + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + // v0 o0 ((v1 o1 c) o2 v2) + typedef typename synthesize_vocov_expression0::node_type lcl_vocov_t; + + const lcl_vocov_t* vocov = static_cast(branch[1]); + const Type& v0 = static_cast*>(branch[0])->ref(); + const Type& v1 = vocov->t0(); + const Type c = vocov->t1(); + const Type& v2 = vocov->t2(); + const details::operator_type o0 = operation; + const details::operator_type o1 = expr_gen.get_operator(vocov->f0()); + const details::operator_type o2 = expr_gen.get_operator(vocov->f1()); + + binary_functor_t f0 = reinterpret_cast(0); + binary_functor_t f1 = vocov->f0(); + binary_functor_t f2 = vocov->f1(); + + details::free_node(*(expr_gen.node_allocator_),branch[1]); + + expression_node_ptr result = error_node(); + + if (synthesize_sf4ext_expression::template compile(expr_gen,id(expr_gen,o0,o1,o2),v0,v1,c,v2,result)) + return result; + else if (!expr_gen.valid_operator(o0,f0)) + return error_node(); + + exprtk_debug(("v0 o0 ((v1 o1 c) o2 v2)\n")); + + return node_type::allocate(*(expr_gen.node_allocator_),v0,v1,c,v2,f0,f1,f2); + } + + static inline std::string id(expression_generator& expr_gen, + const details::operator_type o0, + const details::operator_type o1, + const details::operator_type o2) + { + return (details::build_string() << "t" << expr_gen.to_str(o0) << "((t" << expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t)"); + } + }; + + struct synthesize_vocovov_expression2 + { + typedef typename vocovov_t::type2 node_type; + typedef typename vocovov_t::sf4_type sf4_type; + typedef typename node_type::T0 T0; + typedef typename node_type::T1 T1; + typedef typename node_type::T2 T2; + typedef typename node_type::T3 T3; + + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + // v0 o0 ((c o1 v1) o2 v2) + typedef typename synthesize_covov_expression0::node_type lcl_covov_t; + + const lcl_covov_t* covov = static_cast(branch[1]); + const Type& v0 = static_cast*>(branch[0])->ref(); + const Type c = covov->t0(); + const Type& v1 = covov->t1(); + const Type& v2 = covov->t2(); + const details::operator_type o0 = operation; + const details::operator_type o1 = expr_gen.get_operator(covov->f0()); + const details::operator_type o2 = expr_gen.get_operator(covov->f1()); + + binary_functor_t f0 = reinterpret_cast(0); + binary_functor_t f1 = covov->f0(); + binary_functor_t f2 = covov->f1(); + + details::free_node(*(expr_gen.node_allocator_),branch[1]); + + expression_node_ptr result = error_node(); + + if (synthesize_sf4ext_expression::template compile(expr_gen,id(expr_gen,o0,o1,o2),v0,c,v1,v2,result)) + return result; + else if (!expr_gen.valid_operator(o0,f0)) + return error_node(); + + exprtk_debug(("v0 o0 ((c o1 v1) o2 v2)\n")); + + return node_type::allocate(*(expr_gen.node_allocator_),v0,c,v1,v2,f0,f1,f2); + } + + static inline std::string id(expression_generator& expr_gen, + const details::operator_type o0, + const details::operator_type o1, + const details::operator_type o2) + { + return (details::build_string() << "t" << expr_gen.to_str(o0) << "((t" << expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t)"); + } + }; + + struct synthesize_covovov_expression2 + { + typedef typename covovov_t::type2 node_type; + typedef typename covovov_t::sf4_type sf4_type; + typedef typename node_type::T0 T0; + typedef typename node_type::T1 T1; + typedef typename node_type::T2 T2; + typedef typename node_type::T3 T3; + + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + // c o0 ((v1 o1 v2) o2 v3) + typedef typename synthesize_vovov_expression0::node_type lcl_vovov_t; + + const lcl_vovov_t* vovov = static_cast(branch[1]); + const Type c = static_cast*>(branch[0])->value(); + const Type& v0 = vovov->t0(); + const Type& v1 = vovov->t1(); + const Type& v2 = vovov->t2(); + const details::operator_type o0 = operation; + const details::operator_type o1 = expr_gen.get_operator(vovov->f0()); + const details::operator_type o2 = expr_gen.get_operator(vovov->f1()); + + binary_functor_t f0 = reinterpret_cast(0); + binary_functor_t f1 = vovov->f0(); + binary_functor_t f2 = vovov->f1(); + + details::free_node(*(expr_gen.node_allocator_),branch[0]); + details::free_node(*(expr_gen.node_allocator_),branch[1]); + + expression_node_ptr result = error_node(); + + if (synthesize_sf4ext_expression::template compile(expr_gen,id(expr_gen,o0,o1,o2),c,v0,v1,v2,result)) + return result; + else if (!expr_gen.valid_operator(o0,f0)) + return error_node(); + + exprtk_debug(("c o0 ((v1 o1 v2) o2 v3)\n")); + + return node_type::allocate(*(expr_gen.node_allocator_),c,v0,v1,v2,f0,f1,f2); + } + + static inline std::string id(expression_generator& expr_gen, + const details::operator_type o0, + const details::operator_type o1, + const details::operator_type o2) + { + return (details::build_string() << "t" << expr_gen.to_str(o0) << "((t" << expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t)"); + } + }; + + struct synthesize_covocov_expression2 + { + typedef typename covocov_t::type2 node_type; + typedef typename covocov_t::sf4_type sf4_type; + typedef typename node_type::T0 T0; + typedef typename node_type::T1 T1; + typedef typename node_type::T2 T2; + typedef typename node_type::T3 T3; + + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + // c0 o0 ((v0 o1 c1) o2 v1) + typedef typename synthesize_vocov_expression0::node_type lcl_vocov_t; + + const lcl_vocov_t* vocov = static_cast(branch[1]); + const Type c0 = static_cast*>(branch[0])->value(); + const Type& v0 = vocov->t0(); + const Type c1 = vocov->t1(); + const Type& v1 = vocov->t2(); + const details::operator_type o0 = operation; + const details::operator_type o1 = expr_gen.get_operator(vocov->f0()); + const details::operator_type o2 = expr_gen.get_operator(vocov->f1()); + + binary_functor_t f0 = reinterpret_cast(0); + binary_functor_t f1 = vocov->f0(); + binary_functor_t f2 = vocov->f1(); + + details::free_node(*(expr_gen.node_allocator_),branch[0]); + details::free_node(*(expr_gen.node_allocator_),branch[1]); + + expression_node_ptr result = error_node(); + + if (synthesize_sf4ext_expression::template compile(expr_gen,id(expr_gen,o0,o1,o2),c0,v0,c1,v1,result)) + return result; + else if (!expr_gen.valid_operator(o0,f0)) + return error_node(); + + exprtk_debug(("c0 o0 ((v0 o1 c1) o2 v1)\n")); + + return node_type::allocate(*(expr_gen.node_allocator_),c0,v0,c1,v1,f0,f1,f2); + } + + static inline std::string id(expression_generator& expr_gen, + const details::operator_type o0, + const details::operator_type o1, + const details::operator_type o2) + { + return (details::build_string() << "t" << expr_gen.to_str(o0) << "((t" << expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t)"); + } + }; + + struct synthesize_vocovoc_expression2 + { + typedef typename vocovoc_t::type2 node_type; + typedef typename vocovoc_t::sf4_type sf4_type; + typedef typename node_type::T0 T0; + typedef typename node_type::T1 T1; + typedef typename node_type::T2 T2; + typedef typename node_type::T3 T3; + + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + // v0 o0 ((c0 o1 v1) o2 c1) + typedef typename synthesize_covoc_expression0::node_type lcl_covoc_t; + + const lcl_covoc_t* covoc = static_cast(branch[1]); + const Type& v0 = static_cast*>(branch[0])->ref(); + const Type c0 = covoc->t0(); + const Type& v1 = covoc->t1(); + const Type c1 = covoc->t2(); + const details::operator_type o0 = operation; + const details::operator_type o1 = expr_gen.get_operator(covoc->f0()); + const details::operator_type o2 = expr_gen.get_operator(covoc->f1()); + + binary_functor_t f0 = reinterpret_cast(0); + binary_functor_t f1 = covoc->f0(); + binary_functor_t f2 = covoc->f1(); + + details::free_node(*(expr_gen.node_allocator_),branch[1]); + + expression_node_ptr result = error_node(); + + if (synthesize_sf4ext_expression::template compile(expr_gen,id(expr_gen,o0,o1,o2),v0,c0,v1,c1,result)) + return result; + else if (!expr_gen.valid_operator(o0,f0)) + return error_node(); + + exprtk_debug(("v0 o0 ((c0 o1 v1) o2 c1)\n")); + + return node_type::allocate(*(expr_gen.node_allocator_),v0,c0,v1,c1,f0,f1,f2); + } + + static inline std::string id(expression_generator& expr_gen, + const details::operator_type o0, + const details::operator_type o1, + const details::operator_type o2) + { + return (details::build_string() << "t" << expr_gen.to_str(o0) << "((t" << expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t)"); + } + }; + + struct synthesize_covovoc_expression2 + { + typedef typename covovoc_t::type2 node_type; + typedef typename covovoc_t::sf4_type sf4_type; + typedef typename node_type::T0 T0; + typedef typename node_type::T1 T1; + typedef typename node_type::T2 T2; + typedef typename node_type::T3 T3; + + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + // c0 o0 ((v0 o1 v1) o2 c1) + typedef typename synthesize_vovoc_expression0::node_type lcl_vovoc_t; + + const lcl_vovoc_t* vovoc = static_cast(branch[1]); + const Type c0 = static_cast*>(branch[0])->value(); + const Type& v0 = vovoc->t0(); + const Type& v1 = vovoc->t1(); + const Type c1 = vovoc->t2(); + const details::operator_type o0 = operation; + const details::operator_type o1 = expr_gen.get_operator(vovoc->f0()); + const details::operator_type o2 = expr_gen.get_operator(vovoc->f1()); + + binary_functor_t f0 = reinterpret_cast(0); + binary_functor_t f1 = vovoc->f0(); + binary_functor_t f2 = vovoc->f1(); + + details::free_node(*(expr_gen.node_allocator_),branch[0]); + details::free_node(*(expr_gen.node_allocator_),branch[1]); + + expression_node_ptr result = error_node(); + + if (synthesize_sf4ext_expression::template compile(expr_gen,id(expr_gen,o0,o1,o2),c0,v0,v1,c1,result)) + return result; + else if (!expr_gen.valid_operator(o0,f0)) + return error_node(); + + exprtk_debug(("c0 o0 ((v0 o1 v1) o2 c1)\n")); + + return node_type::allocate(*(expr_gen.node_allocator_),c0,v0,v1,c1,f0,f1,f2); + } + + static inline std::string id(expression_generator& expr_gen, + const details::operator_type o0, + const details::operator_type o1, + const details::operator_type o2) + { + return (details::build_string() << "t" << expr_gen.to_str(o0) << "((t" << expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t)"); + } + }; + + struct synthesize_vococov_expression2 + { + typedef typename vococov_t::type2 node_type; + static inline expression_node_ptr process(expression_generator&, const details::operator_type&, expression_node_ptr (&)[2]) + { + // v0 o0 ((c0 o1 c1) o2 v1) - Not possible + exprtk_debug(("v0 o0 ((c0 o1 c1) o2 v1) - Not possible\n")); + return error_node(); + } + + static inline std::string id(expression_generator&, + const details::operator_type, const details::operator_type, const details::operator_type) + { + return "INVALID"; + } + }; + + struct synthesize_vovovov_expression3 + { + typedef typename vovovov_t::type3 node_type; + typedef typename vovovov_t::sf4_type sf4_type; + typedef typename node_type::T0 T0; + typedef typename node_type::T1 T1; + typedef typename node_type::T2 T2; + typedef typename node_type::T3 T3; + + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + // ((v0 o0 v1) o1 v2) o2 v3 + typedef typename synthesize_vovov_expression0::node_type lcl_vovov_t; + + const lcl_vovov_t* vovov = static_cast(branch[0]); + const Type& v0 = vovov->t0(); + const Type& v1 = vovov->t1(); + const Type& v2 = vovov->t2(); + const Type& v3 = static_cast*>(branch[1])->ref(); + const details::operator_type o0 = expr_gen.get_operator(vovov->f0()); + const details::operator_type o1 = expr_gen.get_operator(vovov->f1()); + const details::operator_type o2 = operation; + + binary_functor_t f0 = vovov->f0(); + binary_functor_t f1 = vovov->f1(); + binary_functor_t f2 = reinterpret_cast(0); + + details::free_node(*(expr_gen.node_allocator_),branch[0]); + + expression_node_ptr result = error_node(); + + if (synthesize_sf4ext_expression::template compile(expr_gen,id(expr_gen,o0,o1,o2),v0,v1,v2,v3,result)) + return result; + else if (!expr_gen.valid_operator(o2,f2)) + return error_node(); + + exprtk_debug(("((v0 o0 v1) o1 v2) o2 v3\n")); + + return node_type::allocate(*(expr_gen.node_allocator_),v0,v1,v2,v3,f0,f1,f2); + } + + static inline std::string id(expression_generator& expr_gen, + const details::operator_type o0, + const details::operator_type o1, + const details::operator_type o2) + { + return (details::build_string() << "((t" << expr_gen.to_str(o0) << "t)" << expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t"); + } + }; + + struct synthesize_vovovoc_expression3 + { + typedef typename vovovoc_t::type3 node_type; + typedef typename vovovoc_t::sf4_type sf4_type; + typedef typename node_type::T0 T0; + typedef typename node_type::T1 T1; + typedef typename node_type::T2 T2; + typedef typename node_type::T3 T3; + + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + // ((v0 o0 v1) o1 v2) o2 c + typedef typename synthesize_vovov_expression0::node_type lcl_vovov_t; + + const lcl_vovov_t* vovov = static_cast(branch[0]); + const Type& v0 = vovov->t0(); + const Type& v1 = vovov->t1(); + const Type& v2 = vovov->t2(); + const Type c = static_cast*>(branch[1])->value(); + const details::operator_type o0 = expr_gen.get_operator(vovov->f0()); + const details::operator_type o1 = expr_gen.get_operator(vovov->f1()); + const details::operator_type o2 = operation; + + binary_functor_t f0 = vovov->f0(); + binary_functor_t f1 = vovov->f1(); + binary_functor_t f2 = reinterpret_cast(0); + + details::free_node(*(expr_gen.node_allocator_),branch[0]); + details::free_node(*(expr_gen.node_allocator_),branch[1]); + + expression_node_ptr result = error_node(); + + if (synthesize_sf4ext_expression::template compile(expr_gen,id(expr_gen,o0,o1,o2),v0,v1,v2,c,result)) + return result; + else if (!expr_gen.valid_operator(o2,f2)) + return error_node(); + + exprtk_debug(("((v0 o0 v1) o1 v2) o2 c\n")); + + return node_type::allocate(*(expr_gen.node_allocator_),v0,v1,v2,c,f0,f1,f2); + } + + static inline std::string id(expression_generator& expr_gen, + const details::operator_type o0, + const details::operator_type o1, + const details::operator_type o2) + { + return (details::build_string() << "((t" << expr_gen.to_str(o0) << "t)" << expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t"); + } + }; + + struct synthesize_vovocov_expression3 + { + typedef typename vovocov_t::type3 node_type; + typedef typename vovocov_t::sf4_type sf4_type; + typedef typename node_type::T0 T0; + typedef typename node_type::T1 T1; + typedef typename node_type::T2 T2; + typedef typename node_type::T3 T3; + + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + // ((v0 o0 v1) o1 c) o2 v2 + typedef typename synthesize_vovoc_expression0::node_type lcl_vovoc_t; + + const lcl_vovoc_t* vovoc = static_cast(branch[0]); + const Type& v0 = vovoc->t0(); + const Type& v1 = vovoc->t1(); + const Type c = vovoc->t2(); + const Type& v2 = static_cast*>(branch[1])->ref(); + const details::operator_type o0 = expr_gen.get_operator(vovoc->f0()); + const details::operator_type o1 = expr_gen.get_operator(vovoc->f1()); + const details::operator_type o2 = operation; + + binary_functor_t f0 = vovoc->f0(); + binary_functor_t f1 = vovoc->f1(); + binary_functor_t f2 = reinterpret_cast(0); + + details::free_node(*(expr_gen.node_allocator_),branch[0]); + + expression_node_ptr result = error_node(); + + if (synthesize_sf4ext_expression::template compile(expr_gen,id(expr_gen,o0,o1,o2),v0,v1,c,v2,result)) + return result; + else if (!expr_gen.valid_operator(o2,f2)) + return error_node(); + + exprtk_debug(("((v0 o0 v1) o1 c) o2 v2\n")); + + return node_type::allocate(*(expr_gen.node_allocator_),v0,v1,c,v2,f0,f1,f2); + } + + static inline std::string id(expression_generator& expr_gen, + const details::operator_type o0, + const details::operator_type o1, + const details::operator_type o2) + { + return (details::build_string() << "((t" << expr_gen.to_str(o0) << "t)" << expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t"); + } + }; + + struct synthesize_vocovov_expression3 + { + typedef typename vocovov_t::type3 node_type; + typedef typename vocovov_t::sf4_type sf4_type; + typedef typename node_type::T0 T0; + typedef typename node_type::T1 T1; + typedef typename node_type::T2 T2; + typedef typename node_type::T3 T3; + + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + // ((v0 o0 c) o1 v1) o2 v2 + typedef typename synthesize_vocov_expression0::node_type lcl_vocov_t; + + const lcl_vocov_t* vocov = static_cast(branch[0]); + const Type& v0 = vocov->t0(); + const Type c = vocov->t1(); + const Type& v1 = vocov->t2(); + const Type& v2 = static_cast*>(branch[1])->ref(); + const details::operator_type o0 = expr_gen.get_operator(vocov->f0()); + const details::operator_type o1 = expr_gen.get_operator(vocov->f1()); + const details::operator_type o2 = operation; + + binary_functor_t f0 = vocov->f0(); + binary_functor_t f1 = vocov->f1(); + binary_functor_t f2 = reinterpret_cast(0); + + details::free_node(*(expr_gen.node_allocator_),branch[0]); + + expression_node_ptr result = error_node(); + + if (synthesize_sf4ext_expression::template compile(expr_gen,id(expr_gen,o0,o1,o2),v0,c,v1,v2,result)) + return result; + else if (!expr_gen.valid_operator(o2,f2)) + return error_node(); + + exprtk_debug(("((v0 o0 c) o1 v1) o2 v2\n")); + + return node_type::allocate(*(expr_gen.node_allocator_),v0,c,v1,v2,f0,f1,f2); + } + + static inline std::string id(expression_generator& expr_gen, + const details::operator_type o0, + const details::operator_type o1, + const details::operator_type o2) + { + return (details::build_string() << "((t" << expr_gen.to_str(o0) << "t)" << expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t"); + } + }; + + struct synthesize_covovov_expression3 + { + typedef typename covovov_t::type3 node_type; + typedef typename covovov_t::sf4_type sf4_type; + typedef typename node_type::T0 T0; + typedef typename node_type::T1 T1; + typedef typename node_type::T2 T2; + typedef typename node_type::T3 T3; + + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + // ((c o0 v0) o1 v1) o2 v2 + typedef typename synthesize_covov_expression0::node_type lcl_covov_t; + + const lcl_covov_t* covov = static_cast(branch[0]); + const Type c = covov->t0(); + const Type& v0 = covov->t1(); + const Type& v1 = covov->t2(); + const Type& v2 = static_cast*>(branch[1])->ref(); + const details::operator_type o0 = expr_gen.get_operator(covov->f0()); + const details::operator_type o1 = expr_gen.get_operator(covov->f1()); + const details::operator_type o2 = operation; + + binary_functor_t f0 = covov->f0(); + binary_functor_t f1 = covov->f1(); + binary_functor_t f2 = reinterpret_cast(0); + + details::free_node(*(expr_gen.node_allocator_),branch[0]); + + expression_node_ptr result = error_node(); + + if (synthesize_sf4ext_expression::template compile(expr_gen,id(expr_gen,o0,o1,o2),c,v0,v1,v2,result)) + return result; + else if (!expr_gen.valid_operator(o2,f2)) + return error_node(); + + exprtk_debug(("((c o0 v0) o1 v1) o2 v2\n")); + + return node_type::allocate(*(expr_gen.node_allocator_),c,v0,v1,v2,f0,f1,f2); + } + + static inline std::string id(expression_generator& expr_gen, + const details::operator_type o0, + const details::operator_type o1, + const details::operator_type o2) + { + return (details::build_string() << "((t" << expr_gen.to_str(o0) << "t)" << expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t"); + } + }; + + struct synthesize_covocov_expression3 + { + typedef typename covocov_t::type3 node_type; + typedef typename covocov_t::sf4_type sf4_type; + typedef typename node_type::T0 T0; + typedef typename node_type::T1 T1; + typedef typename node_type::T2 T2; + typedef typename node_type::T3 T3; + + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + // ((c0 o0 v0) o1 c1) o2 v1 + typedef typename synthesize_covoc_expression0::node_type lcl_covoc_t; + + const lcl_covoc_t* covoc = static_cast(branch[0]); + const Type c0 = covoc->t0(); + const Type& v0 = covoc->t1(); + const Type c1 = covoc->t2(); + const Type& v1 = static_cast*>(branch[1])->ref(); + const details::operator_type o0 = expr_gen.get_operator(covoc->f0()); + const details::operator_type o1 = expr_gen.get_operator(covoc->f1()); + const details::operator_type o2 = operation; + + binary_functor_t f0 = covoc->f0(); + binary_functor_t f1 = covoc->f1(); + binary_functor_t f2 = reinterpret_cast(0); + + details::free_node(*(expr_gen.node_allocator_),branch[0]); + + expression_node_ptr result = error_node(); + + if (synthesize_sf4ext_expression::template compile(expr_gen,id(expr_gen,o0,o1,o2),c0,v0,c1,v1,result)) + return result; + else if (!expr_gen.valid_operator(o2,f2)) + return error_node(); + + exprtk_debug(("((c0 o0 v0) o1 c1) o2 v1\n")); + + return node_type::allocate(*(expr_gen.node_allocator_),c0,v0,c1,v1,f0,f1,f2); + } + + static inline std::string id(expression_generator& expr_gen, + const details::operator_type o0, + const details::operator_type o1, + const details::operator_type o2) + { + return (details::build_string() << "((t" << expr_gen.to_str(o0) << "t)" << expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t"); + } + }; + + struct synthesize_vocovoc_expression3 + { + typedef typename vocovoc_t::type3 node_type; + typedef typename vocovoc_t::sf4_type sf4_type; + typedef typename node_type::T0 T0; + typedef typename node_type::T1 T1; + typedef typename node_type::T2 T2; + typedef typename node_type::T3 T3; + + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + // ((v0 o0 c0) o1 v1) o2 c1 + typedef typename synthesize_vocov_expression0::node_type lcl_vocov_t; + + const lcl_vocov_t* vocov = static_cast(branch[0]); + const Type& v0 = vocov->t0(); + const Type c0 = vocov->t1(); + const Type& v1 = vocov->t2(); + const Type c1 = static_cast*>(branch[1])->value(); + const details::operator_type o0 = expr_gen.get_operator(vocov->f0()); + const details::operator_type o1 = expr_gen.get_operator(vocov->f1()); + const details::operator_type o2 = operation; + + binary_functor_t f0 = vocov->f0(); + binary_functor_t f1 = vocov->f1(); + binary_functor_t f2 = reinterpret_cast(0); + + details::free_node(*(expr_gen.node_allocator_),branch[0]); + details::free_node(*(expr_gen.node_allocator_),branch[1]); + + expression_node_ptr result = error_node(); + + if (synthesize_sf4ext_expression::template compile(expr_gen,id(expr_gen,o0,o1,o2),v0,c0,v1,c1,result)) + return result; + else if (!expr_gen.valid_operator(o2,f2)) + return error_node(); + + exprtk_debug(("((v0 o0 c0) o1 v1) o2 c1\n")); + + return node_type::allocate(*(expr_gen.node_allocator_),v0,c0,v1,c1,f0,f1,f2); + } + + static inline std::string id(expression_generator& expr_gen, + const details::operator_type o0, + const details::operator_type o1, + const details::operator_type o2) + { + return (details::build_string() << "((t" << expr_gen.to_str(o0) << "t)" << expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t"); + } + }; + + struct synthesize_covovoc_expression3 + { + typedef typename covovoc_t::type3 node_type; + typedef typename covovoc_t::sf4_type sf4_type; + typedef typename node_type::T0 T0; + typedef typename node_type::T1 T1; + typedef typename node_type::T2 T2; + typedef typename node_type::T3 T3; + + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + // ((c0 o0 v0) o1 v1) o2 c1 + typedef typename synthesize_covov_expression0::node_type lcl_covov_t; + + const lcl_covov_t* covov = static_cast(branch[0]); + const Type c0 = covov->t0(); + const Type& v0 = covov->t1(); + const Type& v1 = covov->t2(); + const Type c1 = static_cast*>(branch[1])->value(); + const details::operator_type o0 = expr_gen.get_operator(covov->f0()); + const details::operator_type o1 = expr_gen.get_operator(covov->f1()); + const details::operator_type o2 = operation; + + binary_functor_t f0 = covov->f0(); + binary_functor_t f1 = covov->f1(); + binary_functor_t f2 = reinterpret_cast(0); + + details::free_node(*(expr_gen.node_allocator_),branch[0]); + details::free_node(*(expr_gen.node_allocator_),branch[1]); + + expression_node_ptr result = error_node(); + + if (synthesize_sf4ext_expression::template compile(expr_gen,id(expr_gen,o0,o1,o2),c0,v0,v1,c1,result)) + return result; + else if (!expr_gen.valid_operator(o2,f2)) + return error_node(); + + exprtk_debug(("((c0 o0 v0) o1 v1) o2 c1\n")); + + return node_type::allocate(*(expr_gen.node_allocator_),c0,v0,v1,c1,f0,f1,f2); + } + + static inline std::string id(expression_generator& expr_gen, + const details::operator_type o0, + const details::operator_type o1, + const details::operator_type o2) + { + return (details::build_string() << "((t" << expr_gen.to_str(o0) << "t)" << expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t"); + } + }; + + struct synthesize_vococov_expression3 + { + typedef typename vococov_t::type3 node_type; + typedef typename vococov_t::sf4_type sf4_type; + typedef typename node_type::T0 T0; + typedef typename node_type::T1 T1; + typedef typename node_type::T2 T2; + typedef typename node_type::T3 T3; + + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + // ((v0 o0 c0) o1 c1) o2 v1 + typedef typename synthesize_vococ_expression0::node_type lcl_vococ_t; + + const lcl_vococ_t* vococ = static_cast(branch[0]); + const Type& v0 = vococ->t0(); + const Type c0 = vococ->t1(); + const Type c1 = vococ->t2(); + const Type& v1 = static_cast*>(branch[1])->ref(); + const details::operator_type o0 = expr_gen.get_operator(vococ->f0()); + const details::operator_type o1 = expr_gen.get_operator(vococ->f1()); + const details::operator_type o2 = operation; + + binary_functor_t f0 = vococ->f0(); + binary_functor_t f1 = vococ->f1(); + binary_functor_t f2 = reinterpret_cast(0); + + details::free_node(*(expr_gen.node_allocator_),branch[0]); + + expression_node_ptr result = error_node(); + + if (synthesize_sf4ext_expression::template compile(expr_gen,id(expr_gen,o0,o1,o2),v0,c0,c1,v1,result)) + return result; + else if (!expr_gen.valid_operator(o2,f2)) + return error_node(); + + exprtk_debug(("((v0 o0 c0) o1 c1) o2 v1\n")); + + return node_type::allocate(*(expr_gen.node_allocator_),v0,c0,c1,v1,f0,f1,f2); + } + + static inline std::string id(expression_generator& expr_gen, + const details::operator_type o0, + const details::operator_type o1, + const details::operator_type o2) + { + return (details::build_string() << "((t" << expr_gen.to_str(o0) << "t)" << expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t"); + } + }; + + struct synthesize_vovovov_expression4 + { + typedef typename vovovov_t::type4 node_type; + typedef typename vovovov_t::sf4_type sf4_type; + typedef typename node_type::T0 T0; + typedef typename node_type::T1 T1; + typedef typename node_type::T2 T2; + typedef typename node_type::T3 T3; + + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + // (v0 o0 (v1 o1 v2)) o2 v3 + typedef typename synthesize_vovov_expression1::node_type lcl_vovov_t; + + const lcl_vovov_t* vovov = static_cast(branch[0]); + const Type& v0 = vovov->t0(); + const Type& v1 = vovov->t1(); + const Type& v2 = vovov->t2(); + const Type& v3 = static_cast*>(branch[1])->ref(); + const details::operator_type o0 = expr_gen.get_operator(vovov->f0()); + const details::operator_type o1 = expr_gen.get_operator(vovov->f1()); + const details::operator_type o2 = operation; + + binary_functor_t f0 = vovov->f0(); + binary_functor_t f1 = vovov->f1(); + binary_functor_t f2 = reinterpret_cast(0); + + details::free_node(*(expr_gen.node_allocator_),branch[0]); + + expression_node_ptr result = error_node(); + + if (synthesize_sf4ext_expression::template compile(expr_gen,id(expr_gen,o0,o1,o2),v0,v1,v2,v3,result)) + return result; + else if (!expr_gen.valid_operator(o2,f2)) + return error_node(); + + exprtk_debug(("(v0 o0 (v1 o1 v2)) o2 v3\n")); + + return node_type::allocate(*(expr_gen.node_allocator_),v0,v1,v2,v3,f0,f1,f2); + } + + static inline std::string id(expression_generator& expr_gen, + const details::operator_type o0, + const details::operator_type o1, + const details::operator_type o2) + { + return (details::build_string() << "(t" << expr_gen.to_str(o0) << "(t" << expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t"); + } + }; + + struct synthesize_vovovoc_expression4 + { + typedef typename vovovoc_t::type4 node_type; + typedef typename vovovoc_t::sf4_type sf4_type; + typedef typename node_type::T0 T0; + typedef typename node_type::T1 T1; + typedef typename node_type::T2 T2; + typedef typename node_type::T3 T3; + + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + // ((v0 o0 (v1 o1 v2)) o2 c) + typedef typename synthesize_vovov_expression1::node_type lcl_vovov_t; + + const lcl_vovov_t* vovov = static_cast(branch[0]); + const Type& v0 = vovov->t0(); + const Type& v1 = vovov->t1(); + const Type& v2 = vovov->t2(); + const Type c = static_cast*>(branch[1])->value(); + const details::operator_type o0 = expr_gen.get_operator(vovov->f0()); + const details::operator_type o1 = expr_gen.get_operator(vovov->f1()); + const details::operator_type o2 = operation; + + binary_functor_t f0 = vovov->f0(); + binary_functor_t f1 = vovov->f1(); + binary_functor_t f2 = reinterpret_cast(0); + + details::free_node(*(expr_gen.node_allocator_),branch[0]); + details::free_node(*(expr_gen.node_allocator_),branch[1]); + + expression_node_ptr result = error_node(); + + if (synthesize_sf4ext_expression::template compile(expr_gen,id(expr_gen,o0,o1,o2),v0,v1,v2,c,result)) + return result; + else if (!expr_gen.valid_operator(o2,f2)) + return error_node(); + + exprtk_debug(("((v0 o0 (v1 o1 v2)) o2 c)\n")); + + return node_type::allocate(*(expr_gen.node_allocator_),v0,v1,v2,c,f0,f1,f2); + } + + static inline std::string id(expression_generator& expr_gen, + const details::operator_type o0, + const details::operator_type o1, + const details::operator_type o2) + { + return (details::build_string() << "(t" << expr_gen.to_str(o0) << "(t" << expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t"); + } + }; + + struct synthesize_vovocov_expression4 + { + typedef typename vovocov_t::type4 node_type; + typedef typename vovocov_t::sf4_type sf4_type; + typedef typename node_type::T0 T0; + typedef typename node_type::T1 T1; + typedef typename node_type::T2 T2; + typedef typename node_type::T3 T3; + + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + // ((v0 o0 (v1 o1 c)) o2 v1) + typedef typename synthesize_vovoc_expression1::node_type lcl_vovoc_t; + + const lcl_vovoc_t* vovoc = static_cast(branch[0]); + const Type& v0 = vovoc->t0(); + const Type& v1 = vovoc->t1(); + const Type c = vovoc->t2(); + const Type& v2 = static_cast*>(branch[1])->ref(); + const details::operator_type o0 = expr_gen.get_operator(vovoc->f0()); + const details::operator_type o1 = expr_gen.get_operator(vovoc->f1()); + const details::operator_type o2 = operation; + + binary_functor_t f0 = vovoc->f0(); + binary_functor_t f1 = vovoc->f1(); + binary_functor_t f2 = reinterpret_cast(0); + + details::free_node(*(expr_gen.node_allocator_),branch[0]); + + expression_node_ptr result = error_node(); + + if (synthesize_sf4ext_expression::template compile(expr_gen,id(expr_gen,o0,o1,o2),v0,v1,c,v2,result)) + return result; + else if (!expr_gen.valid_operator(o2,f2)) + return error_node(); + + exprtk_debug(("((v0 o0 (v1 o1 c)) o2 v1)\n")); + + return node_type::allocate(*(expr_gen.node_allocator_),v0,v1,c,v2,f0,f1,f2); + } + + static inline std::string id(expression_generator& expr_gen, + const details::operator_type o0, + const details::operator_type o1, + const details::operator_type o2) + { + return (details::build_string() << "(t" << expr_gen.to_str(o0) << "(t" << expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t"); + } + }; + + struct synthesize_vocovov_expression4 + { + typedef typename vocovov_t::type4 node_type; + typedef typename vocovov_t::sf4_type sf4_type; + typedef typename node_type::T0 T0; + typedef typename node_type::T1 T1; + typedef typename node_type::T2 T2; + typedef typename node_type::T3 T3; + + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + // ((v0 o0 (c o1 v1)) o2 v2) + typedef typename synthesize_vocov_expression1::node_type lcl_vocov_t; + + const lcl_vocov_t* vocov = static_cast(branch[0]); + const Type& v0 = vocov->t0(); + const Type c = vocov->t1(); + const Type& v1 = vocov->t2(); + const Type& v2 = static_cast*>(branch[1])->ref(); + const details::operator_type o0 = expr_gen.get_operator(vocov->f0()); + const details::operator_type o1 = expr_gen.get_operator(vocov->f1()); + const details::operator_type o2 = operation; + + binary_functor_t f0 = vocov->f0(); + binary_functor_t f1 = vocov->f1(); + binary_functor_t f2 = reinterpret_cast(0); + + details::free_node(*(expr_gen.node_allocator_),branch[0]); + expression_node_ptr result = error_node(); + + if (synthesize_sf4ext_expression::template compile(expr_gen,id(expr_gen,o0,o1,o2),v0,c,v1,v2,result)) + return result; + else if (!expr_gen.valid_operator(o2,f2)) + return error_node(); + + exprtk_debug(("((v0 o0 (c o1 v1)) o2 v2)\n")); + + return node_type::allocate(*(expr_gen.node_allocator_),v0,c,v1,v2,f0,f1,f2); + } + + static inline std::string id(expression_generator& expr_gen, + const details::operator_type o0, + const details::operator_type o1, + const details::operator_type o2) + { + return (details::build_string() << "(t" << expr_gen.to_str(o0) << "(t" << expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t"); + } + }; + + struct synthesize_covovov_expression4 + { + typedef typename covovov_t::type4 node_type; + typedef typename covovov_t::sf4_type sf4_type; + typedef typename node_type::T0 T0; + typedef typename node_type::T1 T1; + typedef typename node_type::T2 T2; + typedef typename node_type::T3 T3; + + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + // ((c o0 (v0 o1 v1)) o2 v2) + typedef typename synthesize_covov_expression1::node_type lcl_covov_t; + + const lcl_covov_t* covov = static_cast(branch[0]); + const Type c = covov->t0(); + const Type& v0 = covov->t1(); + const Type& v1 = covov->t2(); + const Type& v2 = static_cast*>(branch[1])->ref(); + const details::operator_type o0 = expr_gen.get_operator(covov->f0()); + const details::operator_type o1 = expr_gen.get_operator(covov->f1()); + const details::operator_type o2 = operation; + + binary_functor_t f0 = covov->f0(); + binary_functor_t f1 = covov->f1(); + binary_functor_t f2 = reinterpret_cast(0); + + details::free_node(*(expr_gen.node_allocator_),branch[0]); + + expression_node_ptr result = error_node(); + + if (synthesize_sf4ext_expression::template compile(expr_gen,id(expr_gen,o0,o1,o2),c,v0,v1,v2,result)) + return result; + else if (!expr_gen.valid_operator(o2,f2)) + return error_node(); + + exprtk_debug(("((c o0 (v0 o1 v1)) o2 v2)\n")); + + return node_type::allocate(*(expr_gen.node_allocator_),c,v0,v1,v2,f0,f1,f2); + } + + static inline std::string id(expression_generator& expr_gen, + const details::operator_type o0, + const details::operator_type o1, + const details::operator_type o2) + { + return (details::build_string() << "(t" << expr_gen.to_str(o0) << "(t" << expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t"); + } + }; + + struct synthesize_covocov_expression4 + { + typedef typename covocov_t::type4 node_type; + typedef typename covocov_t::sf4_type sf4_type; + typedef typename node_type::T0 T0; + typedef typename node_type::T1 T1; + typedef typename node_type::T2 T2; + typedef typename node_type::T3 T3; + + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + // ((c0 o0 (v0 o1 c1)) o2 v1) + typedef typename synthesize_covoc_expression1::node_type lcl_covoc_t; + + const lcl_covoc_t* covoc = static_cast(branch[0]); + const Type c0 = covoc->t0(); + const Type& v0 = covoc->t1(); + const Type c1 = covoc->t2(); + const Type& v1 = static_cast*>(branch[1])->ref(); + const details::operator_type o0 = expr_gen.get_operator(covoc->f0()); + const details::operator_type o1 = expr_gen.get_operator(covoc->f1()); + const details::operator_type o2 = operation; + + binary_functor_t f0 = covoc->f0(); + binary_functor_t f1 = covoc->f1(); + binary_functor_t f2 = reinterpret_cast(0); + + details::free_node(*(expr_gen.node_allocator_),branch[0]); + + expression_node_ptr result = error_node(); + + if (synthesize_sf4ext_expression::template compile(expr_gen,id(expr_gen,o0,o1,o2),c0,v0,c1,v1,result)) + return result; + else if (!expr_gen.valid_operator(o2,f2)) + return error_node(); + + exprtk_debug(("((c0 o0 (v0 o1 c1)) o2 v1)\n")); + + return node_type::allocate(*(expr_gen.node_allocator_),c0,v0,c1,v1,f0,f1,f2); + } + + static inline std::string id(expression_generator& expr_gen, + const details::operator_type o0, + const details::operator_type o1, + const details::operator_type o2) + { + return (details::build_string() << "(t" << expr_gen.to_str(o0) << "(t" << expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t"); + } + }; + + struct synthesize_vocovoc_expression4 + { + typedef typename vocovoc_t::type4 node_type; + typedef typename vocovoc_t::sf4_type sf4_type; + typedef typename node_type::T0 T0; + typedef typename node_type::T1 T1; + typedef typename node_type::T2 T2; + typedef typename node_type::T3 T3; + + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + // ((v0 o0 (c0 o1 v1)) o2 c1) + typedef typename synthesize_vocov_expression1::node_type lcl_vocov_t; + + const lcl_vocov_t* vocov = static_cast(branch[0]); + const Type& v0 = vocov->t0(); + const Type c0 = vocov->t1(); + const Type& v1 = vocov->t2(); + const Type c1 = static_cast*>(branch[1])->value(); + const details::operator_type o0 = expr_gen.get_operator(vocov->f0()); + const details::operator_type o1 = expr_gen.get_operator(vocov->f1()); + const details::operator_type o2 = operation; + + binary_functor_t f0 = vocov->f0(); + binary_functor_t f1 = vocov->f1(); + binary_functor_t f2 = reinterpret_cast(0); + + details::free_node(*(expr_gen.node_allocator_),branch[0]); + details::free_node(*(expr_gen.node_allocator_),branch[1]); + + expression_node_ptr result = error_node(); + + if (synthesize_sf4ext_expression::template compile(expr_gen,id(expr_gen,o0,o1,o2),v0,c0,v1,c1,result)) + return result; + else if (!expr_gen.valid_operator(o2,f2)) + return error_node(); + + exprtk_debug(("((v0 o0 (c0 o1 v1)) o2 c1)\n")); + + return node_type::allocate(*(expr_gen.node_allocator_),v0,c0,v1,c1,f0,f1,f2); + } + + static inline std::string id(expression_generator& expr_gen, + const details::operator_type o0, + const details::operator_type o1, + const details::operator_type o2) + { + return (details::build_string() << "(t" << expr_gen.to_str(o0) << "(t" << expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t"); + } + }; + + struct synthesize_covovoc_expression4 + { + typedef typename covovoc_t::type4 node_type; + typedef typename covovoc_t::sf4_type sf4_type; + typedef typename node_type::T0 T0; + typedef typename node_type::T1 T1; + typedef typename node_type::T2 T2; + typedef typename node_type::T3 T3; + + static inline expression_node_ptr process(expression_generator& expr_gen, + const details::operator_type& operation, + expression_node_ptr (&branch)[2]) + { + // ((c0 o0 (v0 o1 v1)) o2 c1) + typedef typename synthesize_covov_expression1::node_type lcl_covov_t; + + const lcl_covov_t* covov = static_cast(branch[0]); + const Type c0 = covov->t0(); + const Type& v0 = covov->t1(); + const Type& v1 = covov->t2(); + const Type c1 = static_cast*>(branch[1])->value(); + const details::operator_type o0 = expr_gen.get_operator(covov->f0()); + const details::operator_type o1 = expr_gen.get_operator(covov->f1()); + const details::operator_type o2 = operation; + + binary_functor_t f0 = covov->f0(); + binary_functor_t f1 = covov->f1(); + binary_functor_t f2 = reinterpret_cast(0); + + details::free_node(*(expr_gen.node_allocator_),branch[0]); + details::free_node(*(expr_gen.node_allocator_),branch[1]); + + expression_node_ptr result = error_node(); + + if (synthesize_sf4ext_expression::template compile(expr_gen,id(expr_gen,o0,o1,o2),c0,v0,v1,c1,result)) + return result; + else if (!expr_gen.valid_operator(o2,f2)) + return error_node(); + + exprtk_debug(("((c0 o0 (v0 o1 v1)) o2 c1)\n")); + + return node_type::allocate(*(expr_gen.node_allocator_),c0,v0,v1,c1,f0,f1,f2); + } + + static inline std::string id(expression_generator& expr_gen, + const details::operator_type o0, + const details::operator_type o1, + const details::operator_type o2) + { + return (details::build_string() << "(t" << expr_gen.to_str(o0) << "(t" << expr_gen.to_str(o1) << "t)" << expr_gen.to_str(o2) << "t"); + } + }; + + struct synthesize_vococov_expression4 + { + typedef typename vococov_t::type4 node_type; + static inline expression_node_ptr process(expression_generator&, const details::operator_type&, expression_node_ptr (&)[2]) + { + // ((v0 o0 (c0 o1 c1)) o2 v1) - Not possible + exprtk_debug(("((v0 o0 (c0 o1 c1)) o2 v1) - Not possible\n")); + return error_node(); + } + + static inline std::string id(expression_generator&, + const details::operator_type, const details::operator_type, const details::operator_type) + { + return "INVALID"; + } + }; + #endif + + inline expression_node_ptr synthesize_uvouv_expression(const details::operator_type& operation, expression_node_ptr (&branch)[2]) + { + // Definition: uv o uv + details::operator_type o0 = static_cast*>(branch[0])->operation(); + details::operator_type o1 = static_cast*>(branch[1])->operation(); + const Type& v0 = static_cast*>(branch[0])->v(); + const Type& v1 = static_cast*>(branch[1])->v(); + unary_functor_t u0 = reinterpret_cast (0); + unary_functor_t u1 = reinterpret_cast (0); + binary_functor_t f = reinterpret_cast(0); + + if (!valid_operator(o0,u0)) + return error_node(); + else if (!valid_operator(o1,u1)) + return error_node(); + else if (!valid_operator(operation,f)) + return error_node(); + + expression_node_ptr result = error_node(); + + if ( + (details::e_neg == o0) && + (details::e_neg == o1) + ) + { + switch (operation) + { + // (-v0 + -v1) --> -(v0 + v1) + case details::e_add : result = (*this)(details::e_neg, + node_allocator_-> + allocate_rr > >(v0,v1)); + exprtk_debug(("(-v0 + -v1) --> -(v0 + v1)\n")); + break; + + // (-v0 - -v1) --> (v1 - v0) + case details::e_sub : result = node_allocator_-> + allocate_rr > >(v1,v0); + exprtk_debug(("(-v0 - -v1) --> (v1 - v0)\n")); + break; + + // (-v0 * -v1) --> (v0 * v1) + case details::e_mul : result = node_allocator_-> + allocate_rr > >(v0,v1); + exprtk_debug(("(-v0 * -v1) --> (v0 * v1)\n")); + break; + + // (-v0 / -v1) --> (v0 / v1) + case details::e_div : result = node_allocator_-> + allocate_rr > >(v0,v1); + exprtk_debug(("(-v0 / -v1) --> (v0 / v1)\n")); + break; + + default : break; + } + } + + if (0 == result) + { + result = node_allocator_-> + allocate_rrrrr >(v0,v1,u0,u1,f); + } + + details::free_all_nodes(*node_allocator_,branch); + return result; + } + + #undef basic_opr_switch_statements + #undef extended_opr_switch_statements + #undef unary_opr_switch_statements + + #ifndef exprtk_disable_string_capabilities + + #define string_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_in ,details:: in_op) \ + case_stmt(details::e_like ,details:: like_op) \ + case_stmt(details::e_ilike,details::ilike_op) \ + + template + inline expression_node_ptr synthesize_str_xrox_expression_impl(const details::operator_type& opr, + T0 s0, T1 s1, + range_t rp0) + { + switch (opr) + { + #define case_stmt(op0,op1) \ + case op0 : return node_allocator_-> \ + allocate_ttt >,T0,T1> \ + (s0,s1,rp0); \ + + string_opr_switch_statements + #undef case_stmt + default : return error_node(); + } + } + + template + inline expression_node_ptr synthesize_str_xoxr_expression_impl(const details::operator_type& opr, + T0 s0, T1 s1, + range_t rp1) + { + switch (opr) + { + #define case_stmt(op0,op1) \ + case op0 : return node_allocator_-> \ + allocate_ttt >,T0,T1> \ + (s0,s1,rp1); \ + + string_opr_switch_statements + #undef case_stmt + default : return error_node(); + } + } + + template + inline expression_node_ptr synthesize_str_xroxr_expression_impl(const details::operator_type& opr, + T0 s0, T1 s1, + range_t rp0, range_t rp1) + { + switch (opr) + { + #define case_stmt(op0,op1) \ + case op0 : return node_allocator_-> \ + allocate_tttt >,T0,T1> \ + (s0,s1,rp0,rp1); \ + + string_opr_switch_statements + #undef case_stmt + default : return error_node(); + } + } + + template + inline expression_node_ptr synthesize_sos_expression_impl(const details::operator_type& opr, T0 s0, T1 s1) + { + switch (opr) + { + #define case_stmt(op0,op1) \ + case op0 : return node_allocator_-> \ + allocate_tt >,T0,T1>(s0,s1); \ + + string_opr_switch_statements + #undef case_stmt + default : return error_node(); + } + } + + inline expression_node_ptr synthesize_sos_expression(const details::operator_type& opr, expression_node_ptr (&branch)[2]) + { + std::string& s0 = static_cast*>(branch[0])->ref(); + std::string& s1 = static_cast*>(branch[1])->ref(); + + return synthesize_sos_expression_impl(opr,s0,s1); + } + + inline expression_node_ptr synthesize_sros_expression(const details::operator_type& opr, expression_node_ptr (&branch)[2]) + { + std::string& s0 = static_cast*>(branch[0])->ref (); + std::string& s1 = static_cast*> (branch[1])->ref (); + range_t rp0 = static_cast*>(branch[0])->range(); + + static_cast*>(branch[0])->range_ref().clear(); + + free_node(*node_allocator_,branch[0]); + + return synthesize_str_xrox_expression_impl(opr,s0,s1,rp0); + } + + inline expression_node_ptr synthesize_sosr_expression(const details::operator_type& opr, expression_node_ptr (&branch)[2]) + { + std::string& s0 = static_cast*> (branch[0])->ref (); + std::string& s1 = static_cast*>(branch[1])->ref (); + range_t rp1 = static_cast*>(branch[1])->range(); + + static_cast*>(branch[1])->range_ref().clear(); + + free_node(*node_allocator_,branch[1]); + + return synthesize_str_xoxr_expression_impl(opr,s0,s1,rp1); + } + + inline expression_node_ptr synthesize_socsr_expression(const details::operator_type& opr, expression_node_ptr (&branch)[2]) + { + std::string& s0 = static_cast*> (branch[0])->ref (); + std::string s1 = static_cast*>(branch[1])->str (); + range_t rp1 = static_cast*>(branch[1])->range(); + + static_cast*>(branch[1])->range_ref().clear(); + + free_node(*node_allocator_,branch[1]); + + return synthesize_str_xoxr_expression_impl(opr,s0,s1,rp1); + } + + inline expression_node_ptr synthesize_srosr_expression(const details::operator_type& opr, expression_node_ptr (&branch)[2]) + { + std::string& s0 = static_cast*>(branch[0])->ref (); + std::string& s1 = static_cast*>(branch[1])->ref (); + range_t rp0 = static_cast*>(branch[0])->range(); + range_t rp1 = static_cast*>(branch[1])->range(); + + static_cast*>(branch[0])->range_ref().clear(); + static_cast*>(branch[1])->range_ref().clear(); + + details::free_node(*node_allocator_,branch[0]); + details::free_node(*node_allocator_,branch[1]); + + return synthesize_str_xroxr_expression_impl(opr,s0,s1,rp0,rp1); + } + + inline expression_node_ptr synthesize_socs_expression(const details::operator_type& opr, expression_node_ptr (&branch)[2]) + { + std::string& s0 = static_cast< details::stringvar_node*>(branch[0])->ref(); + std::string s1 = static_cast*>(branch[1])->str(); + + details::free_node(*node_allocator_,branch[1]); + + return synthesize_sos_expression_impl(opr,s0,s1); + } + + inline expression_node_ptr synthesize_csos_expression(const details::operator_type& opr, expression_node_ptr (&branch)[2]) + { + std::string s0 = static_cast*>(branch[0])->str(); + std::string& s1 = static_cast< details::stringvar_node*>(branch[1])->ref(); + + details::free_node(*node_allocator_,branch[0]); + + return synthesize_sos_expression_impl(opr,s0,s1); + } + + inline expression_node_ptr synthesize_csosr_expression(const details::operator_type& opr, expression_node_ptr (&branch)[2]) + { + std::string s0 = static_cast*>(branch[0])->str (); + std::string& s1 = static_cast*> (branch[1])->ref (); + range_t rp1 = static_cast*> (branch[1])->range(); + + static_cast*>(branch[1])->range_ref().clear(); + + details::free_node(*node_allocator_,branch[0]); + details::free_node(*node_allocator_,branch[1]); + + return synthesize_str_xoxr_expression_impl(opr,s0,s1,rp1); + } + + inline expression_node_ptr synthesize_srocs_expression(const details::operator_type& opr, expression_node_ptr (&branch)[2]) + { + std::string& s0 = static_cast*> (branch[0])->ref (); + std::string s1 = static_cast*>(branch[1])->str (); + range_t rp0 = static_cast*> (branch[0])->range(); + + static_cast*>(branch[0])->range_ref().clear(); + + details::free_node(*node_allocator_,branch[0]); + details::free_node(*node_allocator_,branch[1]); + + return synthesize_str_xrox_expression_impl(opr,s0,s1,rp0); + } + + inline expression_node_ptr synthesize_srocsr_expression(const details::operator_type& opr, expression_node_ptr (&branch)[2]) + { + std::string& s0 = static_cast*> (branch[0])->ref (); + std::string s1 = static_cast*>(branch[1])->str (); + range_t rp0 = static_cast*> (branch[0])->range(); + range_t rp1 = static_cast*>(branch[1])->range(); + + static_cast*> (branch[0])->range_ref().clear(); + static_cast*>(branch[1])->range_ref().clear(); + + details::free_node(*node_allocator_,branch[0]); + details::free_node(*node_allocator_,branch[1]); + + return synthesize_str_xroxr_expression_impl(opr,s0,s1,rp0,rp1); + } + + inline expression_node_ptr synthesize_csocs_expression(const details::operator_type& opr, expression_node_ptr (&branch)[2]) + { + const std::string s0 = static_cast*>(branch[0])->str(); + const std::string s1 = static_cast*>(branch[1])->str(); + + expression_node_ptr result = error_node(); + + if (details::e_add == opr) + result = node_allocator_->allocate_c >(s0 + s1); + else if (details::e_in == opr) + result = node_allocator_->allocate_c >(details::in_op::process(s0,s1)); + else if (details::e_like == opr) + result = node_allocator_->allocate_c >(details::like_op::process(s0,s1)); + else if (details::e_ilike == opr) + result = node_allocator_->allocate_c >(details::ilike_op::process(s0,s1)); + else + { + expression_node_ptr temp = synthesize_sos_expression_impl(opr,s0,s1); + Type v = temp->value(); + details::free_node(*node_allocator_,temp); + result = node_allocator_->allocate(v); + } + + details::free_all_nodes(*node_allocator_,branch); + + return result; + } + + inline expression_node_ptr synthesize_csocsr_expression(const details::operator_type& opr, expression_node_ptr (&branch)[2]) + { + const std::string s0 = static_cast*> (branch[0])->str (); + std::string s1 = static_cast*>(branch[1])->str (); + range_t rp1 = static_cast*>(branch[1])->range(); + + static_cast*>(branch[1])->range_ref().clear(); + + free_node(*node_allocator_,branch[0]); + free_node(*node_allocator_,branch[1]); + + return synthesize_str_xoxr_expression_impl(opr,s0,s1,rp1); + } + + inline expression_node_ptr synthesize_csros_expression(const details::operator_type& opr, expression_node_ptr (&branch)[2]) + { + std::string s0 = static_cast*>(branch[0])->str (); + std::string& s1 = static_cast*> (branch[1])->ref (); + range_t rp0 = static_cast*>(branch[0])->range(); + + static_cast*>(branch[0])->range_ref().clear(); + + free_node(*node_allocator_,branch[0]); + + return synthesize_str_xrox_expression_impl(opr,s0,s1,rp0); + } + + inline expression_node_ptr synthesize_csrosr_expression(const details::operator_type& opr, expression_node_ptr (&branch)[2]) + { + const std::string s0 = static_cast*>(branch[0])->str (); + std::string& s1 = static_cast*> (branch[1])->ref (); + range_t rp0 = static_cast*>(branch[0])->range(); + range_t rp1 = static_cast*> (branch[1])->range(); + + static_cast*>(branch[0])->range_ref().clear(); + static_cast*> (branch[1])->range_ref().clear(); + + free_node(*node_allocator_,branch[0]); + free_node(*node_allocator_,branch[1]); + + return synthesize_str_xroxr_expression_impl(opr,s0,s1,rp0,rp1); + } + + inline expression_node_ptr synthesize_csrocs_expression(const details::operator_type& opr, expression_node_ptr (&branch)[2]) + { + std::string s0 = static_cast*>(branch[0])->str (); + const std::string s1 = static_cast*> (branch[1])->str (); + range_t rp0 = static_cast*>(branch[0])->range(); + + static_cast*>(branch[0])->range_ref().clear(); + + details::free_all_nodes(*node_allocator_,branch); + + return synthesize_str_xrox_expression_impl(opr,s0,s1,rp0); + } + + inline expression_node_ptr synthesize_csrocsr_expression(const details::operator_type& opr, expression_node_ptr (&branch)[2]) + { + std::string s0 = static_cast*>(branch[0])->str (); + std::string s1 = static_cast*>(branch[1])->str (); + range_t rp0 = static_cast*>(branch[0])->range(); + range_t rp1 = static_cast*>(branch[1])->range(); + + static_cast*>(branch[0])->range_ref().clear(); + static_cast*>(branch[1])->range_ref().clear(); + + details::free_all_nodes(*node_allocator_,branch); + + return synthesize_str_xroxr_expression_impl(opr,s0,s1,rp0,rp1); + } + + inline expression_node_ptr synthesize_strogen_expression(const details::operator_type& opr, expression_node_ptr (&branch)[2]) + { + switch (opr) + { + #define case_stmt(op0,op1) \ + case op0 : return node_allocator_-> \ + allocate_ttt > > \ + (opr,branch[0],branch[1]); \ + + string_opr_switch_statements + #undef case_stmt + default : return error_node(); + } + } + #endif + + #ifndef exprtk_disable_string_capabilities + inline expression_node_ptr synthesize_string_expression(const details::operator_type& opr, expression_node_ptr (&branch)[2]) + { + if ((0 == branch[0]) || (0 == branch[1])) + { + details::free_all_nodes(*node_allocator_,branch); + + return error_node(); + } + + const bool b0_is_s = details::is_string_node (branch[0]); + const bool b0_is_cs = details::is_const_string_node (branch[0]); + const bool b0_is_sr = details::is_string_range_node (branch[0]); + const bool b0_is_csr = details::is_const_string_range_node(branch[0]); + + const bool b1_is_s = details::is_string_node (branch[1]); + const bool b1_is_cs = details::is_const_string_node (branch[1]); + const bool b1_is_sr = details::is_string_range_node (branch[1]); + const bool b1_is_csr = details::is_const_string_range_node(branch[1]); + + const bool b0_is_gen = details::is_string_assignment_node (branch[0]) || + details::is_genricstring_range_node(branch[0]) || + details::is_string_concat_node (branch[0]) || + details::is_string_function_node (branch[0]) || + details::is_string_condition_node (branch[0]) || + details::is_string_ccondition_node (branch[0]) || + details::is_string_vararg_node (branch[0]) ; + + const bool b1_is_gen = details::is_string_assignment_node (branch[1]) || + details::is_genricstring_range_node(branch[1]) || + details::is_string_concat_node (branch[1]) || + details::is_string_function_node (branch[1]) || + details::is_string_condition_node (branch[1]) || + details::is_string_ccondition_node (branch[1]) || + details::is_string_vararg_node (branch[1]) ; + + if (details::e_add == opr) + { + if (!b0_is_cs || !b1_is_cs) + { + return synthesize_expression(opr,branch); + } + } + + if (b0_is_gen || b1_is_gen) + { + return synthesize_strogen_expression(opr,branch); + } + else if (b0_is_s) + { + if (b1_is_s ) return synthesize_sos_expression (opr,branch); + else if (b1_is_cs ) return synthesize_socs_expression (opr,branch); + else if (b1_is_sr ) return synthesize_sosr_expression (opr,branch); + else if (b1_is_csr) return synthesize_socsr_expression (opr,branch); + } + else if (b0_is_cs) + { + if (b1_is_s ) return synthesize_csos_expression (opr,branch); + else if (b1_is_cs ) return synthesize_csocs_expression (opr,branch); + else if (b1_is_sr ) return synthesize_csosr_expression (opr,branch); + else if (b1_is_csr) return synthesize_csocsr_expression(opr,branch); + } + else if (b0_is_sr) + { + if (b1_is_s ) return synthesize_sros_expression (opr,branch); + else if (b1_is_sr ) return synthesize_srosr_expression (opr,branch); + else if (b1_is_cs ) return synthesize_srocs_expression (opr,branch); + else if (b1_is_csr) return synthesize_srocsr_expression(opr,branch); + } + else if (b0_is_csr) + { + if (b1_is_s ) return synthesize_csros_expression (opr,branch); + else if (b1_is_sr ) return synthesize_csrosr_expression (opr,branch); + else if (b1_is_cs ) return synthesize_csrocs_expression (opr,branch); + else if (b1_is_csr) return synthesize_csrocsr_expression(opr,branch); + } + + return error_node(); + } + #else + inline expression_node_ptr synthesize_string_expression(const details::operator_type&, expression_node_ptr (&branch)[2]) + { + details::free_all_nodes(*node_allocator_,branch); + return error_node(); + } + #endif + + #ifndef exprtk_disable_string_capabilities + inline expression_node_ptr synthesize_string_expression(const details::operator_type& opr, expression_node_ptr (&branch)[3]) + { + if (details::e_inrange != opr) + return error_node(); + else if ((0 == branch[0]) || (0 == branch[1]) || (0 == branch[2])) + { + details::free_all_nodes(*node_allocator_,branch); + + return error_node(); + } + else if ( + details::is_const_string_node(branch[0]) && + details::is_const_string_node(branch[1]) && + details::is_const_string_node(branch[2]) + ) + { + const std::string s0 = static_cast*>(branch[0])->str(); + const std::string s1 = static_cast*>(branch[1])->str(); + const std::string s2 = static_cast*>(branch[2])->str(); + + Type v = (((s0 <= s1) && (s1 <= s2)) ? Type(1) : Type(0)); + details::free_all_nodes(*node_allocator_,branch); + + return node_allocator_->allocate_c >(v); + } + else if ( + details::is_string_node(branch[0]) && + details::is_string_node(branch[1]) && + details::is_string_node(branch[2]) + ) + { + std::string& s0 = static_cast*>(branch[0])->ref(); + std::string& s1 = static_cast*>(branch[1])->ref(); + std::string& s2 = static_cast*>(branch[2])->ref(); + + typedef typename details::sosos_node > inrange_t; + + return node_allocator_->allocate_type(s0,s1,s2); + } + else if ( + details::is_const_string_node(branch[0]) && + details::is_string_node(branch[1]) && + details::is_const_string_node(branch[2]) + ) + { + std::string s0 = static_cast*>(branch[0])->str(); + std::string& s1 = static_cast< details::stringvar_node*>(branch[1])->ref(); + std::string s2 = static_cast*>(branch[2])->str(); + + typedef typename details::sosos_node > inrange_t; + + details::free_node(*node_allocator_,branch[0]); + details::free_node(*node_allocator_,branch[2]); + + return node_allocator_->allocate_type(s0,s1,s2); + } + else if ( + details::is_string_node(branch[0]) && + details::is_const_string_node(branch[1]) && + details::is_string_node(branch[2]) + ) + { + std::string& s0 = static_cast< details::stringvar_node*>(branch[0])->ref(); + std::string s1 = static_cast*>(branch[1])->str(); + std::string& s2 = static_cast< details::stringvar_node*>(branch[2])->ref(); + + typedef typename details::sosos_node > inrange_t; + + details::free_node(*node_allocator_,branch[1]); + + return node_allocator_->allocate_type(s0,s1,s2); + } + else if ( + details::is_string_node(branch[0]) && + details::is_string_node(branch[1]) && + details::is_const_string_node(branch[2]) + ) + { + std::string& s0 = static_cast< details::stringvar_node*>(branch[0])->ref(); + std::string& s1 = static_cast< details::stringvar_node*>(branch[1])->ref(); + std::string s2 = static_cast*>(branch[2])->str(); + + typedef typename details::sosos_node > inrange_t; + + details::free_node(*node_allocator_,branch[2]); + + return node_allocator_->allocate_type(s0,s1,s2); + } + else if ( + details::is_const_string_node(branch[0]) && + details:: is_string_node(branch[1]) && + details:: is_string_node(branch[2]) + ) + { + std::string s0 = static_cast*>(branch[0])->str(); + std::string& s1 = static_cast< details::stringvar_node*>(branch[1])->ref(); + std::string& s2 = static_cast< details::stringvar_node*>(branch[2])->ref(); + + typedef typename details::sosos_node > inrange_t; + + details::free_node(*node_allocator_,branch[0]); + + return node_allocator_->allocate_type(s0,s1,s2); + } + else + return error_node(); + } + #else + inline expression_node_ptr synthesize_string_expression(const details::operator_type&, expression_node_ptr (&branch)[3]) + { + details::free_all_nodes(*node_allocator_,branch); + return error_node(); + } + #endif + + inline expression_node_ptr synthesize_null_expression(const details::operator_type& operation, expression_node_ptr (&branch)[2]) + { + /* + Note: The following are the type promotion rules + that relate to operations that include 'null': + 0. null ==/!= null --> true false + 1. null operation null --> null + 2. x ==/!= null --> true/false + 3. null ==/!= x --> true/false + 4. x operation null --> x + 5. null operation x --> x + */ + + typedef typename details::null_eq_node nulleq_node_t; + + bool b0_null = details::is_null_node(branch[0]); + bool b1_null = details::is_null_node(branch[1]); + + if (b0_null && b1_null) + { + expression_node_ptr result = error_node(); + + if (details::e_eq == operation) + result = node_allocator_->allocate_c(T(1)); + else if (details::e_ne == operation) + result = node_allocator_->allocate_c(T(0)); + + if (result) + { + details::free_node(*node_allocator_,branch[0]); + details::free_node(*node_allocator_,branch[1]); + + return result; + } + + details::free_node(*node_allocator_,branch[1]); + + return branch[0]; + } + else if (details::e_eq == operation) + { + expression_node_ptr result = node_allocator_-> + allocate_rc(branch[b0_null ? 0 : 1],true); + + details::free_node(*node_allocator_,branch[b0_null ? 1 : 0]); + + return result; + } + else if (details::e_ne == operation) + { + expression_node_ptr result = node_allocator_-> + allocate_rc(branch[b0_null ? 0 : 1],false); + + details::free_node(*node_allocator_,branch[b0_null ? 1 : 0]); + + return result; + } + else if (b0_null) + { + details::free_node(*node_allocator_,branch[0]); + branch[0] = branch[1]; + branch[1] = error_node(); + } + else if (b1_null) + { + details::free_node(*node_allocator_,branch[1]); + branch[1] = error_node(); + } + + if ( + (details::e_add == operation) || (details::e_sub == operation) || + (details::e_mul == operation) || (details::e_div == operation) || + (details::e_mod == operation) || (details::e_pow == operation) + ) + { + return branch[0]; + } + else if ( + (details::e_lt == operation) || (details::e_lte == operation) || + (details::e_gt == operation) || (details::e_gte == operation) || + (details::e_and == operation) || (details::e_nand == operation) || + (details::e_or == operation) || (details::e_nor == operation) || + (details::e_xor == operation) || (details::e_xnor == operation) || + (details::e_in == operation) || (details::e_like == operation) || + (details::e_ilike == operation) + ) + { + return node_allocator_->allocate_c(T(0)); + } + + details::free_node(*node_allocator_,branch[0]); + + return node_allocator_->allocate >(); + } + + template + inline expression_node_ptr synthesize_expression(const details::operator_type& operation, expression_node_ptr (&branch)[N]) + { + if ( + (details::e_in == operation) || + (details::e_like == operation) || + (details::e_ilike == operation) + ) + return error_node(); + else if (!details::all_nodes_valid(branch)) + { + free_all_nodes(*node_allocator_,branch); + + return error_node(); + } + else if ((details::e_default != operation)) + { + // Attempt simple constant folding optimisation. + expression_node_ptr expression_point = node_allocator_->allocate(operation,branch); + + if (is_constant_foldable(branch)) + { + Type v = expression_point->value(); + details::free_node(*node_allocator_,expression_point); + + return node_allocator_->allocate(v); + } + else + return expression_point; + } + else + return error_node(); + } + + template + inline expression_node_ptr synthesize_expression(F* f, expression_node_ptr (&branch)[N]) + { + if (!details::all_nodes_valid(branch)) + { + free_all_nodes(*node_allocator_,branch); + + return error_node(); + } + + typedef typename details::function_N_node function_N_node_t; + + // Attempt simple constant folding optimisation. + + expression_node_ptr expression_point = node_allocator_->allocate(f); + function_N_node_t* func_node_ptr = dynamic_cast(expression_point); + + if (0 == func_node_ptr) + { + free_all_nodes(*node_allocator_,branch); + + return error_node(); + } + else + func_node_ptr->init_branches(branch); + + if (is_constant_foldable(branch) && !f->has_side_effects()) + { + Type v = expression_point->value(); + details::free_node(*node_allocator_,expression_point); + + return node_allocator_->allocate(v); + } + + parser_->state_.activate_side_effect("synthesize_expression(function)"); + + return expression_point; + } + + bool strength_reduction_enabled_; + details::node_allocator* node_allocator_; + synthesize_map_t synthesize_map_; + unary_op_map_t* unary_op_map_; + binary_op_map_t* binary_op_map_; + inv_binary_op_map_t* inv_binary_op_map_; + sf3_map_t* sf3_map_; + sf4_map_t* sf4_map_; + parser_t* parser_; + }; + + inline void set_error(const parser_error::type& error_type) + { + error_list_.push_back(error_type); + } + + inline void remove_last_error() + { + if (!error_list_.empty()) + { + error_list_.pop_back(); + } + } + + inline void set_synthesis_error(const std::string& synthesis_error_message) + { + if (synthesis_error_.empty()) + { + synthesis_error_ = synthesis_error_message; + } + } + + inline void register_local_vars(expression& e) + { + for (std::size_t i = 0; i < sem_.size(); ++i) + { + scope_element& se = sem_.get_element(i); + + if ( + (scope_element::e_variable == se.type) || + (scope_element::e_vecelem == se.type) + ) + { + if (se.var_node) + { + e.register_local_var(se.var_node); + } + + if (se.data) + { + e.register_local_data(se.data,1,0); + } + } + else if (scope_element::e_vector == se.type) + { + if (se.vec_node) + { + e.register_local_var(se.vec_node); + } + + if (se.data) + { + e.register_local_data(se.data,se.size,1); + } + } + #ifndef exprtk_disable_string_capabilities + else if (scope_element::e_string == se.type) + { + if (se.str_node) + { + e.register_local_var(se.str_node); + } + + if (se.data) + { + e.register_local_data(se.data,se.size,2); + } + } + #endif + + se.var_node = 0; + se.vec_node = 0; + #ifndef exprtk_disable_string_capabilities + se.str_node = 0; + #endif + se.data = 0; + se.ref_count = 0; + se.active = false; + } + } + + inline void register_return_results(expression& e) + { + e.register_return_results(results_context_); + results_context_ = 0; + } + + inline void load_unary_operations_map(unary_op_map_t& m) + { + #define register_unary_op(Op,UnaryFunctor) \ + m.insert(std::make_pair(Op,UnaryFunctor::process)); \ + + register_unary_op(details:: e_abs,details:: abs_op) + register_unary_op(details:: e_acos,details:: acos_op) + register_unary_op(details::e_acosh,details::acosh_op) + register_unary_op(details:: e_asin,details:: asin_op) + register_unary_op(details::e_asinh,details::asinh_op) + register_unary_op(details::e_atanh,details::atanh_op) + register_unary_op(details:: e_ceil,details:: ceil_op) + register_unary_op(details:: e_cos,details:: cos_op) + register_unary_op(details:: e_cosh,details:: cosh_op) + register_unary_op(details:: e_exp,details:: exp_op) + register_unary_op(details::e_expm1,details::expm1_op) + register_unary_op(details::e_floor,details::floor_op) + register_unary_op(details:: e_log,details:: log_op) + register_unary_op(details::e_log10,details::log10_op) + register_unary_op(details:: e_log2,details:: log2_op) + register_unary_op(details::e_log1p,details::log1p_op) + register_unary_op(details:: e_neg,details:: neg_op) + register_unary_op(details:: e_pos,details:: pos_op) + register_unary_op(details::e_round,details::round_op) + register_unary_op(details:: e_sin,details:: sin_op) + register_unary_op(details:: e_sinc,details:: sinc_op) + register_unary_op(details:: e_sinh,details:: sinh_op) + register_unary_op(details:: e_sqrt,details:: sqrt_op) + register_unary_op(details:: e_tan,details:: tan_op) + register_unary_op(details:: e_tanh,details:: tanh_op) + register_unary_op(details:: e_cot,details:: cot_op) + register_unary_op(details:: e_sec,details:: sec_op) + register_unary_op(details:: e_csc,details:: csc_op) + register_unary_op(details:: e_r2d,details:: r2d_op) + register_unary_op(details:: e_d2r,details:: d2r_op) + register_unary_op(details:: e_d2g,details:: d2g_op) + register_unary_op(details:: e_g2d,details:: g2d_op) + register_unary_op(details:: e_notl,details:: notl_op) + register_unary_op(details:: e_sgn,details:: sgn_op) + register_unary_op(details:: e_erf,details:: erf_op) + register_unary_op(details:: e_erfc,details:: erfc_op) + register_unary_op(details:: e_ncdf,details:: ncdf_op) + register_unary_op(details:: e_frac,details:: frac_op) + register_unary_op(details::e_trunc,details::trunc_op) + #undef register_unary_op + } + + inline void load_binary_operations_map(binary_op_map_t& m) + { + typedef typename binary_op_map_t::value_type value_type; + + #define register_binary_op(Op,BinaryFunctor) \ + m.insert(value_type(Op,BinaryFunctor::process)); \ + + register_binary_op(details:: e_add,details:: add_op) + register_binary_op(details:: e_sub,details:: sub_op) + register_binary_op(details:: e_mul,details:: mul_op) + register_binary_op(details:: e_div,details:: div_op) + register_binary_op(details:: e_mod,details:: mod_op) + register_binary_op(details:: e_pow,details:: pow_op) + register_binary_op(details:: e_lt,details:: lt_op) + register_binary_op(details:: e_lte,details:: lte_op) + register_binary_op(details:: e_gt,details:: gt_op) + register_binary_op(details:: e_gte,details:: gte_op) + register_binary_op(details:: e_eq,details:: eq_op) + register_binary_op(details:: e_ne,details:: ne_op) + register_binary_op(details:: e_and,details:: and_op) + register_binary_op(details::e_nand,details::nand_op) + register_binary_op(details:: e_or,details:: or_op) + register_binary_op(details:: e_nor,details:: nor_op) + register_binary_op(details:: e_xor,details:: xor_op) + register_binary_op(details::e_xnor,details::xnor_op) + #undef register_binary_op + } + + inline void load_inv_binary_operations_map(inv_binary_op_map_t& m) + { + typedef typename inv_binary_op_map_t::value_type value_type; + + #define register_binary_op(Op,BinaryFunctor) \ + m.insert(value_type(BinaryFunctor::process,Op)); \ + + register_binary_op(details:: e_add,details:: add_op) + register_binary_op(details:: e_sub,details:: sub_op) + register_binary_op(details:: e_mul,details:: mul_op) + register_binary_op(details:: e_div,details:: div_op) + register_binary_op(details:: e_mod,details:: mod_op) + register_binary_op(details:: e_pow,details:: pow_op) + register_binary_op(details:: e_lt,details:: lt_op) + register_binary_op(details:: e_lte,details:: lte_op) + register_binary_op(details:: e_gt,details:: gt_op) + register_binary_op(details:: e_gte,details:: gte_op) + register_binary_op(details:: e_eq,details:: eq_op) + register_binary_op(details:: e_ne,details:: ne_op) + register_binary_op(details:: e_and,details:: and_op) + register_binary_op(details::e_nand,details::nand_op) + register_binary_op(details:: e_or,details:: or_op) + register_binary_op(details:: e_nor,details:: nor_op) + register_binary_op(details:: e_xor,details:: xor_op) + register_binary_op(details::e_xnor,details::xnor_op) + #undef register_binary_op + } + + inline void load_sf3_map(sf3_map_t& sf3_map) + { + typedef std::pair pair_t; + + #define register_sf3(Op) \ + sf3_map[details::sf##Op##_op::id()] = pair_t(details::sf##Op##_op::process,details::e_sf##Op); \ + + register_sf3(00) register_sf3(01) register_sf3(02) register_sf3(03) + register_sf3(04) register_sf3(05) register_sf3(06) register_sf3(07) + register_sf3(08) register_sf3(09) register_sf3(10) register_sf3(11) + register_sf3(12) register_sf3(13) register_sf3(14) register_sf3(15) + register_sf3(16) register_sf3(17) register_sf3(18) register_sf3(19) + register_sf3(20) register_sf3(21) register_sf3(22) register_sf3(23) + register_sf3(24) register_sf3(25) register_sf3(26) register_sf3(27) + register_sf3(28) register_sf3(29) register_sf3(30) + #undef register_sf3 + } + + inline void load_sf4_map(sf4_map_t& sf4_map) + { + typedef std::pair pair_t; + + #define register_sf4(Op) \ + sf4_map[details::sf##Op##_op::id()] = pair_t(details::sf##Op##_op::process,details::e_sf##Op); \ + + register_sf4(48) register_sf4(49) register_sf4(50) register_sf4(51) + register_sf4(52) register_sf4(53) register_sf4(54) register_sf4(55) + register_sf4(56) register_sf4(57) register_sf4(58) register_sf4(59) + register_sf4(60) register_sf4(61) register_sf4(62) register_sf4(63) + register_sf4(64) register_sf4(65) register_sf4(66) register_sf4(67) + register_sf4(68) register_sf4(69) register_sf4(70) register_sf4(71) + register_sf4(72) register_sf4(73) register_sf4(74) register_sf4(75) + register_sf4(76) register_sf4(77) register_sf4(78) register_sf4(79) + register_sf4(80) register_sf4(81) register_sf4(82) register_sf4(83) + #undef register_sf4 + + #define register_sf4ext(Op) \ + sf4_map[details::sfext##Op##_op::id()] = pair_t(details::sfext##Op##_op::process,details::e_sf4ext##Op); \ + + register_sf4ext(00) register_sf4ext(01) register_sf4ext(02) register_sf4ext(03) + register_sf4ext(04) register_sf4ext(05) register_sf4ext(06) register_sf4ext(07) + register_sf4ext(08) register_sf4ext(09) register_sf4ext(10) register_sf4ext(11) + register_sf4ext(12) register_sf4ext(13) register_sf4ext(14) register_sf4ext(15) + register_sf4ext(16) register_sf4ext(17) register_sf4ext(18) register_sf4ext(19) + register_sf4ext(20) register_sf4ext(21) register_sf4ext(22) register_sf4ext(23) + register_sf4ext(24) register_sf4ext(25) register_sf4ext(26) register_sf4ext(27) + register_sf4ext(28) register_sf4ext(29) register_sf4ext(30) register_sf4ext(31) + register_sf4ext(32) register_sf4ext(33) register_sf4ext(34) register_sf4ext(35) + register_sf4ext(36) register_sf4ext(36) register_sf4ext(38) register_sf4ext(39) + register_sf4ext(40) register_sf4ext(41) register_sf4ext(42) register_sf4ext(43) + register_sf4ext(44) register_sf4ext(45) register_sf4ext(46) register_sf4ext(47) + register_sf4ext(48) register_sf4ext(49) register_sf4ext(50) register_sf4ext(51) + register_sf4ext(52) register_sf4ext(53) register_sf4ext(54) register_sf4ext(55) + register_sf4ext(56) register_sf4ext(57) register_sf4ext(58) register_sf4ext(59) + register_sf4ext(60) register_sf4ext(61) + #undef register_sf4ext + } + + inline results_context_t& results_ctx() + { + if (0 == results_context_) + { + results_context_ = new results_context_t(); + } + + return (*results_context_); + } + + inline void return_cleanup() + { + #ifndef exprtk_disable_return_statement + if (results_context_) + { + delete results_context_; + results_context_ = 0; + } + + state_.return_stmt_present = false; + #endif + } + + private: + + parser(const parser&); + parser& operator=(const parser&); + + settings_store settings_; + expression_generator expression_generator_; + details::node_allocator node_allocator_; + symtab_store symtab_store_; + dependent_entity_collector dec_; + std::deque error_list_; + std::deque brkcnt_list_; + parser_state state_; + bool resolve_unknown_symbol_; + results_context_t* results_context_; + unknown_symbol_resolver* unknown_symbol_resolver_; + unknown_symbol_resolver default_usr_; + base_ops_map_t base_ops_map_; + unary_op_map_t unary_op_map_; + binary_op_map_t binary_op_map_; + inv_binary_op_map_t inv_binary_op_map_; + sf3_map_t sf3_map_; + sf4_map_t sf4_map_; + std::string synthesis_error_; + scope_element_manager sem_; + + lexer::helper::helper_assembly helper_assembly_; + + lexer::helper::commutative_inserter commutative_inserter_; + lexer::helper::operator_joiner operator_joiner_2_; + lexer::helper::operator_joiner operator_joiner_3_; + lexer::helper::symbol_replacer symbol_replacer_; + lexer::helper::bracket_checker bracket_checker_; + lexer::helper::numeric_checker numeric_checker_; + lexer::helper::sequence_validator sequence_validator_; + + template + friend void details::disable_type_checking(ParserType& p); + }; + + template class Sequence> + inline bool collect_variables(const std::string& expr_str, + Sequence& symbol_list) + { + typedef double T; + typedef exprtk::symbol_table symbol_table_t; + typedef exprtk::expression expression_t; + typedef exprtk::parser parser_t; + typedef parser_t::dependent_entity_collector::symbol_t symbol_t; + + symbol_table_t symbol_table; + expression_t expression; + parser_t parser; + + expression.register_symbol_table(symbol_table); + + parser.enable_unknown_symbol_resolver(); + parser.dec().collect_variables() = true; + + if (!parser.compile(expr_str, expression)) + return false; + + std::deque symb_list; + + parser.dec().symbols(symb_list); + + for (std::size_t i = 0; i < symb_list.size(); ++i) + { + symbol_list.push_back(symb_list[i].first); + } + + return true; + } + + template class Sequence> + inline bool collect_variables(const std::string& expr_str, + exprtk::symbol_table& extrnl_symbol_table, + Sequence& symbol_list) + { + typedef exprtk::symbol_table symbol_table_t; + typedef exprtk::expression expression_t; + typedef exprtk::parser parser_t; + typedef typename parser_t::dependent_entity_collector::symbol_t symbol_t; + + symbol_table_t symbol_table; + expression_t expression; + parser_t parser; + + expression.register_symbol_table(symbol_table); + expression.register_symbol_table(extrnl_symbol_table); + + parser.enable_unknown_symbol_resolver(); + parser.dec().collect_variables() = true; + + details::disable_type_checking(parser); + + if (!parser.compile(expr_str, expression)) + return false; + + std::deque symb_list; + + parser.dec().symbols(symb_list); + + for (std::size_t i = 0; i < symb_list.size(); ++i) + { + symbol_list.push_back(symb_list[i].first); + } + + return true; + } + + template class Sequence> + inline bool collect_functions(const std::string& expr_str, + Sequence& symbol_list) + { + typedef double T; + typedef exprtk::symbol_table symbol_table_t; + typedef exprtk::expression expression_t; + typedef exprtk::parser parser_t; + typedef parser_t::dependent_entity_collector::symbol_t symbol_t; + + symbol_table_t symbol_table; + expression_t expression; + parser_t parser; + + expression.register_symbol_table(symbol_table); + + parser.enable_unknown_symbol_resolver(); + parser.dec().collect_functions() = true; + + if (!parser.compile(expr_str, expression)) + return false; + + std::deque symb_list; + + parser.dec().symbols(symb_list); + + for (std::size_t i = 0; i < symb_list.size(); ++i) + { + symbol_list.push_back(symb_list[i].first); + } + + return true; + } + + template class Sequence> + inline bool collect_functions(const std::string& expr_str, + exprtk::symbol_table& extrnl_symbol_table, + Sequence& symbol_list) + { + typedef exprtk::symbol_table symbol_table_t; + typedef exprtk::expression expression_t; + typedef exprtk::parser parser_t; + typedef typename parser_t::dependent_entity_collector::symbol_t symbol_t; + + symbol_table_t symbol_table; + expression_t expression; + parser_t parser; + + expression.register_symbol_table(symbol_table); + expression.register_symbol_table(extrnl_symbol_table); + + parser.enable_unknown_symbol_resolver(); + parser.dec().collect_functions() = true; + + details::disable_type_checking(parser); + + if (!parser.compile(expr_str, expression)) + return false; + + std::deque symb_list; + + parser.dec().symbols(symb_list); + + for (std::size_t i = 0; i < symb_list.size(); ++i) + { + symbol_list.push_back(symb_list[i].first); + } + + return true; + } + + template + inline T integrate(const expression& e, + T& x, + const T& r0, const T& r1, + const std::size_t number_of_intervals = 1000000) + { + if (r0 > r1) + return T(0); + + T h = (r1 - r0) / (T(2) * number_of_intervals); + T total_area = T(0); + + for (std::size_t i = 0; i < number_of_intervals; ++i) + { + x = r0 + T(2) * i * h; + T y0 = e.value(); x += h; + T y1 = e.value(); x += h; + T y2 = e.value(); x += h; + total_area += h * (y0 + T(4) * y1 + y2) / T(3); + } + + return total_area; + } + + template + inline T integrate(const expression& e, + const std::string& variable_name, + const T& r0, const T& r1, + const std::size_t number_of_intervals = 1000000) + { + const symbol_table& sym_table = e.get_symbol_table(); + + if (!sym_table.valid()) + return std::numeric_limits::quiet_NaN(); + + details::variable_node* var = sym_table.get_variable(variable_name); + + if (var) + { + T& x = var->ref(); + T x_original = x; + T result = integrate(e,x,r0,r1,number_of_intervals); + x = x_original; + + return result; + } + else + return std::numeric_limits::quiet_NaN(); + } + + template + inline T derivative(const expression& e, + T& x, + const T& h = T(0.00000001)) + { + const T x_init = x; + const T _2h = T(2) * h; + + x = x_init + _2h; + T y0 = e.value(); + x = x_init + h; + T y1 = e.value(); + x = x_init - h; + T y2 = e.value(); + x = x_init - _2h; + T y3 = e.value(); + x = x_init; + + return (-y0 + T(8) * (y1 - y2) + y3) / (T(12) * h); + } + + template + inline T second_derivative(const expression& e, + T& x, + const T& h = T(0.00001)) + { + const T x_init = x; + const T _2h = T(2) * h; + + T y = e.value(); + x = x_init + _2h; + T y0 = e.value(); + x = x_init + h; + T y1 = e.value(); + x = x_init - h; + T y2 = e.value(); + x = x_init - _2h; + T y3 = e.value(); + x = x_init; + + return (-y0 + T(16) * (y1 + y2) - T(30) * y - y3) / (T(12) * h * h); + } + + template + inline T third_derivative(const expression& e, + T& x, + const T& h = T(0.0001)) + { + const T x_init = x; + const T _2h = T(2) * h; + + x = x_init + _2h; + T y0 = e.value(); + x = x_init + h; + T y1 = e.value(); + x = x_init - h; + T y2 = e.value(); + x = x_init - _2h; + T y3 = e.value(); + x = x_init; + + return (y0 + T(2) * (y2 - y1) - y3) / (T(2) * h * h * h); + } + + template + inline T derivative(const expression& e, + const std::string& variable_name, + const T& h = T(0.00000001)) + { + const symbol_table& sym_table = e.get_symbol_table(); + + if (!sym_table.valid()) + { + return std::numeric_limits::quiet_NaN(); + } + + details::variable_node* var = sym_table.get_variable(variable_name); + + if (var) + { + T& x = var->ref(); + T x_original = x; + T result = derivative(e,x,h); + x = x_original; + + return result; + } + else + return std::numeric_limits::quiet_NaN(); + } + + template + inline T second_derivative(const expression& e, + const std::string& variable_name, + const T& h = T(0.00001)) + { + const symbol_table& sym_table = e.get_symbol_table(); + + if (!sym_table.valid()) + { + return std::numeric_limits::quiet_NaN(); + } + + details::variable_node* var = sym_table.get_variable(variable_name); + + if (var) + { + T& x = var->ref(); + T x_original = x; + T result = second_derivative(e,x,h); + x = x_original; + + return result; + } + else + return std::numeric_limits::quiet_NaN(); + } + + template + inline T third_derivative(const expression& e, + const std::string& variable_name, + const T& h = T(0.0001)) + { + const symbol_table& sym_table = e.get_symbol_table(); + + if (!sym_table.valid()) + { + return std::numeric_limits::quiet_NaN(); + } + + details::variable_node* var = sym_table.get_variable(variable_name); + + if (var) + { + T& x = var->ref(); + T x_original = x; + T result = third_derivative(e,x,h); + x = x_original; + + return result; + } + else + return std::numeric_limits::quiet_NaN(); + } + + /* + Note: The following 'compute' routines are simple helpers, + for quickly setting up the required pieces of code in order + to evaluate an expression. By virtue of how they operate + there will be an overhead with regards to their setup and + teardown and hence should not be used in time critical + sections of code. + Furthermore they only assume a small sub set of variables, + no string variables or user defined functions. + */ + template + inline bool compute(const std::string& expression_string, T& result) + { + // No variables + symbol_table symbol_table; + symbol_table.add_constants(); + + expression expression; + expression.register_symbol_table(symbol_table); + + parser parser; + + if (parser.compile(expression_string,expression)) + { + result = expression.value(); + + return true; + } + else + return false; + } + + template + inline bool compute(const std::string& expression_string, + const T& x, + T& result) + { + // Only 'x' + static const std::string x_var("x"); + + symbol_table symbol_table; + symbol_table.add_constants(); + symbol_table.add_constant(x_var,x); + + expression expression; + expression.register_symbol_table(symbol_table); + + parser parser; + + if (parser.compile(expression_string,expression)) + { + result = expression.value(); + + return true; + } + else + return false; + } + + template + inline bool compute(const std::string& expression_string, + const T&x, const T& y, + T& result) + { + // Only 'x' and 'y' + static const std::string x_var("x"); + static const std::string y_var("y"); + + symbol_table symbol_table; + symbol_table.add_constants(); + symbol_table.add_constant(x_var,x); + symbol_table.add_constant(y_var,y); + + expression expression; + expression.register_symbol_table(symbol_table); + + parser parser; + + if (parser.compile(expression_string,expression)) + { + result = expression.value(); + + return true; + } + else + return false; + } + + template + inline bool compute(const std::string& expression_string, + const T& x, const T& y, const T& z, + T& result) + { + // Only 'x', 'y' or 'z' + static const std::string x_var("x"); + static const std::string y_var("y"); + static const std::string z_var("z"); + + symbol_table symbol_table; + symbol_table.add_constants(); + symbol_table.add_constant(x_var,x); + symbol_table.add_constant(y_var,y); + symbol_table.add_constant(z_var,z); + + expression expression; + expression.register_symbol_table(symbol_table); + + parser parser; + + if (parser.compile(expression_string,expression)) + { + result = expression.value(); + + return true; + } + else + return false; + } + + template + class polynomial : public ifunction + { + private: + + template + struct poly_impl { }; + + template + struct poly_impl + { + static inline T evaluate(const Type x, + const Type c12, const Type c11, const Type c10, const Type c9, const Type c8, + const Type c7, const Type c6, const Type c5, const Type c4, const Type c3, + const Type c2, const Type c1, const Type c0) + { + // p(x) = c_12x^12 + c_11x^11 + c_10x^10 + c_9x^9 + c_8x^8 + c_7x^7 + c_6x^6 + c_5x^5 + c_4x^4 + c_3x^3 + c_2x^2 + c_1x^1 + c_0x^0 + return ((((((((((((c12 * x + c11) * x + c10) * x + c9) * x + c8) * x + c7) * x + c6) * x + c5) * x + c4) * x + c3) * x + c2) * x + c1) * x + c0); + } + }; + + template + struct poly_impl + { + static inline T evaluate(const Type x, + const Type c11, const Type c10, const Type c9, const Type c8, const Type c7, + const Type c6, const Type c5, const Type c4, const Type c3, const Type c2, + const Type c1, const Type c0) + { + // p(x) = c_11x^11 + c_10x^10 + c_9x^9 + c_8x^8 + c_7x^7 + c_6x^6 + c_5x^5 + c_4x^4 + c_3x^3 + c_2x^2 + c_1x^1 + c_0x^0 + return (((((((((((c11 * x + c10) * x + c9) * x + c8) * x + c7) * x + c6) * x + c5) * x + c4) * x + c3) * x + c2) * x + c1) * x + c0); + } + }; + + template + struct poly_impl + { + static inline T evaluate(const Type x, + const Type c10, const Type c9, const Type c8, const Type c7, const Type c6, + const Type c5, const Type c4, const Type c3, const Type c2, const Type c1, + const Type c0) + { + // p(x) = c_10x^10 + c_9x^9 + c_8x^8 + c_7x^7 + c_6x^6 + c_5x^5 + c_4x^4 + c_3x^3 + c_2x^2 + c_1x^1 + c_0x^0 + return ((((((((((c10 * x + c9) * x + c8) * x + c7) * x + c6) * x + c5) * x + c4) * x + c3) * x + c2) * x + c1) * x + c0); + } + }; + + template + struct poly_impl + { + static inline T evaluate(const Type x, + const Type c9, const Type c8, const Type c7, const Type c6, const Type c5, + const Type c4, const Type c3, const Type c2, const Type c1, const Type c0) + { + // p(x) = c_9x^9 + c_8x^8 + c_7x^7 + c_6x^6 + c_5x^5 + c_4x^4 + c_3x^3 + c_2x^2 + c_1x^1 + c_0x^0 + return (((((((((c9 * x + c8) * x + c7) * x + c6) * x + c5) * x + c4) * x + c3) * x + c2) * x + c1) * x + c0); + } + }; + + template + struct poly_impl + { + static inline T evaluate(const Type x, + const Type c8, const Type c7, const Type c6, const Type c5, const Type c4, + const Type c3, const Type c2, const Type c1, const Type c0) + { + // p(x) = c_8x^8 + c_7x^7 + c_6x^6 + c_5x^5 + c_4x^4 + c_3x^3 + c_2x^2 + c_1x^1 + c_0x^0 + return ((((((((c8 * x + c7) * x + c6) * x + c5) * x + c4) * x + c3) * x + c2) * x + c1) * x + c0); + } + }; + + template + struct poly_impl + { + static inline T evaluate(const Type x, + const Type c7, const Type c6, const Type c5, const Type c4, const Type c3, + const Type c2, const Type c1, const Type c0) + { + // p(x) = c_7x^7 + c_6x^6 + c_5x^5 + c_4x^4 + c_3x^3 + c_2x^2 + c_1x^1 + c_0x^0 + return (((((((c7 * x + c6) * x + c5) * x + c4) * x + c3) * x + c2) * x + c1) * x + c0); + } + }; + + template + struct poly_impl + { + static inline T evaluate(const Type x, + const Type c6, const Type c5, const Type c4, const Type c3, const Type c2, + const Type c1, const Type c0) + { + // p(x) = c_6x^6 + c_5x^5 + c_4x^4 + c_3x^3 + c_2x^2 + c_1x^1 + c_0x^0 + return ((((((c6 * x + c5) * x + c4) * x + c3) * x + c2) * x + c1) * x + c0); + } + }; + + template + struct poly_impl + { + static inline T evaluate(const Type x, + const Type c5, const Type c4, const Type c3, const Type c2, + const Type c1, const Type c0) + { + // p(x) = c_5x^5 + c_4x^4 + c_3x^3 + c_2x^2 + c_1x^1 + c_0x^0 + return (((((c5 * x + c4) * x + c3) * x + c2) * x + c1) * x + c0); + } + }; + + template + struct poly_impl + { + static inline T evaluate(const Type x, const Type c4, const Type c3, const Type c2, const Type c1, const Type c0) + { + // p(x) = c_4x^4 + c_3x^3 + c_2x^2 + c_1x^1 + c_0x^0 + return ((((c4 * x + c3) * x + c2) * x + c1) * x + c0); + } + }; + + template + struct poly_impl + { + static inline T evaluate(const Type x, const Type c3, const Type c2, const Type c1, const Type c0) + { + // p(x) = c_3x^3 + c_2x^2 + c_1x^1 + c_0x^0 + return (((c3 * x + c2) * x + c1) * x + c0); + } + }; + + template + struct poly_impl + { + static inline T evaluate(const Type x, const Type c2, const Type c1, const Type c0) + { + // p(x) = c_2x^2 + c_1x^1 + c_0x^0 + return ((c2 * x + c1) * x + c0); + } + }; + + template + struct poly_impl + { + static inline T evaluate(const Type x, const Type c1, const Type c0) + { + // p(x) = c_1x^1 + c_0x^0 + return (c1 * x + c0); + } + }; + + public: + + using ifunction::operator(); + + polynomial() + : ifunction((N+2 <= 20) ? (N + 2) : std::numeric_limits::max()) + { + disable_has_side_effects(*this); + } + + virtual ~polynomial() + {} + + #define poly_rtrn(NN) \ + return (NN != N) ? std::numeric_limits::quiet_NaN() : + + inline virtual T operator()(const T& x, const T& c1, const T& c0) + { + poly_rtrn(1) poly_impl::evaluate(x,c1,c0); + } + + inline virtual T operator()(const T& x, const T& c2, const T& c1, const T& c0) + { + poly_rtrn(2) poly_impl::evaluate(x,c2,c1,c0); + } + + inline virtual T operator()(const T& x, const T& c3, const T& c2, const T& c1, const T& c0) + { + poly_rtrn(3) poly_impl::evaluate(x,c3,c2,c1,c0); + } + + inline virtual T operator()(const T& x, const T& c4, const T& c3, const T& c2, const T& c1, const T& c0) + { + poly_rtrn(4) poly_impl::evaluate(x,c4,c3,c2,c1,c0); + } + + inline virtual T operator()(const T& x, const T& c5, const T& c4, const T& c3, const T& c2, const T& c1, const T& c0) + { + poly_rtrn(5) poly_impl::evaluate(x,c5,c4,c3,c2,c1,c0); + } + + inline virtual T operator()(const T& x, const T& c6, const T& c5, const T& c4, const T& c3, const T& c2, const T& c1, const T& c0) + { + poly_rtrn(6) poly_impl::evaluate(x,c6,c5,c4,c3,c2,c1,c0); + } + + inline virtual T operator()(const T& x, const T& c7, const T& c6, const T& c5, const T& c4, const T& c3, const T& c2, const T& c1, const T& c0) + { + poly_rtrn(7) poly_impl::evaluate(x,c7,c6,c5,c4,c3,c2,c1,c0); + } + + inline virtual T operator()(const T& x, const T& c8, const T& c7, const T& c6, const T& c5, const T& c4, const T& c3, const T& c2, const T& c1, const T& c0) + { + poly_rtrn(8) poly_impl::evaluate(x,c8,c7,c6,c5,c4,c3,c2,c1,c0); + } + + inline virtual T operator()(const T& x, const T& c9, const T& c8, const T& c7, const T& c6, const T& c5, const T& c4, const T& c3, const T& c2, const T& c1, const T& c0) + { + poly_rtrn(9) poly_impl::evaluate(x,c9,c8,c7,c6,c5,c4,c3,c2,c1,c0); + } + + inline virtual T operator()(const T& x, const T& c10, const T& c9, const T& c8, const T& c7, const T& c6, const T& c5, const T& c4, const T& c3, const T& c2, const T& c1, const T& c0) + { + poly_rtrn(10) poly_impl::evaluate(x,c10,c9,c8,c7,c6,c5,c4,c3,c2,c1,c0); + } + + inline virtual T operator()(const T& x, const T& c11, const T& c10, const T& c9, const T& c8, const T& c7, const T& c6, const T& c5, const T& c4, const T& c3, const T& c2, const T& c1, const T& c0) + { + poly_rtrn(11) poly_impl::evaluate(x,c11,c10,c9,c8,c7,c6,c5,c4,c3,c2,c1,c0); + } + + inline virtual T operator()(const T& x, const T& c12, const T& c11, const T& c10, const T& c9, const T& c8, const T& c7, const T& c6, const T& c5, const T& c4, const T& c3, const T& c2, const T& c1, const T& c0) + { + poly_rtrn(12) poly_impl::evaluate(x,c12,c11,c10,c9,c8,c7,c6,c5,c4,c3,c2,c1,c0); + } + + #undef poly_rtrn + + 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(); + } + }; + + template + class function_compositor + { + public: + + typedef exprtk::expression expression_t; + typedef exprtk::symbol_table symbol_table_t; + typedef exprtk::parser parser_t; + typedef typename parser_t::settings_store settings_t; + + struct function + { + function() + {} + + function(const std::string& n) + : name_(n) + {} + + function(const std::string& name, + const std::string& expression) + : name_(name), + expression_(expression) + {} + + function(const std::string& name, + const std::string& expression, + const std::string& v0) + : name_(name), + expression_(expression) + { + v_.push_back(v0); + } + + function(const std::string& name, + const std::string& expression, + const std::string& v0, const std::string& v1) + : name_(name), + expression_(expression) + { + v_.push_back(v0); v_.push_back(v1); + } + + function(const std::string& name, + const std::string& expression, + const std::string& v0, const std::string& v1, + const std::string& v2) + : name_(name), + expression_(expression) + { + v_.push_back(v0); v_.push_back(v1); + v_.push_back(v2); + } + + function(const std::string& name, + const std::string& expression, + const std::string& v0, const std::string& v1, + const std::string& v2, const std::string& v3) + : name_(name), + expression_(expression) + { + v_.push_back(v0); v_.push_back(v1); + v_.push_back(v2); v_.push_back(v3); + } + + function(const std::string& name, + const std::string& expression, + const std::string& v0, const std::string& v1, + const std::string& v2, const std::string& v3, + const std::string& v4) + : name_(name), + expression_(expression) + { + v_.push_back(v0); v_.push_back(v1); + v_.push_back(v2); v_.push_back(v3); + v_.push_back(v4); + } + + inline function& name(const std::string& n) + { + name_ = n; + return (*this); + } + + inline function& expression(const std::string& e) + { + expression_ = e; + return (*this); + } + + inline function& var(const std::string& v) + { + v_.push_back(v); + return (*this); + } + + std::string name_; + std::string expression_; + std::deque v_; + }; + + private: + + struct base_func : public exprtk::ifunction + { + typedef const T& type; + typedef exprtk::ifunction function_t; + typedef std::vector varref_t; + typedef std::vector var_t; + typedef std::pair lvarref_t; + typedef std::vector lvr_vec_t; + + using exprtk::ifunction::operator(); + + base_func(const std::size_t& pc = 0) + : exprtk::ifunction(pc), + local_var_stack_size(0), + stack_depth(0) + { + v.resize(pc); + } + + virtual ~base_func() + {} + + inline void update(const T& v0) + { + (*v[0]) = v0; + } + + inline void update(const T& v0, const T& v1) + { + (*v[0]) = v0; (*v[1]) = v1; + } + + inline void update(const T& v0, const T& v1, const T& v2) + { + (*v[0]) = v0; (*v[1]) = v1; + (*v[2]) = v2; + } + + inline void update(const T& v0, const T& v1, const T& v2, const T& v3) + { + (*v[0]) = v0; (*v[1]) = v1; + (*v[2]) = v2; (*v[3]) = v3; + } + + inline void update(const T& v0, const T& v1, const T& v2, const T& v3, const T& v4) + { + (*v[0]) = v0; (*v[1]) = v1; + (*v[2]) = v2; (*v[3]) = v3; + (*v[4]) = v4; + } + + inline void update(const T& v0, const T& v1, const T& v2, const T& v3, const T& v4, const T& v5) + { + (*v[0]) = v0; (*v[1]) = v1; + (*v[2]) = v2; (*v[3]) = v3; + (*v[4]) = v4; (*v[5]) = v5; + } + + inline function_t& setup(expression_t& expr) + { + expression = expr; + + typedef typename expression_t::control_block::local_data_list_t ldl_t; + + ldl_t ldl = expr.local_data_list(); + + std::vector index_list; + + for (std::size_t i = 0; i < ldl.size(); ++i) + { + if (ldl[i].size) + { + index_list.push_back(i); + } + } + + std::size_t input_param_count = 0; + + for (std::size_t i = 0; i < index_list.size(); ++i) + { + const std::size_t index = index_list[i]; + + if (i < (index_list.size() - v.size())) + { + lv.push_back( + std::make_pair( + reinterpret_cast(ldl[index].pointer), + ldl[index].size)); + + local_var_stack_size += ldl[index].size; + } + else + v[input_param_count++] = reinterpret_cast(ldl[index].pointer); + } + + clear_stack(); + + return (*this); + } + + inline void pre() + { + if (stack_depth++) + { + if (!v.empty()) + { + var_t var_stack(v.size(),T(0)); + copy(v,var_stack); + param_stack.push_back(var_stack); + } + + if (!lv.empty()) + { + var_t local_var_stack(local_var_stack_size,T(0)); + copy(lv,local_var_stack); + local_stack.push_back(local_var_stack); + } + } + } + + inline void post() + { + if (--stack_depth) + { + if (!v.empty()) + { + copy(param_stack.back(),v); + param_stack.pop_back(); + } + + if (!lv.empty()) + { + copy(local_stack.back(),lv); + local_stack.pop_back(); + } + } + } + + void copy(const varref_t& src_v, var_t& dest_v) + { + for (std::size_t i = 0; i < src_v.size(); ++i) + { + dest_v[i] = (*src_v[i]); + } + } + + void copy(const var_t& src_v, varref_t& dest_v) + { + for (std::size_t i = 0; i < src_v.size(); ++i) + { + (*dest_v[i]) = src_v[i]; + } + } + + void copy(const lvr_vec_t& src_v, var_t& dest_v) + { + typename var_t::iterator itr = dest_v.begin(); + + for (std::size_t i = 0; i < src_v.size(); ++i) + { + lvarref_t vr = src_v[i]; + + if (1 == vr.second) + *itr++ = (*vr.first); + else + { + std::copy(vr.first,vr.first + vr.second,itr); + itr += vr.second; + } + } + } + + void copy(const var_t& src_v, lvr_vec_t& dest_v) + { + typename var_t::const_iterator itr = src_v.begin(); + + for (std::size_t i = 0; i < src_v.size(); ++i) + { + lvarref_t vr = dest_v[i]; + + if (1 == vr.second) + (*vr.first) = *itr++; + else + { + std::copy(itr,itr + vr.second,vr.first); + itr += vr.second; + } + } + } + + inline void clear_stack() + { + for (std::size_t i = 0; i < v.size(); ++i) + { + (*v[i]) = 0; + } + } + + inline virtual T value(expression_t& e) + { + return e.value(); + } + + expression_t expression; + varref_t v; + lvr_vec_t lv; + std::size_t local_var_stack_size; + std::size_t stack_depth; + std::deque param_stack; + std::deque local_stack; + }; + + typedef std::map funcparam_t; + + struct func_0param : public base_func + { + using exprtk::ifunction::operator(); + + func_0param() : base_func(0) {} + + inline T operator()() + { + return this->value(base_func::expression); + } + }; + + typedef const T& type; + + template + struct scoped_bft + { + scoped_bft(BaseFuncType& bft) : bft_(bft) { bft_.pre (); } + ~scoped_bft() { bft_.post(); } + + BaseFuncType& bft_; + + private: + + scoped_bft(scoped_bft&); + scoped_bft& operator=(scoped_bft&); + }; + + struct func_1param : public base_func + { + using exprtk::ifunction::operator(); + + func_1param() : base_func(1) {} + + inline T operator()(type v0) + { + scoped_bft sb(*this); + base_func::update(v0); + T result = this->value(base_func::expression); + + return result; + } + }; + + struct func_2param : public base_func + { + using exprtk::ifunction::operator(); + + func_2param() : base_func(2) {} + + inline T operator()(type v0, type v1) + { + scoped_bft sb(*this); + base_func::update(v0,v1); + T result = this->value(base_func::expression); + + return result; + } + }; + + struct func_3param : public base_func + { + using exprtk::ifunction::operator(); + + func_3param() : base_func(3) {} + + inline T operator()(type v0, type v1, type v2) + { + scoped_bft sb(*this); + base_func::update(v0,v1,v2); + T result = this->value(base_func::expression); + + return result; + } + }; + + struct func_4param : public base_func + { + using exprtk::ifunction::operator(); + + func_4param() : base_func(4) {} + + inline T operator()(type v0, type v1, type v2, type v3) + { + scoped_bft sb(*this); + base_func::update(v0,v1,v2,v3); + T result = this->value(base_func::expression); + + return result; + } + }; + + struct func_5param : public base_func + { + using exprtk::ifunction::operator(); + + func_5param() : base_func(5) {} + + inline T operator()(type v0, type v1, type v2, type v3, type v4) + { + scoped_bft sb(*this); + base_func::update(v0,v1,v2,v3,v4); + T result = this->value(base_func::expression); + + return result; + } + }; + + struct func_6param : public base_func + { + using exprtk::ifunction::operator(); + + func_6param() : base_func(6) {} + + inline T operator()(type v0, type v1, type v2, type v3, type v4, type v5) + { + scoped_bft sb(*this); + base_func::update(v0,v1,v2,v3,v4,v5); + T result = this->value(base_func::expression); + + return result; + } + }; + + static T return_value(expression_t& e) + { + typedef exprtk::results_context results_context_t; + typedef typename results_context_t::type_store_t type_t; + typedef typename type_t::scalar_view scalar_t; + + T result = e.value(); + + if (e.return_invoked()) + { + // Due to the post compilation checks, it can be safely + // assumed that there will be at least one parameter + // and that the first parameter will always be scalar. + return scalar_t(e.results()[0])(); + } + + return result; + } + + #define def_fp_retval(N) \ + struct func_##N##param_retval : public func_##N##param \ + { \ + inline T value(expression_t& e) \ + { \ + return return_value(e); \ + } \ + }; \ + + def_fp_retval(0) + def_fp_retval(1) + def_fp_retval(2) + def_fp_retval(3) + def_fp_retval(4) + def_fp_retval(5) + def_fp_retval(6) + + template class Sequence> + inline bool add(const std::string& name, + const std::string& expression, + const Sequence& var_list, + const bool override = false) + { + const std::size_t n = var_list.size(); + + typename std::map::iterator itr = expr_map_.find(name); + + if (expr_map_.end() != itr) + { + if (!override) + { + exprtk_debug(("Compositor error(add): function '%s' already defined\n", + name.c_str())); + + return false; + } + + remove(name, var_list.size()); + } + + if (compile_expression(name,expression,var_list)) + { + fp_map_[n][name]->setup(expr_map_[name]); + + return true; + } + else + { + exprtk_debug(("Compositor error(add): Failed to compile function '%s'\n", + name.c_str())); + + return false; + } + } + + public: + + function_compositor() + : parser_(settings_t::compile_all_opts + + settings_t::e_disable_zero_return), + fp_map_(7) + {} + + function_compositor(const symbol_table_t& st) + : symbol_table_(st), + parser_(settings_t::compile_all_opts + + settings_t::e_disable_zero_return), + fp_map_(7) + {} + + ~function_compositor() + { + clear(); + } + + inline symbol_table_t& symbol_table() + { + return symbol_table_; + } + + inline void add_auxiliary_symtab(symbol_table_t& symtab) + { + auxiliary_symtab_list_.push_back(&symtab); + } + + void clear() + { + symbol_table_.clear(); + expr_map_ .clear(); + + for (std::size_t i = 0; i < fp_map_.size(); ++i) + { + typename funcparam_t::iterator itr = fp_map_[i].begin(); + typename funcparam_t::iterator end = fp_map_[i].end (); + + while (itr != end) + { + delete itr->second; + ++itr; + } + + fp_map_[i].clear(); + } + } + + inline bool add(const function& f, const bool override = false) + { + return add(f.name_,f.expression_,f.v_,override); + } + + private: + + template class Sequence> + bool compile_expression(const std::string& name, + const std::string& expression, + const Sequence& input_var_list, + bool return_present = false) + { + expression_t compiled_expression; + symbol_table_t local_symbol_table; + + local_symbol_table.load_from(symbol_table_); + local_symbol_table.add_constants(); + + if (!valid(name,input_var_list.size())) + return false; + + if (!forward(name, + input_var_list.size(), + local_symbol_table, + return_present)) + return false; + + compiled_expression.register_symbol_table(local_symbol_table); + + for (std::size_t i = 0; i < auxiliary_symtab_list_.size(); ++i) + { + compiled_expression.register_symbol_table((*auxiliary_symtab_list_[i])); + } + + std::string mod_expression; + + for (std::size_t i = 0; i < input_var_list.size(); ++i) + { + mod_expression += " var " + input_var_list[i] + "{};\n"; + } + + if ( + ('{' == details::front(expression)) && + ('}' == details::back (expression)) + ) + mod_expression += "~" + expression + ";"; + else + mod_expression += "~{" + expression + "};"; + + if (!parser_.compile(mod_expression,compiled_expression)) + { + exprtk_debug(("Compositor Error: %s\n",parser_.error().c_str())); + exprtk_debug(("Compositor modified expression: \n%s\n",mod_expression.c_str())); + + remove(name,input_var_list.size()); + + return false; + } + + if (!return_present && parser_.dec().return_present()) + { + remove(name,input_var_list.size()); + + return compile_expression(name,expression,input_var_list,true); + } + + // Make sure every return point has a scalar as its first parameter + if (parser_.dec().return_present()) + { + typedef std::vector str_list_t; + + str_list_t ret_param_list = parser_.dec().return_param_type_list(); + + for (std::size_t i = 0; i < ret_param_list.size(); ++i) + { + const std::string& params = ret_param_list[i]; + + if (params.empty() || ('T' != params[0])) + { + exprtk_debug(("Compositor Error: Return statement in function '%s' is invalid\n", + name.c_str())); + + remove(name,input_var_list.size()); + + return false; + } + } + } + + expr_map_[name] = compiled_expression; + + exprtk::ifunction& ifunc = (*(fp_map_[input_var_list.size()])[name]); + + if (symbol_table_.add_function(name,ifunc)) + return true; + else + { + exprtk_debug(("Compositor Error: Failed to add function '%s' to symbol table\n", + name.c_str())); + return false; + } + } + + inline bool symbol_used(const std::string& symbol) const + { + return ( + symbol_table_.is_variable (symbol) || + symbol_table_.is_stringvar (symbol) || + symbol_table_.is_function (symbol) || + symbol_table_.is_vector (symbol) || + symbol_table_.is_vararg_function(symbol) + ); + } + + inline bool valid(const std::string& name, + const std::size_t& arg_count) const + { + if (arg_count > 6) + return false; + else if (symbol_used(name)) + return false; + else if (fp_map_[arg_count].end() != fp_map_[arg_count].find(name)) + return false; + else + return true; + } + + inline bool forward(const std::string& name, + const std::size_t& arg_count, + symbol_table_t& sym_table, + const bool ret_present = false) + { + switch (arg_count) + { + #define case_stmt(N) \ + case N : (fp_map_[arg_count])[name] = \ + (!ret_present) ? static_cast \ + (new func_##N##param) : \ + static_cast \ + (new func_##N##param_retval) ; \ + break; \ + + case_stmt(0) case_stmt(1) case_stmt(2) + case_stmt(3) case_stmt(4) case_stmt(5) + case_stmt(6) + #undef case_stmt + } + + exprtk::ifunction& ifunc = (*(fp_map_[arg_count])[name]); + + return sym_table.add_function(name,ifunc); + } + + inline void remove(const std::string& name, const std::size_t& arg_count) + { + if (arg_count > 6) + return; + + typename std::map::iterator em_itr = expr_map_.find(name); + + if (expr_map_.end() != em_itr) + { + expr_map_.erase(em_itr); + } + + typename funcparam_t::iterator fp_itr = fp_map_[arg_count].find(name); + + if (fp_map_[arg_count].end() != fp_itr) + { + delete fp_itr->second; + fp_map_[arg_count].erase(fp_itr); + } + + symbol_table_.remove_function(name); + } + + private: + + symbol_table_t symbol_table_; + parser_t parser_; + std::map expr_map_; + std::vector fp_map_; + std::vector auxiliary_symtab_list_; + }; + + template + inline bool pgo_primer() + { + static const std::string expression_list[] + = { + "(y + x)", + "2 * (y + x)", + "(2 * y + 2 * x)", + "(y + x / y) * (x - y / x)", + "x / ((x + y) * (x - y)) / y", + "1 - ((x * y) + (y / x)) - 3", + "sin(2 * x) + cos(pi / y)", + "1 - sin(2 * x) + cos(pi / y)", + "sqrt(1 - sin(2 * x) + cos(pi / y) / 3)", + "(x^2 / sin(2 * pi / y)) -x / 2", + "x + (cos(y - sin(2 / x * pi)) - sin(x - cos(2 * y / pi))) - y", + "clamp(-1.0, sin(2 * pi * x) + cos(y / 2 * pi), +1.0)", + "iclamp(-1.0, sin(2 * pi * x) + cos(y / 2 * pi), +1.0)", + "max(3.33, min(sqrt(1 - sin(2 * x) + cos(pi / y) / 3), 1.11))", + "if(avg(x,y) <= x + y, x - y, x * y) + 2 * pi / x", + "1.1x^1 + 2.2y^2 - 3.3x^3 + 4.4y^4 - 5.5x^5 + 6.6y^6 - 7.7x^27 + 8.8y^55", + "(yy + xx)", + "2 * (yy + xx)", + "(2 * yy + 2 * xx)", + "(yy + xx / yy) * (xx - yy / xx)", + "xx / ((xx + yy) * (xx - yy)) / yy", + "1 - ((xx * yy) + (yy / xx)) - 3", + "sin(2 * xx) + cos(pi / yy)", + "1 - sin(2 * xx) + cos(pi / yy)", + "sqrt(1 - sin(2 * xx) + cos(pi / yy) / 3)", + "(xx^2 / sin(2 * pi / yy)) -xx / 2", + "xx + (cos(yy - sin(2 / xx * pi)) - sin(xx - cos(2 * yy / pi))) - yy", + "clamp(-1.0, sin(2 * pi * xx) + cos(yy / 2 * pi), +1.0)", + "max(3.33, min(sqrt(1 - sin(2 * xx) + cos(pi / yy) / 3), 1.11))", + "if(avg(xx,yy) <= xx + yy, xx - yy, xx * yy) + 2 * pi / xx", + "1.1xx^1 + 2.2yy^2 - 3.3xx^3 + 4.4yy^4 - 5.5xx^5 + 6.6yy^6 - 7.7xx^27 + 8.8yy^55", + "(1.1*(2.2*(3.3*(4.4*(5.5*(6.6*(7.7*(8.8*(9.9+x)))))))))", + "(((((((((x+9.9)*8.8)*7.7)*6.6)*5.5)*4.4)*3.3)*2.2)*1.1)", + "(x + y) * z", "x + (y * z)", "(x + y) * 7", "x + (y * 7)", + "(x + 7) * y", "x + (7 * y)", "(7 + x) * y", "7 + (x * y)", + "(2 + x) * 3", "2 + (x * 3)", "(2 + 3) * x", "2 + (3 * x)", + "(x + 2) * 3", "x + (2 * 3)", + "(x + y) * (z / w)", "(x + y) * (z / 7)", "(x + y) * (7 / z)", "(x + 7) * (y / z)", + "(7 + x) * (y / z)", "(2 + x) * (y / z)", "(x + 2) * (y / 3)", "(2 + x) * (y / 3)", + "(x + 2) * (3 / y)", "x + (y * (z / w))", "x + (y * (z / 7))", "x + (y * (7 / z))", + "x + (7 * (y / z))", "7 + (x * (y / z))", "2 + (x * (3 / y))", "x + (2 * (y / 4))", + "2 + (x * (y / 3))", "x + (2 * (3 / y))", + "x + ((y * z) / w)", "x + ((y * z) / 7)", "x + ((y * 7) / z)", "x + ((7 * y) / z)", + "7 + ((y * z) / w)", "2 + ((x * 3) / y)", "x + ((2 * y) / 3)", "2 + ((x * y) / 3)", + "x + ((2 * 3) / y)", "(((x + y) * z) / w)", + "(((x + y) * z) / 7)", "(((x + y) * 7) / z)", "(((x + 7) * y) / z)", "(((7 + x) * y) / z)", + "(((2 + x) * 3) / y)", "(((x + 2) * y) / 3)", "(((2 + x) * y) / 3)", "(((x + 2) * 3) / y)", + "((x + (y * z)) / w)", "((x + (y * z)) / 7)", "((x + (y * 7)) / y)", "((x + (7 * y)) / z)", + "((7 + (x * y)) / z)", "((2 + (x * 3)) / y)", "((x + (2 * y)) / 3)", "((2 + (x * y)) / 3)", + "((x + (2 * 3)) / y)", + "(xx + yy) * zz", "xx + (yy * zz)", + "(xx + yy) * 7", "xx + (yy * 7)", + "(xx + 7) * yy", "xx + (7 * yy)", + "(7 + xx) * yy", "7 + (xx * yy)", + "(2 + x) * 3", "2 + (x * 3)", + "(2 + 3) * x", "2 + (3 * x)", + "(x + 2) * 3", "x + (2 * 3)", + "(xx + yy) * (zz / ww)", "(xx + yy) * (zz / 7)", + "(xx + yy) * (7 / zz)", "(xx + 7) * (yy / zz)", + "(7 + xx) * (yy / zz)", "(2 + xx) * (yy / zz)", + "(xx + 2) * (yy / 3)", "(2 + xx) * (yy / 3)", + "(xx + 2) * (3 / yy)", "xx + (yy * (zz / ww))", + "xx + (yy * (zz / 7))", "xx + (yy * (7 / zz))", + "xx + (7 * (yy / zz))", "7 + (xx * (yy / zz))", + "2 + (xx * (3 / yy))", "xx + (2 * (yy / 4))", + "2 + (xx * (yy / 3))", "xx + (2 * (3 / yy))", + "xx + ((yy * zz) / ww)", "xx + ((yy * zz) / 7)", + "xx + ((yy * 7) / zz)", "xx + ((7 * yy) / zz)", + "7 + ((yy * zz) / ww)", "2 + ((xx * 3) / yy)", + "xx + ((2 * yy) / 3)", "2 + ((xx * yy) / 3)", + "xx + ((2 * 3) / yy)", "(((xx + yy) * zz) / ww)", + "(((xx + yy) * zz) / 7)", "(((xx + yy) * 7) / zz)", + "(((xx + 7) * yy) / zz)", "(((7 + xx) * yy) / zz)", + "(((2 + xx) * 3) / yy)", "(((xx + 2) * yy) / 3)", + "(((2 + xx) * yy) / 3)", "(((xx + 2) * 3) / yy)", + "((xx + (yy * zz)) / ww)", "((xx + (yy * zz)) / 7)", + "((xx + (yy * 7)) / yy)", "((xx + (7 * yy)) / zz)", + "((7 + (xx * yy)) / zz)", "((2 + (xx * 3)) / yy)", + "((xx + (2 * yy)) / 3)", "((2 + (xx * yy)) / 3)", + "((xx + (2 * 3)) / yy)" + }; + static const std::size_t expression_list_size = sizeof(expression_list) / sizeof(std::string); + + T x = T(0); + T y = T(0); + T z = T(0); + T w = T(0); + T xx = T(0); + T yy = T(0); + T zz = T(0); + T ww = T(0); + + exprtk::symbol_table symbol_table; + symbol_table.add_constants(); + symbol_table.add_variable( "x", x); + symbol_table.add_variable( "y", y); + symbol_table.add_variable( "z", z); + symbol_table.add_variable( "w", w); + symbol_table.add_variable("xx",xx); + symbol_table.add_variable("yy",yy); + symbol_table.add_variable("zz",zz); + symbol_table.add_variable("ww",ww); + + typedef typename std::deque > expr_list_t; + expr_list_t expr_list; + + const std::size_t rounds = 50; + + { + for (std::size_t r = 0; r < rounds; ++r) + { + expr_list.clear(); + exprtk::parser parser; + + for (std::size_t i = 0; i < expression_list_size; ++i) + { + exprtk::expression expression; + expression.register_symbol_table(symbol_table); + + if (!parser.compile(expression_list[i],expression)) + { + return false; + } + + expr_list.push_back(expression); + } + } + } + + struct execute + { + static inline T process(T& x, T& y, expression& expression) + { + static const T lower_bound = T(-20); + static const T upper_bound = T(+20); + + T delta = T(0.1); + T total = T(0); + + for (x = lower_bound; x <= upper_bound; x += delta) + { + for (y = lower_bound; y <= upper_bound; y += delta) + { + total += expression.value(); + } + } + + return total; + } + }; + + for (std::size_t i = 0; i < expr_list.size(); ++i) + { + execute::process( x, y, expr_list[i]); + execute::process(xx, yy, expr_list[i]); + } + + { + for (std::size_t i = 0; i < 10000; ++i) + { + T v = T(123.456 + i); + + if (details::is_true(details::numeric::nequal(details::numeric::fast_exp::result(v),details::numeric::pow(v,T( 1))))) + return false; + + #define else_stmt(N) \ + else if (details::is_true(details::numeric::nequal(details::numeric::fast_exp::result(v),details::numeric::pow(v,T(N))))) \ + return false; \ + + else_stmt( 2) else_stmt( 3) else_stmt( 4) else_stmt( 5) + else_stmt( 6) else_stmt( 7) else_stmt( 8) else_stmt( 9) + else_stmt(10) else_stmt(11) else_stmt(12) else_stmt(13) + else_stmt(14) else_stmt(15) else_stmt(16) else_stmt(17) + else_stmt(18) else_stmt(19) else_stmt(20) else_stmt(21) + else_stmt(22) else_stmt(23) else_stmt(24) else_stmt(25) + else_stmt(26) else_stmt(27) else_stmt(28) else_stmt(29) + else_stmt(30) else_stmt(31) else_stmt(32) else_stmt(33) + else_stmt(34) else_stmt(35) else_stmt(36) else_stmt(37) + else_stmt(38) else_stmt(39) else_stmt(40) else_stmt(41) + else_stmt(42) else_stmt(43) else_stmt(44) else_stmt(45) + else_stmt(46) else_stmt(47) else_stmt(48) else_stmt(49) + else_stmt(50) else_stmt(51) else_stmt(52) else_stmt(53) + else_stmt(54) else_stmt(55) else_stmt(56) else_stmt(57) + else_stmt(58) else_stmt(59) else_stmt(60) else_stmt(61) + } + } + + return true; + } +} + +#if defined(_WIN32) || defined(__WIN32__) || defined(WIN32) +# ifndef NOMINMAX +# define NOMINMAX +# endif +# ifndef WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +# endif +# include +# include +#else +# include +# include +# include #endif - - inline expression_node_ptr synthesize_uvouv_expression(const details::operator_type& operation, expression_node_ptr (&branch)[2]) - { - // Definition: uv o uv - details::operator_type o0 = static_cast*>(branch[0])->operation(); - details::operator_type o1 = static_cast*>(branch[1])->operation(); - const Type& v0 = static_cast*>(branch[0])->v(); - const Type& v1 = static_cast*>(branch[1])->v(); - unary_functor_t u0 = reinterpret_cast (0); - unary_functor_t u1 = reinterpret_cast (0); - binary_functor_t f = reinterpret_cast(0); - - if (!valid_operator(o0,u0)) - return error_node(); - else if (!valid_operator(o1,u1)) - return error_node(); - else if (!valid_operator(operation,f)) - return error_node(); - - expression_node_ptr result = error_node(); - - if ( - (details::e_neg == o0) && - (details::e_neg == o1) - ) - { - switch (operation) - { - // (-v0 + -v1) --> -(v0 + v1) - case details::e_add : result = (*this)(details::e_neg, - node_allocator_-> - allocate_rr > >(v0,v1)); - exprtk_debug(("(-v0 + -v1) --> -(v0 + v1)\n")); - break; - - // (-v0 - -v1) --> (v1 - v0) - case details::e_sub : result = node_allocator_-> - allocate_rr > >(v1,v0); - exprtk_debug(("(-v0 - -v1) --> (v1 - v0)\n")); - break; - - // (-v0 * -v1) --> (v0 * v1) - case details::e_mul : result = node_allocator_-> - allocate_rr > >(v0,v1); - exprtk_debug(("(-v0 * -v1) --> (v0 * v1)\n")); - break; - - // (-v0 / -v1) --> (v0 / v1) - case details::e_div : result = node_allocator_-> - allocate_rr > >(v0,v1); - exprtk_debug(("(-v0 / -v1) --> (v0 / v1)\n")); - break; - - default : break; - } - } - - if (0 == result) - { - result = node_allocator_-> - allocate_rrrrr >(v0,v1,u0,u1,f); - } - - details::free_all_nodes(*node_allocator_,branch); - return result; - } - -#undef basic_opr_switch_statements -#undef extended_opr_switch_statements -#undef unary_opr_switch_statements - -#ifndef exprtk_disable_string_capabilities - -#define string_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_in ,details:: in_op) \ -case_stmt(details::e_like ,details:: like_op) \ -case_stmt(details::e_ilike,details::ilike_op) \ - - template - inline expression_node_ptr synthesize_str_xrox_expression_impl(const details::operator_type& opr, - T0 s0, T1 s1, - range_t rp0) - { - switch (opr) - { -#define case_stmt(op0,op1) \ -case op0 : return node_allocator_-> \ -allocate_ttt >,T0,T1> \ -(s0,s1,rp0); \ - - string_opr_switch_statements -#undef case_stmt - default : return error_node(); - } - } - - template - inline expression_node_ptr synthesize_str_xoxr_expression_impl(const details::operator_type& opr, - T0 s0, T1 s1, - range_t rp1) - { - switch (opr) - { -#define case_stmt(op0,op1) \ -case op0 : return node_allocator_-> \ -allocate_ttt >,T0,T1> \ -(s0,s1,rp1); \ - - string_opr_switch_statements -#undef case_stmt - default : return error_node(); - } - } - - template - inline expression_node_ptr synthesize_str_xroxr_expression_impl(const details::operator_type& opr, - T0 s0, T1 s1, - range_t rp0, range_t rp1) - { - switch (opr) - { -#define case_stmt(op0,op1) \ -case op0 : return node_allocator_-> \ -allocate_tttt >,T0,T1> \ -(s0,s1,rp0,rp1); \ - - string_opr_switch_statements -#undef case_stmt - default : return error_node(); - } - } - - template - inline expression_node_ptr synthesize_sos_expression_impl(const details::operator_type& opr, T0 s0, T1 s1) - { - switch (opr) - { -#define case_stmt(op0,op1) \ -case op0 : return node_allocator_-> \ -allocate_tt >,T0,T1>(s0,s1); \ - - string_opr_switch_statements -#undef case_stmt - default : return error_node(); - } - } - - inline expression_node_ptr synthesize_sos_expression(const details::operator_type& opr, expression_node_ptr (&branch)[2]) - { - std::string& s0 = static_cast*>(branch[0])->ref(); - std::string& s1 = static_cast*>(branch[1])->ref(); - - return synthesize_sos_expression_impl(opr,s0,s1); - } - - inline expression_node_ptr synthesize_sros_expression(const details::operator_type& opr, expression_node_ptr (&branch)[2]) - { - std::string& s0 = static_cast*>(branch[0])->ref (); - std::string& s1 = static_cast*> (branch[1])->ref (); - range_t rp0 = static_cast*>(branch[0])->range(); - - static_cast*>(branch[0])->range_ref().clear(); - - free_node(*node_allocator_,branch[0]); - - return synthesize_str_xrox_expression_impl(opr,s0,s1,rp0); - } - - inline expression_node_ptr synthesize_sosr_expression(const details::operator_type& opr, expression_node_ptr (&branch)[2]) - { - std::string& s0 = static_cast*> (branch[0])->ref (); - std::string& s1 = static_cast*>(branch[1])->ref (); - range_t rp1 = static_cast*>(branch[1])->range(); - - static_cast*>(branch[1])->range_ref().clear(); - - free_node(*node_allocator_,branch[1]); - - return synthesize_str_xoxr_expression_impl(opr,s0,s1,rp1); - } - - inline expression_node_ptr synthesize_socsr_expression(const details::operator_type& opr, expression_node_ptr (&branch)[2]) - { - std::string& s0 = static_cast*> (branch[0])->ref (); - std::string s1 = static_cast*>(branch[1])->str (); - range_t rp1 = static_cast*>(branch[1])->range(); - - static_cast*>(branch[1])->range_ref().clear(); - - free_node(*node_allocator_,branch[1]); - - return synthesize_str_xoxr_expression_impl(opr,s0,s1,rp1); - } - - inline expression_node_ptr synthesize_srosr_expression(const details::operator_type& opr, expression_node_ptr (&branch)[2]) - { - std::string& s0 = static_cast*>(branch[0])->ref (); - std::string& s1 = static_cast*>(branch[1])->ref (); - range_t rp0 = static_cast*>(branch[0])->range(); - range_t rp1 = static_cast*>(branch[1])->range(); - - static_cast*>(branch[0])->range_ref().clear(); - static_cast*>(branch[1])->range_ref().clear(); - - details::free_node(*node_allocator_,branch[0]); - details::free_node(*node_allocator_,branch[1]); - - return synthesize_str_xroxr_expression_impl(opr,s0,s1,rp0,rp1); - } - - inline expression_node_ptr synthesize_socs_expression(const details::operator_type& opr, expression_node_ptr (&branch)[2]) - { - std::string& s0 = static_cast< details::stringvar_node*>(branch[0])->ref(); - std::string s1 = static_cast*>(branch[1])->str(); - - details::free_node(*node_allocator_,branch[1]); - - return synthesize_sos_expression_impl(opr,s0,s1); - } - - inline expression_node_ptr synthesize_csos_expression(const details::operator_type& opr, expression_node_ptr (&branch)[2]) - { - std::string s0 = static_cast*>(branch[0])->str(); - std::string& s1 = static_cast< details::stringvar_node*>(branch[1])->ref(); - - details::free_node(*node_allocator_,branch[0]); - - return synthesize_sos_expression_impl(opr,s0,s1); - } - - inline expression_node_ptr synthesize_csosr_expression(const details::operator_type& opr, expression_node_ptr (&branch)[2]) - { - std::string s0 = static_cast*>(branch[0])->str (); - std::string& s1 = static_cast*> (branch[1])->ref (); - range_t rp1 = static_cast*> (branch[1])->range(); - - static_cast*>(branch[1])->range_ref().clear(); - - details::free_node(*node_allocator_,branch[0]); - details::free_node(*node_allocator_,branch[1]); - - return synthesize_str_xoxr_expression_impl(opr,s0,s1,rp1); - } - - inline expression_node_ptr synthesize_srocs_expression(const details::operator_type& opr, expression_node_ptr (&branch)[2]) - { - std::string& s0 = static_cast*> (branch[0])->ref (); - std::string s1 = static_cast*>(branch[1])->str (); - range_t rp0 = static_cast*> (branch[0])->range(); - - static_cast*>(branch[0])->range_ref().clear(); - - details::free_node(*node_allocator_,branch[0]); - details::free_node(*node_allocator_,branch[1]); - - return synthesize_str_xrox_expression_impl(opr,s0,s1,rp0); - } - - inline expression_node_ptr synthesize_srocsr_expression(const details::operator_type& opr, expression_node_ptr (&branch)[2]) - { - std::string& s0 = static_cast*> (branch[0])->ref (); - std::string s1 = static_cast*>(branch[1])->str (); - range_t rp0 = static_cast*> (branch[0])->range(); - range_t rp1 = static_cast*>(branch[1])->range(); - - static_cast*> (branch[0])->range_ref().clear(); - static_cast*>(branch[1])->range_ref().clear(); - - details::free_node(*node_allocator_,branch[0]); - details::free_node(*node_allocator_,branch[1]); - - return synthesize_str_xroxr_expression_impl(opr,s0,s1,rp0,rp1); - } - - inline expression_node_ptr synthesize_csocs_expression(const details::operator_type& opr, expression_node_ptr (&branch)[2]) - { - const std::string s0 = static_cast*>(branch[0])->str(); - const std::string s1 = static_cast*>(branch[1])->str(); - - expression_node_ptr result = error_node(); - - if (details::e_add == opr) - result = node_allocator_->allocate_c >(s0 + s1); - else if (details::e_in == opr) - result = node_allocator_->allocate_c >(details::in_op::process(s0,s1)); - else if (details::e_like == opr) - result = node_allocator_->allocate_c >(details::like_op::process(s0,s1)); - else if (details::e_ilike == opr) - result = node_allocator_->allocate_c >(details::ilike_op::process(s0,s1)); - else - { - expression_node_ptr temp = synthesize_sos_expression_impl(opr,s0,s1); - Type v = temp->value(); - details::free_node(*node_allocator_,temp); - result = node_allocator_->allocate(v); - } - - details::free_all_nodes(*node_allocator_,branch); - - return result; - } - - inline expression_node_ptr synthesize_csocsr_expression(const details::operator_type& opr, expression_node_ptr (&branch)[2]) - { - const std::string s0 = static_cast*> (branch[0])->str (); - std::string s1 = static_cast*>(branch[1])->str (); - range_t rp1 = static_cast*>(branch[1])->range(); - - static_cast*>(branch[1])->range_ref().clear(); - - free_node(*node_allocator_,branch[0]); - free_node(*node_allocator_,branch[1]); - - return synthesize_str_xoxr_expression_impl(opr,s0,s1,rp1); - } - - inline expression_node_ptr synthesize_csros_expression(const details::operator_type& opr, expression_node_ptr (&branch)[2]) - { - std::string s0 = static_cast*>(branch[0])->str (); - std::string& s1 = static_cast*> (branch[1])->ref (); - range_t rp0 = static_cast*>(branch[0])->range(); - - static_cast*>(branch[0])->range_ref().clear(); - - free_node(*node_allocator_,branch[0]); - - return synthesize_str_xrox_expression_impl(opr,s0,s1,rp0); - } - - inline expression_node_ptr synthesize_csrosr_expression(const details::operator_type& opr, expression_node_ptr (&branch)[2]) - { - const std::string s0 = static_cast*>(branch[0])->str (); - std::string& s1 = static_cast*> (branch[1])->ref (); - range_t rp0 = static_cast*>(branch[0])->range(); - range_t rp1 = static_cast*> (branch[1])->range(); - - static_cast*>(branch[0])->range_ref().clear(); - static_cast*> (branch[1])->range_ref().clear(); - - free_node(*node_allocator_,branch[0]); - free_node(*node_allocator_,branch[1]); - - return synthesize_str_xroxr_expression_impl(opr,s0,s1,rp0,rp1); - } - - inline expression_node_ptr synthesize_csrocs_expression(const details::operator_type& opr, expression_node_ptr (&branch)[2]) - { - std::string s0 = static_cast*>(branch[0])->str (); - const std::string s1 = static_cast*> (branch[1])->str (); - range_t rp0 = static_cast*>(branch[0])->range(); - - static_cast*>(branch[0])->range_ref().clear(); - - details::free_all_nodes(*node_allocator_,branch); - - return synthesize_str_xrox_expression_impl(opr,s0,s1,rp0); - } - - inline expression_node_ptr synthesize_csrocsr_expression(const details::operator_type& opr, expression_node_ptr (&branch)[2]) - { - std::string s0 = static_cast*>(branch[0])->str (); - std::string s1 = static_cast*>(branch[1])->str (); - range_t rp0 = static_cast*>(branch[0])->range(); - range_t rp1 = static_cast*>(branch[1])->range(); - - static_cast*>(branch[0])->range_ref().clear(); - static_cast*>(branch[1])->range_ref().clear(); - - details::free_all_nodes(*node_allocator_,branch); - - return synthesize_str_xroxr_expression_impl(opr,s0,s1,rp0,rp1); - } - - inline expression_node_ptr synthesize_strogen_expression(const details::operator_type& opr, expression_node_ptr (&branch)[2]) - { - switch (opr) - { -#define case_stmt(op0,op1) \ -case op0 : return node_allocator_-> \ -allocate_ttt > > \ -(opr,branch[0],branch[1]); \ - - string_opr_switch_statements -#undef case_stmt - default : return error_node(); - } + +namespace exprtk +{ + class timer + { + public: + + #if defined(_WIN32) || defined(__WIN32__) || defined(WIN32) + timer() + : in_use_(false) + { + QueryPerformanceFrequency(&clock_frequency_); + } + + inline void start() + { + in_use_ = true; + QueryPerformanceCounter(&start_time_); + } + + inline void stop() + { + QueryPerformanceCounter(&stop_time_); + in_use_ = false; + } + + inline double time() const + { + return (1.0 * (stop_time_.QuadPart - start_time_.QuadPart)) / (1.0 * clock_frequency_.QuadPart); + } + + #else + + timer() + : in_use_(false) + { + start_time_.tv_sec = 0; + start_time_.tv_usec = 0; + stop_time_.tv_sec = 0; + stop_time_.tv_usec = 0; + } + + inline void start() + { + in_use_ = true; + gettimeofday(&start_time_,0); + } + + inline void stop() + { + gettimeofday(&stop_time_, 0); + in_use_ = false; + } + + inline unsigned long long int usec_time() const + { + if (!in_use_) + { + if (stop_time_.tv_sec >= start_time_.tv_sec) + { + return 1000000 * (stop_time_.tv_sec - start_time_.tv_sec ) + + (stop_time_.tv_usec - start_time_.tv_usec); + } + else + return std::numeric_limits::max(); + } + else + return std::numeric_limits::max(); + } + + inline double time() const + { + return usec_time() * 0.000001; + } + + #endif + + inline bool in_use() const + { + return in_use_; + } + + private: + + bool in_use_; + + #if defined(_WIN32) || defined(__WIN32__) || defined(WIN32) + LARGE_INTEGER start_time_; + LARGE_INTEGER stop_time_; + LARGE_INTEGER clock_frequency_; + #else + struct timeval start_time_; + struct timeval stop_time_; + #endif + }; + +} // namespace exprtk + +#ifndef exprtk_disable_rtl_io +namespace exprtk +{ + namespace rtl { namespace io { namespace details + { + template + inline void print_type(const std::string& fmt, + const T v, + exprtk::details::numeric::details::real_type_tag) + { + printf(fmt.c_str(),v); + } + + template + struct print_impl + { + typedef typename igeneric_function::generic_type generic_type; + typedef typename igeneric_function::parameter_list_t parameter_list_t; + typedef typename generic_type::scalar_view scalar_t; + typedef typename generic_type::vector_view vector_t; + typedef typename generic_type::string_view string_t; + typedef typename exprtk::details::numeric::details::number_type::type num_type; + + static void process(const std::string& scalar_format, parameter_list_t parameters) + { + for (std::size_t i = 0; i < parameters.size(); ++i) + { + generic_type& gt = parameters[i]; + + switch (gt.type) + { + case generic_type::e_scalar : print(scalar_format,scalar_t(gt)); + break; + + case generic_type::e_vector : print(scalar_format,vector_t(gt)); + break; + + case generic_type::e_string : print(string_t(gt)); + break; + + default : continue; + } + } + } + + static inline void print(const std::string& scalar_format, const scalar_t& s) + { + print_type(scalar_format,s(),num_type()); + } + + static inline void print(const std::string& scalar_format, const vector_t& v) + { + for (std::size_t i = 0; i < v.size(); ++i) + { + print_type(scalar_format,v[i],num_type()); + + if ((i + 1) < v.size()) + printf(" "); } + } + + static inline void print(const string_t& s) + { + printf("%s",to_str(s).c_str()); + } + }; + + } // namespace exprtk::rtl::io::details + + template + struct print : public exprtk::igeneric_function + { + typedef typename igeneric_function::parameter_list_t parameter_list_t; + + using exprtk::igeneric_function::operator(); + + print(const std::string& scalar_format = "%10.5f") + : scalar_format_(scalar_format) + { + exprtk::enable_zero_parameters(*this); + } + + inline T operator()(parameter_list_t parameters) + { + details::print_impl::process(scalar_format_,parameters); + return T(0); + } + + std::string scalar_format_; + }; + + template + struct println : public exprtk::igeneric_function + { + typedef typename igeneric_function::parameter_list_t parameter_list_t; + + using exprtk::igeneric_function::operator(); + + println(const std::string& scalar_format = "%10.5f") + : scalar_format_(scalar_format) + { + exprtk::enable_zero_parameters(*this); + } + + inline T operator()(parameter_list_t parameters) + { + details::print_impl::process(scalar_format_,parameters); + printf("\n"); + return T(0); + } + + std::string scalar_format_; + }; + + template + struct package + { + print p; + println pl; + + bool register_package(exprtk::symbol_table& symtab) + { + #define exprtk_register_function(FunctionName,FunctionType) \ + if (!symtab.add_function(FunctionName,FunctionType)) \ + { \ + exprtk_debug(( \ + "exprtk::rtl::io::register_package - Failed to add function: %s\n", \ + FunctionName)); \ + return false; \ + } \ + + exprtk_register_function("print" , p) + exprtk_register_function("println" ,pl) + #undef exprtk_register_function + + return true; + } + }; + + } // namespace exprtk::rtl::io + } // namespace exprtk::rtl +} // namespace exprtk #endif - -#ifndef exprtk_disable_string_capabilities - inline expression_node_ptr synthesize_string_expression(const details::operator_type& opr, expression_node_ptr (&branch)[2]) - { - if ((0 == branch[0]) || (0 == branch[1])) - { - details::free_all_nodes(*node_allocator_,branch); - - return error_node(); - } - - const bool b0_is_s = details::is_string_node (branch[0]); - const bool b0_is_cs = details::is_const_string_node (branch[0]); - const bool b0_is_sr = details::is_string_range_node (branch[0]); - const bool b0_is_csr = details::is_const_string_range_node(branch[0]); - - const bool b1_is_s = details::is_string_node (branch[1]); - const bool b1_is_cs = details::is_const_string_node (branch[1]); - const bool b1_is_sr = details::is_string_range_node (branch[1]); - const bool b1_is_csr = details::is_const_string_range_node(branch[1]); - - const bool b0_is_gen = details::is_string_assignment_node (branch[0]) || - details::is_genricstring_range_node(branch[0]) || - details::is_string_concat_node (branch[0]) || - details::is_string_function_node (branch[0]) || - details::is_string_condition_node (branch[0]) || - details::is_string_ccondition_node (branch[0]) ; - - const bool b1_is_gen = details::is_string_assignment_node (branch[1]) || - details::is_genricstring_range_node(branch[1]) || - details::is_string_concat_node (branch[1]) || - details::is_string_function_node (branch[1]) || - details::is_string_condition_node (branch[1]) || - details::is_string_ccondition_node (branch[1]) ; - - if (details::e_add == opr) - { - if (!b0_is_cs || !b1_is_cs) - { - return synthesize_expression(opr,branch); - } - } - - if (b0_is_gen || b1_is_gen) - { - return synthesize_strogen_expression(opr,branch); - } - else if (b0_is_s) - { - if (b1_is_s ) return synthesize_sos_expression (opr,branch); - else if (b1_is_cs ) return synthesize_socs_expression (opr,branch); - else if (b1_is_sr ) return synthesize_sosr_expression (opr,branch); - else if (b1_is_csr) return synthesize_socsr_expression (opr,branch); - } - else if (b0_is_cs) - { - if (b1_is_s ) return synthesize_csos_expression (opr,branch); - else if (b1_is_cs ) return synthesize_csocs_expression (opr,branch); - else if (b1_is_sr ) return synthesize_csosr_expression (opr,branch); - else if (b1_is_csr) return synthesize_csocsr_expression(opr,branch); - } - else if (b0_is_sr) - { - if (b1_is_s ) return synthesize_sros_expression (opr,branch); - else if (b1_is_sr ) return synthesize_srosr_expression (opr,branch); - else if (b1_is_cs ) return synthesize_srocs_expression (opr,branch); - else if (b1_is_csr) return synthesize_srocsr_expression(opr,branch); - } - else if (b0_is_csr) - { - if (b1_is_s ) return synthesize_csros_expression (opr,branch); - else if (b1_is_sr ) return synthesize_csrosr_expression (opr,branch); - else if (b1_is_cs ) return synthesize_csrocs_expression (opr,branch); - else if (b1_is_csr) return synthesize_csrocsr_expression(opr,branch); - } - - return error_node(); + +#ifndef exprtk_disable_rtl_io_file +#include +namespace exprtk +{ + namespace rtl { namespace io { namespace file { namespace details + { + enum file_mode + { + e_error = 0, + e_read = 1, + e_write = 2, + e_rdwrt = 4 + }; + + struct file_descriptor + { + file_descriptor(const std::string& fname, const std::string& access) + : stream_ptr(0), + mode(get_file_mode(access)), + file_name(fname) + {} + + void* stream_ptr; + file_mode mode; + std::string file_name; + + bool open() + { + if (e_read == mode) + { + std::ifstream* stream = new std::ifstream(file_name.c_str(),std::ios::binary); + + if (!(*stream)) + { + file_name.clear(); + delete stream; + + return false; + } + else + stream_ptr = stream; + + return true; } -#else - inline expression_node_ptr synthesize_string_expression(const details::operator_type&, expression_node_ptr (&branch)[2]) + else if (e_write == mode) + { + std::ofstream* stream = new std::ofstream(file_name.c_str(),std::ios::binary); + + if (!(*stream)) + { + file_name.clear(); + delete stream; + + return false; + } + else + stream_ptr = stream; + + return true; + } + else if (e_rdwrt == mode) + { + std::fstream* stream = new std::fstream(file_name.c_str(),std::ios::binary); + + if (!(*stream)) + { + file_name.clear(); + delete stream; + + return false; + } + else + stream_ptr = stream; + + return true; + } + else + return false; + } + + template + void close(Ptr& p) + { + Stream* stream = reinterpret_cast(p); + stream->close(); + delete stream; + p = reinterpret_cast(0); + } + + bool close() + { + switch (mode) + { + case e_read : close(stream_ptr); + break; + + case e_write : close(stream_ptr); + break; + + case e_rdwrt : close (stream_ptr); + break; + + default : return false; + } + + return true; + } + + template + bool write(const View& view, const std::size_t amount, const std::size_t offset = 0) + { + switch (mode) + { + case e_write : reinterpret_cast(stream_ptr)-> + write(reinterpret_cast(view.begin() + offset), amount * sizeof(typename View::value_t)); + break; + + case e_rdwrt : reinterpret_cast(stream_ptr)-> + write(reinterpret_cast(view.begin() + offset) , amount * sizeof(typename View::value_t)); + break; + + default : return false; + } + + return true; + } + + template + bool read(View& view, const std::size_t amount, const std::size_t offset = 0) + { + switch (mode) + { + case e_read : reinterpret_cast(stream_ptr)-> + read(reinterpret_cast(view.begin() + offset), amount * sizeof(typename View::value_t)); + break; + + case e_rdwrt : reinterpret_cast(stream_ptr)-> + read(reinterpret_cast(view.begin() + offset) , amount * sizeof(typename View::value_t)); + break; + + default : return false; + } + + return true; + } + + bool getline(std::string& s) + { + switch (mode) { - details::free_all_nodes(*node_allocator_,branch); - return error_node(); + case e_read : return (!!std::getline(*reinterpret_cast(stream_ptr),s)); + case e_rdwrt : return (!!std::getline(*reinterpret_cast(stream_ptr),s)); + default : return false; } + } + + bool eof() + { + switch (mode) + { + case e_read : return reinterpret_cast(stream_ptr)->eof(); + case e_write : return reinterpret_cast(stream_ptr)->eof(); + case e_rdwrt : return reinterpret_cast(stream_ptr)->eof(); + default : return true; + } + } + + file_mode get_file_mode(const std::string& access) + { + if (access.empty() || access.size() > 2) + return e_error; + + std::size_t w_cnt = 0; + std::size_t r_cnt = 0; + + for (std::size_t i = 0; i < access.size(); ++i) + { + #ifdef MODIFICATION + switch (access[i]) + #else + switch (std::tolower(access[i])) + #endif + { + case 'r' : r_cnt++; break; + case 'w' : w_cnt++; break; + default : return e_error; + } + } + + if ((0 == r_cnt) && (0 == w_cnt)) + return e_error; + else if ((r_cnt > 1) || (w_cnt > 1)) + return e_error; + else if ((1 == r_cnt) && (1 == w_cnt)) + return e_rdwrt; + else if (1 == r_cnt) + return e_read; + else + return e_write; + } + }; + + template + file_descriptor* make_handle(T v) + { + file_descriptor* fd = reinterpret_cast(0); + + std::memcpy(reinterpret_cast(&fd), + reinterpret_cast(&v), + sizeof(fd)); + return fd; + } + + template + void perform_check() + { + #ifdef _MSC_VER + #pragma warning(push) + #pragma warning(disable: 4127) + #endif + if (sizeof(T) < sizeof(void*)) + { + throw std::runtime_error("exprtk::rtl::io::file - Error - pointer size larger than holder."); + } + #ifdef _MSC_VER + #pragma warning(pop) + #endif + } + } // namespace exprtk::rtl::io::file::details + + template + class open : public exprtk::igeneric_function + { + public: + + typedef typename exprtk::igeneric_function igfun_t; + typedef typename igfun_t::parameter_list_t parameter_list_t; + typedef typename igfun_t::generic_type generic_type; + typedef typename generic_type::string_view string_t; + + using exprtk::igeneric_function::operator(); + + open() + : exprtk::igeneric_function("S|SS") + { details::perform_check(); } + + inline T operator()(const std::size_t& ps_index, parameter_list_t parameters) + { + std::string file_name; + std::string access; + + file_name = to_str(string_t(parameters[0])); + + if (file_name.empty()) + return T(0); + + if (0 == ps_index) + access = "r"; + else if (0 == string_t(parameters[1]).size()) + return T(0); + else + access = to_str(string_t(parameters[1])); + + details::file_descriptor* fd = new details::file_descriptor(file_name,access); + + if (fd->open()) + { + T t = T(0); + + std::memcpy(reinterpret_cast(&t), + reinterpret_cast(&fd), + sizeof(fd)); + return t; + } + else + { + delete fd; + return T(0); + } + } + }; + + template + struct close : public exprtk::ifunction + { + using exprtk::ifunction::operator(); + + close() + : exprtk::ifunction(1) + { details::perform_check(); } + + inline T operator()(const T& v) + { + details::file_descriptor* fd = details::make_handle(v); + + if (!fd->close()) + return T(0); + + delete fd; + + return T(1); + } + }; + + template + class write : public exprtk::igeneric_function + { + public: + + typedef typename exprtk::igeneric_function igfun_t; + typedef typename igfun_t::parameter_list_t parameter_list_t; + typedef typename igfun_t::generic_type generic_type; + typedef typename generic_type::string_view string_t; + typedef typename generic_type::scalar_view scalar_t; + typedef typename generic_type::vector_view vector_t; + + using exprtk::igeneric_function::operator(); + + write() + : igfun_t("TS|TST|TV|TVT") + { details::perform_check(); } + + inline T operator()(const std::size_t& ps_index, parameter_list_t parameters) + { + details::file_descriptor* fd = details::make_handle(scalar_t(parameters[0])()); + + std::size_t amount = 0; + + switch (ps_index) + { + case 0 : { + string_t buffer(parameters[1]); + amount = buffer.size(); + return T(fd->write(buffer,amount) ? 1 : 0); + } + + case 1 : { + string_t buffer(parameters[1]); + amount = std::min(buffer.size(), + static_cast(scalar_t(parameters[2])())); + return T(fd->write(buffer,amount) ? 1 : 0); + } + + case 2 : { + vector_t vec(parameters[1]); + amount = vec.size(); + return T(fd->write(vec,amount) ? 1 : 0); + } + + case 3 : { + vector_t vec(parameters[1]); + amount = std::min(vec.size(), + static_cast(scalar_t(parameters[2])())); + return T(fd->write(vec,amount) ? 1 : 0); + } + } + + return T(0); + } + }; + + template + class read : public exprtk::igeneric_function + { + public: + + typedef typename exprtk::igeneric_function igfun_t; + typedef typename igfun_t::parameter_list_t parameter_list_t; + typedef typename igfun_t::generic_type generic_type; + typedef typename generic_type::string_view string_t; + typedef typename generic_type::scalar_view scalar_t; + typedef typename generic_type::vector_view vector_t; + + using exprtk::igeneric_function::operator(); + + read() + : igfun_t("TS|TST|TV|TVT") + { details::perform_check(); } + + inline T operator()(const std::size_t& ps_index, parameter_list_t parameters) + { + details::file_descriptor* fd = details::make_handle(scalar_t(parameters[0])()); + + std::size_t amount = 0; + + switch (ps_index) + { + case 0 : { + string_t buffer(parameters[1]); + amount = buffer.size(); + return T(fd->read(buffer,amount) ? 1 : 0); + } + + case 1 : { + string_t buffer(parameters[1]); + amount = std::min(buffer.size(), + static_cast(scalar_t(parameters[2])())); + return T(fd->read(buffer,amount) ? 1 : 0); + } + + case 2 : { + vector_t vec(parameters[1]); + amount = vec.size(); + return T(fd->read(vec,amount) ? 1 : 0); + } + + case 3 : { + vector_t vec(parameters[1]); + amount = std::min(vec.size(), + static_cast(scalar_t(parameters[2])())); + return T(fd->read(vec,amount) ? 1 : 0); + } + } + + return T(0); + } + }; + + template + class getline : public exprtk::igeneric_function + { + public: + + typedef typename exprtk::igeneric_function igfun_t; + typedef typename igfun_t::parameter_list_t parameter_list_t; + typedef typename igfun_t::generic_type generic_type; + typedef typename generic_type::string_view string_t; + typedef typename generic_type::scalar_view scalar_t; + + using exprtk::igeneric_function::operator(); + + getline() + : igfun_t("T",igfun_t::e_rtrn_string) + { details::perform_check(); } + + inline T operator()(std::string& result, + parameter_list_t parameters) + { + details::file_descriptor* fd = details::make_handle(scalar_t(parameters[0])()); + return T(fd->getline(result) ? 1 : 0); + } + }; + + template + struct eof : public exprtk::ifunction + { + using exprtk::ifunction::operator(); + + eof() + : exprtk::ifunction(1) + { details::perform_check(); } + + inline T operator()(const T& v) + { + details::file_descriptor* fd = details::make_handle(v); + + return (fd->eof() ? T(1) : T(0)); + } + }; + + template + struct package + { + open o; + close c; + write w; + read r; + getline g; + eof e; + + bool register_package(exprtk::symbol_table& symtab) + { + #define exprtk_register_function(FunctionName,FunctionType) \ + if (!symtab.add_function(FunctionName,FunctionType)) \ + { \ + exprtk_debug(( \ + "exprtk::rtl::io::file::register_package - Failed to add function: %s\n", \ + FunctionName)); \ + return false; \ + } \ + + exprtk_register_function("open" ,o) + exprtk_register_function("close" ,c) + exprtk_register_function("write" ,w) + exprtk_register_function("read" ,r) + exprtk_register_function("getline",g) + exprtk_register_function("eof" ,e) + #undef exprtk_register_function + + return true; + } + }; + + } // namespace exprtk::rtl::io::file + } // namespace exprtk::rtl::io + } // namespace exprtk::rtl +} // namespace exprtk #endif - -#ifndef exprtk_disable_string_capabilities - inline expression_node_ptr synthesize_string_expression(const details::operator_type& opr, expression_node_ptr (&branch)[3]) - { - if (details::e_inrange != opr) - return error_node(); - else if ((0 == branch[0]) || (0 == branch[1]) || (0 == branch[2])) - { - details::free_all_nodes(*node_allocator_,branch); - - return error_node(); - } - else if ( - details::is_const_string_node(branch[0]) && - details::is_const_string_node(branch[1]) && - details::is_const_string_node(branch[2]) - ) - { - const std::string s0 = static_cast*>(branch[0])->str(); - const std::string s1 = static_cast*>(branch[1])->str(); - const std::string s2 = static_cast*>(branch[2])->str(); - - Type v = (((s0 <= s1) && (s1 <= s2)) ? Type(1) : Type(0)); - details::free_all_nodes(*node_allocator_,branch); - - return node_allocator_->allocate_c >(v); - } - else if ( - details::is_string_node(branch[0]) && - details::is_string_node(branch[1]) && - details::is_string_node(branch[2]) - ) - { - std::string& s0 = static_cast*>(branch[0])->ref(); - std::string& s1 = static_cast*>(branch[1])->ref(); - std::string& s2 = static_cast*>(branch[2])->ref(); - - typedef typename details::sosos_node > inrange_t; - - return node_allocator_->allocate_type(s0,s1,s2); - } - else if ( - details::is_const_string_node(branch[0]) && - details::is_string_node(branch[1]) && - details::is_const_string_node(branch[2]) - ) - { - std::string s0 = static_cast*>(branch[0])->str(); - std::string& s1 = static_cast< details::stringvar_node*>(branch[1])->ref(); - std::string s2 = static_cast*>(branch[2])->str(); - - typedef typename details::sosos_node > inrange_t; - - details::free_node(*node_allocator_,branch[0]); - details::free_node(*node_allocator_,branch[2]); - - return node_allocator_->allocate_type(s0,s1,s2); - } - else if ( - details::is_string_node(branch[0]) && - details::is_const_string_node(branch[1]) && - details::is_string_node(branch[2]) - ) - { - std::string& s0 = static_cast< details::stringvar_node*>(branch[0])->ref(); - std::string s1 = static_cast*>(branch[1])->str(); - std::string& s2 = static_cast< details::stringvar_node*>(branch[2])->ref(); - - typedef typename details::sosos_node > inrange_t; - - details::free_node(*node_allocator_,branch[1]); - - return node_allocator_->allocate_type(s0,s1,s2); - } - else if ( - details::is_string_node(branch[0]) && - details::is_string_node(branch[1]) && - details::is_const_string_node(branch[2]) - ) - { - std::string& s0 = static_cast< details::stringvar_node*>(branch[0])->ref(); - std::string& s1 = static_cast< details::stringvar_node*>(branch[1])->ref(); - std::string s2 = static_cast*>(branch[2])->str(); - - typedef typename details::sosos_node > inrange_t; - - details::free_node(*node_allocator_,branch[2]); - - return node_allocator_->allocate_type(s0,s1,s2); - } - else if ( - details::is_const_string_node(branch[0]) && - details:: is_string_node(branch[1]) && - details:: is_string_node(branch[2]) - ) - { - std::string s0 = static_cast*>(branch[0])->str(); - std::string& s1 = static_cast< details::stringvar_node*>(branch[1])->ref(); - std::string& s2 = static_cast< details::stringvar_node*>(branch[2])->ref(); - - typedef typename details::sosos_node > inrange_t; - - details::free_node(*node_allocator_,branch[0]); - - return node_allocator_->allocate_type(s0,s1,s2); - } - else - return error_node(); + +#ifndef exprtk_disable_rtl_vecops +namespace exprtk +{ + namespace rtl { namespace vecops { + + namespace helper + { + template + inline bool invalid_range(const Vector& v, const std::size_t r0, const std::size_t r1) + { + if (r0 > (v.size() - 1)) + return true; + else if (r1 > (v.size() - 1)) + return true; + else if (r1 < r0) + return true; + else + return false; + } + + template + struct load_vector_range + { + typedef typename exprtk::igeneric_function igfun_t; + typedef typename igfun_t::parameter_list_t parameter_list_t; + typedef typename igfun_t::generic_type generic_type; + typedef typename generic_type::scalar_view scalar_t; + typedef typename generic_type::vector_view vector_t; + + static inline bool process(parameter_list_t& parameters, + std::size_t& r0, std::size_t& r1, + const std::size_t& r0_prmidx, + const std::size_t& r1_prmidx, + const std::size_t vec_idx = 0) + { + if (r0_prmidx >= parameters.size()) + return false; + + if (r1_prmidx >= parameters.size()) + return false; + + if (!scalar_t(parameters[r0_prmidx]).to_uint(r0)) + return false; + + if (!scalar_t(parameters[r1_prmidx]).to_uint(r1)) + return false; + + return !invalid_range(vector_t(parameters[vec_idx]),r0,r1); + } + }; + } + + namespace details + { + template + inline void kahan_sum(T& sum, T& error, T v) + { + T x = v - error; + T y = sum + x; + error = (y - sum) - x; + sum = y; + } + + } // namespace exprtk::rtl::details + + template + class all_true : public exprtk::igeneric_function + { + public: + + typedef typename exprtk::igeneric_function igfun_t; + typedef typename igfun_t::parameter_list_t parameter_list_t; + typedef typename igfun_t::generic_type generic_type; + typedef typename generic_type::vector_view vector_t; + + using exprtk::igeneric_function::operator(); + + all_true() + : exprtk::igeneric_function("V|VTT") + /* + Overloads: + 0. V - vector + 1. VTT - vector, r0, r1 + */ + {} + + inline T operator()(const std::size_t& ps_index, parameter_list_t parameters) + { + const vector_t& vec(parameters[0]); + + std::size_t r0 = 0; + std::size_t r1 = vec.size() - 1; + + if ((1 == ps_index) && !helper::load_vector_range::process(parameters,r0,r1,1,2,0)) + return std::numeric_limits::quiet_NaN(); + + for (std::size_t i = r0; i <= r1; ++i) + { + if (vec[i] == T(0)) + { + return T(0); + } + } + + return T(1); + } + }; + + template + class all_false : public exprtk::igeneric_function + { + public: + + typedef typename exprtk::igeneric_function igfun_t; + typedef typename igfun_t::parameter_list_t parameter_list_t; + typedef typename igfun_t::generic_type generic_type; + typedef typename generic_type::vector_view vector_t; + + using exprtk::igeneric_function::operator(); + + all_false() + : exprtk::igeneric_function("V|VTT") + /* + Overloads: + 0. V - vector + 1. VTT - vector, r0, r1 + */ + {} + + inline T operator()(const std::size_t& ps_index, parameter_list_t parameters) + { + const vector_t& vec(parameters[0]); + + std::size_t r0 = 0; + std::size_t r1 = vec.size() - 1; + + if ((1 == ps_index) && !helper::load_vector_range::process(parameters,r0,r1,1,2,0)) + return std::numeric_limits::quiet_NaN(); + + for (std::size_t i = r0; i <= r1; ++i) + { + if (vec[i] != T(0)) + { + return T(0); + } + } + + return T(1); + } + }; + + template + class any_true : public exprtk::igeneric_function + { + public: + + typedef typename exprtk::igeneric_function igfun_t; + typedef typename igfun_t::parameter_list_t parameter_list_t; + typedef typename igfun_t::generic_type generic_type; + typedef typename generic_type::vector_view vector_t; + + using exprtk::igeneric_function::operator(); + + any_true() + : exprtk::igeneric_function("V|VTT") + /* + Overloads: + 0. V - vector + 1. VTT - vector, r0, r1 + */ + {} + + inline T operator()(const std::size_t& ps_index, parameter_list_t parameters) + { + const vector_t& vec(parameters[0]); + + std::size_t r0 = 0; + std::size_t r1 = vec.size() - 1; + + if ((1 == ps_index) && !helper::load_vector_range::process(parameters,r0,r1,1,2,0)) + return std::numeric_limits::quiet_NaN(); + + for (std::size_t i = r0; i <= r1; ++i) + { + if (vec[i] != T(0)) + { + return T(1); } -#else - inline expression_node_ptr synthesize_string_expression(const details::operator_type&, expression_node_ptr (&branch)[3]) + } + + return T(0); + } + }; + + template + class any_false : public exprtk::igeneric_function + { + public: + + typedef typename exprtk::igeneric_function igfun_t; + typedef typename igfun_t::parameter_list_t parameter_list_t; + typedef typename igfun_t::generic_type generic_type; + typedef typename generic_type::vector_view vector_t; + + using exprtk::igeneric_function::operator(); + + any_false() + : exprtk::igeneric_function("V|VTT") + /* + Overloads: + 0. V - vector + 1. VTT - vector, r0, r1 + */ + {} + + inline T operator()(const std::size_t& ps_index, parameter_list_t parameters) + { + const vector_t& vec(parameters[0]); + + std::size_t r0 = 0; + std::size_t r1 = vec.size() - 1; + + if ((1 == ps_index) && !helper::load_vector_range::process(parameters,r0,r1,1,2,0)) + return std::numeric_limits::quiet_NaN(); + + for (std::size_t i = r0; i <= r1; ++i) + { + if (vec[i] == T(0)) { - details::free_all_nodes(*node_allocator_,branch); - return error_node(); + return T(1); } -#endif - - inline expression_node_ptr synthesize_null_expression(const details::operator_type& operation, expression_node_ptr (&branch)[2]) - { - /* - Note: The following are the type promotion rules - that relate to operations that include 'null': - 0. null ==/!= null --> true false - 1. null operation null --> null - 2. x ==/!= null --> true/false - 3. null ==/!= x --> true/false - 4. x operation null --> x - 5. null operation x --> x - */ - - typedef typename details::null_eq_node nulleq_node_t; - - bool b0_null = details::is_null_node(branch[0]); - bool b1_null = details::is_null_node(branch[1]); - - if (b0_null && b1_null) - { - expression_node_ptr result = error_node(); - - if (details::e_eq == operation) - result = node_allocator_->allocate_c(T(1)); - else if (details::e_ne == operation) - result = node_allocator_->allocate_c(T(0)); - - if (result) - { - details::free_node(*node_allocator_,branch[0]); - details::free_node(*node_allocator_,branch[1]); - - return result; - } - - details::free_node(*node_allocator_,branch[1]); - - return branch[0]; - } - else if (details::e_eq == operation) - { - expression_node_ptr result = node_allocator_-> - allocate_rc(branch[b0_null ? 0 : 1],true); - - details::free_node(*node_allocator_,branch[b0_null ? 1 : 0]); - - return result; - } - else if (details::e_ne == operation) - { - expression_node_ptr result = node_allocator_-> - allocate_rc(branch[b0_null ? 0 : 1],false); - - details::free_node(*node_allocator_,branch[b0_null ? 1 : 0]); - - return result; - } - else if (b0_null) - { - details::free_node(*node_allocator_,branch[0]); - branch[0] = branch[1]; - branch[1] = error_node(); - } - else if (b1_null) - { - details::free_node(*node_allocator_,branch[1]); - branch[1] = error_node(); - } - - if ( - (details::e_add == operation) || (details::e_sub == operation) || - (details::e_mul == operation) || (details::e_div == operation) || - (details::e_mod == operation) || (details::e_pow == operation) - ) - { - return branch[0]; - } - else if ( - (details::e_lt == operation) || (details::e_lte == operation) || - (details::e_gt == operation) || (details::e_gte == operation) || - (details::e_and == operation) || (details::e_nand == operation) || - (details::e_or == operation) || (details::e_nor == operation) || - (details::e_xor == operation) || (details::e_xnor == operation) || - (details::e_in == operation) || (details::e_like == operation) || - (details::e_ilike == operation) - ) - { - return node_allocator_->allocate_c(T(0)); - } - - details::free_node(*node_allocator_,branch[0]); - - return node_allocator_->allocate >(); - } - - template - inline expression_node_ptr synthesize_expression(const details::operator_type& operation, expression_node_ptr (&branch)[N]) - { - if ( - (details::e_in == operation) || - (details::e_like == operation) || - (details::e_ilike == operation) - ) - return error_node(); - else if (!details::all_nodes_valid(branch)) - { - free_all_nodes(*node_allocator_,branch); - - return error_node(); - } - else if ((details::e_default != operation)) - { - // Attempt simple constant folding optimisation. - expression_node_ptr expression_point = node_allocator_->allocate(operation,branch); - - if (is_constant_foldable(branch)) - { - Type v = expression_point->value(); - details::free_node(*node_allocator_,expression_point); - - return node_allocator_->allocate(v); - } - else - return expression_point; - } - else - return error_node(); - } - - template - inline expression_node_ptr synthesize_expression(F* f, expression_node_ptr (&branch)[N]) - { - if (!details::all_nodes_valid(branch)) - { - free_all_nodes(*node_allocator_,branch); - - return error_node(); - } - - typedef typename details::function_N_node function_N_node_t; - - // Attempt simple constant folding optimisation. - - expression_node_ptr expression_point = node_allocator_->allocate(f); - function_N_node_t* func_node_ptr = dynamic_cast(expression_point); - - if (0 == func_node_ptr) - { - free_all_nodes(*node_allocator_,branch); - - return error_node(); - } - else - func_node_ptr->init_branches(branch); - - if (is_constant_foldable(branch) && !f->has_side_effects()) - { - Type v = expression_point->value(); - details::free_node(*node_allocator_,expression_point); - - return node_allocator_->allocate(v); - } - - parser_->state_.activate_side_effect("synthesize_expression(function)"); - - return expression_point; - } - - bool strength_reduction_enabled_; - details::node_allocator* node_allocator_; - synthesize_map_t synthesize_map_; - unary_op_map_t* unary_op_map_; - binary_op_map_t* binary_op_map_; - inv_binary_op_map_t* inv_binary_op_map_; - sf3_map_t* sf3_map_; - sf4_map_t* sf4_map_; - parser_t* parser_; - }; - - inline void set_error(const parser_error::type& error_type) - { - error_list_.push_back(error_type); - } - - inline void remove_last_error() - { - if (!error_list_.empty()) - { - error_list_.pop_back(); - } - } - - inline void set_synthesis_error(const std::string& synthesis_error_message) - { - if (synthesis_error_.empty()) - { - synthesis_error_ = synthesis_error_message; - } - } - - inline void register_local_vars(expression& e) - { - for (std::size_t i = 0; i < sem_.size(); ++i) - { - scope_element& se = sem_.get_element(i); - - if ( - (scope_element::e_variable == se.type) || - (scope_element::e_vecelem == se.type) - ) - { - if (se.var_node) - { - e.register_local_var(se.var_node); - } - - if (se.data) - { - e.register_local_data(se.data,1,0); - } - } - else if (scope_element::e_vector == se.type) - { - if (se.vec_node) - { - e.register_local_var(se.vec_node); - } - - if (se.data) - { - e.register_local_data(se.data,se.size,1); - } - } -#ifndef exprtk_disable_string_capabilities - else if (scope_element::e_string == se.type) - { - if (se.str_node) - { - e.register_local_var(se.str_node); - } - - if (se.data) - { - e.register_local_data(se.data,se.size,2); - } - } -#endif - - se.var_node = 0; - se.vec_node = 0; -#ifndef exprtk_disable_string_capabilities - se.str_node = 0; -#endif - se.data = 0; - se.ref_count = 0; - se.active = false; - } - } - - inline void register_return_results(expression& e) - { - e.register_return_results(results_context_); - results_context_ = 0; - } - - inline void load_unary_operations_map(unary_op_map_t& m) - { -#define register_unary_op(Op,UnaryFunctor) \ -m.insert(std::make_pair(Op,UnaryFunctor::process)); \ - - register_unary_op(details:: e_abs,details:: abs_op) - register_unary_op(details:: e_acos,details:: acos_op) - register_unary_op(details::e_acosh,details::acosh_op) - register_unary_op(details:: e_asin,details:: asin_op) - register_unary_op(details::e_asinh,details::asinh_op) - register_unary_op(details::e_atanh,details::atanh_op) - register_unary_op(details:: e_ceil,details:: ceil_op) - register_unary_op(details:: e_cos,details:: cos_op) - register_unary_op(details:: e_cosh,details:: cosh_op) - register_unary_op(details:: e_exp,details:: exp_op) - register_unary_op(details::e_expm1,details::expm1_op) - register_unary_op(details::e_floor,details::floor_op) - register_unary_op(details:: e_log,details:: log_op) - register_unary_op(details::e_log10,details::log10_op) - register_unary_op(details:: e_log2,details:: log2_op) - register_unary_op(details::e_log1p,details::log1p_op) - register_unary_op(details:: e_neg,details:: neg_op) - register_unary_op(details:: e_pos,details:: pos_op) - register_unary_op(details::e_round,details::round_op) - register_unary_op(details:: e_sin,details:: sin_op) - register_unary_op(details:: e_sinc,details:: sinc_op) - register_unary_op(details:: e_sinh,details:: sinh_op) - register_unary_op(details:: e_sqrt,details:: sqrt_op) - register_unary_op(details:: e_tan,details:: tan_op) - register_unary_op(details:: e_tanh,details:: tanh_op) - register_unary_op(details:: e_cot,details:: cot_op) - register_unary_op(details:: e_sec,details:: sec_op) - register_unary_op(details:: e_csc,details:: csc_op) - register_unary_op(details:: e_r2d,details:: r2d_op) - register_unary_op(details:: e_d2r,details:: d2r_op) - register_unary_op(details:: e_d2g,details:: d2g_op) - register_unary_op(details:: e_g2d,details:: g2d_op) - register_unary_op(details:: e_notl,details:: notl_op) - register_unary_op(details:: e_sgn,details:: sgn_op) - register_unary_op(details:: e_erf,details:: erf_op) - register_unary_op(details:: e_erfc,details:: erfc_op) - register_unary_op(details:: e_ncdf,details:: ncdf_op) - register_unary_op(details:: e_frac,details:: frac_op) - register_unary_op(details::e_trunc,details::trunc_op) -#undef register_unary_op - } - - inline void load_binary_operations_map(binary_op_map_t& m) - { - typedef typename binary_op_map_t::value_type value_type; - -#define register_binary_op(Op,BinaryFunctor) \ -m.insert(value_type(Op,BinaryFunctor::process)); \ - - register_binary_op(details:: e_add,details:: add_op) - register_binary_op(details:: e_sub,details:: sub_op) - register_binary_op(details:: e_mul,details:: mul_op) - register_binary_op(details:: e_div,details:: div_op) - register_binary_op(details:: e_mod,details:: mod_op) - register_binary_op(details:: e_pow,details:: pow_op) - register_binary_op(details:: e_lt,details:: lt_op) - register_binary_op(details:: e_lte,details:: lte_op) - register_binary_op(details:: e_gt,details:: gt_op) - register_binary_op(details:: e_gte,details:: gte_op) - register_binary_op(details:: e_eq,details:: eq_op) - register_binary_op(details:: e_ne,details:: ne_op) - register_binary_op(details:: e_and,details:: and_op) - register_binary_op(details::e_nand,details::nand_op) - register_binary_op(details:: e_or,details:: or_op) - register_binary_op(details:: e_nor,details:: nor_op) - register_binary_op(details:: e_xor,details:: xor_op) - register_binary_op(details::e_xnor,details::xnor_op) -#undef register_binary_op - } - - inline void load_inv_binary_operations_map(inv_binary_op_map_t& m) - { - typedef typename inv_binary_op_map_t::value_type value_type; - -#define register_binary_op(Op,BinaryFunctor) \ -m.insert(value_type(BinaryFunctor::process,Op)); \ - - register_binary_op(details:: e_add,details:: add_op) - register_binary_op(details:: e_sub,details:: sub_op) - register_binary_op(details:: e_mul,details:: mul_op) - register_binary_op(details:: e_div,details:: div_op) - register_binary_op(details:: e_mod,details:: mod_op) - register_binary_op(details:: e_pow,details:: pow_op) - register_binary_op(details:: e_lt,details:: lt_op) - register_binary_op(details:: e_lte,details:: lte_op) - register_binary_op(details:: e_gt,details:: gt_op) - register_binary_op(details:: e_gte,details:: gte_op) - register_binary_op(details:: e_eq,details:: eq_op) - register_binary_op(details:: e_ne,details:: ne_op) - register_binary_op(details:: e_and,details:: and_op) - register_binary_op(details::e_nand,details::nand_op) - register_binary_op(details:: e_or,details:: or_op) - register_binary_op(details:: e_nor,details:: nor_op) - register_binary_op(details:: e_xor,details:: xor_op) - register_binary_op(details::e_xnor,details::xnor_op) -#undef register_binary_op - } - - inline void load_sf3_map(sf3_map_t& sf3_map) - { - typedef std::pair pair_t; - -#define register_sf3(Op) \ -sf3_map[details::sf##Op##_op::id()] = pair_t(details::sf##Op##_op::process,details::e_sf##Op); \ - - register_sf3(00) register_sf3(01) register_sf3(02) register_sf3(03) - register_sf3(04) register_sf3(05) register_sf3(06) register_sf3(07) - register_sf3(08) register_sf3(09) register_sf3(10) register_sf3(11) - register_sf3(12) register_sf3(13) register_sf3(14) register_sf3(15) - register_sf3(16) register_sf3(17) register_sf3(18) register_sf3(19) - register_sf3(20) register_sf3(21) register_sf3(22) register_sf3(23) - register_sf3(24) register_sf3(25) register_sf3(26) register_sf3(27) - register_sf3(28) register_sf3(29) register_sf3(30) -#undef register_sf3 - } - - inline void load_sf4_map(sf4_map_t& sf4_map) - { - typedef std::pair pair_t; - -#define register_sf4(Op) \ -sf4_map[details::sf##Op##_op::id()] = pair_t(details::sf##Op##_op::process,details::e_sf##Op); \ - - register_sf4(48) register_sf4(49) register_sf4(50) register_sf4(51) - register_sf4(52) register_sf4(53) register_sf4(54) register_sf4(55) - register_sf4(56) register_sf4(57) register_sf4(58) register_sf4(59) - register_sf4(60) register_sf4(61) register_sf4(62) register_sf4(63) - register_sf4(64) register_sf4(65) register_sf4(66) register_sf4(67) - register_sf4(68) register_sf4(69) register_sf4(70) register_sf4(71) - register_sf4(72) register_sf4(73) register_sf4(74) register_sf4(75) - register_sf4(76) register_sf4(77) register_sf4(78) register_sf4(79) - register_sf4(80) register_sf4(81) register_sf4(82) register_sf4(83) -#undef register_sf4 - -#define register_sf4ext(Op) \ -sf4_map[details::sfext##Op##_op::id()] = pair_t(details::sfext##Op##_op::process,details::e_sf4ext##Op); \ - - register_sf4ext(00) register_sf4ext(01) register_sf4ext(02) register_sf4ext(03) - register_sf4ext(04) register_sf4ext(05) register_sf4ext(06) register_sf4ext(07) - register_sf4ext(08) register_sf4ext(09) register_sf4ext(10) register_sf4ext(11) - register_sf4ext(12) register_sf4ext(13) register_sf4ext(14) register_sf4ext(15) - register_sf4ext(16) register_sf4ext(17) register_sf4ext(18) register_sf4ext(19) - register_sf4ext(20) register_sf4ext(21) register_sf4ext(22) register_sf4ext(23) - register_sf4ext(24) register_sf4ext(25) register_sf4ext(26) register_sf4ext(27) - register_sf4ext(28) register_sf4ext(29) register_sf4ext(30) register_sf4ext(31) - register_sf4ext(32) register_sf4ext(33) register_sf4ext(34) register_sf4ext(35) - register_sf4ext(36) register_sf4ext(36) register_sf4ext(38) register_sf4ext(39) - register_sf4ext(40) register_sf4ext(41) register_sf4ext(42) register_sf4ext(43) - register_sf4ext(44) register_sf4ext(45) register_sf4ext(46) register_sf4ext(47) - register_sf4ext(48) register_sf4ext(49) register_sf4ext(50) register_sf4ext(51) - register_sf4ext(52) register_sf4ext(53) register_sf4ext(54) register_sf4ext(55) - register_sf4ext(56) register_sf4ext(57) register_sf4ext(58) register_sf4ext(59) - register_sf4ext(60) -#undef register_sf4ext - } - - inline results_context_t& results_ctx() - { - if (0 == results_context_) - { - results_context_ = new results_context_t(); - } - - return (*results_context_); - } - - inline void return_cleanup() - { - if (results_context_) - { - delete results_context_; - results_context_ = 0; - } - - state_.return_stmt_present = false; - } - - private: - - parser(const parser&); - parser& operator=(const parser&); - - settings_store settings_; - expression_generator expression_generator_; - details::node_allocator node_allocator_; - symtab_store symtab_store_; - dependent_entity_collector dec_; - std::deque error_list_; - std::deque brkcnt_list_; - parser_state state_; - bool resolve_unknown_symbol_; - results_context_t* results_context_; - unknown_symbol_resolver* unknown_symbol_resolver_; - unknown_symbol_resolver default_usr_; - base_ops_map_t base_ops_map_; - unary_op_map_t unary_op_map_; - binary_op_map_t binary_op_map_; - inv_binary_op_map_t inv_binary_op_map_; - sf3_map_t sf3_map_; - sf4_map_t sf4_map_; - std::string synthesis_error_; - scope_element_manager sem_; - - lexer::helper::helper_assembly helper_assembly_; - - lexer::helper::commutative_inserter commutative_inserter_; - lexer::helper::operator_joiner operator_joiner_2_; - lexer::helper::operator_joiner operator_joiner_3_; - lexer::helper::symbol_replacer symbol_replacer_; - lexer::helper::bracket_checker bracket_checker_; - lexer::helper::numeric_checker numeric_checker_; - lexer::helper::sequence_validator sequence_validator_; - }; - - template - inline T integrate(const expression& e, - T& x, - const T& r0, const T& r1, - const std::size_t number_of_intervals = 1000000) - { - if (r0 > r1) + } + + return T(0); + } + }; + + template + class count : public exprtk::igeneric_function + { + public: + + typedef typename exprtk::igeneric_function igfun_t; + typedef typename igfun_t::parameter_list_t parameter_list_t; + typedef typename igfun_t::generic_type generic_type; + typedef typename generic_type::vector_view vector_t; + + using exprtk::igeneric_function::operator(); + + count() + : exprtk::igeneric_function("V|VTT") + /* + Overloads: + 0. V - vector + 1. VTT - vector, r0, r1 + */ + {} + + inline T operator()(const std::size_t& ps_index, parameter_list_t parameters) + { + const vector_t& vec(parameters[0]); + + std::size_t r0 = 0; + std::size_t r1 = vec.size() - 1; + + if ((1 == ps_index) && !helper::load_vector_range::process(parameters,r0,r1,1,2,0)) + return std::numeric_limits::quiet_NaN(); + + std::size_t cnt = 0; + + for (std::size_t i = r0; i <= r1; ++i) + { + if (vec[i] != T(0)) ++cnt; + } + + return T(cnt); + } + }; + + template + class copy : public exprtk::igeneric_function + { + public: + + typedef typename exprtk::igeneric_function igfun_t; + typedef typename igfun_t::parameter_list_t parameter_list_t; + typedef typename igfun_t::generic_type generic_type; + typedef typename generic_type::scalar_view scalar_t; + typedef typename generic_type::vector_view vector_t; + + using exprtk::igeneric_function::operator(); + + copy() + : exprtk::igeneric_function("VV|VTTVTT") + /* + Overloads: + 0. VV - x(vector), y(vector) + 1. VTTVTT - x(vector), xr0, xr1, y(vector), yr0, yr1, + */ + {} + + inline T operator()(const std::size_t& ps_index, parameter_list_t parameters) + { + vector_t x(parameters[0]); + vector_t y(parameters[(0 == ps_index) ? 1 : 3]); + + std::size_t xr0 = 0; + std::size_t xr1 = x.size() - 1; + + std::size_t yr0 = 0; + std::size_t yr1 = y.size() - 1; + + if ((1 == ps_index) && !helper::load_vector_range::process(parameters,xr0,xr1,1,2,0)) return T(0); - - T h = (r1 - r0) / (T(2) * number_of_intervals); - T total_area = T(0); - - for (std::size_t i = 0; i < number_of_intervals; ++i) - { - x = r0 + T(2) * i * h; - T y0 = e.value(); x += h; - T y1 = e.value(); x += h; - T y2 = e.value(); x += h; - total_area += h * (y0 + T(4) * y1 + y2) / T(3); - } - - return total_area; - } - - template - inline T integrate(const expression& e, - const std::string& variable_name, - const T& r0, const T& r1, - const std::size_t number_of_intervals = 1000000) - { - const symbol_table& sym_table = e.get_symbol_table(); - - if (!sym_table.valid()) + if ((1 == ps_index) && !helper::load_vector_range::process(parameters,yr0,yr1,4,5,3)) + return T(0); + + const std::size_t n = std::min(xr1 - xr0 + 1, yr1 - yr0 + 1); + + std::copy(x.begin() + xr0, x.begin() + xr0 + n, y.begin() + yr0); + + return T(n); + } + }; + + template + class rol : public exprtk::igeneric_function + { + public: + + typedef typename exprtk::igeneric_function igfun_t; + typedef typename igfun_t::parameter_list_t parameter_list_t; + typedef typename igfun_t::generic_type generic_type; + typedef typename generic_type::scalar_view scalar_t; + typedef typename generic_type::vector_view vector_t; + + using exprtk::igeneric_function::operator(); + + rol() + : exprtk::igeneric_function("VT|VTTT") + /* + Overloads: + 0. VT - vector, N + 1. VTTT - vector, N, r0, r1 + */ + {} + + inline T operator()(const std::size_t& ps_index, parameter_list_t parameters) + { + vector_t vec(parameters[0]); + + std::size_t n = 0; + std::size_t r0 = 0; + std::size_t r1 = vec.size() - 1; + + if (!scalar_t(parameters[1]).to_uint(n)) + return T(0); + + if ((1 == ps_index) && !helper::load_vector_range::process(parameters,r0,r1,2,3,0)) + return T(0); + + std::size_t dist = r1 - r0 + 1; + std::size_t shift = n % dist; + + std::rotate(vec.begin() + r0, vec.begin() + r0 + shift, vec.begin() + r1 + 1); + + return T(1); + } + }; + + template + class ror : public exprtk::igeneric_function + { + public: + + typedef typename exprtk::igeneric_function igfun_t; + typedef typename igfun_t::parameter_list_t parameter_list_t; + typedef typename igfun_t::generic_type generic_type; + typedef typename generic_type::scalar_view scalar_t; + typedef typename generic_type::vector_view vector_t; + + using exprtk::igeneric_function::operator(); + + ror() + : exprtk::igeneric_function("VT|VTTT") + /* + Overloads: + 0. VT - vector, N + 1. VTTT - vector, N, r0, r1 + */ + {} + + inline T operator()(const std::size_t& ps_index, parameter_list_t parameters) + { + vector_t vec(parameters[0]); + + std::size_t n = 0; + std::size_t r0 = 0; + std::size_t r1 = vec.size() - 1; + + if (!scalar_t(parameters[1]).to_uint(n)) + return T(0); + + if ((1 == ps_index) && !helper::load_vector_range::process(parameters,r0,r1,2,3,0)) + return T(0); + + std::size_t dist = r1 - r0 + 1; + std::size_t shift = (dist - (n % dist)) % dist; + + std::rotate(vec.begin() + r0, vec.begin() + r0 + shift, vec.begin() + r1 + 1); + + return T(1); + } + }; + + template + class shift_left : public exprtk::igeneric_function + { + public: + + typedef typename exprtk::igeneric_function igfun_t; + typedef typename igfun_t::parameter_list_t parameter_list_t; + typedef typename igfun_t::generic_type generic_type; + typedef typename generic_type::scalar_view scalar_t; + typedef typename generic_type::vector_view vector_t; + + using exprtk::igeneric_function::operator(); + + shift_left() + : exprtk::igeneric_function("VT|VTTT") + /* + Overloads: + 0. VT - vector, N + 1. VTTT - vector, N, r0, r1 + */ + {} + + inline T operator()(const std::size_t& ps_index, parameter_list_t parameters) + { + vector_t vec(parameters[0]); + + std::size_t n = 0; + std::size_t r0 = 0; + std::size_t r1 = vec.size() - 1; + + if (!scalar_t(parameters[1]).to_uint(n)) + return T(0); + + if ((1 == ps_index) && !helper::load_vector_range::process(parameters,r0,r1,2,3,0)) + return T(0); + + std::size_t dist = r1 - r0 + 1; + + if (n > dist) + return T(0); + + std::rotate(vec.begin() + r0, vec.begin() + r0 + n, vec.begin() + r1 + 1); + + for (std::size_t i = r1 - n + 1; i <= r1; ++i) + { + vec[i] = T(0); + } + + return T(1); + } + }; + + template + class shift_right : public exprtk::igeneric_function + { + public: + + typedef typename exprtk::igeneric_function igfun_t; + typedef typename igfun_t::parameter_list_t parameter_list_t; + typedef typename igfun_t::generic_type generic_type; + typedef typename generic_type::scalar_view scalar_t; + typedef typename generic_type::vector_view vector_t; + + using exprtk::igeneric_function::operator(); + + shift_right() + : exprtk::igeneric_function("VT|VTTT") + /* + Overloads: + 0. VT - vector, N + 1. VTTT - vector, N, r0, r1 + */ + {} + + inline T operator()(const std::size_t& ps_index, parameter_list_t parameters) + { + vector_t vec(parameters[0]); + + std::size_t n = 0; + std::size_t r0 = 0; + std::size_t r1 = vec.size() - 1; + + if (!scalar_t(parameters[1]).to_uint(n)) + return T(0); + + if ((1 == ps_index) && !helper::load_vector_range::process(parameters,r0,r1,2,3,0)) + return T(0); + + std::size_t dist = r1 - r0 + 1; + + if (n > dist) + return T(0); + + std::size_t shift = (dist - (n % dist)) % dist; + + std::rotate(vec.begin() + r0, vec.begin() + r0 + shift, vec.begin() + r1 + 1); + + for (std::size_t i = r0; i < r0 + n; ++i) + { + vec[i] = T(0); + } + + return T(1); + } + }; + + template + class sort : public exprtk::igeneric_function + { + public: + + typedef typename exprtk::igeneric_function igfun_t; + typedef typename igfun_t::parameter_list_t parameter_list_t; + typedef typename igfun_t::generic_type generic_type; + typedef typename generic_type::string_view string_t; + typedef typename generic_type::vector_view vector_t; + + using exprtk::igeneric_function::operator(); + + sort() + : exprtk::igeneric_function("V|VTT|VS|VSTT") + /* + Overloads: + 0. V - vector + 1. VTT - vector, r0, r1 + 2. VS - vector, string + 3. VSTT - vector, string, r0, r1 + */ + {} + + inline T operator()(const std::size_t& ps_index, parameter_list_t parameters) + { + vector_t vec(parameters[0]); + + std::size_t r0 = 0; + std::size_t r1 = vec.size() - 1; + + if ((1 == ps_index) && !helper::load_vector_range::process(parameters,r0,r1,1,2,0)) + return T(0); + if ((3 == ps_index) && !helper::load_vector_range::process(parameters,r0,r1,2,3,0)) + return T(0); + + bool ascending = true; + + if ((2 == ps_index) || (3 == ps_index)) + { + if (exprtk::details::imatch(to_str(string_t(parameters[1])),"ascending")) + ascending = true; + else if (exprtk::details::imatch(to_str(string_t(parameters[1])),"descending")) + ascending = false; + else + return T(0); + } + + if (ascending) + std::sort(vec.begin() + r0, vec.begin() + r1 + 1, std::less ()); + else + std::sort(vec.begin() + r0, vec.begin() + r1 + 1, std::greater()); + + return T(1); + } + }; + + template + class nthelement : public exprtk::igeneric_function + { + public: + + typedef typename exprtk::igeneric_function igfun_t; + typedef typename igfun_t::parameter_list_t parameter_list_t; + typedef typename igfun_t::generic_type generic_type; + typedef typename generic_type::scalar_view scalar_t; + typedef typename generic_type::vector_view vector_t; + + using exprtk::igeneric_function::operator(); + + nthelement() + : exprtk::igeneric_function("VT|VTTT") + /* + Overloads: + 0. VT - vector, nth-element + 1. VTTT - vector, nth-element, r0, r1 + */ + {} + + inline T operator()(const std::size_t& ps_index, parameter_list_t parameters) + { + vector_t vec(parameters[0]); + + std::size_t n = 0; + std::size_t r0 = 0; + std::size_t r1 = vec.size() - 1; + + if (!scalar_t(parameters[1]).to_uint(n)) + return T(0); + + if ((1 == ps_index) && !helper::load_vector_range::process(parameters,r0,r1,2,3,0)) return std::numeric_limits::quiet_NaN(); - - details::variable_node* var = sym_table.get_variable(variable_name); - - if (var) - { - T& x = var->ref(); - T x_original = x; - T result = integrate(e,x,r0,r1,number_of_intervals); - x = x_original; - - return result; - } - else + + std::nth_element(vec.begin() + r0, vec.begin() + r0 + n , vec.begin() + r1 + 1); + + return T(1); + } + }; + + template + class iota : public exprtk::igeneric_function + { + public: + + typedef typename exprtk::igeneric_function igfun_t; + typedef typename igfun_t::parameter_list_t parameter_list_t; + typedef typename igfun_t::generic_type generic_type; + typedef typename generic_type::scalar_view scalar_t; + typedef typename generic_type::vector_view vector_t; + + using exprtk::igeneric_function::operator(); + + iota() + : exprtk::igeneric_function("VT|VTT|VTTT|VTTTT") + /* + Overloads: + 0. VT - vector, increment + 1. VTT - vector, increment, base + 2. VTTTT - vector, increment, r0, r1 + 3. VTTTT - vector, increment, base, r0, r1 + */ + {} + + inline T operator()(const std::size_t& ps_index, parameter_list_t parameters) + { + vector_t vec(parameters[0]); + + T increment = scalar_t(parameters[1])(); + T base = ((1 == ps_index) || (3 == ps_index)) ? scalar_t(parameters[2])() : T(0); + + std::size_t r0 = 0; + std::size_t r1 = vec.size() - 1; + + if ((2 == ps_index) && !helper::load_vector_range::process(parameters,r0,r1,2,3,0)) return std::numeric_limits::quiet_NaN(); - } - - template - inline T derivative(const expression& e, - T& x, - const T& h = T(0.00000001)) - { - T x_init = x; - x = x_init + T(2) * h; - T y0 = e.value(); - x = x_init + h; - T y1 = e.value(); - x = x_init - h; - T y2 = e.value(); - x = x_init - T(2) * h; - T y3 = e.value(); - x = x_init; - - return (-y0 + T(8) * (y1 - y2) + y3) / (T(12) * h); - } - - template - inline T second_derivative(const expression& e, - T& x, - const T& h = T(0.00001)) - { - T y = e.value(); - T x_init = x; - x = x_init + T(2) * h; - T y0 = e.value(); - x = x_init + h; - T y1 = e.value(); - x = x_init - h; - T y2 = e.value(); - x = x_init - T(2) * h; - T y3 = e.value(); - x = x_init; - - return (-y0 + T(16) * (y1 + y2) - T(30) * y - y3) / (T(12) * h * h); - } - - template - inline T third_derivative(const expression& e, - T& x, - const T& h = T(0.0001)) - { - T x_init = x; - x = x_init + T(2) * h; - T y0 = e.value(); - x = x_init + h; - T y1 = e.value(); - x = x_init - h; - T y2 = e.value(); - x = x_init - T(2) * h; - T y3 = e.value(); - x = x_init; - - return (y0 + T(2) * (y2 - y1) - y3) / (T(2) * h * h * h); - } - - template - inline T derivative(const expression& e, - const std::string& variable_name, - const T& h = T(0.00000001)) - { - const symbol_table& sym_table = e.get_symbol_table(); - - if (!sym_table.valid()) - { + else if ((3 == ps_index) && !helper::load_vector_range::process(parameters,r0,r1,3,4,0)) return std::numeric_limits::quiet_NaN(); - } - - details::variable_node* var = sym_table.get_variable(variable_name); - - if (var) - { - T& x = var->ref(); - T x_original = x; - T result = derivative(e,x,h); - x = x_original; - - return result; - } - else + else + { + long long j = 0; + + for (std::size_t i = r0; i <= r1; ++i, ++j) + { + vec[i] = base + (increment * j); + } + } + + return T(1); + } + }; + + template + class sumk : public exprtk::igeneric_function + { + public: + + typedef typename exprtk::igeneric_function igfun_t; + typedef typename igfun_t::parameter_list_t parameter_list_t; + typedef typename igfun_t::generic_type generic_type; + typedef typename generic_type::vector_view vector_t; + + using exprtk::igeneric_function::operator(); + + sumk() + : exprtk::igeneric_function("V|VTT") + /* + Overloads: + 0. V - vector + 1. VTT - vector, r0, r1 + */ + {} + + inline T operator()(const std::size_t& ps_index, parameter_list_t parameters) + { + vector_t vec(parameters[0]); + + std::size_t r0 = 0; + std::size_t r1 = vec.size() - 1; + + if ((1 == ps_index) && !helper::load_vector_range::process(parameters,r0,r1,1,2,0)) return std::numeric_limits::quiet_NaN(); - } - - template - inline T second_derivative(const expression& e, - const std::string& variable_name, - const T& h = T(0.00001)) - { - const symbol_table& sym_table = e.get_symbol_table(); - - if (!sym_table.valid()) - { + + T result = T(0); + T error = T(0); + + for (std::size_t i = r0; i <= r1; ++i) + { + details::kahan_sum(result,error,vec[i]); + } + + return result; + } + }; + + template + class axpy : public exprtk::igeneric_function + { + public: + + typedef typename exprtk::igeneric_function igfun_t; + typedef typename igfun_t::parameter_list_t parameter_list_t; + typedef typename igfun_t::generic_type generic_type; + typedef typename generic_type::scalar_view scalar_t; + typedef typename generic_type::vector_view vector_t; + + using exprtk::igeneric_function::operator(); + + axpy() + : exprtk::igeneric_function("TVV|TVVTT") + /* + y <- ax + y + Overloads: + 0. TVV - a, x(vector), y(vector) + 1. TVVTT - a, x(vector), y(vector), r0, r1 + */ + {} + + inline T operator()(const std::size_t& ps_index, parameter_list_t parameters) + { + vector_t x(parameters[1]); + vector_t y(parameters[2]); + + std::size_t r0 = 0; + std::size_t r1 = std::min(x.size(),y.size()) - 1; + + if ((1 == ps_index) && !helper::load_vector_range::process(parameters,r0,r1,3,4,1)) return std::numeric_limits::quiet_NaN(); - } - - details::variable_node* var = sym_table.get_variable(variable_name); - - if (var) - { - T& x = var->ref(); - T x_original = x; - T result = second_derivative(e,x,h); - x = x_original; - - return result; - } - else + else if (helper::invalid_range(y,r0,r1)) return std::numeric_limits::quiet_NaN(); - } - - template - inline T third_derivative(const expression& e, - const std::string& variable_name, - const T& h = T(0.0001)) - { - const symbol_table& sym_table = e.get_symbol_table(); - - if (!sym_table.valid()) - { + + T a = scalar_t(parameters[0])(); + + for (std::size_t i = r0; i <= r1; ++i) + { + y[i] = a * x[i] + y[i]; + } + + return T(1); + } + }; + + template + class axpby : public exprtk::igeneric_function + { + public: + + typedef typename exprtk::igeneric_function igfun_t; + typedef typename igfun_t::parameter_list_t parameter_list_t; + typedef typename igfun_t::generic_type generic_type; + typedef typename generic_type::scalar_view scalar_t; + typedef typename generic_type::vector_view vector_t; + + using exprtk::igeneric_function::operator(); + + axpby() + : exprtk::igeneric_function("TVTV|TVTVTT") + /* + y <- ax + by + Overloads: + 0. TVTV - a, x(vector), b, y(vector) + 1. TVTVTT - a, x(vector), b, y(vector), r0, r1 + */ + {} + + inline T operator()(const std::size_t& ps_index, parameter_list_t parameters) + { + vector_t x(parameters[1]); + vector_t y(parameters[3]); + + std::size_t r0 = 0; + std::size_t r1 = std::min(x.size(),y.size()) - 1; + + if ((1 == ps_index) && !helper::load_vector_range::process(parameters,r0,r1,4,5,1)) return std::numeric_limits::quiet_NaN(); - } - - details::variable_node* var = sym_table.get_variable(variable_name); - - if (var) - { - T& x = var->ref(); - T x_original = x; - T result = third_derivative(e,x,h); - x = x_original; - - return result; - } - else + else if (helper::invalid_range(y,r0,r1)) return std::numeric_limits::quiet_NaN(); - } - - /* - Note: The following 'compute' routines are simple helpers, - for quickly setting up the required pieces of code in order - to evaluate an expression. By virtue of how they operate - there will be an overhead with regards to their setup and - teardown and hence should not be used in time critical - sections of code. - Furthermore they only assume a small sub set of variables - no - string variables or user defined functions. - */ - template - inline bool compute(const std::string& expression_string, T& result) - { - // No variables - symbol_table symbol_table; - symbol_table.add_constants(); - - expression expression; - parser parser; - - if (parser.compile(expression_string,expression)) - { - result = expression.value(); - - return true; - } - else - return false; - } - - template - inline bool compute(const std::string& expression_string, - const T& x, - T& result) - { - // Only 'x' - static const std::string x_var("x"); - - symbol_table symbol_table; - symbol_table.add_constants(); - symbol_table.add_variable(x_var,x); - - expression expression; - parser parser; - - if (parser.compile(expression_string,expression)) - { - result = expression.value(); - - return true; - } - else - return false; - } - - template - inline bool compute(const std::string& expression_string, - const T&x, const T& y, - T& result) - { - // Only 'x' and 'y' - static const std::string x_var("x"); - static const std::string y_var("y"); - - symbol_table symbol_table; - symbol_table.add_constants(); - symbol_table.add_variable(x_var,x); - symbol_table.add_variable(y_var,y); - - expression expression; - parser parser; - - if (parser.compile(expression_string,expression)) - { - result = expression.value(); - - return true; - } - else - return false; - } - - template - inline bool compute(const std::string& expression_string, - const T& x, const T& y, const T& z, - T& result) - { - // Only 'x', 'y' or 'z' - static const std::string x_var("x"); - static const std::string y_var("y"); - static const std::string z_var("z"); - - symbol_table symbol_table; - symbol_table.add_constants(); - symbol_table.add_variable(x_var,x); - symbol_table.add_variable(y_var,y); - symbol_table.add_variable(z_var,z); - - expression expression; - parser parser; - - if (parser.compile(expression_string,expression)) - { - result = expression.value(); - - return true; - } - else - return false; - } - - template - class polynomial : public ifunction - { - private: - - template - struct poly_impl { }; - - template - struct poly_impl - { - static inline T evaluate(const Type x, - const Type c12, const Type c11, const Type c10, const Type c9, const Type c8, - const Type c7, const Type c6, const Type c5, const Type c4, const Type c3, - const Type c2, const Type c1, const Type c0) - { - // p(x) = c_12x^12 + c_11x^11 + c_10x^10 + c_9x^9 + c_8x^8 + c_7x^7 + c_6x^6 + c_5x^5 + c_4x^4 + c_3x^3 + c_2x^2 + c_1x^1 + c_0x^0 - return ((((((((((((c12 * x + c11) * x + c10) * x + c9) * x + c8) * x + c7) * x + c6) * x + c5) * x + c4) * x + c3) * x + c2) * x + c1) * x + c0); - } - }; - - template - struct poly_impl - { - static inline T evaluate(const Type x, - const Type c11, const Type c10, const Type c9, const Type c8, const Type c7, - const Type c6, const Type c5, const Type c4, const Type c3, const Type c2, - const Type c1, const Type c0) - { - // p(x) = c_11x^11 + c_10x^10 + c_9x^9 + c_8x^8 + c_7x^7 + c_6x^6 + c_5x^5 + c_4x^4 + c_3x^3 + c_2x^2 + c_1x^1 + c_0x^0 - return (((((((((((c11 * x + c10) * x + c9) * x + c8) * x + c7) * x + c6) * x + c5) * x + c4) * x + c3) * x + c2) * x + c1) * x + c0); - } - }; - - template - struct poly_impl - { - static inline T evaluate(const Type x, - const Type c10, const Type c9, const Type c8, const Type c7, const Type c6, - const Type c5, const Type c4, const Type c3, const Type c2, const Type c1, - const Type c0) - { - // p(x) = c_10x^10 + c_9x^9 + c_8x^8 + c_7x^7 + c_6x^6 + c_5x^5 + c_4x^4 + c_3x^3 + c_2x^2 + c_1x^1 + c_0x^0 - return ((((((((((c10 * x + c9) * x + c8) * x + c7) * x + c6) * x + c5) * x + c4) * x + c3) * x + c2) * x + c1) * x + c0); - } - }; - - template - struct poly_impl - { - static inline T evaluate(const Type x, - const Type c9, const Type c8, const Type c7, const Type c6, const Type c5, - const Type c4, const Type c3, const Type c2, const Type c1, const Type c0) - { - // p(x) = c_9x^9 + c_8x^8 + c_7x^7 + c_6x^6 + c_5x^5 + c_4x^4 + c_3x^3 + c_2x^2 + c_1x^1 + c_0x^0 - return (((((((((c9 * x + c8) * x + c7) * x + c6) * x + c5) * x + c4) * x + c3) * x + c2) * x + c1) * x + c0); - } - }; - - template - struct poly_impl - { - static inline T evaluate(const Type x, - const Type c8, const Type c7, const Type c6, const Type c5, const Type c4, - const Type c3, const Type c2, const Type c1, const Type c0) - { - // p(x) = c_8x^8 + c_7x^7 + c_6x^6 + c_5x^5 + c_4x^4 + c_3x^3 + c_2x^2 + c_1x^1 + c_0x^0 - return ((((((((c8 * x + c7) * x + c6) * x + c5) * x + c4) * x + c3) * x + c2) * x + c1) * x + c0); - } - }; - - template - struct poly_impl - { - static inline T evaluate(const Type x, - const Type c7, const Type c6, const Type c5, const Type c4, const Type c3, - const Type c2, const Type c1, const Type c0) - { - // p(x) = c_7x^7 + c_6x^6 + c_5x^5 + c_4x^4 + c_3x^3 + c_2x^2 + c_1x^1 + c_0x^0 - return (((((((c7 * x + c6) * x + c5) * x + c4) * x + c3) * x + c2) * x + c1) * x + c0); - } - }; - - template - struct poly_impl - { - static inline T evaluate(const Type x, - const Type c6, const Type c5, const Type c4, const Type c3, const Type c2, - const Type c1, const Type c0) - { - // p(x) = c_6x^6 + c_5x^5 + c_4x^4 + c_3x^3 + c_2x^2 + c_1x^1 + c_0x^0 - return ((((((c6 * x + c5) * x + c4) * x + c3) * x + c2) * x + c1) * x + c0); - } - }; - - template - struct poly_impl - { - static inline T evaluate(const Type x, - const Type c5, const Type c4, const Type c3, const Type c2, - const Type c1, const Type c0) - { - // p(x) = c_5x^5 + c_4x^4 + c_3x^3 + c_2x^2 + c_1x^1 + c_0x^0 - return (((((c5 * x + c4) * x + c3) * x + c2) * x + c1) * x + c0); - } - }; - - template - struct poly_impl - { - static inline T evaluate(const Type x, const Type c4, const Type c3, const Type c2, const Type c1, const Type c0) - { - // p(x) = c_4x^4 + c_3x^3 + c_2x^2 + c_1x^1 + c_0x^0 - return ((((c4 * x + c3) * x + c2) * x + c1) * x + c0); - } - }; - - template - struct poly_impl - { - static inline T evaluate(const Type x, const Type c3, const Type c2, const Type c1, const Type c0) - { - // p(x) = c_3x^3 + c_2x^2 + c_1x^1 + c_0x^0 - return (((c3 * x + c2) * x + c1) * x + c0); - } - }; - - template - struct poly_impl - { - static inline T evaluate(const Type x, const Type c2, const Type c1, const Type c0) - { - // p(x) = c_2x^2 + c_1x^1 + c_0x^0 - return ((c2 * x + c1) * x + c0); - } - }; - - template - struct poly_impl - { - static inline T evaluate(const Type x, const Type c1, const Type c0) - { - // p(x) = c_1x^1 + c_0x^0 - return (c1 * x + c0); - } - }; - - public: - - using ifunction::operator(); - - polynomial() - : ifunction((N+2 <= 20) ? (N + 2) : std::numeric_limits::max()) - { - disable_has_side_effects(*this); - } - - virtual ~polynomial() - {} - -#define poly_rtrn(NN) \ -return (NN != N) ? std::numeric_limits::quiet_NaN() : - - inline virtual T operator()(const T& x, const T& c1, const T& c0) - { - poly_rtrn(1) poly_impl::evaluate(x,c1,c0); - } - - inline virtual T operator()(const T& x, const T& c2, const T& c1, const T& c0) - { - poly_rtrn(2) poly_impl::evaluate(x,c2,c1,c0); - } - - inline virtual T operator()(const T& x, const T& c3, const T& c2, const T& c1, const T& c0) - { - poly_rtrn(3) poly_impl::evaluate(x,c3,c2,c1,c0); - } - - inline virtual T operator()(const T& x, const T& c4, const T& c3, const T& c2, const T& c1, const T& c0) - { - poly_rtrn(4) poly_impl::evaluate(x,c4,c3,c2,c1,c0); - } - - inline virtual T operator()(const T& x, const T& c5, const T& c4, const T& c3, const T& c2, const T& c1, const T& c0) - { - poly_rtrn(5) poly_impl::evaluate(x,c5,c4,c3,c2,c1,c0); - } - - inline virtual T operator()(const T& x, const T& c6, const T& c5, const T& c4, const T& c3, const T& c2, const T& c1, const T& c0) - { - poly_rtrn(6) poly_impl::evaluate(x,c6,c5,c4,c3,c2,c1,c0); - } - - inline virtual T operator()(const T& x, const T& c7, const T& c6, const T& c5, const T& c4, const T& c3, const T& c2, const T& c1, const T& c0) - { - poly_rtrn(7) poly_impl::evaluate(x,c7,c6,c5,c4,c3,c2,c1,c0); - } - - inline virtual T operator()(const T& x, const T& c8, const T& c7, const T& c6, const T& c5, const T& c4, const T& c3, const T& c2, const T& c1, const T& c0) - { - poly_rtrn(8) poly_impl::evaluate(x,c8,c7,c6,c5,c4,c3,c2,c1,c0); - } - - inline virtual T operator()(const T& x, const T& c9, const T& c8, const T& c7, const T& c6, const T& c5, const T& c4, const T& c3, const T& c2, const T& c1, const T& c0) - { - poly_rtrn(9) poly_impl::evaluate(x,c9,c8,c7,c6,c5,c4,c3,c2,c1,c0); - } - - inline virtual T operator()(const T& x, const T& c10, const T& c9, const T& c8, const T& c7, const T& c6, const T& c5, const T& c4, const T& c3, const T& c2, const T& c1, const T& c0) - { - poly_rtrn(10) poly_impl::evaluate(x,c10,c9,c8,c7,c6,c5,c4,c3,c2,c1,c0); - } - - inline virtual T operator()(const T& x, const T& c11, const T& c10, const T& c9, const T& c8, const T& c7, const T& c6, const T& c5, const T& c4, const T& c3, const T& c2, const T& c1, const T& c0) - { - poly_rtrn(11) poly_impl::evaluate(x,c11,c10,c9,c8,c7,c6,c5,c4,c3,c2,c1,c0); - } - - inline virtual T operator()(const T& x, const T& c12, const T& c11, const T& c10, const T& c9, const T& c8, const T& c7, const T& c6, const T& c5, const T& c4, const T& c3, const T& c2, const T& c1, const T& c0) - { - poly_rtrn(12) poly_impl::evaluate(x,c12,c11,c10,c9,c8,c7,c6,c5,c4,c3,c2,c1,c0); - } - -#undef poly_rtrn - - inline virtual T operator()() - { + + const T a = scalar_t(parameters[0])(); + const T b = scalar_t(parameters[2])(); + + for (std::size_t i = r0; i <= r1; ++i) + { + y[i] = (a * x[i]) + (b * y[i]); + } + + return T(1); + } + }; + + template + class axpyz : public exprtk::igeneric_function + { + public: + + typedef typename exprtk::igeneric_function igfun_t; + typedef typename igfun_t::parameter_list_t parameter_list_t; + typedef typename igfun_t::generic_type generic_type; + typedef typename generic_type::scalar_view scalar_t; + typedef typename generic_type::vector_view vector_t; + + using exprtk::igeneric_function::operator(); + + axpyz() + : exprtk::igeneric_function("TVVV|TVVVTT") + /* + z <- ax + y + Overloads: + 0. TVVV - a, x(vector), y(vector), z(vector) + 1. TVVVTT - a, x(vector), y(vector), z(vector), r0, r1 + */ + {} + + inline T operator()(const std::size_t& ps_index, parameter_list_t parameters) + { + vector_t x(parameters[1]); + vector_t y(parameters[2]); + vector_t z(parameters[3]); + + std::size_t r0 = 0; + std::size_t r1 = std::min(x.size(),y.size()) - 1; + + if ((1 == ps_index) && !helper::load_vector_range::process(parameters,r0,r1,3,4,1)) + return std::numeric_limits::quiet_NaN(); + else if (helper::invalid_range(y,r0,r1)) + return std::numeric_limits::quiet_NaN(); + else if (helper::invalid_range(z,r0,r1)) + return std::numeric_limits::quiet_NaN(); + + T a = scalar_t(parameters[0])(); + + for (std::size_t i = r0; i <= r1; ++i) + { + z[i] = a * x[i] + y[i]; + } + + return T(1); + } + }; + + template + class axpbyz : public exprtk::igeneric_function + { + public: + + typedef typename exprtk::igeneric_function igfun_t; + typedef typename igfun_t::parameter_list_t parameter_list_t; + typedef typename igfun_t::generic_type generic_type; + typedef typename generic_type::scalar_view scalar_t; + typedef typename generic_type::vector_view vector_t; + + using exprtk::igeneric_function::operator(); + + axpbyz() + : exprtk::igeneric_function("TVTVV|TVTVVTT") + /* + z <- ax + by + Overloads: + 0. TVTVV - a, x(vector), b, y(vector), z(vector) + 1. TVTVVTT - a, x(vector), b, y(vector), z(vector), r0, r1 + */ + {} + + inline T operator()(const std::size_t& ps_index, parameter_list_t parameters) + { + vector_t x(parameters[1]); + vector_t y(parameters[3]); + vector_t z(parameters[4]); + + std::size_t r0 = 0; + std::size_t r1 = std::min(x.size(),y.size()) - 1; + + if ((1 == ps_index) && !helper::load_vector_range::process(parameters,r0,r1,4,5,1)) + return std::numeric_limits::quiet_NaN(); + else if (helper::invalid_range(y,r0,r1)) + return std::numeric_limits::quiet_NaN(); + else if (helper::invalid_range(z,r0,r1)) + return std::numeric_limits::quiet_NaN(); + + const T a = scalar_t(parameters[0])(); + const T b = scalar_t(parameters[2])(); + + for (std::size_t i = r0; i <= r1; ++i) + { + z[i] = (a * x[i]) + (b * y[i]); + } + + return T(1); + } + }; + + template + class axpbz : public exprtk::igeneric_function + { + public: + + typedef typename exprtk::igeneric_function igfun_t; + typedef typename igfun_t::parameter_list_t parameter_list_t; + typedef typename igfun_t::generic_type generic_type; + typedef typename generic_type::scalar_view scalar_t; + typedef typename generic_type::vector_view vector_t; + + using exprtk::igeneric_function::operator(); + + axpbz() + : exprtk::igeneric_function("TVTV|TVTVTT") + /* + z <- ax + b + Overloads: + 0. TVTV - a, x(vector), b, z(vector) + 1. TVTVTT - a, x(vector), b, z(vector), r0, r1 + */ + {} + + inline T operator()(const std::size_t& ps_index, parameter_list_t parameters) + { + vector_t x(parameters[1]); + vector_t z(parameters[3]); + + std::size_t r0 = 0; + std::size_t r1 = x.size() - 1; + + if ((1 == ps_index) && !helper::load_vector_range::process(parameters,r0,r1,4,5,1)) + return std::numeric_limits::quiet_NaN(); + else if (helper::invalid_range(z,r0,r1)) + return std::numeric_limits::quiet_NaN(); + + const T a = scalar_t(parameters[0])(); + const T b = scalar_t(parameters[2])(); + + for (std::size_t i = r0; i <= r1; ++i) + { + z[i] = a * x[i] + b; + } + + return T(1); + } + }; + + template + class dot : public exprtk::igeneric_function + { + public: + + typedef typename exprtk::igeneric_function igfun_t; + typedef typename igfun_t::parameter_list_t parameter_list_t; + typedef typename igfun_t::generic_type generic_type; + typedef typename generic_type::scalar_view scalar_t; + typedef typename generic_type::vector_view vector_t; + + using exprtk::igeneric_function::operator(); + + dot() + : exprtk::igeneric_function("VV|VVTT") + /* + Overloads: + 0. VV - x(vector), y(vector) + 1. VVTT - x(vector), y(vector), r0, r1 + */ + {} + + inline T operator()(const std::size_t& ps_index, parameter_list_t parameters) + { + vector_t x(parameters[0]); + vector_t y(parameters[1]); + + std::size_t r0 = 0; + std::size_t r1 = std::min(x.size(),y.size()) - 1; + + if ((1 == ps_index) && !helper::load_vector_range::process(parameters,r0,r1,2,3,0)) return std::numeric_limits::quiet_NaN(); - } - - inline virtual T operator()(const T&) - { + else if (helper::invalid_range(y,r0,r1)) return std::numeric_limits::quiet_NaN(); - } - - inline virtual T operator()(const T&, const T&) - { + + T result = T(0); + + for (std::size_t i = r0; i <= r1; ++i) + { + result += (x[i] * y[i]); + } + + return result; + } + }; + + template + class dotk : public exprtk::igeneric_function + { + public: + + typedef typename exprtk::igeneric_function igfun_t; + typedef typename igfun_t::parameter_list_t parameter_list_t; + typedef typename igfun_t::generic_type generic_type; + typedef typename generic_type::scalar_view scalar_t; + typedef typename generic_type::vector_view vector_t; + + using exprtk::igeneric_function::operator(); + + dotk() + : exprtk::igeneric_function("VV|VVTT") + /* + Overloads: + 0. VV - x(vector), y(vector) + 1. VVTT - x(vector), y(vector), r0, r1 + */ + {} + + inline T operator()(const std::size_t& ps_index, parameter_list_t parameters) + { + vector_t x(parameters[0]); + vector_t y(parameters[1]); + + std::size_t r0 = 0; + std::size_t r1 = std::min(x.size(),y.size()) - 1; + + if ((1 == ps_index) && !helper::load_vector_range::process(parameters,r0,r1,2,3,0)) + return std::numeric_limits::quiet_NaN(); + else if (helper::invalid_range(y,r0,r1)) return std::numeric_limits::quiet_NaN(); - } - }; - - template - class function_compositor - { - public: - - typedef exprtk::expression expression_t; - typedef exprtk::symbol_table symbol_table_t; - typedef exprtk::parser parser_t; - typedef typename parser_t::settings_store settings_t; - - struct function - { - function() - {} - - function(const std::string& n) - : name_(n) - {} - - function(const std::string& name, - const std::string& expression) - : name_(name), - expression_(expression) - {} - - function(const std::string& name, - const std::string& expression, - const std::string& v0) - : name_(name), - expression_(expression) - { - v_.push_back(v0); - } - - function(const std::string& name, - const std::string& expression, - const std::string& v0, const std::string& v1) - : name_(name), - expression_(expression) - { - v_.push_back(v0); v_.push_back(v1); - } - - function(const std::string& name, - const std::string& expression, - const std::string& v0, const std::string& v1, - const std::string& v2) - : name_(name), - expression_(expression) - { - v_.push_back(v0); v_.push_back(v1); - v_.push_back(v2); - } - - function(const std::string& name, - const std::string& expression, - const std::string& v0, const std::string& v1, - const std::string& v2, const std::string& v3) - : name_(name), - expression_(expression) - { - v_.push_back(v0); v_.push_back(v1); - v_.push_back(v2); v_.push_back(v3); - } - - function(const std::string& name, - const std::string& expression, - const std::string& v0, const std::string& v1, - const std::string& v2, const std::string& v3, - const std::string& v4) - : name_(name), - expression_(expression) - { - v_.push_back(v0); v_.push_back(v1); - v_.push_back(v2); v_.push_back(v3); - v_.push_back(v4); - } - - inline function& name(const std::string& n) - { - name_ = n; - return (*this); - } - - inline function& expression(const std::string& e) - { - expression_ = e; - return (*this); - } - - inline function& var(const std::string& v) - { - v_.push_back(v); - return (*this); - } - - std::string name_; - std::string expression_; - std::deque v_; - }; - - private: - - struct base_func : public exprtk::ifunction - { - typedef const T& type; - typedef exprtk::ifunction function_t; - typedef std::vector varref_t; - typedef std::vector var_t; - typedef std::pair lvarref_t; - typedef std::vector lvr_vec_t; - - using exprtk::ifunction::operator(); - - base_func(const std::size_t& pc = 0) - : exprtk::ifunction(pc), - local_var_stack_size(0), - stack_depth(0) - { - v.resize(pc); - } - - virtual ~base_func() - {} - - inline void update(const T& v0) - { - (*v[0]) = v0; - } - - inline void update(const T& v0, const T& v1) - { - (*v[0]) = v0; (*v[1]) = v1; - } - - inline void update(const T& v0, const T& v1, const T& v2) - { - (*v[0]) = v0; (*v[1]) = v1; - (*v[2]) = v2; - } - - inline void update(const T& v0, const T& v1, const T& v2, const T& v3) - { - (*v[0]) = v0; (*v[1]) = v1; - (*v[2]) = v2; (*v[3]) = v3; - } - - inline void update(const T& v0, const T& v1, const T& v2, const T& v3, const T& v4) - { - (*v[0]) = v0; (*v[1]) = v1; - (*v[2]) = v2; (*v[3]) = v3; - (*v[4]) = v4; - } - - inline void update(const T& v0, const T& v1, const T& v2, const T& v3, const T& v4, const T& v5) - { - (*v[0]) = v0; (*v[1]) = v1; - (*v[2]) = v2; (*v[3]) = v3; - (*v[4]) = v4; (*v[5]) = v5; - } - - inline function_t& setup(expression_t& expr) - { - expression = expr; - - typedef typename expression_t::control_block::local_data_list_t ldl_t; - - ldl_t ldl = expr.local_data_list(); - - std::vector index_list; - - for (std::size_t i = 0; i < ldl.size(); ++i) - { - if (ldl[i].size) - { - index_list.push_back(i); - } - } - - std::size_t input_param_count = 0; - - for (std::size_t i = 0; i < index_list.size(); ++i) - { - const std::size_t index = index_list[i]; - - if (i < (index_list.size() - v.size())) - { - lv.push_back( - std::make_pair( - reinterpret_cast(ldl[index].pointer), - ldl[index].size)); - - local_var_stack_size += ldl[index].size; - } - else - v[input_param_count++] = reinterpret_cast(ldl[index].pointer); - } - - clear_stack(); - - return (*this); - } - - inline void pre() - { - if (stack_depth++) - { - if (!v.empty()) - { - var_t var_stack(v.size(),T(0)); - copy(v,var_stack); - param_stack.push_back(var_stack); - } - - if (!lv.empty()) - { - var_t local_var_stack(local_var_stack_size,T(0)); - copy(lv,local_var_stack); - local_stack.push_back(local_var_stack); - } - } - } - - inline void post() - { - if (--stack_depth) - { - if (!v.empty()) - { - copy(param_stack.back(),v); - param_stack.pop_back(); - } - - if (!lv.empty()) - { - copy(local_stack.back(),lv); - local_stack.pop_back(); - } - } - } - - void copy(const varref_t& src_v, var_t& dest_v) - { - for (std::size_t i = 0; i < src_v.size(); ++i) - { - dest_v[i] = (*src_v[i]); - } - } - - void copy(const var_t& src_v, varref_t& dest_v) - { - for (std::size_t i = 0; i < src_v.size(); ++i) - { - (*dest_v[i]) = src_v[i]; - } - } - - void copy(const lvr_vec_t& src_v, var_t& dest_v) - { - typename var_t::iterator itr = dest_v.begin(); - - for (std::size_t i = 0; i < src_v.size(); ++i) - { - lvarref_t vr = src_v[i]; - - if (1 == vr.second) - *itr++ = (*vr.first); - else - { - std::copy(vr.first,vr.first + vr.second,itr); - itr += vr.second; - } - } - } - - void copy(const var_t& src_v, lvr_vec_t& dest_v) - { - typename var_t::const_iterator itr = src_v.begin(); - - for (std::size_t i = 0; i < src_v.size(); ++i) - { - lvarref_t vr = dest_v[i]; - - if (1 == vr.second) - (*vr.first) = *itr++; - else - { - std::copy(itr,itr + vr.second,vr.first); - itr += vr.second; - } - } - } - - inline void clear_stack() - { - for (std::size_t i = 0; i < v.size(); ++i) - { - (*v[i]) = 0; - } - } - - inline virtual T value(expression_t& e) - { - return e.value(); - } - - expression_t expression; - varref_t v; - lvr_vec_t lv; - std::size_t local_var_stack_size; - std::size_t stack_depth; - std::deque param_stack; - std::deque local_stack; - }; - - typedef std::map funcparam_t; - - struct func_0param : public base_func - { - using exprtk::ifunction::operator(); - - func_0param() : base_func(0) {} - - inline T operator()() - { - return this->value(base_func::expression); - } - }; - - typedef const T& type; - - template - struct scoped_bft - { - scoped_bft(BaseFuncType& bft) : bft_(bft) { bft_.pre (); } - ~scoped_bft() { bft_.post(); } - - BaseFuncType& bft_; - - private: - - scoped_bft(scoped_bft&); - scoped_bft& operator=(scoped_bft&); - }; - - struct func_1param : public base_func - { - using exprtk::ifunction::operator(); - - func_1param() : base_func(1) {} - - inline T operator()(type v0) - { - scoped_bft sb(*this); - base_func::update(v0); - T result = this->value(base_func::expression); - - return result; - } - }; - - struct func_2param : public base_func - { - using exprtk::ifunction::operator(); - - func_2param() : base_func(2) {} - - inline T operator()(type v0, type v1) - { - scoped_bft sb(*this); - base_func::update(v0,v1); - T result = this->value(base_func::expression); - - return result; - } - }; - - struct func_3param : public base_func - { - using exprtk::ifunction::operator(); - - func_3param() : base_func(3) {} - - inline T operator()(type v0, type v1, type v2) - { - scoped_bft sb(*this); - base_func::update(v0,v1,v2); - T result = this->value(base_func::expression); - - return result; - } - }; - - struct func_4param : public base_func - { - using exprtk::ifunction::operator(); - - func_4param() : base_func(4) {} - - inline T operator()(type v0, type v1, type v2, type v3) - { - scoped_bft sb(*this); - base_func::update(v0,v1,v2,v3); - T result = this->value(base_func::expression); - - return result; - } - }; - - struct func_5param : public base_func - { - using exprtk::ifunction::operator(); - - func_5param() : base_func(5) {} - - inline T operator()(type v0, type v1, type v2, type v3, type v4) - { - scoped_bft sb(*this); - base_func::update(v0,v1,v2,v3,v4); - T result = this->value(base_func::expression); - - return result; - } - }; - - struct func_6param : public base_func - { - using exprtk::ifunction::operator(); - - func_6param() : base_func(6) {} - - inline T operator()(type v0, type v1, type v2, type v3, type v4, type v5) - { - scoped_bft sb(*this); - base_func::update(v0,v1,v2,v3,v4,v5); - T result = this->value(base_func::expression); - - return result; - } - }; - - static T return_value(expression_t& e) - { - typedef exprtk::results_context results_context_t; - typedef typename results_context_t::type_store_t type_t; - typedef typename type_t::scalar_view scalar_t; - - T result = e.value(); - - if (e.return_invoked()) - { - // Due to the post compilation checks, it can be safely - // assumed that there will be at least one parameter - // and that the first parameter will always be scalar. - return scalar_t(e.results()[0])(); - } - - return result; - } - -#define def_fp_retval(N) \ -struct func_##N##param_retval : public func_##N##param \ -{ \ -inline T value(expression_t& e) \ -{ \ -return return_value(e); \ -} \ -}; \ - - def_fp_retval(0) - def_fp_retval(1) - def_fp_retval(2) - def_fp_retval(3) - def_fp_retval(4) - def_fp_retval(5) - def_fp_retval(6) - - template class Sequence> - inline bool add(const std::string& name, - const std::string& expression, - const Sequence& var_list, - const bool override = false) - { - const std::size_t n = var_list.size(); - - typename std::map::iterator itr = expr_map_.find(name); - - if (expr_map_.end() != itr) - { - if (!override) - { - exprtk_debug(("Compositor error(add): function '%s' already defined\n", - name.c_str())); - - return false; - } - - remove(name, var_list.size()); - } - - if (compile_expression(name,expression,var_list)) - { - fp_map_[n][name]->setup(expr_map_[name]); - - return true; - } - else - { - exprtk_debug(("Compositor error(add): Failed to compile function '%s'\n", - name.c_str())); - - return false; - } - } - - public: - - function_compositor() - : parser_(settings_t::compile_all_opts + - settings_t::e_disable_zero_return), - fp_map_(7) - {} - - function_compositor(const symbol_table_t& st) - : symbol_table_(st), - parser_(settings_t::compile_all_opts + - settings_t::e_disable_zero_return), - fp_map_(7) - {} - - ~function_compositor() - { - clear(); - } - - inline symbol_table_t& symbol_table() - { - return symbol_table_; - } - - inline void add_auxiliary_symtab(symbol_table_t& symtab) - { - auxiliary_symtab_list_.push_back(&symtab); - } - - void clear() - { - symbol_table_.clear(); - expr_map_ .clear(); - - for (std::size_t i = 0; i < fp_map_.size(); ++i) - { - typename funcparam_t::iterator itr = fp_map_[i].begin(); - typename funcparam_t::iterator end = fp_map_[i].end (); - - while (itr != end) - { - delete itr->second; - ++itr; - } - - fp_map_[i].clear(); - } - } - - inline bool add(const function& f, const bool override = false) - { - return add(f.name_,f.expression_,f.v_,override); - } - - private: - - template class Sequence> - bool compile_expression(const std::string& name, - const std::string& expression, - const Sequence& input_var_list, - bool return_present = false) - { - expression_t compiled_expression; - symbol_table_t local_symbol_table; - - local_symbol_table.load_from(symbol_table_); - local_symbol_table.add_constants(); - - if (!valid(name,input_var_list.size())) - return false; - - if (!forward(name, - input_var_list.size(), - local_symbol_table, - return_present)) - return false; - - compiled_expression.register_symbol_table(local_symbol_table); - - for (std::size_t i = 0; i < auxiliary_symtab_list_.size(); ++i) - { - compiled_expression.register_symbol_table((*auxiliary_symtab_list_[i])); - } - - std::string mod_expression; - - for (std::size_t i = 0; i < input_var_list.size(); ++i) - { - mod_expression += " var " + input_var_list[i] + "{};\n"; - } - - if ( - ('{' == details::front(expression)) && - ('}' == details::back (expression)) - ) - mod_expression += "~" + expression + ";"; - else - mod_expression += "~{" + expression + "};"; - - if (!parser_.compile(mod_expression,compiled_expression)) - { - exprtk_debug(("Compositor Error: %s\n",parser_.error().c_str())); - exprtk_debug(("Compositor modified expression: \n%s\n",mod_expression.c_str())); - - remove(name,input_var_list.size()); - - return false; - } - - if (!return_present && parser_.dec().return_present()) - { - remove(name,input_var_list.size()); - - return compile_expression(name,expression,input_var_list,true); - } - - // Make sure every return point has a scalar as its first parameter - if (parser_.dec().return_present()) - { - typedef std::vector str_list_t; - - str_list_t ret_param_list = parser_.dec().return_param_type_list(); - - for (std::size_t i = 0; i < ret_param_list.size(); ++i) - { - const std::string& params = ret_param_list[i]; - - if (params.empty() || ('T' != params[0])) - { - exprtk_debug(("Compositor Error: Return statement in function '%s' is invalid\n", - name.c_str())); - - remove(name,input_var_list.size()); - - return false; - } - } - } - - expr_map_[name] = compiled_expression; - - exprtk::ifunction& ifunc = (*(fp_map_[input_var_list.size()])[name]); - - if (symbol_table_.add_function(name,ifunc)) - return true; - else - { - exprtk_debug(("Compositor Error: Failed to add function '%s' to symbol table\n", - name.c_str())); - return false; - } - } - - inline bool symbol_used(const std::string& symbol) const - { - return ( - symbol_table_.is_variable (symbol) || - symbol_table_.is_stringvar (symbol) || - symbol_table_.is_function (symbol) || - symbol_table_.is_vector (symbol) || - symbol_table_.is_vararg_function(symbol) - ); - } - - inline bool valid(const std::string& name, - const std::size_t& arg_count) const - { - if (arg_count > 6) - return false; - else if (symbol_used(name)) - return false; - else if (fp_map_[arg_count].end() != fp_map_[arg_count].find(name)) - return false; - else - return true; - } - - inline bool forward(const std::string& name, - const std::size_t& arg_count, - symbol_table_t& sym_table, - const bool ret_present = false) - { - switch (arg_count) - { -#define case_stmt(N) \ -case N : (fp_map_[arg_count])[name] = \ -(!ret_present) ? static_cast \ -(new func_##N##param) : \ -static_cast \ -(new func_##N##param_retval) ; \ -break; \ - - case_stmt(0) case_stmt(1) case_stmt(2) - case_stmt(3) case_stmt(4) case_stmt(5) - case_stmt(6) -#undef case_stmt - } - - exprtk::ifunction& ifunc = (*(fp_map_[arg_count])[name]); - - return sym_table.add_function(name,ifunc); - } - - inline void remove(const std::string& name, const std::size_t& arg_count) - { - if (arg_count > 6) - return; - - typename std::map::iterator em_itr = expr_map_.find(name); - - if (expr_map_.end() != em_itr) - { - expr_map_.erase(em_itr); - } - - typename funcparam_t::iterator fp_itr = fp_map_[arg_count].find(name); - - if (fp_map_[arg_count].end() != fp_itr) - { - delete fp_itr->second; - fp_map_[arg_count].erase(fp_itr); - } - - symbol_table_.remove_function(name); - } - - private: - - symbol_table_t symbol_table_; - parser_t parser_; - std::map expr_map_; - std::vector fp_map_; - std::vector auxiliary_symtab_list_; - }; - - template - inline bool pgo_primer() - { - static const std::string expression_list[] - = { - "(y + x)", - "2 * (y + x)", - "(2 * y + 2 * x)", - "(y + x / y) * (x - y / x)", - "x / ((x + y) * (x - y)) / y", - "1 - ((x * y) + (y / x)) - 3", - "sin(2 * x) + cos(pi / y)", - "1 - sin(2 * x) + cos(pi / y)", - "sqrt(1 - sin(2 * x) + cos(pi / y) / 3)", - "(x^2 / sin(2 * pi / y)) -x / 2", - "x + (cos(y - sin(2 / x * pi)) - sin(x - cos(2 * y / pi))) - y", - "clamp(-1.0, sin(2 * pi * x) + cos(y / 2 * pi), +1.0)", - "iclamp(-1.0, sin(2 * pi * x) + cos(y / 2 * pi), +1.0)", - "max(3.33, min(sqrt(1 - sin(2 * x) + cos(pi / y) / 3), 1.11))", - "if(avg(x,y) <= x + y, x - y, x * y) + 2 * pi / x", - "1.1x^1 + 2.2y^2 - 3.3x^3 + 4.4y^4 - 5.5x^5 + 6.6y^6 - 7.7x^27 + 8.8y^55", - "(yy + xx)", - "2 * (yy + xx)", - "(2 * yy + 2 * xx)", - "(yy + xx / yy) * (xx - yy / xx)", - "xx / ((xx + yy) * (xx - yy)) / yy", - "1 - ((xx * yy) + (yy / xx)) - 3", - "sin(2 * xx) + cos(pi / yy)", - "1 - sin(2 * xx) + cos(pi / yy)", - "sqrt(1 - sin(2 * xx) + cos(pi / yy) / 3)", - "(xx^2 / sin(2 * pi / yy)) -xx / 2", - "xx + (cos(yy - sin(2 / xx * pi)) - sin(xx - cos(2 * yy / pi))) - yy", - "clamp(-1.0, sin(2 * pi * xx) + cos(yy / 2 * pi), +1.0)", - "max(3.33, min(sqrt(1 - sin(2 * xx) + cos(pi / yy) / 3), 1.11))", - "if(avg(xx,yy) <= xx + yy, xx - yy, xx * yy) + 2 * pi / xx", - "1.1xx^1 + 2.2yy^2 - 3.3xx^3 + 4.4yy^4 - 5.5xx^5 + 6.6yy^6 - 7.7xx^27 + 8.8yy^55", - "(1.1*(2.2*(3.3*(4.4*(5.5*(6.6*(7.7*(8.8*(9.9+x)))))))))", - "(((((((((x+9.9)*8.8)*7.7)*6.6)*5.5)*4.4)*3.3)*2.2)*1.1)", - "(x + y) * z", "x + (y * z)", "(x + y) * 7", "x + (y * 7)", - "(x + 7) * y", "x + (7 * y)", "(7 + x) * y", "7 + (x * y)", - "(2 + x) * 3", "2 + (x * 3)", "(2 + 3) * x", "2 + (3 * x)", - "(x + 2) * 3", "x + (2 * 3)", - "(x + y) * (z / w)", "(x + y) * (z / 7)", "(x + y) * (7 / z)", "(x + 7) * (y / z)", - "(7 + x) * (y / z)", "(2 + x) * (y / z)", "(x + 2) * (y / 3)", "(2 + x) * (y / 3)", - "(x + 2) * (3 / y)", "x + (y * (z / w))", "x + (y * (z / 7))", "x + (y * (7 / z))", - "x + (7 * (y / z))", "7 + (x * (y / z))", "2 + (x * (3 / y))", "x + (2 * (y / 4))", - "2 + (x * (y / 3))", "x + (2 * (3 / y))", - "x + ((y * z) / w)", "x + ((y * z) / 7)", "x + ((y * 7) / z)", "x + ((7 * y) / z)", - "7 + ((y * z) / w)", "2 + ((x * 3) / y)", "x + ((2 * y) / 3)", "2 + ((x * y) / 3)", - "x + ((2 * 3) / y)", "(((x + y) * z) / w)", - "(((x + y) * z) / 7)", "(((x + y) * 7) / z)", "(((x + 7) * y) / z)", "(((7 + x) * y) / z)", - "(((2 + x) * 3) / y)", "(((x + 2) * y) / 3)", "(((2 + x) * y) / 3)", "(((x + 2) * 3) / y)", - "((x + (y * z)) / w)", "((x + (y * z)) / 7)", "((x + (y * 7)) / y)", "((x + (7 * y)) / z)", - "((7 + (x * y)) / z)", "((2 + (x * 3)) / y)", "((x + (2 * y)) / 3)", "((2 + (x * y)) / 3)", - "((x + (2 * 3)) / y)", - "(xx + yy) * zz", "xx + (yy * zz)", - "(xx + yy) * 7", "xx + (yy * 7)", - "(xx + 7) * yy", "xx + (7 * yy)", - "(7 + xx) * yy", "7 + (xx * yy)", - "(2 + x) * 3", "2 + (x * 3)", - "(2 + 3) * x", "2 + (3 * x)", - "(x + 2) * 3", "x + (2 * 3)", - "(xx + yy) * (zz / ww)", "(xx + yy) * (zz / 7)", - "(xx + yy) * (7 / zz)", "(xx + 7) * (yy / zz)", - "(7 + xx) * (yy / zz)", "(2 + xx) * (yy / zz)", - "(xx + 2) * (yy / 3)", "(2 + xx) * (yy / 3)", - "(xx + 2) * (3 / yy)", "xx + (yy * (zz / ww))", - "xx + (yy * (zz / 7))", "xx + (yy * (7 / zz))", - "xx + (7 * (yy / zz))", "7 + (xx * (yy / zz))", - "2 + (xx * (3 / yy))", "xx + (2 * (yy / 4))", - "2 + (xx * (yy / 3))", "xx + (2 * (3 / yy))", - "xx + ((yy * zz) / ww)", "xx + ((yy * zz) / 7)", - "xx + ((yy * 7) / zz)", "xx + ((7 * yy) / zz)", - "7 + ((yy * zz) / ww)", "2 + ((xx * 3) / yy)", - "xx + ((2 * yy) / 3)", "2 + ((xx * yy) / 3)", - "xx + ((2 * 3) / yy)", "(((xx + yy) * zz) / ww)", - "(((xx + yy) * zz) / 7)", "(((xx + yy) * 7) / zz)", - "(((xx + 7) * yy) / zz)", "(((7 + xx) * yy) / zz)", - "(((2 + xx) * 3) / yy)", "(((xx + 2) * yy) / 3)", - "(((2 + xx) * yy) / 3)", "(((xx + 2) * 3) / yy)", - "((xx + (yy * zz)) / ww)", "((xx + (yy * zz)) / 7)", - "((xx + (yy * 7)) / yy)", "((xx + (7 * yy)) / zz)", - "((7 + (xx * yy)) / zz)", "((2 + (xx * 3)) / yy)", - "((xx + (2 * yy)) / 3)", "((2 + (xx * yy)) / 3)", - "((xx + (2 * 3)) / yy)" - }; - static const std::size_t expression_list_size = sizeof(expression_list) / sizeof(std::string); - - T x = T(0); - T y = T(0); - T z = T(0); - T w = T(0); - T xx = T(0); - T yy = T(0); - T zz = T(0); - T ww = T(0); - - exprtk::symbol_table symbol_table; - symbol_table.add_constants(); - symbol_table.add_variable( "x", x); - symbol_table.add_variable( "y", y); - symbol_table.add_variable( "z", z); - symbol_table.add_variable( "w", w); - symbol_table.add_variable("xx",xx); - symbol_table.add_variable("yy",yy); - symbol_table.add_variable("zz",zz); - symbol_table.add_variable("ww",ww); - - typedef typename std::deque > expr_list_t; - expr_list_t expr_list; - - const std::size_t rounds = 50; - - { - for (std::size_t r = 0; r < rounds; ++r) - { - expr_list.clear(); - exprtk::parser parser; - - for (std::size_t i = 0; i < expression_list_size; ++i) - { - exprtk::expression expression; - expression.register_symbol_table(symbol_table); - - if (!parser.compile(expression_list[i],expression)) - { - return false; - } - - expr_list.push_back(expression); - } - } - } - - struct execute - { - static inline T process(T& x, T& y, expression& expression) - { - static const T lower_bound = T(-20); - static const T upper_bound = T(+20); - - T delta = T(0.1); - T total = T(0); - - for (x = lower_bound; x <= upper_bound; x += delta) - { - for (y = lower_bound; y <= upper_bound; y += delta) - { - total += expression.value(); - } - } - - return total; - } - }; - - for (std::size_t i = 0; i < expr_list.size(); ++i) - { - execute::process( x, y, expr_list[i]); - execute::process(xx, yy, expr_list[i]); - } - - { - for (std::size_t i = 0; i < 10000; ++i) - { - T v = T(123.456 + i); - - if (details::is_true(details::numeric::nequal(details::numeric::fast_exp::result(v),details::numeric::pow(v,T( 1))))) - return false; - -#define else_stmt(N) \ -else if (details::is_true(details::numeric::nequal(details::numeric::fast_exp::result(v),details::numeric::pow(v,T(N))))) \ -return false; \ - - else_stmt( 2) else_stmt( 3) else_stmt( 4) else_stmt( 5) - else_stmt( 6) else_stmt( 7) else_stmt( 8) else_stmt( 9) - else_stmt(10) else_stmt(11) else_stmt(12) else_stmt(13) - else_stmt(14) else_stmt(15) else_stmt(16) else_stmt(17) - else_stmt(18) else_stmt(19) else_stmt(20) else_stmt(21) - else_stmt(22) else_stmt(23) else_stmt(24) else_stmt(25) - else_stmt(26) else_stmt(27) else_stmt(28) else_stmt(29) - else_stmt(30) else_stmt(31) else_stmt(32) else_stmt(33) - else_stmt(34) else_stmt(35) else_stmt(36) else_stmt(37) - else_stmt(38) else_stmt(39) else_stmt(40) else_stmt(41) - else_stmt(42) else_stmt(43) else_stmt(44) else_stmt(45) - else_stmt(46) else_stmt(47) else_stmt(48) else_stmt(49) - else_stmt(50) else_stmt(51) else_stmt(52) else_stmt(53) - else_stmt(54) else_stmt(55) else_stmt(56) else_stmt(57) - else_stmt(58) else_stmt(59) else_stmt(60) - } - } - - return true; - } -} -#if defined(_WIN32) || defined(__WIN32__) || defined(WIN32) -# ifndef NOMINMAX -# define NOMINMAX -# endif -# ifndef WIN32_LEAN_AND_MEAN -# define WIN32_LEAN_AND_MEAN -# endif -# include -# include -#else -# include -# include -# include -#endif + T result = T(0); + T error = T(0); -namespace exprtk -{ - class timer - { - public: - -#if defined(_WIN32) || defined(__WIN32__) || defined(WIN32) - timer() - : in_use_(false) - { - QueryPerformanceFrequency(&clock_frequency_); - } - - inline void start() - { - in_use_ = true; - QueryPerformanceCounter(&start_time_); - } - - inline void stop() - { - QueryPerformanceCounter(&stop_time_); - in_use_ = false; - } - - inline double time() const - { - return (1.0 * (stop_time_.QuadPart - start_time_.QuadPart)) / (1.0 * clock_frequency_.QuadPart); - } - -#else - - timer() - : in_use_(false) - { - start_time_.tv_sec = 0; - start_time_.tv_usec = 0; - stop_time_.tv_sec = 0; - stop_time_.tv_usec = 0; - } - - inline void start() - { - in_use_ = true; - gettimeofday(&start_time_,0); - } - - inline void stop() - { - gettimeofday(&stop_time_, 0); - in_use_ = false; - } - - inline unsigned long long int usec_time() const - { - if (!in_use_) - { - if (stop_time_.tv_sec >= start_time_.tv_sec) - { - return 1000000 * (stop_time_.tv_sec - start_time_.tv_sec ) + - (stop_time_.tv_usec - start_time_.tv_usec); - } - else - return std::numeric_limits::max(); - } - else - return std::numeric_limits::max(); - } - - inline double time() const - { - return usec_time() * 0.000001; - } - -#endif - - inline bool in_use() const - { - return in_use_; - } - - private: - - bool in_use_; - -#if defined(_WIN32) || defined(__WIN32__) || defined(WIN32) - LARGE_INTEGER start_time_; - LARGE_INTEGER stop_time_; - LARGE_INTEGER clock_frequency_; -#else - struct timeval start_time_; - struct timeval stop_time_; -#endif - }; - -} // namespace exprtk + for (std::size_t i = r0; i <= r1; ++i) + { + details::kahan_sum(result,error,(x[i] * y[i])); + } -#ifndef exprtk_disable_rtl_io -namespace exprtk -{ - namespace rtl { namespace io { namespace details - { - template - inline void print_type(const std::string& fmt, - const T v, - exprtk::details::numeric::details::real_type_tag) - { - printf(fmt.c_str(),v); - } - - template - struct print_impl - { - typedef typename igeneric_function::generic_type generic_type; - typedef typename igeneric_function::parameter_list_t parameter_list_t; - typedef typename generic_type::scalar_view scalar_t; - typedef typename generic_type::vector_view vector_t; - typedef typename generic_type::string_view string_t; - typedef typename exprtk::details::numeric::details::number_type::type num_type; - - static void process(const std::string& scalar_format, parameter_list_t parameters) - { - for (std::size_t i = 0; i < parameters.size(); ++i) - { - generic_type& gt = parameters[i]; - - switch (gt.type) - { - case generic_type::e_scalar : print(scalar_format,scalar_t(gt)); - break; - - case generic_type::e_vector : print(scalar_format,vector_t(gt)); - break; - - case generic_type::e_string : print(string_t(gt)); - break; - - default : continue; - } - } - } - - static inline void print(const std::string& scalar_format, const scalar_t& s) - { - print_type(scalar_format,s(),num_type()); - } - - static inline void print(const std::string& scalar_format, const vector_t& v) - { - for (std::size_t i = 0; i < v.size(); ++i) - { - print_type(scalar_format,v[i],num_type()); - - if ((i + 1) < v.size()) - printf(" "); - } - } - - static inline void print(const string_t& s) - { - printf("%s",to_str(s).c_str()); - } - }; - - } // namespace exprtk::rtl::io::details - - template - struct print : public exprtk::igeneric_function - { - typedef typename igeneric_function::parameter_list_t parameter_list_t; - - using exprtk::igeneric_function::operator(); - - print(const std::string& scalar_format = "%10.5f") - : scalar_format_(scalar_format) - { - exprtk::enable_zero_parameters(*this); - } - - inline T operator()(parameter_list_t parameters) - { - details::print_impl::process(scalar_format_,parameters); - return T(0); - } - - std::string scalar_format_; - }; - - template - struct println : public exprtk::igeneric_function - { - typedef typename igeneric_function::parameter_list_t parameter_list_t; - - using exprtk::igeneric_function::operator(); - - println(const std::string& scalar_format = "%10.5f") - : scalar_format_(scalar_format) - { - exprtk::enable_zero_parameters(*this); - } - - inline T operator()(parameter_list_t parameters) - { - details::print_impl::process(scalar_format_,parameters); - printf("\n"); - return T(0); - } - - std::string scalar_format_; - }; - - template - struct package - { - print p; - println pl; - - bool register_package(exprtk::symbol_table& symtab) - { - if (!symtab.add_function("print" ,p)) - return false; - else if (!symtab.add_function("println" ,pl)) - return false; - else - return true; - } - }; - - } // namespace exprtk::rtl::io - } // namespace exprtk::rtl -} // namespace exprtk -#endif + return result; + } + }; -#ifndef exprtk_disable_rtl_io_file -#include -namespace exprtk -{ - namespace rtl { namespace io { namespace file { namespace details - { - enum file_mode - { - e_error = 0, - e_read = 1, - e_write = 2, - e_rdwrt = 4 - }; - - struct file_descriptor - { - file_descriptor(const std::string& fname, const std::string& access) - : stream_ptr(0), - mode(get_file_mode(access)), - file_name(fname) - {} - - void* stream_ptr; - file_mode mode; - std::string file_name; - - bool open() - { - if (e_read == mode) - { - std::ifstream* stream = new std::ifstream(file_name.c_str(),std::ios::binary); - - if (!(*stream)) - { - file_name.clear(); - delete stream; - - return false; - } - else - stream_ptr = stream; - - return true; - } - else if (e_write == mode) - { - std::ofstream* stream = new std::ofstream(file_name.c_str(),std::ios::binary); - - if (!(*stream)) - { - file_name.clear(); - delete stream; - - return false; - } - else - stream_ptr = stream; - - return true; - } - else if (e_rdwrt == mode) - { - std::fstream* stream = new std::fstream(file_name.c_str(),std::ios::binary); - - if (!(*stream)) - { - file_name.clear(); - delete stream; - - return false; - } - else - stream_ptr = stream; - - return true; - } - else - return false; - } - - template - void close(Ptr& p) - { - Stream* stream = reinterpret_cast(p); - stream->close(); - delete stream; - p = reinterpret_cast(0); - } - - bool close() - { - switch (mode) - { - case e_read : close(stream_ptr); - break; - - case e_write : close(stream_ptr); - break; - - case e_rdwrt : close (stream_ptr); - break; - - default : return false; - } - - return true; - } - - template - bool write(const View& view, const std::size_t amount, const std::size_t offset = 0) - { - switch (mode) - { - case e_write : reinterpret_cast(stream_ptr)-> - write(reinterpret_cast(view.begin() + offset), amount * sizeof(typename View::value_t)); - break; - - case e_rdwrt : reinterpret_cast(stream_ptr)-> - write(reinterpret_cast(view.begin() + offset) , amount * sizeof(typename View::value_t)); - break; - - default : return false; - } - - return true; - } - - template - bool read(View& view, const std::size_t amount, const std::size_t offset = 0) - { - switch (mode) - { - case e_read : reinterpret_cast(stream_ptr)-> - read(reinterpret_cast(view.begin() + offset), amount * sizeof(typename View::value_t)); - break; - - case e_rdwrt : reinterpret_cast(stream_ptr)-> - read(reinterpret_cast(view.begin() + offset) , amount * sizeof(typename View::value_t)); - break; - - default : return false; - } - - return true; - } - - bool getline(std::string& s) - { - switch (mode) - { - case e_read : return (!!std::getline(*reinterpret_cast(stream_ptr),s)); - case e_rdwrt : return (!!std::getline(*reinterpret_cast(stream_ptr),s)); - default : return false; - } - } - - bool eof() - { - switch (mode) - { - case e_read : return reinterpret_cast(stream_ptr)->eof(); - case e_write : return reinterpret_cast(stream_ptr)->eof(); - case e_rdwrt : return reinterpret_cast(stream_ptr)->eof(); - default : return true; - } - } - - file_mode get_file_mode(const std::string& access) - { - std::size_t w_cnt = 0; - std::size_t r_cnt = 0; - - for (std::size_t i = 0; i < access.size(); ++i) - { -#ifdef MODIFICATION - switch (access[i]) -#else - switch (std::tolower(access[i])) -#endif - { - case 'r' : r_cnt++; break; - case 'w' : w_cnt++; break; - } - } - - if ((0 == r_cnt) && (0 == w_cnt)) - return e_error; - else if ((r_cnt > 1) || (w_cnt > 1)) - return e_error; - else if ((1 == r_cnt) && (1 == w_cnt)) - return e_rdwrt; - else if (1 == r_cnt) - return e_read; - else - return e_write; - } - }; - - template - file_descriptor* make_handle(T v) - { - file_descriptor* fd = reinterpret_cast(0); - - std::memcpy(reinterpret_cast(&fd), - reinterpret_cast(&v), - sizeof(fd)); - return fd; - } - - template - void perform_check() - { -#ifdef _MSC_VER -#pragma warning(push) -#pragma warning(disable: 4127) -#endif - if (sizeof(T) < sizeof(void*)) - { - throw std::runtime_error("exprtk::rtl::io::file - Error - pointer size larger than holder."); - } -#ifdef _MSC_VER -#pragma warning(pop) -#endif - } - } // namespace exprtk::rtl::io::file::details - - template - class open : public exprtk::igeneric_function - { - public: - - typedef typename exprtk::igeneric_function igfun_t; - typedef typename igfun_t::parameter_list_t parameter_list_t; - typedef typename igfun_t::generic_type generic_type; - typedef typename generic_type::string_view string_t; - - using exprtk::igeneric_function::operator(); - - open() - : exprtk::igeneric_function("S|SS") - { details::perform_check(); } - - inline T operator()(const std::size_t& ps_index, parameter_list_t parameters) - { - std::string file_name; - std::string access; - - file_name = to_str(string_t(parameters[0])); - - if (file_name.empty()) - return T(0); - - if (0 == ps_index) - access = "r"; - else if (0 == string_t(parameters[1]).size()) - return T(0); - else - access = to_str(string_t(parameters[1])); - - details::file_descriptor* fd = new details::file_descriptor(file_name,access); - - if (fd->open()) - { - T t = T(0); - - std::memcpy(reinterpret_cast(&t), - reinterpret_cast(&fd), - sizeof(fd)); - return t; - } - else - { - delete fd; - return T(0); - } - } - }; - - template - struct close : public exprtk::ifunction - { - using exprtk::ifunction::operator(); - - close() - : exprtk::ifunction(1) - { details::perform_check(); } - - inline T operator()(const T& v) - { - details::file_descriptor* fd = details::make_handle(v); - - if (!fd->close()) - return T(0); - - delete fd; - - return T(1); - } - }; - - template - class write : public exprtk::igeneric_function - { - public: - - typedef typename exprtk::igeneric_function igfun_t; - typedef typename igfun_t::parameter_list_t parameter_list_t; - typedef typename igfun_t::generic_type generic_type; - typedef typename generic_type::string_view string_t; - typedef typename generic_type::scalar_view scalar_t; - typedef typename generic_type::vector_view vector_t; - - using exprtk::igeneric_function::operator(); - - write() - : igfun_t("TS|TST|TV|TVT") - { details::perform_check(); } - - inline T operator()(const std::size_t& ps_index, parameter_list_t parameters) - { - details::file_descriptor* fd = details::make_handle(scalar_t(parameters[0])()); - - std::size_t amount = 0; - - switch (ps_index) - { - case 0 : { - string_t buffer(parameters[1]); - amount = buffer.size(); - return T(fd->write(buffer,amount) ? 1 : 0); - } - - case 1 : { - string_t buffer(parameters[1]); - amount = std::min(buffer.size(), - static_cast(scalar_t(parameters[2])())); - return T(fd->write(buffer,amount) ? 1 : 0); - } - - case 2 : { - vector_t vec(parameters[1]); - amount = vec.size(); - return T(fd->write(vec,amount) ? 1 : 0); - } - - case 3 : { - vector_t vec(parameters[1]); - amount = std::min(vec.size(), - static_cast(scalar_t(parameters[2])())); - return T(fd->write(vec,amount) ? 1 : 0); - } - } - - return T(0); - } - }; - - template - class read : public exprtk::igeneric_function - { - public: - - typedef typename exprtk::igeneric_function igfun_t; - typedef typename igfun_t::parameter_list_t parameter_list_t; - typedef typename igfun_t::generic_type generic_type; - typedef typename generic_type::string_view string_t; - typedef typename generic_type::scalar_view scalar_t; - typedef typename generic_type::vector_view vector_t; - - using exprtk::igeneric_function::operator(); - - read() - : igfun_t("TS|TST|TV|TVT") - { details::perform_check(); } - - inline T operator()(const std::size_t& ps_index, parameter_list_t parameters) - { - details::file_descriptor* fd = details::make_handle(scalar_t(parameters[0])()); - - std::size_t amount = 0; - - switch (ps_index) - { - case 0 : { - string_t buffer(parameters[1]); - amount = buffer.size(); - return T(fd->read(buffer,amount) ? 1 : 0); - } - - case 1 : { - string_t buffer(parameters[1]); - amount = std::min(buffer.size(), - static_cast(scalar_t(parameters[2])())); - return T(fd->read(buffer,amount) ? 1 : 0); - } - - case 2 : { - vector_t vec(parameters[1]); - amount = vec.size(); - return T(fd->read(vec,amount) ? 1 : 0); - } - - case 3 : { - vector_t vec(parameters[1]); - amount = std::min(vec.size(), - static_cast(scalar_t(parameters[2])())); - return T(fd->read(vec,amount) ? 1 : 0); - } - } - - return T(0); - } - }; - - template - class getline : public exprtk::igeneric_function - { - public: - - typedef typename exprtk::igeneric_function igfun_t; - typedef typename igfun_t::parameter_list_t parameter_list_t; - typedef typename igfun_t::generic_type generic_type; - typedef typename generic_type::string_view string_t; - typedef typename generic_type::scalar_view scalar_t; - - using exprtk::igeneric_function::operator(); - - getline() - : igfun_t("T",igfun_t::e_rtrn_string) - { details::perform_check(); } - - inline T operator()(std::string& result, - parameter_list_t parameters) - { - details::file_descriptor* fd = details::make_handle(scalar_t(parameters[0])()); - return T(fd->getline(result) ? 1 : 0); - } - }; - - template - struct eof : public exprtk::ifunction - { - using exprtk::ifunction::operator(); - - eof() - : exprtk::ifunction(1) - { details::perform_check(); } - - inline T operator()(const T& v) - { - details::file_descriptor* fd = details::make_handle(v); - - return (fd->eof() ? T(1) : T(0)); - } - }; - - template - struct package - { - open o; - close c; - write w; - read r; - getline g; - eof e; - - bool register_package(exprtk::symbol_table& symtab) - { - if (!symtab.add_function("open" ,o)) - return false; - else if (!symtab.add_function("close" ,c)) - return false; - else if (!symtab.add_function("write" ,w)) - return false; - else if (!symtab.add_function("read" ,r)) - return false; - else if (!symtab.add_function("getline",g)) - return false; - else if (!symtab.add_function("eof" ,e)) - return false; - else - return true; - } - }; - - } // namespace exprtk::rtl::io::file - } // namespace exprtk::rtl::io - } // namespace exprtk::rtl -} // namespace exprtk -#endif + template + struct package + { + all_true at; + all_false af; + any_true nt; + any_false nf; + count c; + copy cp; + rol rl; + ror rr; + shift_left sl; + shift_right sr; + sort st; + nthelement ne; + iota ia; + sumk sk; + axpy b1_axpy; + axpby b1_axpby; + axpyz b1_axpyz; + axpbyz b1_axpbyz; + axpbz b1_axpbz; + dot dt; + dotk dtk; -#ifndef exprtk_disable_rtl_vecops -namespace exprtk -{ - namespace rtl { namespace vecops { - - namespace helper - { - template - inline bool invalid_range(const Vector& v, const std::size_t r0, const std::size_t r1) - { - if (r0 > (v.size() - 1)) - return true; - else if (r1 > (v.size() - 1)) - return true; - else if (r1 < r0) - return true; - else - return false; - } - - template - struct load_vector_range - { - typedef typename exprtk::igeneric_function igfun_t; - typedef typename igfun_t::parameter_list_t parameter_list_t; - typedef typename igfun_t::generic_type generic_type; - typedef typename generic_type::scalar_view scalar_t; - typedef typename generic_type::vector_view vector_t; - - static inline bool process(parameter_list_t& parameters, - std::size_t& r0, std::size_t& r1, - const std::size_t& r0_prmidx, - const std::size_t& r1_prmidx, - const std::size_t vec_idx = 0) - { - if (r0_prmidx >= parameters.size()) - return false; - - if (r1_prmidx >= parameters.size()) - return false; - - if (!scalar_t(parameters[r0_prmidx]).to_uint(r0)) - return false; - - if (!scalar_t(parameters[r1_prmidx]).to_uint(r1)) - return false; - - return !invalid_range(vector_t(parameters[vec_idx]),r0,r1); - } - }; - } - - namespace details - { - template - inline void kahan_sum(T& sum, T& error, T v) - { - T x = v - error; - T y = sum + x; - error = (y - sum) - x; - sum = y; - } - - } // namespace exprtk::rtl::details - - template - class all_true : public exprtk::igeneric_function - { - public: - - typedef typename exprtk::igeneric_function igfun_t; - typedef typename igfun_t::parameter_list_t parameter_list_t; - typedef typename igfun_t::generic_type generic_type; - typedef typename generic_type::vector_view vector_t; - - using exprtk::igeneric_function::operator(); - - all_true() - : exprtk::igeneric_function("V|VTT") - /* - Overloads: - 0. V - vector - 1. VTT - vector, r0, r1 - */ - {} - - inline T operator()(const std::size_t& ps_index, parameter_list_t parameters) - { - const vector_t& vec(parameters[0]); - - std::size_t r0 = 0; - std::size_t r1 = vec.size() - 1; - - if ((1 == ps_index) && !helper::load_vector_range::process(parameters,r0,r1,1,2,0)) - return std::numeric_limits::quiet_NaN(); - - for (std::size_t i = r0; i <= r1; ++i) - { - if (vec[i] == T(0)) - { - return T(0); - } - } - - return T(1); - } - }; - - template - class all_false : public exprtk::igeneric_function - { - public: - - typedef typename exprtk::igeneric_function igfun_t; - typedef typename igfun_t::parameter_list_t parameter_list_t; - typedef typename igfun_t::generic_type generic_type; - typedef typename generic_type::vector_view vector_t; - - using exprtk::igeneric_function::operator(); - - all_false() - : exprtk::igeneric_function("V|VTT") - /* - Overloads: - 0. V - vector - 1. VTT - vector, r0, r1 - */ - {} - - inline T operator()(const std::size_t& ps_index, parameter_list_t parameters) - { - const vector_t& vec(parameters[0]); - - std::size_t r0 = 0; - std::size_t r1 = vec.size() - 1; - - if ((1 == ps_index) && !helper::load_vector_range::process(parameters,r0,r1,1,2,0)) - return std::numeric_limits::quiet_NaN(); - - for (std::size_t i = r0; i <= r1; ++i) - { - if (vec[i] != T(0)) - { - return T(0); - } - } - - return T(1); - } - }; - - template - class any_true : public exprtk::igeneric_function - { - public: - - typedef typename exprtk::igeneric_function igfun_t; - typedef typename igfun_t::parameter_list_t parameter_list_t; - typedef typename igfun_t::generic_type generic_type; - typedef typename generic_type::vector_view vector_t; - - using exprtk::igeneric_function::operator(); - - any_true() - : exprtk::igeneric_function("V|VTT") - /* - Overloads: - 0. V - vector - 1. VTT - vector, r0, r1 - */ - {} - - inline T operator()(const std::size_t& ps_index, parameter_list_t parameters) - { - const vector_t& vec(parameters[0]); - - std::size_t r0 = 0; - std::size_t r1 = vec.size() - 1; - - if ((1 == ps_index) && !helper::load_vector_range::process(parameters,r0,r1,1,2,0)) - return std::numeric_limits::quiet_NaN(); - - for (std::size_t i = r0; i <= r1; ++i) - { - if (vec[i] != T(0)) - { - return T(1); - } - } - - return T(0); - } - }; - - template - class any_false : public exprtk::igeneric_function - { - public: - - typedef typename exprtk::igeneric_function igfun_t; - typedef typename igfun_t::parameter_list_t parameter_list_t; - typedef typename igfun_t::generic_type generic_type; - typedef typename generic_type::vector_view vector_t; - - using exprtk::igeneric_function::operator(); - - any_false() - : exprtk::igeneric_function("V|VTT") - /* - Overloads: - 0. V - vector - 1. VTT - vector, r0, r1 - */ - {} - - inline T operator()(const std::size_t& ps_index, parameter_list_t parameters) - { - const vector_t& vec(parameters[0]); - - std::size_t r0 = 0; - std::size_t r1 = vec.size() - 1; - - if ((1 == ps_index) && !helper::load_vector_range::process(parameters,r0,r1,1,2,0)) - return std::numeric_limits::quiet_NaN(); - - for (std::size_t i = r0; i <= r1; ++i) - { - if (vec[i] == T(0)) - { - return T(1); - } - } - - return T(0); - } - }; - - template - class count : public exprtk::igeneric_function - { - public: - - typedef typename exprtk::igeneric_function igfun_t; - typedef typename igfun_t::parameter_list_t parameter_list_t; - typedef typename igfun_t::generic_type generic_type; - typedef typename generic_type::vector_view vector_t; - - using exprtk::igeneric_function::operator(); - - count() - : exprtk::igeneric_function("V|VTT") - /* - Overloads: - 0. V - vector - 1. VTT - vector, r0, r1 - */ - {} - - inline T operator()(const std::size_t& ps_index, parameter_list_t parameters) - { - const vector_t& vec(parameters[0]); - - std::size_t r0 = 0; - std::size_t r1 = vec.size() - 1; - - if ((1 == ps_index) && !helper::load_vector_range::process(parameters,r0,r1,1,2,0)) - return std::numeric_limits::quiet_NaN(); - - std::size_t cnt = 0; - - for (std::size_t i = r0; i <= r1; ++i) - { - if (vec[i] != T(0)) ++cnt; - } - - return T(cnt); - } - }; - - template - class copy : public exprtk::igeneric_function - { - public: - - typedef typename exprtk::igeneric_function igfun_t; - typedef typename igfun_t::parameter_list_t parameter_list_t; - typedef typename igfun_t::generic_type generic_type; - typedef typename generic_type::scalar_view scalar_t; - typedef typename generic_type::vector_view vector_t; - - using exprtk::igeneric_function::operator(); - - copy() - : exprtk::igeneric_function("VV|VTTVTT") - /* - Overloads: - 0. VV - x(vector), y(vector) - 1. VTTVTT - x(vector), xr0, xr1, y(vector), yr0, yr1, - */ - {} - - inline T operator()(const std::size_t& ps_index, parameter_list_t parameters) - { - vector_t x(parameters[0]); - vector_t y(parameters[(0 == ps_index) ? 1 : 3]); - - std::size_t xr0 = 0; - std::size_t xr1 = x.size() - 1; - - std::size_t yr0 = 0; - std::size_t yr1 = y.size() - 1; - - if ((1 == ps_index) && !helper::load_vector_range::process(parameters,xr0,xr1,1,2,0)) - return T(0); - if ((1 == ps_index) && !helper::load_vector_range::process(parameters,yr0,yr1,4,5,3)) - return T(0); - - const std::size_t n = std::min(xr1 - xr0 + 1, yr1 - yr0 + 1); - - std::copy(x.begin() + xr0, x.begin() + xr0 + n, y.begin() + yr0); - - return T(n); - } - }; - - template - class rol : public exprtk::igeneric_function - { - public: - - typedef typename exprtk::igeneric_function igfun_t; - typedef typename igfun_t::parameter_list_t parameter_list_t; - typedef typename igfun_t::generic_type generic_type; - typedef typename generic_type::scalar_view scalar_t; - typedef typename generic_type::vector_view vector_t; - - using exprtk::igeneric_function::operator(); - - rol() - : exprtk::igeneric_function("VT|VTTT") - /* - Overloads: - 0. VT - vector, N - 1. VTTT - vector, N, r0, r1 - */ - {} - - inline T operator()(const std::size_t& ps_index, parameter_list_t parameters) - { - vector_t vec(parameters[0]); - - std::size_t n = 0; - std::size_t r0 = 0; - std::size_t r1 = vec.size() - 1; - - if (!scalar_t(parameters[1]).to_uint(n)) - return T(0); - - if ((1 == ps_index) && !helper::load_vector_range::process(parameters,r0,r1,2,3,0)) - return T(0); - - std::size_t dist = r1 - r0 + 1; - std::size_t shift = n % dist; - - std::rotate(vec.begin() + r0, vec.begin() + r0 + shift, vec.begin() + r1 + 1); - - return T(1); - } - }; - - template - class ror : public exprtk::igeneric_function - { - public: - - typedef typename exprtk::igeneric_function igfun_t; - typedef typename igfun_t::parameter_list_t parameter_list_t; - typedef typename igfun_t::generic_type generic_type; - typedef typename generic_type::scalar_view scalar_t; - typedef typename generic_type::vector_view vector_t; - - using exprtk::igeneric_function::operator(); - - ror() - : exprtk::igeneric_function("VT|VTTT") - /* - Overloads: - 0. VT - vector, N - 1. VTTT - vector, N, r0, r1 - */ - {} - - inline T operator()(const std::size_t& ps_index, parameter_list_t parameters) - { - vector_t vec(parameters[0]); - - std::size_t n = 0; - std::size_t r0 = 0; - std::size_t r1 = vec.size() - 1; - - if (!scalar_t(parameters[1]).to_uint(n)) - return T(0); - - if ((1 == ps_index) && !helper::load_vector_range::process(parameters,r0,r1,2,3,0)) - return T(0); - - std::size_t dist = r1 - r0 + 1; - std::size_t shift = (dist - (n % dist)) % dist; - - std::rotate(vec.begin() + r0, vec.begin() + r0 + shift, vec.begin() + r1 + 1); - - return T(1); - } - }; - - template - class shift_left : public exprtk::igeneric_function - { - public: - - typedef typename exprtk::igeneric_function igfun_t; - typedef typename igfun_t::parameter_list_t parameter_list_t; - typedef typename igfun_t::generic_type generic_type; - typedef typename generic_type::scalar_view scalar_t; - typedef typename generic_type::vector_view vector_t; - - using exprtk::igeneric_function::operator(); - - shift_left() - : exprtk::igeneric_function("VT|VTTT") - /* - Overloads: - 0. VT - vector, N - 1. VTTT - vector, N, r0, r1 - */ - {} - - inline T operator()(const std::size_t& ps_index, parameter_list_t parameters) - { - vector_t vec(parameters[0]); - - std::size_t n = 0; - std::size_t r0 = 0; - std::size_t r1 = vec.size() - 1; - - if (!scalar_t(parameters[1]).to_uint(n)) - return T(0); - - if ((1 == ps_index) && !helper::load_vector_range::process(parameters,r0,r1,2,3,0)) - return T(0); - - std::size_t dist = r1 - r0 + 1; - - if (n > dist) - return T(0); - - std::rotate(vec.begin() + r0, vec.begin() + r0 + n, vec.begin() + r1 + 1); - - for (std::size_t i = r1 - n + 1; i <= r1; ++i) - { - vec[i] = T(0); - } - - return T(1); - } - }; - - template - class shift_right : public exprtk::igeneric_function - { - public: - - typedef typename exprtk::igeneric_function igfun_t; - typedef typename igfun_t::parameter_list_t parameter_list_t; - typedef typename igfun_t::generic_type generic_type; - typedef typename generic_type::scalar_view scalar_t; - typedef typename generic_type::vector_view vector_t; - - using exprtk::igeneric_function::operator(); - - shift_right() - : exprtk::igeneric_function("VT|VTTT") - /* - Overloads: - 0. VT - vector, N - 1. VTTT - vector, N, r0, r1 - */ - {} - - inline T operator()(const std::size_t& ps_index, parameter_list_t parameters) - { - vector_t vec(parameters[0]); - - std::size_t n = 0; - std::size_t r0 = 0; - std::size_t r1 = vec.size() - 1; - - if (!scalar_t(parameters[1]).to_uint(n)) - return T(0); - - if ((1 == ps_index) && !helper::load_vector_range::process(parameters,r0,r1,2,3,0)) - return T(0); - - std::size_t dist = r1 - r0 + 1; - - if (n > dist) - return T(0); - - std::size_t shift = (dist - (n % dist)) % dist; - - std::rotate(vec.begin() + r0, vec.begin() + r0 + shift, vec.begin() + r1 + 1); - - for (std::size_t i = r0; i < r0 + n; ++i) - { - vec[i] = T(0); - } - - return T(1); - } - }; - - template - class sort : public exprtk::igeneric_function - { - public: - - typedef typename exprtk::igeneric_function igfun_t; - typedef typename igfun_t::parameter_list_t parameter_list_t; - typedef typename igfun_t::generic_type generic_type; - typedef typename generic_type::string_view string_t; - typedef typename generic_type::vector_view vector_t; - - using exprtk::igeneric_function::operator(); - - sort() - : exprtk::igeneric_function("V|VTT|VS|VSTT") - /* - Overloads: - 0. V - vector - 1. VTT - vector, r0, r1 - 2. VS - vector, string - 3. VSTT - vector, string, r0, r1 - */ - {} - - inline T operator()(const std::size_t& ps_index, parameter_list_t parameters) - { - vector_t vec(parameters[0]); - - std::size_t r0 = 0; - std::size_t r1 = vec.size() - 1; - - if ((1 == ps_index) && !helper::load_vector_range::process(parameters,r0,r1,1,2,0)) - return T(0); - if ((3 == ps_index) && !helper::load_vector_range::process(parameters,r0,r1,2,3,0)) - return T(0); - - bool ascending = true; - - if ((2 == ps_index) || (3 == ps_index)) - { - if (exprtk::details::imatch(to_str(string_t(parameters[1])),"ascending")) - ascending = true; - else if (exprtk::details::imatch(to_str(string_t(parameters[1])),"descending")) - ascending = false; - else - return T(0); - } - - if (ascending) - std::sort(vec.begin() + r0, vec.begin() + r1 + 1, std::less ()); - else - std::sort(vec.begin() + r0, vec.begin() + r1 + 1, std::greater()); - - return T(1); - } - }; - - template - class nthelement : public exprtk::igeneric_function - { - public: - - typedef typename exprtk::igeneric_function igfun_t; - typedef typename igfun_t::parameter_list_t parameter_list_t; - typedef typename igfun_t::generic_type generic_type; - typedef typename generic_type::scalar_view scalar_t; - typedef typename generic_type::vector_view vector_t; - - using exprtk::igeneric_function::operator(); - - nthelement() - : exprtk::igeneric_function("VT|VTTT") - /* - Overloads: - 0. VT - vector, nth-element - 1. VTTT - vector, nth-element, r0, r1 - */ - {} - - inline T operator()(const std::size_t& ps_index, parameter_list_t parameters) - { - vector_t vec(parameters[0]); - - std::size_t n = 0; - std::size_t r0 = 0; - std::size_t r1 = vec.size() - 1; - - if (!scalar_t(parameters[1]).to_uint(n)) - return T(0); - - if ((1 == ps_index) && !helper::load_vector_range::process(parameters,r0,r1,2,3,0)) - return std::numeric_limits::quiet_NaN(); - - std::nth_element(vec.begin() + r0, vec.begin() + r0 + n , vec.begin() + r1 + 1); - - return T(1); - } - }; - - template - class iota : public exprtk::igeneric_function - { - public: - - typedef typename exprtk::igeneric_function igfun_t; - typedef typename igfun_t::parameter_list_t parameter_list_t; - typedef typename igfun_t::generic_type generic_type; - typedef typename generic_type::scalar_view scalar_t; - typedef typename generic_type::vector_view vector_t; - - using exprtk::igeneric_function::operator(); - - iota() - : exprtk::igeneric_function("VT|VTT|VTTT|VTTTT") - /* - Overloads: - 0. VT - vector, increment - 1. VTT - vector, increment, base - 2. VTTTT - vector, increment, r0, r1 - 3. VTTTT - vector, increment, base, r0, r1 - */ - {} - - inline T operator()(const std::size_t& ps_index, parameter_list_t parameters) - { - vector_t vec(parameters[0]); - - T increment = scalar_t(parameters[1])(); - T base = ((1 == ps_index) || (3 == ps_index))? scalar_t(parameters[2])() : T(0); - - std::size_t r0 = 0; - std::size_t r1 = vec.size() - 1; - - if ((2 == ps_index) && !helper::load_vector_range::process(parameters,r0,r1,2,3,0)) - return std::numeric_limits::quiet_NaN(); - else if ((3 == ps_index) && !helper::load_vector_range::process(parameters,r0,r1,3,4,0)) - return std::numeric_limits::quiet_NaN(); - else - { - long long j = 0; - - for (std::size_t i = r0; i <= r1; ++i, ++j) - { - vec[i] = base + (increment * j); - } - } - - return T(1); - } - }; - - template - class sumk : public exprtk::igeneric_function - { - public: - - typedef typename exprtk::igeneric_function igfun_t; - typedef typename igfun_t::parameter_list_t parameter_list_t; - typedef typename igfun_t::generic_type generic_type; - typedef typename generic_type::vector_view vector_t; - - using exprtk::igeneric_function::operator(); - - sumk() - : exprtk::igeneric_function("V|VTT") - /* - Overloads: - 0. V - vector - 1. VTT - vector, r0, r1 - */ - {} - - inline T operator()(const std::size_t& ps_index, parameter_list_t parameters) - { - vector_t vec(parameters[0]); - - std::size_t r0 = 0; - std::size_t r1 = vec.size() - 1; - - if ((1 == ps_index) && !helper::load_vector_range::process(parameters,r0,r1,1,2,0)) - return std::numeric_limits::quiet_NaN(); - - T result = T(0); - T error = T(0); - - for (std::size_t i = r0; i <= r1; ++i) - { - details::kahan_sum(result,error,vec[i]); - } - - return result; - } - }; - - template - class axpy : public exprtk::igeneric_function - { - public: - - typedef typename exprtk::igeneric_function igfun_t; - typedef typename igfun_t::parameter_list_t parameter_list_t; - typedef typename igfun_t::generic_type generic_type; - typedef typename generic_type::scalar_view scalar_t; - typedef typename generic_type::vector_view vector_t; - - using exprtk::igeneric_function::operator(); - - axpy() - : exprtk::igeneric_function("TVV|TVVTT") - /* - y <- ax + y - Overloads: - 0. TVV - a, x(vector), y(vector) - 1. TVVTT - a, x(vector), y(vector), r0, r1 - */ - {} - - inline T operator()(const std::size_t& ps_index, parameter_list_t parameters) - { - vector_t x(parameters[1]); - vector_t y(parameters[2]); - - std::size_t r0 = 0; - std::size_t r1 = std::min(x.size(),y.size()) - 1; - - if ((1 == ps_index) && !helper::load_vector_range::process(parameters,r0,r1,3,4,1)) - return std::numeric_limits::quiet_NaN(); - else if (helper::invalid_range(y,r0,r1)) - return std::numeric_limits::quiet_NaN(); - - T a = scalar_t(parameters[0])(); - - for (std::size_t i = r0; i <= r1; ++i) - { - y[i] = a * x[i] + y[i]; - } - - return T(1); - } - }; - - template - class axpby : public exprtk::igeneric_function - { - public: - - typedef typename exprtk::igeneric_function igfun_t; - typedef typename igfun_t::parameter_list_t parameter_list_t; - typedef typename igfun_t::generic_type generic_type; - typedef typename generic_type::scalar_view scalar_t; - typedef typename generic_type::vector_view vector_t; - - using exprtk::igeneric_function::operator(); - - axpby() - : exprtk::igeneric_function("TVTV|TVTVTT") - /* - y <- ax + by - Overloads: - 0. TVTV - a, x(vector), b, y(vector) - 1. TVTVTT - a, x(vector), b, y(vector), r0, r1 - */ - {} - - inline T operator()(const std::size_t& ps_index, parameter_list_t parameters) - { - vector_t x(parameters[1]); - vector_t y(parameters[3]); - - std::size_t r0 = 0; - std::size_t r1 = std::min(x.size(),y.size()) - 1; - - if ((1 == ps_index) && !helper::load_vector_range::process(parameters,r0,r1,4,5,1)) - return std::numeric_limits::quiet_NaN(); - else if (helper::invalid_range(y,r0,r1)) - return std::numeric_limits::quiet_NaN(); - - const T a = scalar_t(parameters[0])(); - const T b = scalar_t(parameters[2])(); - - for (std::size_t i = r0; i <= r1; ++i) - { - y[i] = (a * x[i]) + (b * y[i]); - } - - return T(1); - } - }; - - template - class axpyz : public exprtk::igeneric_function - { - public: - - typedef typename exprtk::igeneric_function igfun_t; - typedef typename igfun_t::parameter_list_t parameter_list_t; - typedef typename igfun_t::generic_type generic_type; - typedef typename generic_type::scalar_view scalar_t; - typedef typename generic_type::vector_view vector_t; - - using exprtk::igeneric_function::operator(); - - axpyz() - : exprtk::igeneric_function("TVVV|TVVVTT") - /* - z <- ax + y - Overloads: - 0. TVVV - a, x(vector), y(vector), z(vector) - 1. TVVVTT - a, x(vector), y(vector), z(vector), r0, r1 - */ - {} - - inline T operator()(const std::size_t& ps_index, parameter_list_t parameters) - { - vector_t x(parameters[1]); - vector_t y(parameters[2]); - vector_t z(parameters[3]); - - std::size_t r0 = 0; - std::size_t r1 = std::min(x.size(),y.size()) - 1; - - if ((1 == ps_index) && !helper::load_vector_range::process(parameters,r0,r1,3,4,1)) - return std::numeric_limits::quiet_NaN(); - else if (helper::invalid_range(y,r0,r1)) - return std::numeric_limits::quiet_NaN(); - else if (helper::invalid_range(z,r0,r1)) - return std::numeric_limits::quiet_NaN(); - - T a = scalar_t(parameters[0])(); - - for (std::size_t i = r0; i <= r1; ++i) - { - z[i] = a * x[i] + y[i]; - } - - return T(1); - } - }; - - template - class axpbyz : public exprtk::igeneric_function - { - public: - - typedef typename exprtk::igeneric_function igfun_t; - typedef typename igfun_t::parameter_list_t parameter_list_t; - typedef typename igfun_t::generic_type generic_type; - typedef typename generic_type::scalar_view scalar_t; - typedef typename generic_type::vector_view vector_t; - - using exprtk::igeneric_function::operator(); - - axpbyz() - : exprtk::igeneric_function("TVTVV|TVTVVTT") - /* - z <- ax + by - Overloads: - 0. TVTVV - a, x(vector), b, y(vector), z(vector) - 1. TVTVVTT - a, x(vector), b, y(vector), z(vector), r0, r1 - */ - {} - - inline T operator()(const std::size_t& ps_index, parameter_list_t parameters) - { - vector_t x(parameters[1]); - vector_t y(parameters[3]); - vector_t z(parameters[4]); - - std::size_t r0 = 0; - std::size_t r1 = std::min(x.size(),y.size()) - 1; - - if ((1 == ps_index) && !helper::load_vector_range::process(parameters,r0,r1,4,5,1)) - return std::numeric_limits::quiet_NaN(); - else if (helper::invalid_range(y,r0,r1)) - return std::numeric_limits::quiet_NaN(); - else if (helper::invalid_range(z,r0,r1)) - return std::numeric_limits::quiet_NaN(); - - const T a = scalar_t(parameters[0])(); - const T b = scalar_t(parameters[2])(); - - for (std::size_t i = r0; i <= r1; ++i) - { - z[i] = (a * x[i]) + (b * y[i]); - } - - return T(1); - } - }; - - template - class axpbz : public exprtk::igeneric_function - { - public: - - typedef typename exprtk::igeneric_function igfun_t; - typedef typename igfun_t::parameter_list_t parameter_list_t; - typedef typename igfun_t::generic_type generic_type; - typedef typename generic_type::scalar_view scalar_t; - typedef typename generic_type::vector_view vector_t; - - using exprtk::igeneric_function::operator(); - - axpbz() - : exprtk::igeneric_function("TVTV|TVTVTT") - /* - z <- ax + b - Overloads: - 0. TVTV - a, x(vector), b, z(vector) - 1. TVTVTT - a, x(vector), b, z(vector), r0, r1 - */ - {} - - inline T operator()(const std::size_t& ps_index, parameter_list_t parameters) - { - vector_t x(parameters[1]); - vector_t z(parameters[3]); - - std::size_t r0 = 0; - std::size_t r1 = x.size() - 1; - - if ((1 == ps_index) && !helper::load_vector_range::process(parameters,r0,r1,4,5,1)) - return std::numeric_limits::quiet_NaN(); - else if (helper::invalid_range(z,r0,r1)) - return std::numeric_limits::quiet_NaN(); - - const T a = scalar_t(parameters[0])(); - const T b = scalar_t(parameters[2])(); - - for (std::size_t i = r0; i <= r1; ++i) - { - z[i] = a * x[i] + b; - } - - return T(1); - } - }; - - template - class dot : public exprtk::igeneric_function - { - public: - - typedef typename exprtk::igeneric_function igfun_t; - typedef typename igfun_t::parameter_list_t parameter_list_t; - typedef typename igfun_t::generic_type generic_type; - typedef typename generic_type::scalar_view scalar_t; - typedef typename generic_type::vector_view vector_t; - - using exprtk::igeneric_function::operator(); - - dot() - : exprtk::igeneric_function("VV|VVTT") - /* - Overloads: - 0. VV - x(vector), y(vector) - 1. VVTT - x(vector), y(vector), r0, r1 - */ - {} - - inline T operator()(const std::size_t& ps_index, parameter_list_t parameters) - { - vector_t x(parameters[0]); - vector_t y(parameters[1]); - - std::size_t r0 = 0; - std::size_t r1 = std::min(x.size(),y.size()) - 1; - - if ((1 == ps_index) && !helper::load_vector_range::process(parameters,r0,r1,2,3,0)) - return std::numeric_limits::quiet_NaN(); - else if (helper::invalid_range(y,r0,r1)) - return std::numeric_limits::quiet_NaN(); - - T result = T(0); - - for (std::size_t i = r0; i <= r1; ++i) - { - result += (x[i] * y[i]); - } - - return result; - } - }; - - template - class dotk : public exprtk::igeneric_function - { - public: - - typedef typename exprtk::igeneric_function igfun_t; - typedef typename igfun_t::parameter_list_t parameter_list_t; - typedef typename igfun_t::generic_type generic_type; - typedef typename generic_type::scalar_view scalar_t; - typedef typename generic_type::vector_view vector_t; - - using exprtk::igeneric_function::operator(); - - dotk() - : exprtk::igeneric_function("VV|VVTT") - /* - Overloads: - 0. VV - x(vector), y(vector) - 1. VVTT - x(vector), y(vector), r0, r1 - */ - {} - - inline T operator()(const std::size_t& ps_index, parameter_list_t parameters) - { - vector_t x(parameters[0]); - vector_t y(parameters[1]); - - std::size_t r0 = 0; - std::size_t r1 = std::min(x.size(),y.size()) - 1; - - if ((1 == ps_index) && !helper::load_vector_range::process(parameters,r0,r1,2,3,0)) - return std::numeric_limits::quiet_NaN(); - else if (helper::invalid_range(y,r0,r1)) - return std::numeric_limits::quiet_NaN(); - - T result = T(0); - T error = T(0); - - for (std::size_t i = r0; i <= r1; ++i) - { - details::kahan_sum(result,error,(x[i] * y[i])); - } - - return result; - } - }; - - template - struct package - { - all_true at; - all_false af; - any_true nt; - any_false nf; - count c; - copy cp; - rol rl; - ror rr; - shift_left sl; - shift_right sr; - sort st; - nthelement ne; - iota ia; - sumk sk; - axpy b1_axpy; - axpby b1_axpby; - axpyz b1_axpyz; - axpbyz b1_axpbyz; - axpbz b1_axpbz; - dot dt; - dotk dtk; - - bool register_package(exprtk::symbol_table& symtab) - { - if (!symtab.add_function("all_true" ,at)) - return false; - else if (!symtab.add_function("all_false" ,af)) - return false; - else if (!symtab.add_function("any_true" ,nt)) - return false; - else if (!symtab.add_function("any_false" ,nf)) - return false; - else if (!symtab.add_function("count" , c)) - return false; - else if (!symtab.add_function("copy" , cp)) - return false; - else if (!symtab.add_function("rotate_left" ,rl)) - return false; - else if (!symtab.add_function("rol" ,rl)) - return false; - else if (!symtab.add_function("rotate_right" ,rr)) - return false; - else if (!symtab.add_function("ror" ,rr)) - return false; - else if (!symtab.add_function("shftl" ,sl)) - return false; - else if (!symtab.add_function("shftr" ,sr)) - return false; - else if (!symtab.add_function("sort" ,st)) - return false; - else if (!symtab.add_function("nth_element" ,ne)) - return false; - else if (!symtab.add_function("iota" ,ia)) - return false; - else if (!symtab.add_function("sumk" ,sk)) - return false; - else if (!symtab.add_function("axpy" ,b1_axpy)) - return false; - else if (!symtab.add_function("axpby" ,b1_axpby)) - return false; - else if (!symtab.add_function("axpyz" ,b1_axpyz)) - return false; - else if (!symtab.add_function("axpbyz",b1_axpbyz)) - return false; - else if (!symtab.add_function("axpbz" ,b1_axpbz)) - return false; - else if (!symtab.add_function("dot" ,dt)) - return false; - else if (!symtab.add_function("dotk" ,dtk)) - return false; - else - return true; - } - }; - - } // namespace exprtk::rtl::vecops - } // namespace exprtk::rtl + bool register_package(exprtk::symbol_table& symtab) + { + #define exprtk_register_function(FunctionName,FunctionType) \ + if (!symtab.add_function(FunctionName,FunctionType)) \ + { \ + exprtk_debug(( \ + "exprtk::rtl::vecops::register_package - Failed to add function: %s\n", \ + FunctionName)); \ + return false; \ + } \ + + exprtk_register_function("all_true" ,at) + exprtk_register_function("all_false" ,af) + exprtk_register_function("any_true" ,nt) + exprtk_register_function("any_false" ,nf) + exprtk_register_function("count" , c) + exprtk_register_function("copy" , cp) + exprtk_register_function("rotate_left" ,rl) + exprtk_register_function("rol" ,rl) + exprtk_register_function("rotate_right" ,rr) + exprtk_register_function("ror" ,rr) + exprtk_register_function("shftl" ,sl) + exprtk_register_function("shftr" ,sr) + exprtk_register_function("sort" ,st) + exprtk_register_function("nth_element" ,ne) + exprtk_register_function("iota" ,ia) + exprtk_register_function("sumk" ,sk) + exprtk_register_function("axpy" ,b1_axpy) + exprtk_register_function("axpby" ,b1_axpby) + exprtk_register_function("axpyz" ,b1_axpyz) + exprtk_register_function("axpbyz",b1_axpbyz) + exprtk_register_function("axpbz" ,b1_axpbz) + exprtk_register_function("dot" ,dt) + exprtk_register_function("dotk" ,dtk) + #undef exprtk_register_function + + return true; + } + }; + + } // namespace exprtk::rtl::vecops + } // namespace exprtk::rtl } // namespace exprtk #endif namespace exprtk { - namespace information - { - static const char* library = "Mathematical Expression Toolkit"; - static const char* version = "2.71828182845904523536028747135266249775" - "7247093699959574966967627724076630353547"; - static const char* date = "20161010"; - - static inline std::string data() - { - static const std::string info_str = std::string(library) + - std::string(" v") + std::string(version) + - std::string(" (") + date + std::string(")"); - return info_str; - } - - } // namespace information - + namespace information + { + static const char* library = "Mathematical Expression Toolkit"; + static const char* version = "2.71828182845904523536028747135266249775724709" + "3699959574966967627724076630353547594571382178"; + static const char* date = "20170404"; + + static inline std::string data() + { + static const std::string info_str = std::string(library) + + std::string(" v") + std::string(version) + + std::string(" (") + date + std::string(")"); + return info_str; + } + + } // namespace information + } // namespace exprtk #endif From 4c997902139d4e6bd13784678952de0739ec9693 Mon Sep 17 00:00:00 2001 From: ArashPartow Date: Thu, 13 Apr 2017 08:35:42 +1000 Subject: [PATCH 2/2] Minor updates to ExprTk Updated unknown symbol resolver interface to handle all types (scalar, string and vector) Added compile-time check for vector indexing when using constant values Added return statement enable/disable via parser settings Added exprtk_disable_return_statement macro for disabling return statements and associated exceptions at the source code level. --- resources/3rdparty/exprtk/exprtk.hpp | 317 +++++++++++++++++---------- 1 file changed, 198 insertions(+), 119 deletions(-) diff --git a/resources/3rdparty/exprtk/exprtk.hpp b/resources/3rdparty/exprtk/exprtk.hpp index 4cb3a776a..e8c156596 100755 --- a/resources/3rdparty/exprtk/exprtk.hpp +++ b/resources/3rdparty/exprtk/exprtk.hpp @@ -4483,14 +4483,14 @@ namespace exprtk } } - static inline control_block* create(const std::size_t& size, data_t data_ptr = data_t(0), bool dstrct = false) + static inline control_block* create(const std::size_t& dsize, data_t data_ptr = data_t(0), bool dstrct = false) { - if (size) + if (dsize) { if (0 == data_ptr) - return new control_block(size); + return new control_block(dsize); else - return new control_block(size, data_ptr, dstrct); + return new control_block(dsize, data_ptr, dstrct); } else return new control_block; @@ -18811,20 +18811,42 @@ namespace exprtk e_usr_constant_type = 1 }; + enum usr_mode + { + e_usrmode_default = 0, + e_usrmode_extended = 1 + }; + + usr_mode mode; + + unknown_symbol_resolver(const usr_mode m = e_usrmode_default) + : mode(m) + {} + virtual ~unknown_symbol_resolver() {} virtual bool process(const std::string& /*unknown_symbol*/, - usr_symbol_type& st, - T& default_value, - std::string& error_message) + usr_symbol_type& st, + T& default_value, + std::string& error_message) { + if (e_usrmode_default != mode) + return false; + st = e_usr_variable_type; default_value = T(0); error_message.clear(); return true; } + + virtual bool process(const std::string& /* unknown_symbol */, + symbol_table_t& /* symbol_table */, + std::string& /* error_message */) + { + return false; + } }; enum collect_type @@ -19971,6 +19993,11 @@ namespace exprtk unknown_symbol_resolver_ = &default_usr_; } + inline void enable_unknown_symbol_resolver(unknown_symbol_resolver& usr) + { + enable_unknown_symbol_resolver(&usr); + } + inline void disable_unknown_symbol_resolver() { resolve_unknown_symbol_ = false; @@ -22628,6 +22655,26 @@ namespace exprtk return error_node(); } + // Perform compile-time range check + if (details::is_constant_node(index_expr)) + { + const std::size_t index = std::size_t(index_expr->value()); + const std::size_t vec_size = vec->size(); + + if (index >= vec_size) + { + set_error( + make_error(parser_error::e_syntax, + current_token(), + "ERR106 - Index of " + details::to_str(index) + " out of range for " + "vector '" + symbol + "' of size " + details::to_str(vec_size))); + + free_node(node_allocator_,index_expr); + + return error_node(); + } + } + return expression_generator_.vector_element(symbol,vec,index_expr); } @@ -22649,7 +22696,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR106 - Zero parameter call to vararg function: " + "ERR107 - Zero parameter call to vararg function: " + vararg_function_name + " not allowed")); return error_node(); @@ -22673,7 +22720,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR107 - Expected ',' for call to vararg function: " + "ERR108 - Expected ',' for call to vararg function: " + vararg_function_name)); return error_node(); @@ -22686,7 +22733,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR108 - Zero parameter call to vararg function: " + "ERR109 - Zero parameter call to vararg function: " + vararg_function_name + " not allowed")); return error_node(); @@ -22697,7 +22744,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR109 - Invalid number of parameters to call to vararg function: " + "ERR110 - Invalid number of parameters to call to vararg function: " + vararg_function_name + ", require at least " + details::to_str(static_cast(vararg_function->min_num_args())) + " parameters")); @@ -22708,7 +22755,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR110 - Invalid number of parameters to call to vararg function: " + "ERR111 - Invalid number of parameters to call to vararg function: " + vararg_function_name + ", require no more than " + details::to_str(static_cast(vararg_function->max_num_args())) + " parameters")); @@ -22770,7 +22817,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, parser_.current_token(), - "ERR111 - Failed parameter type check for function '" + function_name_ + "', " + "ERR112 - Failed parameter type check for function '" + function_name_ + "', " "Expected '" + param_seq_list_[0] + "' call set: '" + param_seq +"'")); } else @@ -22790,7 +22837,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, parser_.current_token(), - "ERR112 - Failed parameter type check for function '" + function_name_ + "', " + "ERR113 - Failed parameter type check for function '" + function_name_ + "', " "Best match: '" + param_seq_list_[max_diff_index] + "' call set: '" + param_seq +"'")); } @@ -22874,7 +22921,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, parser_.current_token(), - "ERR113 - Invalid parameter sequence of '" + err_param_seq + + "ERR114 - Invalid parameter sequence of '" + err_param_seq + "' for function: " + function_name_)); return; @@ -22895,7 +22942,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, parser_.current_token(), - "ERR114 - Invalid parameter sequence of '" + err_param_seq + + "ERR115 - Invalid parameter sequence of '" + err_param_seq + "' for function: " + function_name_)); return; } @@ -22928,7 +22975,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR115 - Type checker instantiation failure for generic function: " + function_name)); + "ERR116 - Type checker instantiation failure for generic function: " + function_name)); return error_node(); } @@ -22942,7 +22989,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR116 - Mismatch in zero parameter condition for generic function: " + "ERR117 - Mismatch in zero parameter condition for generic function: " + function_name)); return error_node(); @@ -22960,7 +23007,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR117 - Zero parameter call to generic function: " + "ERR118 - Zero parameter call to generic function: " + function_name + " not allowed")); return error_node(); @@ -22991,7 +23038,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR118 - Expected ',' for call to generic function: " + function_name)); + "ERR119 - Expected ',' for call to generic function: " + function_name)); return error_node(); } @@ -23007,7 +23054,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR119 - Zero parameter call to generic function: " + "ERR120 - Zero parameter call to generic function: " + function_name + " not allowed")); return error_node(); @@ -23023,7 +23070,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR120 - Expected ',' for call to generic function: " + function_name)); + "ERR121 - Expected ',' for call to generic function: " + function_name)); return error_node(); } @@ -23090,7 +23137,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR121 - Expected ',' for call to string function: " + function_name)); + "ERR122 - Expected ',' for call to string function: " + function_name)); return error_node(); } @@ -23105,7 +23152,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR122 - Expected ',' for call to string function: " + function_name)); + "ERR123 - Expected ',' for call to string function: " + function_name)); return error_node(); } @@ -23142,7 +23189,7 @@ namespace exprtk p.set_error( make_error(parser_error::e_syntax, p.current_token(), - "ERR123 - Expected '(' for special function")); + "ERR124 - Expected '(' for special function")); return error_node(); } @@ -23162,7 +23209,7 @@ namespace exprtk p.set_error( make_error(parser_error::e_syntax, p.current_token(), - "ERR124 - Expected ',' before next parameter of special function")); + "ERR125 - Expected ',' before next parameter of special function")); return p.error_node(); } @@ -23191,7 +23238,7 @@ namespace exprtk set_error( make_error(parser_error::e_token, current_token(), - "ERR125 - Invalid special function[1]: " + current_token().value)); + "ERR126 - Invalid special function[1]: " + current_token().value)); return error_node(); } @@ -23203,7 +23250,7 @@ namespace exprtk set_error( make_error(parser_error::e_token, current_token(), - "ERR126 - Invalid special function[2]: " + current_token().value)); + "ERR127 - Invalid special function[2]: " + current_token().value)); return error_node(); } @@ -23234,7 +23281,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR127 - Break call within a break call is not allowed")); + "ERR128 - Break call within a break call is not allowed")); return error_node(); } @@ -23256,7 +23303,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR128 - Failed to parse return expression for 'break' statement")); + "ERR129 - Failed to parse return expression for 'break' statement")); return error_node(); } @@ -23265,7 +23312,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR129 - Expected ']' at the completion of break's return expression")); + "ERR130 - Expected ']' at the completion of break's return expression")); free_node(node_allocator_,return_expr); @@ -23282,7 +23329,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR130 - Invalid use of 'break', allowed only in the scope of a loop")); + "ERR131 - Invalid use of 'break', allowed only in the scope of a loop")); } return error_node(); @@ -23304,7 +23351,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR131 - Invalid use of 'continue', allowed only in the scope of a loop")); + "ERR132 - Invalid use of 'continue', allowed only in the scope of a loop")); return error_node(); } @@ -23320,7 +23367,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR132 - Expected '[' as part of vector size definition")); + "ERR133 - Expected '[' as part of vector size definition")); return error_node(); } @@ -23329,7 +23376,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR133 - Failed to determine size of vector '" + vec_name + "'")); + "ERR134 - Failed to determine size of vector '" + vec_name + "'")); return error_node(); } @@ -23340,7 +23387,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR134 - Expected a literal number as size of vector '" + vec_name + "'")); + "ERR135 - Expected a literal number as size of vector '" + vec_name + "'")); return error_node(); } @@ -23358,7 +23405,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR135 - Invalid vector size. Must be an integer greater than zero, size: " + + "ERR136 - Invalid vector size. Must be an integer greater than zero, size: " + details::to_str(details::numeric::to_int32(vector_size)))); return error_node(); @@ -23377,7 +23424,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR136 - Expected ']' as part of vector size definition")); + "ERR137 - Expected ']' as part of vector size definition")); return error_node(); } @@ -23388,7 +23435,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR137 - Expected ':=' as part of vector definition")); + "ERR138 - Expected ':=' as part of vector definition")); return error_node(); } @@ -23401,7 +23448,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR138 - Failed to parse single vector initialiser")); + "ERR139 - Failed to parse single vector initialiser")); return error_node(); } @@ -23413,7 +23460,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR139 - Expected ']' to close single value vector initialiser")); + "ERR140 - Expected ']' to close single value vector initialiser")); return error_node(); } @@ -23459,7 +23506,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR140 - Expected '{' as part of vector initialiser list")); + "ERR141 - Expected '{' as part of vector initialiser list")); return error_node(); } @@ -23478,7 +23525,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR141 - Expected '{' as part of vector initialiser list")); + "ERR142 - Expected '{' as part of vector initialiser list")); return error_node(); } @@ -23495,7 +23542,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR142 - Expected ',' between vector initialisers")); + "ERR143 - Expected ',' between vector initialisers")); return error_node(); } @@ -23516,7 +23563,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR143 - Expected ';' at end of vector definition")); + "ERR144 - Expected ';' at end of vector definition")); return error_node(); } @@ -23527,7 +23574,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR144 - Initialiser list larger than the number of elements in the vector: '" + vec_name + "'")); + "ERR145 - Initialiser list larger than the number of elements in the vector: '" + vec_name + "'")); return error_node(); } @@ -23546,7 +23593,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR145 - Illegal redefinition of local vector: '" + vec_name + "'")); + "ERR146 - Illegal redefinition of local vector: '" + vec_name + "'")); return error_node(); } @@ -23579,7 +23626,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR146 - Failed to add new local vector '" + vec_name + "' to SEM")); + "ERR147 - Failed to add new local vector '" + vec_name + "' to SEM")); sem_.free_element(nse); @@ -23633,7 +23680,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR147 - Illegal redefinition of local variable: '" + str_name + "'")); + "ERR148 - Illegal redefinition of local variable: '" + str_name + "'")); free_node(node_allocator_,initialisation_expression); @@ -23664,7 +23711,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR148 - Failed to add new local string variable '" + str_name + "' to SEM")); + "ERR149 - Failed to add new local string variable '" + str_name + "' to SEM")); free_node(node_allocator_,initialisation_expression); @@ -23709,7 +23756,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR149 - Illegal variable definition")); + "ERR150 - Illegal variable definition")); return error_node(); } @@ -23729,7 +23776,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR150 - Expected a symbol for variable definition")); + "ERR151 - Expected a symbol for variable definition")); return error_node(); } @@ -23738,7 +23785,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR151 - Illegal redefinition of reserved keyword: '" + var_name + "'")); + "ERR152 - Illegal redefinition of reserved keyword: '" + var_name + "'")); return error_node(); } @@ -23747,7 +23794,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR152 - Illegal redefinition of variable '" + var_name + "'")); + "ERR153 - Illegal redefinition of variable '" + var_name + "'")); return error_node(); } @@ -23756,7 +23803,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR153 - Illegal redefinition of local variable: '" + var_name + "'")); + "ERR154 - Illegal redefinition of local variable: '" + var_name + "'")); return error_node(); } @@ -23775,7 +23822,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR154 - Failed to parse initialisation expression")); + "ERR155 - Failed to parse initialisation expression")); return error_node(); } @@ -23792,7 +23839,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR155 - Expected ';' after variable definition")); + "ERR156 - Expected ';' after variable definition")); free_node(node_allocator_,initialisation_expression); @@ -23819,7 +23866,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR156 - Illegal redefinition of local variable: '" + var_name + "'")); + "ERR157 - Illegal redefinition of local variable: '" + var_name + "'")); free_node(node_allocator_,initialisation_expression); @@ -23850,7 +23897,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR157 - Failed to add new local variable '" + var_name + "' to SEM")); + "ERR158 - Failed to add new local variable '" + var_name + "' to SEM")); free_node(node_allocator_,initialisation_expression); @@ -23886,7 +23933,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR158 - Expected a '{}' for uninitialised var definition")); + "ERR159 - Expected a '{}' for uninitialised var definition")); return error_node(); } @@ -23895,7 +23942,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR159 - Expected ';' after uninitialised variable definition")); + "ERR160 - Expected ';' after uninitialised variable definition")); return error_node(); } @@ -23911,7 +23958,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR160 - Illegal redefinition of local variable: '" + var_name + "'")); + "ERR161 - Illegal redefinition of local variable: '" + var_name + "'")); return error_node(); } @@ -23940,7 +23987,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR161 - Failed to add new local variable '" + var_name + "' to SEM")); + "ERR162 - Failed to add new local variable '" + var_name + "' to SEM")); sem_.free_element(nse); @@ -23972,7 +24019,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR162 - Expected '(' at start of swap statement")); + "ERR163 - Expected '(' at start of swap statement")); return error_node(); } @@ -23990,7 +24037,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR163 - Expected a symbol for variable or vector element definition")); + "ERR164 - Expected a symbol for variable or vector element definition")); return error_node(); } @@ -24001,7 +24048,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR164 - First parameter to swap is an invalid vector element: '" + var0_name + "'")); + "ERR165 - First parameter to swap is an invalid vector element: '" + var0_name + "'")); return error_node(); } @@ -24033,7 +24080,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR165 - First parameter to swap is an invalid variable: '" + var0_name + "'")); + "ERR166 - First parameter to swap is an invalid variable: '" + var0_name + "'")); return error_node(); } @@ -24046,7 +24093,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR166 - Expected ',' between parameters to swap")); + "ERR167 - Expected ',' between parameters to swap")); if (variable0_generated) { @@ -24063,7 +24110,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR167 - Expected a symbol for variable or vector element definition")); + "ERR168 - Expected a symbol for variable or vector element definition")); if (variable0_generated) { @@ -24079,7 +24126,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR168 - Second parameter to swap is an invalid vector element: '" + var1_name + "'")); + "ERR169 - Second parameter to swap is an invalid vector element: '" + var1_name + "'")); if (variable0_generated) { @@ -24116,7 +24163,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR169 - Second parameter to swap is an invalid variable: '" + var1_name + "'")); + "ERR170 - Second parameter to swap is an invalid variable: '" + var1_name + "'")); if (variable0_generated) { @@ -24134,7 +24181,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR170 - Expected ')' at end of swap statement")); + "ERR171 - Expected ')' at end of swap statement")); if (variable0_generated) { @@ -24188,7 +24235,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR171 - Return call within a return call is not allowed")); + "ERR172 - Return call within a return call is not allowed")); return error_node(); } @@ -24211,7 +24258,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR172 - Expected '[' at start of return statement")); + "ERR173 - Expected '[' at start of return statement")); return error_node(); } @@ -24233,7 +24280,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR173 - Expected ',' between values during call to return")); + "ERR174 - Expected ',' between values during call to return")); return error_node(); } @@ -24244,7 +24291,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR174 - Zero parameter return statement not allowed")); + "ERR175 - Zero parameter return statement not allowed")); return error_node(); } @@ -24258,7 +24305,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, prev_token, - "ERR175 - Invalid ']' found during return call")); + "ERR176 - Invalid ']' found during return call")); return error_node(); } @@ -24310,7 +24357,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR176 - Invalid sequence of variable '"+ symbol + "' and bracket")); + "ERR177 - Invalid sequence of variable '"+ symbol + "' and bracket")); return false; } @@ -24357,7 +24404,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR177 - Invalid sequence of brackets")); + "ERR178 - Invalid sequence of brackets")); return false; } @@ -24453,7 +24500,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR178 - Failed to generate node for function: '" + symbol + "'")); + "ERR179 - Failed to generate node for function: '" + symbol + "'")); return error_node(); } @@ -24478,7 +24525,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR179 - Failed to generate node for vararg function: '" + symbol + "'")); + "ERR180 - Failed to generate node for vararg function: '" + symbol + "'")); return error_node(); } @@ -24503,7 +24550,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR180 - Failed to generate node for generic function: '" + symbol + "'")); + "ERR181 - Failed to generate node for generic function: '" + symbol + "'")); return error_node(); } @@ -24529,7 +24576,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR181 - Failed to generate node for string function: '" + symbol + "'")); + "ERR182 - Failed to generate node for string function: '" + symbol + "'")); return error_node(); } @@ -24551,7 +24598,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR182 - Invalid use of reserved symbol '" + symbol + "'")); + "ERR183 - Invalid use of reserved symbol '" + symbol + "'")); return error_node(); } @@ -24562,63 +24609,93 @@ namespace exprtk { if (!(settings_.rsrvd_sym_usr_disabled() && details::is_reserved_symbol(symbol))) { - T default_value = T(0); + symbol_table_t& symtab = symtab_store_.get_symbol_table(); 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)) + if (unknown_symbol_resolver::e_usrmode_default == unknown_symbol_resolver_->mode) { - bool create_result = false; + T default_value = T(0); + typename unknown_symbol_resolver::usr_symbol_type usr_symbol_type; - symbol_table_t& symtab = symtab_store_.get_symbol_table(); - - switch (usr_symbol_type) + if (unknown_symbol_resolver_->process(symbol, usr_symbol_type, default_value, error_message)) { - case unknown_symbol_resolver::e_usr_variable_type : create_result = symtab.create_variable(symbol,default_value); - break; + bool create_result = false; - case unknown_symbol_resolver::e_usr_constant_type : create_result = symtab.add_constant(symbol,default_value); - break; + switch (usr_symbol_type) + { + case unknown_symbol_resolver::e_usr_variable_type : create_result = symtab.create_variable(symbol, default_value); + break; - default : create_result = false; - } + case unknown_symbol_resolver::e_usr_constant_type : create_result = symtab.add_constant(symbol, default_value); + break; - if (create_result) - { - expression_node_ptr var = symtab_store_.get_variable(symbol); + default : create_result = false; + } - if (var) + if (create_result) { - if (symtab_store_.is_constant_node(symbol)) + expression_node_ptr var = symtab_store_.get_variable(symbol); + + if (var) { - var = expression_generator_(var->value()); - } + if (symtab_store_.is_constant_node(symbol)) + { + var = expression_generator_(var->value()); + } - lodge_symbol(symbol,e_st_variable); + lodge_symbol(symbol,e_st_variable); - if (!post_variable_process(symbol)) - return error_node(); + if (!post_variable_process(symbol)) + return error_node(); - next_token(); + next_token(); - return var; + return var; + } } } set_error( make_error(parser_error::e_symtab, current_token(), - "ERR183 - Failed to create variable: '" + symbol + "'")); + "ERR184 - Failed to create variable: '" + symbol + "'" + + (error_message.empty() ? "" : " - " + error_message))); - return error_node(); } + else if (unknown_symbol_resolver::e_usrmode_extended == unknown_symbol_resolver_->mode) + { + if (unknown_symbol_resolver_->process(symbol, symtab, error_message)) + { + static bool usr_extmode_active = false; + + if (!usr_extmode_active) + { + usr_extmode_active = true; + expression_node_ptr result = parse_symtab_symbol(); + usr_extmode_active = false; + + if (result) + { + return result; + } + } + } + + set_error( + make_error(parser_error::e_symtab, + current_token(), + "ERR185 - Failed to resolve symbol: '" + symbol + "'" + + (error_message.empty() ? "" : " - " + error_message))); + } + + return error_node(); } } set_error( make_error(parser_error::e_syntax, current_token(), - "ERR184 - Undefined symbol: '" + symbol + "'")); + "ERR186 - Undefined symbol: '" + symbol + "'")); return error_node(); } @@ -24724,7 +24801,7 @@ namespace exprtk set_error( make_error(parser_error::e_symtab, current_token(), - "ERR185 - Variable or function detected, yet symbol-table is invalid, Symbol: " + current_token().value)); + "ERR187 - Variable or function detected, yet symbol-table is invalid, Symbol: " + current_token().value)); return error_node(); } @@ -24749,7 +24826,7 @@ namespace exprtk set_error( make_error(parser_error::e_numeric, current_token(), - "ERR186 - Failed to convert '" + current_token().value + "' to a number")); + "ERR188 - Failed to convert '" + current_token().value + "' to a number")); return error_node(); } @@ -24775,7 +24852,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR187 - Expected ')' instead of: '" + current_token().value + "'")); + "ERR189 - Expected ')' instead of: '" + current_token().value + "'")); free_node(node_allocator_,branch); @@ -24799,7 +24876,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR188 - Expected ']' instead of: '" + current_token().value + "'")); + "ERR190 - Expected ']' instead of: '" + current_token().value + "'")); free_node(node_allocator_,branch); @@ -24823,7 +24900,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR189 - Expected '}' instead of: '" + current_token().value + "'")); + "ERR191 - Expected '}' instead of: '" + current_token().value + "'")); free_node(node_allocator_,branch); @@ -24862,7 +24939,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR190 - Premature end of expression[1]")); + "ERR192 - Premature end of expression[1]")); return error_node(); } @@ -24871,7 +24948,7 @@ namespace exprtk set_error( make_error(parser_error::e_syntax, current_token(), - "ERR191 - Premature end of expression[2]")); + "ERR193 - Premature end of expression[2]")); return error_node(); } @@ -26517,12 +26594,14 @@ namespace exprtk else if (all_nodes_variables(arg_list)) return varnode_optimise_varargfunc(operation,arg_list); + #ifndef exprtk_disable_string_capabilities if (details::e_smulti == operation) { return node_allocator_-> allocate > >(arg_list); } else + #endif { switch (operation) {