You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
30167 lines
1.1 MiB
30167 lines
1.1 MiB
/*
|
|
******************************************************************
|
|
* C++ Mathematical Expression Toolkit Library *
|
|
* *
|
|
* Author: Arash Partow (1999-2015) *
|
|
* URL: http://www.partow.net/programming/exprtk/index.html *
|
|
* *
|
|
* Copyright notice: *
|
|
* Free use of the C++ Mathematical Expression Toolkit Library is *
|
|
* permitted under the guidelines and in accordance with the most *
|
|
* current version of the Common Public License. *
|
|
* http://www.opensource.org/licenses/cpl1.0.php *
|
|
* *
|
|
* Example expressions: *
|
|
* (00) (y + x / y) * (x - y / x) *
|
|
* (01) (x^2 / sin(2 * pi / y)) - x / 2 *
|
|
* (02) sqrt(1 - (x^2)) *
|
|
* (03) 1 - sin(2 * x) + cos(pi / y) *
|
|
* (04) a * exp(2 * t) + c *
|
|
* (05) if(((x + 2) == 3) and ((y + 5) <= 9),1 + w, 2 / z) *
|
|
* (06) (avg(x,y) <= x + y ? x - y : x * y) + 2 * pi / x *
|
|
* (07) z := x + sin(2 * pi / y) *
|
|
* (08) u := 2 * (pi * z) / (w := x + cos(y / pi)) *
|
|
* (09) clamp(-1,sin(2 * pi * x) + cos(y / 2 * pi),+1) *
|
|
* (10) inrange(-2,m,+2) == if(({-2 <= m} and [m <= +2]),1,0) *
|
|
* (11) (2sin(x)cos(2y)7 + 1) == (2 * sin(x) * cos(2*y) * 7 + 1) *
|
|
* (12) (x ilike 's*ri?g') and [y < (3 z^7 + w)] *
|
|
* *
|
|
******************************************************************
|
|
*/
|
|
|
|
|
|
#ifndef INCLUDE_EXPRTK_HPP
|
|
#define INCLUDE_EXPRTK_HPP
|
|
|
|
|
|
#include <algorithm>
|
|
#include <cctype>
|
|
#include <cmath>
|
|
#include <cstdio>
|
|
#include <cstdlib>
|
|
#include <deque>
|
|
#include <exception>
|
|
#include <functional>
|
|
#include <iterator>
|
|
#include <limits>
|
|
#include <list>
|
|
#include <map>
|
|
#include <set>
|
|
#include <stack>
|
|
#include <stdexcept>
|
|
#include <string>
|
|
#include <utility>
|
|
#include <vector>
|
|
|
|
|
|
namespace exprtk
|
|
{
|
|
#if exprtk_enable_debugging
|
|
#define exprtk_debug(params) printf params
|
|
#else
|
|
#define exprtk_debug(params) (void)0
|
|
#endif
|
|
|
|
namespace details
|
|
{
|
|
inline bool is_whitespace(const char c)
|
|
{
|
|
return (' ' == c) || ('\n' == c) ||
|
|
('\r' == c) || ('\t' == c) ||
|
|
('\b' == c) || ('\v' == c) ||
|
|
('\f' == c) ;
|
|
}
|
|
|
|
inline bool is_operator_char(const char c)
|
|
{
|
|
return ('+' == c) || ('-' == c) ||
|
|
('*' == c) || ('/' == c) ||
|
|
('^' == c) || ('<' == c) ||
|
|
('>' == c) || ('=' == c) ||
|
|
(',' == c) || ('!' == c) ||
|
|
('(' == c) || (')' == c) ||
|
|
('[' == c) || (']' == c) ||
|
|
('{' == c) || ('}' == c) ||
|
|
('%' == c) || (':' == c) ||
|
|
('?' == c) || ('&' == c) ||
|
|
('|' == c) || (';' == c) ;
|
|
}
|
|
|
|
inline bool is_letter(const char c)
|
|
{
|
|
return (('a' <= c) && (c <= 'z')) ||
|
|
(('A' <= c) && (c <= 'Z')) ;
|
|
}
|
|
|
|
inline bool is_digit(const char c)
|
|
{
|
|
return ('0' <= c) && (c <= '9');
|
|
}
|
|
|
|
inline bool is_letter_or_digit(const char c)
|
|
{
|
|
return is_letter(c) || is_digit(c);
|
|
}
|
|
|
|
inline bool is_left_bracket(const char c)
|
|
{
|
|
return ('(' == c) || ('[' == c) || ('{' == c);
|
|
}
|
|
|
|
inline bool is_right_bracket(const char c)
|
|
{
|
|
return (')' == c) || (']' == c) || ('}' == c);
|
|
}
|
|
|
|
inline bool is_bracket(const char c)
|
|
{
|
|
return is_left_bracket(c) || is_right_bracket(c);
|
|
}
|
|
|
|
inline bool is_sign(const char c)
|
|
{
|
|
return ('+' == c) || ('-' == c);
|
|
}
|
|
|
|
inline bool is_invalid(const char c)
|
|
{
|
|
return !is_whitespace (c) &&
|
|
!is_operator_char(c) &&
|
|
!is_letter (c) &&
|
|
!is_digit (c) &&
|
|
('.' != c) &&
|
|
('_' != c) &&
|
|
('$' != c) &&
|
|
('~' != c) &&
|
|
('\'' != c);
|
|
}
|
|
|
|
inline bool imatch(const char c1, const char c2)
|
|
{
|
|
return std::tolower(c1) == std::tolower(c2);
|
|
}
|
|
|
|
inline bool imatch(const std::string& s1, const std::string& s2)
|
|
{
|
|
if (s1.size() == s2.size())
|
|
{
|
|
for (std::size_t i = 0; i < s1.size(); ++i)
|
|
{
|
|
if (std::tolower(s1[i]) != std::tolower(s2[i]))
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
inline bool is_valid_sf_symbol(const std::string& symbol)
|
|
{
|
|
// Special function: $f12 or $F34
|
|
return (4 == symbol.size()) &&
|
|
('$' == symbol[0]) &&
|
|
imatch('f',symbol[1]) &&
|
|
is_digit(symbol[2]) &&
|
|
is_digit(symbol[3]);
|
|
}
|
|
|
|
inline std::string to_str(int i)
|
|
{
|
|
if (0 == i)
|
|
return std::string("0");
|
|
|
|
std::string result;
|
|
bool negative = (i < 0);
|
|
|
|
if (negative) i *= -1;
|
|
|
|
while (i)
|
|
{
|
|
char digit = '0' + char(i % 10);
|
|
result = (digit + result);
|
|
i /= 10;
|
|
}
|
|
|
|
if (negative)
|
|
result = "-" + result;
|
|
|
|
return result;
|
|
}
|
|
|
|
inline bool is_hex_digit(const std::string::value_type digit)
|
|
{
|
|
return (('0' <= digit) && (digit <= '9')) ||
|
|
(('A' <= digit) && (digit <= 'F')) ||
|
|
(('a' <= digit) && (digit <= 'f')) ;
|
|
}
|
|
|
|
inline unsigned char hex_to_bin(unsigned char h)
|
|
{
|
|
if (('0' <= h) && (h <= '9'))
|
|
return (h - '0');
|
|
else
|
|
return (std::toupper(h) - 'A');
|
|
}
|
|
|
|
template <typename Iterator>
|
|
inline void parse_hex(Iterator& itr, Iterator end, std::string::value_type& result)
|
|
{
|
|
if (
|
|
(end != (itr )) &&
|
|
(end != (itr + 1)) &&
|
|
(end != (itr + 2)) &&
|
|
(end != (itr + 3)) &&
|
|
('0' == *(itr )) &&
|
|
(
|
|
('x' == *(itr + 1)) ||
|
|
('X' == *(itr + 1))
|
|
) &&
|
|
(is_hex_digit(*(itr + 2))) &&
|
|
(is_hex_digit(*(itr + 3)))
|
|
)
|
|
{
|
|
result = hex_to_bin(*(itr + 2)) << 4 | hex_to_bin(*(itr + 3));
|
|
itr += 3;
|
|
}
|
|
else
|
|
result = '\0';
|
|
}
|
|
|
|
inline void cleanup_escapes(std::string& s)
|
|
{
|
|
std::string::iterator itr1 = s.begin();
|
|
std::string::iterator itr2 = s.begin();
|
|
std::string::iterator end = s.end ();
|
|
std::size_t removal_count = 0;
|
|
|
|
while (end != itr1)
|
|
{
|
|
if ('\\' == (*itr1))
|
|
{
|
|
++removal_count;
|
|
|
|
if (end == ++itr1)
|
|
break;
|
|
else if ('\\' != (*itr1))
|
|
{
|
|
switch (*itr1)
|
|
{
|
|
case 'n' : (*itr1) = '\n'; break;
|
|
case 'r' : (*itr1) = '\r'; break;
|
|
case 't' : (*itr1) = '\t'; break;
|
|
case '0' : parse_hex(itr1,end,(*itr1));
|
|
removal_count += 3;
|
|
break;
|
|
}
|
|
|
|
continue;
|
|
}
|
|
}
|
|
|
|
if (itr1 != itr2)
|
|
{
|
|
(*itr2) = (*itr1);
|
|
}
|
|
|
|
++itr1;
|
|
++itr2;
|
|
}
|
|
|
|
s.resize(s.size() - removal_count);
|
|
}
|
|
|
|
class build_string
|
|
{
|
|
public:
|
|
|
|
build_string(const std::size_t& initial_size = 64)
|
|
{
|
|
data_.reserve(initial_size);
|
|
}
|
|
|
|
inline build_string& operator << (const std::string& s)
|
|
{
|
|
data_ += s;
|
|
return (*this);
|
|
}
|
|
|
|
inline build_string& operator << (const char* s)
|
|
{
|
|
data_ += std::string(s);
|
|
return (*this);
|
|
}
|
|
|
|
inline operator std::string () const
|
|
{
|
|
return data_;
|
|
}
|
|
|
|
inline std::string as_string() const
|
|
{
|
|
return data_;
|
|
}
|
|
|
|
private:
|
|
|
|
std::string data_;
|
|
};
|
|
|
|
struct ilesscompare
|
|
{
|
|
inline bool operator()(const std::string& s1, const std::string& s2) const
|
|
{
|
|
const std::size_t length = std::min(s1.size(),s2.size());
|
|
|
|
for (std::size_t i = 0; i < length; ++i)
|
|
{
|
|
const char c1 = static_cast<char>(std::tolower(s1[i]));
|
|
const char c2 = static_cast<char>(std::tolower(s2[i]));
|
|
|
|
if (c1 > c2)
|
|
return false;
|
|
else if (c1 < c2)
|
|
return true;
|
|
}
|
|
|
|
return s1.size() < s2.size();
|
|
}
|
|
};
|
|
|
|
static const std::string reserved_words[] =
|
|
{
|
|
"break", "case", "continue", "default", "false", "for",
|
|
"if", "else", "ilike", "in", "like", "and", "nand", "nor",
|
|
"not", "null", "or", "repeat", "shl", "shr", "swap",
|
|
"switch", "true", "until", "var", "while", "xnor", "xor",
|
|
"&", "|"
|
|
};
|
|
|
|
static const std::size_t reserved_words_size = sizeof(reserved_words) / sizeof(std::string);
|
|
|
|
static const std::string reserved_symbols[] =
|
|
{
|
|
"abs", "acos", "acosh", "and", "asin", "asinh", "atan",
|
|
"atanh", "atan2", "avg", "break", "case", "ceil", "clamp",
|
|
"continue", "cos", "cosh", "cot", "csc", "default",
|
|
"deg2grad", "deg2rad", "equal", "erf", "erfc", "exp",
|
|
"expm1", "false", "floor", "for", "frac", "grad2deg",
|
|
"hypot", "iclamp", "if", "else", "ilike", "in", "inrange",
|
|
"like", "log", "log10", "log2", "logn", "log1p", "mand",
|
|
"max", "min", "mod", "mor", "mul", "ncdf", "nand", "nor",
|
|
"not", "not_equal", "null", "or", "pow", "rad2deg",
|
|
"repeat", "root", "round", "roundn", "sec", "sgn", "shl",
|
|
"shr", "sin", "sinc", "sinh", "sqrt", "sum", "swap",
|
|
"switch", "tan", "tanh", "true", "trunc", "until", "var",
|
|
"while", "xnor", "xor", "&", "|"
|
|
};
|
|
|
|
static const std::size_t reserved_symbols_size = sizeof(reserved_symbols) / sizeof(std::string);
|
|
|
|
inline bool is_reserved_word(const std::string& symbol)
|
|
{
|
|
for (std::size_t i = 0; i < reserved_words_size; ++i)
|
|
{
|
|
if (imatch(symbol,reserved_words[i]))
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
inline bool is_reserved_symbol(const std::string& symbol)
|
|
{
|
|
for (std::size_t i = 0; i < reserved_symbols_size; ++i)
|
|
{
|
|
if (imatch(symbol,reserved_symbols[i]))
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
struct cs_match
|
|
{
|
|
static inline bool cmp(const char c0, const char c1)
|
|
{
|
|
return (c0 == c1);
|
|
}
|
|
};
|
|
|
|
struct cis_match
|
|
{
|
|
static inline bool cmp(const char c0, const char c1)
|
|
{
|
|
return (std::tolower(c0) == std::tolower(c1));
|
|
}
|
|
};
|
|
|
|
template <typename Iterator, typename Compare>
|
|
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<Iterator>::value_type& zero_or_more,
|
|
const typename std::iterator_traits<Iterator>::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<const char*,cs_match>(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<const char*,cis_match>(wild_card.data(),
|
|
wild_card.data() + wild_card.size(),
|
|
str.data(),
|
|
str.data() + str.size(),
|
|
'*',
|
|
'?');
|
|
}
|
|
|
|
inline bool sequence_match(const std::string& pattern,
|
|
const std::string& str,
|
|
std::size_t& diff_index,
|
|
char& diff_value)
|
|
{
|
|
if (str.empty() || pattern.empty())
|
|
return false;
|
|
else if ('*' == pattern[0])
|
|
return false;
|
|
|
|
typedef std::string::const_iterator itr_t;
|
|
|
|
itr_t p_itr = pattern.begin();
|
|
itr_t s_itr = str .begin();
|
|
|
|
itr_t p_end = pattern.end();
|
|
itr_t s_end = str .end();
|
|
|
|
while ((s_end != s_itr) && (p_end != p_itr))
|
|
{
|
|
if ('*' == (*p_itr))
|
|
{
|
|
const char target = std::toupper(*(p_itr - 1));
|
|
|
|
if ('*' == target)
|
|
{
|
|
diff_index = std::distance(str.begin(),s_itr);
|
|
diff_value = std::toupper(*p_itr);
|
|
|
|
return false;
|
|
}
|
|
else
|
|
++p_itr;
|
|
|
|
while (s_itr != s_end)
|
|
{
|
|
if (target != std::toupper(*s_itr))
|
|
break;
|
|
else
|
|
++s_itr;
|
|
}
|
|
|
|
continue;
|
|
}
|
|
else if (
|
|
('?' != *p_itr) &&
|
|
std::toupper(*p_itr) != std::toupper(*s_itr)
|
|
)
|
|
{
|
|
diff_index = std::distance(str.begin(),s_itr);
|
|
diff_value = std::toupper(*p_itr);
|
|
|
|
return false;
|
|
}
|
|
|
|
++p_itr;
|
|
++s_itr;
|
|
}
|
|
|
|
return (
|
|
(s_end == s_itr) &&
|
|
(
|
|
(p_end == p_itr) ||
|
|
('*' == *p_itr)
|
|
)
|
|
);
|
|
}
|
|
|
|
static const double pow10[] = {
|
|
1.0,
|
|
1.0E+001, 1.0E+002, 1.0E+003, 1.0E+004,
|
|
1.0E+005, 1.0E+006, 1.0E+007, 1.0E+008,
|
|
1.0E+009, 1.0E+010, 1.0E+011, 1.0E+012,
|
|
1.0E+013, 1.0E+014, 1.0E+015, 1.0E+016
|
|
};
|
|
|
|
static const std::size_t pow10_size = sizeof(pow10) / sizeof(double);
|
|
|
|
namespace numeric
|
|
{
|
|
namespace constant
|
|
{
|
|
static const double e = 2.718281828459045235360;
|
|
static const double pi = 3.141592653589793238462;
|
|
static const double pi_2 = 1.570796326794896619231;
|
|
static const double pi_4 = 0.785398163397448309616;
|
|
static const double pi_180 = 0.017453292519943295769;
|
|
static const double _1_pi = 0.318309886183790671538;
|
|
static const double _2_pi = 0.636619772367581343076;
|
|
static const double _180_pi = 57.295779513082320876798;
|
|
static const double log2 = 0.693147180559945309417;
|
|
static const double sqrt2 = 1.414213562373095048801;
|
|
}
|
|
|
|
namespace details
|
|
{
|
|
struct unknown_type_tag {};
|
|
struct real_type_tag {};
|
|
struct int_type_tag {};
|
|
|
|
template <typename T>
|
|
struct number_type { typedef unknown_type_tag type; };
|
|
|
|
#define exprtk_register_real_type_tag(T) \
|
|
template<> struct number_type<T> { typedef real_type_tag type; }; \
|
|
|
|
#define exprtk_register_int_type_tag(T) \
|
|
template<> struct number_type<T> { typedef int_type_tag type; }; \
|
|
|
|
exprtk_register_real_type_tag(double )
|
|
exprtk_register_real_type_tag(long double)
|
|
exprtk_register_real_type_tag(float )
|
|
|
|
exprtk_register_int_type_tag(short )
|
|
exprtk_register_int_type_tag(int )
|
|
exprtk_register_int_type_tag(long long int )
|
|
exprtk_register_int_type_tag(unsigned short )
|
|
exprtk_register_int_type_tag(unsigned int )
|
|
exprtk_register_int_type_tag(unsigned long long int)
|
|
|
|
#undef exprtk_register_real_type_tag
|
|
#undef exprtk_register_int_type_tag
|
|
|
|
template <typename T>
|
|
struct epsilon_type
|
|
{
|
|
static inline T value()
|
|
{
|
|
const T epsilon = T(0.0000000001);
|
|
return epsilon;
|
|
}
|
|
};
|
|
|
|
template <>
|
|
struct epsilon_type <float>
|
|
{
|
|
static inline float value()
|
|
{
|
|
const float epsilon = float(0.000001f);
|
|
return epsilon;
|
|
}
|
|
};
|
|
|
|
template <>
|
|
struct epsilon_type <long double>
|
|
{
|
|
static inline long double value()
|
|
{
|
|
const long double epsilon = (long double)(0.000000000001);
|
|
return epsilon;
|
|
}
|
|
};
|
|
|
|
template <typename T>
|
|
inline bool is_nan_impl(const T v, real_type_tag)
|
|
{
|
|
return std::not_equal_to<T>()(v,v);
|
|
}
|
|
|
|
template <typename T>
|
|
inline int to_int32_impl(const T v, real_type_tag)
|
|
{
|
|
return static_cast<int>(v);
|
|
}
|
|
|
|
template <typename T>
|
|
inline long long int to_int64_impl(const T v, real_type_tag)
|
|
{
|
|
return static_cast<long long int>(v);
|
|
}
|
|
|
|
template <typename T>
|
|
inline bool is_true_impl(const T v)
|
|
{
|
|
return std::not_equal_to<T>()(T(0),v);
|
|
}
|
|
|
|
template <typename T>
|
|
inline bool is_false_impl(const T v)
|
|
{
|
|
return std::equal_to<T>()(T(0),v);
|
|
}
|
|
|
|
template <typename T>
|
|
inline T abs_impl(const T v, real_type_tag)
|
|
{
|
|
return ((v >= T(0)) ? v : -v);
|
|
}
|
|
|
|
template <typename T>
|
|
inline T min_impl(const T v0, const T v1, real_type_tag)
|
|
{
|
|
return std::min<T>(v0,v1);
|
|
}
|
|
|
|
template <typename T>
|
|
inline T max_impl(const T v0, const T v1, real_type_tag)
|
|
{
|
|
return std::max<T>(v0,v1);
|
|
}
|
|
|
|
template <typename T>
|
|
inline T equal_impl(const T v0, const T v1, real_type_tag)
|
|
{
|
|
const T epsilon = epsilon_type<T>::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<float>::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 <typename T>
|
|
inline T equal_impl(const T v0, const T v1, int_type_tag)
|
|
{
|
|
return (v0 == v1) ? 1 : 0;
|
|
}
|
|
|
|
template <typename T>
|
|
inline T expm1_impl(const T v, real_type_tag)
|
|
{
|
|
// return std::expm1<T>(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 <typename T>
|
|
inline T expm1_impl(const T v, int_type_tag)
|
|
{
|
|
return T(std::exp<double>(v)) - T(1);
|
|
}
|
|
|
|
template <typename T>
|
|
inline T nequal_impl(const T v0, const T v1, real_type_tag)
|
|
{
|
|
const T epsilon = epsilon_type<T>::value();
|
|
return (abs_impl(v0 - v1,real_type_tag()) > (std::max(T(1),std::max(abs_impl(v0,real_type_tag()),abs_impl(v1,real_type_tag()))) * epsilon)) ? T(1) : T(0);
|
|
}
|
|
|
|
inline float nequal_impl(const float v0, const float v1, real_type_tag)
|
|
{
|
|
const float epsilon = epsilon_type<float>::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 <typename T>
|
|
inline T nequal_impl(const T v0, const T v1, int_type_tag)
|
|
{
|
|
return (v0 != v1) ? 1 : 0;
|
|
}
|
|
|
|
template <typename T>
|
|
inline T modulus_impl(const T v0, const T v1, real_type_tag)
|
|
{
|
|
return std::fmod(v0,v1);
|
|
}
|
|
|
|
template <typename T>
|
|
inline T modulus_impl(const T v0, const T v1, int_type_tag)
|
|
{
|
|
return v0 % v1;
|
|
}
|
|
|
|
template <typename T>
|
|
inline T pow_impl(const T v0, const T v1, real_type_tag)
|
|
{
|
|
return std::pow(v0,v1);
|
|
}
|
|
|
|
template <typename T>
|
|
inline T pow_impl(const T v0, const T v1, int_type_tag)
|
|
{
|
|
return std::pow(static_cast<double>(v0),static_cast<double>(v1));
|
|
}
|
|
|
|
template <typename T>
|
|
inline T logn_impl(const T v0, const T v1, real_type_tag)
|
|
{
|
|
return std::log(v0) / std::log(v1);
|
|
}
|
|
|
|
template <typename T>
|
|
inline T logn_impl(const T v0, const T v1, int_type_tag)
|
|
{
|
|
return static_cast<T>(logn_impl<double>(static_cast<double>(v0),static_cast<double>(v1),real_type_tag()));
|
|
}
|
|
|
|
template <typename T>
|
|
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<T>::quiet_NaN();
|
|
}
|
|
|
|
template <typename T>
|
|
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<T>::quiet_NaN();
|
|
}
|
|
|
|
template <typename T>
|
|
inline T root_impl(const T v0, const T v1, real_type_tag)
|
|
{
|
|
return std::pow(v0,T(1) / v1);
|
|
}
|
|
|
|
template <typename T>
|
|
inline T root_impl(const T v0, const T v1, int_type_tag)
|
|
{
|
|
return root_impl<double>(static_cast<double>(v0),static_cast<double>(v1),real_type_tag());
|
|
}
|
|
|
|
template <typename T>
|
|
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 <typename T>
|
|
inline T roundn_impl(const T v0, const T v1, real_type_tag)
|
|
{
|
|
const int index = std::max<int>(0, std::min<int>(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 <typename T>
|
|
inline T roundn_impl(const T v0, const T, int_type_tag)
|
|
{
|
|
return v0;
|
|
}
|
|
|
|
template <typename T>
|
|
inline T hypot_impl(const T v0, const T v1, real_type_tag)
|
|
{
|
|
return std::sqrt((v0 * v0) + (v1 * v1));
|
|
}
|
|
|
|
template <typename T>
|
|
inline T hypot_impl(const T v0, const T v1, int_type_tag)
|
|
{
|
|
return static_cast<T>(std::sqrt(static_cast<double>((v0 * v0) + (v1 * v1))));
|
|
}
|
|
|
|
template <typename T>
|
|
inline T atan2_impl(const T v0, const T v1, real_type_tag)
|
|
{
|
|
return std::atan2(v0,v1);
|
|
}
|
|
|
|
template <typename T>
|
|
inline T atan2_impl(const T, const T, int_type_tag)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
template <typename T>
|
|
inline T shr_impl(const T v0, const T v1, real_type_tag)
|
|
{
|
|
return v0 * (T(1) / std::pow(T(2),static_cast<T>(static_cast<int>(v1))));
|
|
}
|
|
|
|
template <typename T>
|
|
inline T shr_impl(const T v0, const T v1, int_type_tag)
|
|
{
|
|
return v0 >> v1;
|
|
}
|
|
|
|
template <typename T>
|
|
inline T shl_impl(const T v0, const T v1, real_type_tag)
|
|
{
|
|
return v0 * std::pow(T(2),static_cast<T>(static_cast<int>(v1)));
|
|
}
|
|
|
|
template <typename T>
|
|
inline T shl_impl(const T v0, const T v1, int_type_tag)
|
|
{
|
|
return v0 << v1;
|
|
}
|
|
|
|
template <typename T>
|
|
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 <typename T>
|
|
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 <typename T>
|
|
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 <typename T>
|
|
inline T and_impl(const T v0, const T v1, int_type_tag)
|
|
{
|
|
return v0 && v1;
|
|
}
|
|
|
|
template <typename T>
|
|
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 <typename T>
|
|
inline T nand_impl(const T v0, const T v1, int_type_tag)
|
|
{
|
|
return !(v0 && v1);
|
|
}
|
|
|
|
template <typename T>
|
|
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 <typename T>
|
|
inline T or_impl(const T v0, const T v1, int_type_tag)
|
|
{
|
|
return (v0 || v1);
|
|
}
|
|
|
|
template <typename T>
|
|
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 <typename T>
|
|
inline T nor_impl(const T v0, const T v1, int_type_tag)
|
|
{
|
|
return !(v0 || v1);
|
|
}
|
|
|
|
template <typename T>
|
|
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 <typename T>
|
|
inline T xor_impl(const T v0, const T v1, int_type_tag)
|
|
{
|
|
return v0 ^ v1;
|
|
}
|
|
|
|
template <typename T>
|
|
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 <typename T>
|
|
inline T xnor_impl(const T v0, const T v1, int_type_tag)
|
|
{
|
|
const bool v0_true = is_true_impl(v0);
|
|
const bool v1_true = is_true_impl(v1);
|
|
if ((v0_true && v1_true) || (!v0_true && !v1_true))
|
|
return T(1);
|
|
else
|
|
return T(0);
|
|
}
|
|
|
|
template <typename T>
|
|
inline T erf_impl(T v, real_type_tag)
|
|
{
|
|
#if defined(_WIN32) || defined(__WIN32__) || defined(WIN32)
|
|
// Credits: Abramowitz & Stegun Equations 7.1.25-28
|
|
const T t = T(1) / (T(1) + T(0.5) * abs_impl(v,real_type_tag()));
|
|
static const T c[] = {
|
|
T( 1.26551223), T(1.00002368),
|
|
T( 0.37409196), T(0.09678418),
|
|
T(-0.18628806), T(0.27886807),
|
|
T(-1.13520398), T(1.48851587),
|
|
T(-0.82215223), T(0.17087277)
|
|
};
|
|
T result = T(1) - t * std::exp((-v * v) -
|
|
c[0] + t * (c[1] + t *
|
|
(c[2] + t * (c[3] + t *
|
|
(c[4] + t * (c[5] + t *
|
|
(c[6] + t * (c[7] + t *
|
|
(c[8] + t * (c[9]))))))))));
|
|
return (v >= T(0)) ? result : -result;
|
|
#else
|
|
return ::erf(v);
|
|
#endif
|
|
}
|
|
|
|
template <typename T>
|
|
inline T erf_impl(T v, int_type_tag)
|
|
{
|
|
return erf_impl(static_cast<double>(v),real_type_tag());
|
|
}
|
|
|
|
template <typename T>
|
|
inline T erfc_impl(T v, real_type_tag)
|
|
{
|
|
#if defined(_WIN32) || defined(__WIN32__) || defined(WIN32)
|
|
return T(1) - erf_impl(v,real_type_tag());
|
|
#else
|
|
return ::erfc(v);
|
|
#endif
|
|
}
|
|
|
|
template <typename T>
|
|
inline T erfc_impl(T v, int_type_tag)
|
|
{
|
|
return erfc_impl(static_cast<double>(v),real_type_tag());
|
|
}
|
|
|
|
template <typename T>
|
|
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 <typename T>
|
|
inline T ncdf_impl(T v, int_type_tag)
|
|
{
|
|
return ncdf_impl(static_cast<double>(v),real_type_tag());
|
|
}
|
|
|
|
template <typename T>
|
|
inline T sinc_impl(T v, real_type_tag)
|
|
{
|
|
if (std::abs(v) >= std::numeric_limits<T>::epsilon())
|
|
return(std::sin(v) / v);
|
|
else
|
|
return T(1);
|
|
}
|
|
|
|
template <typename T>
|
|
inline T sinc_impl(T v, int_type_tag)
|
|
{
|
|
return sinc_impl(static_cast<double>(v),real_type_tag());
|
|
}
|
|
|
|
template <typename T> inline T acos_impl(const T v, real_type_tag) { return std::acos (v); }
|
|
template <typename T> inline T acosh_impl(const T v, real_type_tag) { return std::log(v + std::sqrt((v * v) - T(1))); }
|
|
template <typename T> inline T asin_impl(const T v, real_type_tag) { return std::asin (v); }
|
|
template <typename T> inline T asinh_impl(const T v, real_type_tag) { return std::log(v + std::sqrt((v * v) + T(1))); }
|
|
template <typename T> inline T atan_impl(const T v, real_type_tag) { return std::atan (v); }
|
|
template <typename T> inline T atanh_impl(const T v, real_type_tag) { return (std::log(T(1) + v) - log(T(1) - v)) / T(2); }
|
|
template <typename T> inline T ceil_impl(const T v, real_type_tag) { return std::ceil (v); }
|
|
template <typename T> inline T cos_impl(const T v, real_type_tag) { return std::cos (v); }
|
|
template <typename T> inline T cosh_impl(const T v, real_type_tag) { return std::cosh (v); }
|
|
template <typename T> inline T exp_impl(const T v, real_type_tag) { return std::exp (v); }
|
|
template <typename T> inline T floor_impl(const T v, real_type_tag) { return std::floor(v); }
|
|
template <typename T> inline T log_impl(const T v, real_type_tag) { return std::log (v); }
|
|
template <typename T> inline T log10_impl(const T v, real_type_tag) { return std::log10(v); }
|
|
template <typename T> inline T log2_impl(const T v, real_type_tag) { return std::log(v)/T(numeric::constant::log2); }
|
|
template <typename T> inline T neg_impl(const T v, real_type_tag) { return -v; }
|
|
template <typename T> inline T pos_impl(const T v, real_type_tag) { return +v; }
|
|
template <typename T> inline T sin_impl(const T v, real_type_tag) { return std::sin (v); }
|
|
template <typename T> inline T sinh_impl(const T v, real_type_tag) { return std::sinh (v); }
|
|
template <typename T> inline T sqrt_impl(const T v, real_type_tag) { return std::sqrt (v); }
|
|
template <typename T> inline T tan_impl(const T v, real_type_tag) { return std::tan (v); }
|
|
template <typename T> inline T tanh_impl(const T v, real_type_tag) { return std::tanh (v); }
|
|
template <typename T> inline T cot_impl(const T v, real_type_tag) { return T(1) / std::tan(v); }
|
|
template <typename T> inline T sec_impl(const T v, real_type_tag) { return T(1) / std::cos(v); }
|
|
template <typename T> inline T csc_impl(const T v, real_type_tag) { return T(1) / std::sin(v); }
|
|
template <typename T> inline T r2d_impl(const T v, real_type_tag) { return (v * T(numeric::constant::_180_pi)); }
|
|
template <typename T> inline T d2r_impl(const T v, real_type_tag) { return (v * T(numeric::constant::pi_180)); }
|
|
template <typename T> inline T d2g_impl(const T v, real_type_tag) { return (v * T(20.0/9.0)); }
|
|
template <typename T> inline T g2d_impl(const T v, real_type_tag) { return (v * T(9.0/20.0)); }
|
|
template <typename T> inline T notl_impl(const T v, real_type_tag) { return (std::not_equal_to<T>()(T(0),v) ? T(0) : T(1)); }
|
|
template <typename T> inline T frac_impl(const T v, real_type_tag) { return (v - static_cast<long long>(v)); }
|
|
template <typename T> inline T trunc_impl(const T v, real_type_tag) { return T(static_cast<long long>(v)); }
|
|
|
|
template <typename T> inline T abs_impl(const T v, int_type_tag) { return ((v >= T(0)) ? v : -v); }
|
|
template <typename T> inline T exp_impl(const T v, int_type_tag) { return std::exp (v); }
|
|
template <typename T> inline T log_impl(const T v, int_type_tag) { return std::log (v); }
|
|
template <typename T> inline T log10_impl(const T v, int_type_tag) { return std::log10(v); }
|
|
template <typename T> inline T log2_impl(const T v, int_type_tag) { return std::log(v)/T(numeric::constant::log2); }
|
|
template <typename T> inline T neg_impl(const T v, int_type_tag) { return -v; }
|
|
template <typename T> inline T pos_impl(const T v, int_type_tag) { return +v; }
|
|
template <typename T> inline T ceil_impl(const T v, int_type_tag) { return v; }
|
|
template <typename T> inline T floor_impl(const T v, int_type_tag) { return v; }
|
|
template <typename T> inline T round_impl(const T v, int_type_tag) { return v; }
|
|
template <typename T> inline T notl_impl(const T v, int_type_tag) { return !v; }
|
|
template <typename T> inline T sqrt_impl(const T v, int_type_tag) { return std::sqrt (v); }
|
|
template <typename T> inline T frac_impl(const T , int_type_tag) { return T(0); }
|
|
template <typename T> inline T trunc_impl(const T v, int_type_tag) { return v; }
|
|
template <typename T> inline T acos_impl(const T , int_type_tag) { return std::numeric_limits<T>::quiet_NaN(); }
|
|
template <typename T> inline T acosh_impl(const T , int_type_tag) { return std::numeric_limits<T>::quiet_NaN(); }
|
|
template <typename T> inline T asin_impl(const T , int_type_tag) { return std::numeric_limits<T>::quiet_NaN(); }
|
|
template <typename T> inline T asinh_impl(const T , int_type_tag) { return std::numeric_limits<T>::quiet_NaN(); }
|
|
template <typename T> inline T atan_impl(const T , int_type_tag) { return std::numeric_limits<T>::quiet_NaN(); }
|
|
template <typename T> inline T atanh_impl(const T , int_type_tag) { return std::numeric_limits<T>::quiet_NaN(); }
|
|
template <typename T> inline T cos_impl(const T , int_type_tag) { return std::numeric_limits<T>::quiet_NaN(); }
|
|
template <typename T> inline T cosh_impl(const T , int_type_tag) { return std::numeric_limits<T>::quiet_NaN(); }
|
|
template <typename T> inline T sin_impl(const T , int_type_tag) { return std::numeric_limits<T>::quiet_NaN(); }
|
|
template <typename T> inline T sinh_impl(const T , int_type_tag) { return std::numeric_limits<T>::quiet_NaN(); }
|
|
template <typename T> inline T tan_impl(const T , int_type_tag) { return std::numeric_limits<T>::quiet_NaN(); }
|
|
template <typename T> inline T tanh_impl(const T , int_type_tag) { return std::numeric_limits<T>::quiet_NaN(); }
|
|
template <typename T> inline T cot_impl(const T , int_type_tag) { return std::numeric_limits<T>::quiet_NaN(); }
|
|
template <typename T> inline T sec_impl(const T , int_type_tag) { return std::numeric_limits<T>::quiet_NaN(); }
|
|
template <typename T> inline T csc_impl(const T , int_type_tag) { return std::numeric_limits<T>::quiet_NaN(); }
|
|
|
|
template <typename T>
|
|
inline bool is_integer_impl(const T& v, real_type_tag)
|
|
{
|
|
return std::equal_to<T>()(T(0),std::fmod(v,T(1)));
|
|
}
|
|
|
|
template <typename T>
|
|
inline bool is_integer_impl(const T&, int_type_tag)
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
|
|
template <typename Type>
|
|
struct numeric_info { enum { length = 0, size = 32, bound_length = 0, min_exp = 0, max_exp = 0 }; };
|
|
|
|
template<> struct numeric_info<int> { enum { length = 10, size = 16, bound_length = 9}; };
|
|
template<> struct numeric_info<float> { enum { min_exp = -38, max_exp = +38}; };
|
|
template<> struct numeric_info<double> { enum { min_exp = -308, max_exp = +308}; };
|
|
template<> struct numeric_info<long double> { enum { min_exp = -308, max_exp = +308}; };
|
|
|
|
template <typename T>
|
|
inline int to_int32(const T v)
|
|
{
|
|
typename details::number_type<T>::type num_type;
|
|
return to_int32_impl(v,num_type);
|
|
}
|
|
|
|
template <typename T>
|
|
inline long long int to_int64(const T v)
|
|
{
|
|
typename details::number_type<T>::type num_type;
|
|
return to_int64_impl(v,num_type);
|
|
}
|
|
|
|
template <typename T>
|
|
inline bool is_nan(const T v)
|
|
{
|
|
typename details::number_type<T>::type num_type;
|
|
return is_nan_impl(v,num_type);
|
|
}
|
|
|
|
template <typename T>
|
|
inline T min(const T v0, const T v1)
|
|
{
|
|
typename details::number_type<T>::type num_type;
|
|
return min_impl(v0,v1,num_type);
|
|
}
|
|
|
|
template <typename T>
|
|
inline T max(const T v0, const T v1)
|
|
{
|
|
typename details::number_type<T>::type num_type;
|
|
return max_impl(v0,v1,num_type);
|
|
}
|
|
|
|
template <typename T>
|
|
inline T equal(const T v0, const T v1)
|
|
{
|
|
typename details::number_type<T>::type num_type;
|
|
return equal_impl(v0,v1,num_type);
|
|
}
|
|
|
|
template <typename T>
|
|
inline T nequal(const T v0, const T v1)
|
|
{
|
|
typename details::number_type<T>::type num_type;
|
|
return nequal_impl(v0,v1,num_type);
|
|
}
|
|
|
|
template <typename T>
|
|
inline T modulus(const T v0, const T v1)
|
|
{
|
|
typename details::number_type<T>::type num_type;
|
|
return modulus_impl(v0,v1,num_type);
|
|
}
|
|
|
|
template <typename T>
|
|
inline T pow(const T v0, const T v1)
|
|
{
|
|
typename details::number_type<T>::type num_type;
|
|
return pow_impl(v0,v1,num_type);
|
|
}
|
|
|
|
template <typename T>
|
|
inline T logn(const T v0, const T v1)
|
|
{
|
|
typename details::number_type<T>::type num_type;
|
|
return logn_impl(v0,v1,num_type);
|
|
}
|
|
|
|
template <typename T>
|
|
inline T root(const T v0, const T v1)
|
|
{
|
|
typename details::number_type<T>::type num_type;
|
|
return root_impl(v0,v1,num_type);
|
|
}
|
|
|
|
template <typename T>
|
|
inline T roundn(const T v0, const T v1)
|
|
{
|
|
typename details::number_type<T>::type num_type;
|
|
return roundn_impl(v0,v1,num_type);
|
|
}
|
|
|
|
template <typename T>
|
|
inline T hypot(const T v0, const T v1)
|
|
{
|
|
typename details::number_type<T>::type num_type;
|
|
return hypot_impl(v0,v1,num_type);
|
|
}
|
|
|
|
template <typename T>
|
|
inline T atan2(const T v0, const T v1)
|
|
{
|
|
typename details::number_type<T>::type num_type;
|
|
return atan2_impl(v0,v1,num_type);
|
|
}
|
|
|
|
template <typename T>
|
|
inline T shr(const T v0, const T v1)
|
|
{
|
|
typename details::number_type<T>::type num_type;
|
|
return shr_impl(v0,v1,num_type);
|
|
}
|
|
|
|
template <typename T>
|
|
inline T shl(const T v0, const T v1)
|
|
{
|
|
typename details::number_type<T>::type num_type;
|
|
return shl_impl(v0,v1,num_type);
|
|
}
|
|
|
|
template <typename T>
|
|
inline T and_opr(const T v0, const T v1)
|
|
{
|
|
typename details::number_type<T>::type num_type;
|
|
return and_impl(v0,v1,num_type);
|
|
}
|
|
|
|
template <typename T>
|
|
inline T nand_opr(const T v0, const T v1)
|
|
{
|
|
typename details::number_type<T>::type num_type;
|
|
return nand_impl(v0,v1,num_type);
|
|
}
|
|
|
|
template <typename T>
|
|
inline T or_opr(const T v0, const T v1)
|
|
{
|
|
typename details::number_type<T>::type num_type;
|
|
return or_impl(v0,v1,num_type);
|
|
}
|
|
|
|
template <typename T>
|
|
inline T nor_opr(const T v0, const T v1)
|
|
{
|
|
typename details::number_type<T>::type num_type;
|
|
return nor_impl(v0,v1,num_type);
|
|
}
|
|
|
|
template <typename T>
|
|
inline T xor_opr(const T v0, const T v1)
|
|
{
|
|
typename details::number_type<T>::type num_type;
|
|
return xor_impl(v0,v1,num_type);
|
|
}
|
|
|
|
template <typename T>
|
|
inline T xnor_opr(const T v0, const T v1)
|
|
{
|
|
typename details::number_type<T>::type num_type;
|
|
return xnor_impl(v0,v1,num_type);
|
|
}
|
|
|
|
template <typename T>
|
|
inline bool is_integer(const T v)
|
|
{
|
|
typename details::number_type<T>::type num_type;
|
|
return is_integer_impl(v,num_type);
|
|
}
|
|
|
|
template <typename T, unsigned int N>
|
|
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 <typename T> struct fast_exp<T,10> { static inline T result(T v) { T v_5 = fast_exp<T,5>::result(v); return v_5 * v_5; } };
|
|
template <typename T> struct fast_exp<T, 9> { static inline T result(T v) { return fast_exp<T,8>::result(v) * v; } };
|
|
template <typename T> struct fast_exp<T, 8> { static inline T result(T v) { T v_4 = fast_exp<T,4>::result(v); return v_4 * v_4; } };
|
|
template <typename T> struct fast_exp<T, 7> { static inline T result(T v) { return fast_exp<T,6>::result(v) * v; } };
|
|
template <typename T> struct fast_exp<T, 6> { static inline T result(T v) { T v_3 = fast_exp<T,3>::result(v); return v_3 * v_3; } };
|
|
template <typename T> struct fast_exp<T, 5> { static inline T result(T v) { return fast_exp<T,4>::result(v) * v; } };
|
|
template <typename T> struct fast_exp<T, 4> { static inline T result(T v) { T v_2 = v * v; return v_2 * v_2; } };
|
|
template <typename T> struct fast_exp<T, 3> { static inline T result(T v) { return v * v * v; } };
|
|
template <typename T> struct fast_exp<T, 2> { static inline T result(T v) { return v * v; } };
|
|
template <typename T> struct fast_exp<T, 1> { static inline T result(T v) { return v; } };
|
|
template <typename T> struct fast_exp<T, 0> { static inline T result(T ) { return T(1); } };
|
|
|
|
#define exprtk_define_unary_function(FunctionName) \
|
|
template <typename T> \
|
|
inline T FunctionName (const T v) \
|
|
{ \
|
|
typename details::number_type<T>::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 <typename T>
|
|
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<int>(sizeof(fract10) / sizeof(double));
|
|
|
|
const int e = std::abs(exponent);
|
|
|
|
if (exponent >= std::numeric_limits<T>::min_exponent10)
|
|
{
|
|
if (e < fract10_size)
|
|
{
|
|
if (exponent > 0)
|
|
return T(d * fract10[e]);
|
|
else
|
|
return T(d / fract10[e]);
|
|
}
|
|
else
|
|
return T(d * std::pow(10.0, 10.0 * exponent));
|
|
}
|
|
else
|
|
{
|
|
d /= T(fract10[ -std::numeric_limits<T>::min_exponent10]);
|
|
return T(d / fract10[-exponent + std::numeric_limits<T>::min_exponent10]);
|
|
}
|
|
}
|
|
|
|
template <typename Iterator, typename T>
|
|
inline bool string_to_type_converter_impl_ref(Iterator& itr, const Iterator end, T& result)
|
|
{
|
|
if (itr == end)
|
|
return false;
|
|
|
|
bool negative = ('-' == (*itr));
|
|
|
|
if (negative || ('+' == (*itr)))
|
|
{
|
|
if (end == ++itr)
|
|
return false;
|
|
}
|
|
|
|
while ((end != itr) && ('0' == (*itr))) ++itr;
|
|
|
|
bool return_result = true;
|
|
unsigned int digit = 0;
|
|
const std::size_t length = std::distance(itr,end);
|
|
|
|
if (length <= 4)
|
|
{
|
|
switch (length)
|
|
{
|
|
#ifdef exprtk_use_lut
|
|
|
|
#define exprtk_process_digit \
|
|
if ((digit = details::digit_table[(int)*itr++]) < 10) result = result * 10 + (digit); else { return_result = false; break; }
|
|
|
|
#else
|
|
#define exprtk_process_digit \
|
|
if ((digit = (*itr++ - '0')) < 10) result = result * 10 + (digit); else { return_result = false; break; }
|
|
|
|
#endif
|
|
|
|
case 4 : exprtk_process_digit
|
|
case 3 : exprtk_process_digit
|
|
case 2 : exprtk_process_digit
|
|
case 1 : if ((digit = (*itr - '0'))>= 10) { digit = 0; return_result = false; }
|
|
|
|
#undef exprtk_process_digit
|
|
}
|
|
}
|
|
else
|
|
return_result = false;
|
|
|
|
if (length && return_result)
|
|
{
|
|
result = result * 10 + static_cast<T>(digit);
|
|
++itr;
|
|
}
|
|
|
|
result = negative ? -result : result;
|
|
return return_result;
|
|
}
|
|
|
|
template <typename Iterator, typename T>
|
|
static inline bool parse_nan(Iterator& itr, const Iterator end, T& t)
|
|
{
|
|
typedef typename std::iterator_traits<Iterator>::value_type type;
|
|
static const std::size_t nan_length = 3;
|
|
if (std::distance(itr,end) != static_cast<int>(nan_length))
|
|
return false;
|
|
if (static_cast<type>('n') == (*itr))
|
|
{
|
|
if (
|
|
(static_cast<type>('a') != *(itr + 1)) ||
|
|
(static_cast<type>('n') != *(itr + 2))
|
|
)
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
else if (
|
|
(static_cast<type>('A') != *(itr + 1)) ||
|
|
(static_cast<type>('N') != *(itr + 2))
|
|
)
|
|
{
|
|
return false;
|
|
}
|
|
t = std::numeric_limits<T>::quiet_NaN();
|
|
return true;
|
|
}
|
|
|
|
template <typename Iterator, typename T>
|
|
static inline bool parse_inf(Iterator& itr, const Iterator end, T& t, bool negative)
|
|
{
|
|
static const char inf_uc[] = "INFINITY";
|
|
static const char inf_lc[] = "infinity";
|
|
static const std::size_t inf_length = 8;
|
|
const std::size_t length = std::distance(itr,end);
|
|
if ((3 != length) && (inf_length != length))
|
|
return false;
|
|
const char* inf_itr = ('i' == (*itr)) ? inf_lc : inf_uc;
|
|
while (end != itr)
|
|
{
|
|
if (*inf_itr == static_cast<char>(*itr))
|
|
{
|
|
++itr;
|
|
++inf_itr;
|
|
continue;
|
|
}
|
|
else
|
|
return false;
|
|
}
|
|
if (negative)
|
|
t = -std::numeric_limits<T>::infinity();
|
|
else
|
|
t = std::numeric_limits<T>::infinity();
|
|
return true;
|
|
}
|
|
|
|
template <typename Iterator, typename T>
|
|
inline bool string_to_real(Iterator& itr_external, const Iterator end, T& t, numeric::details::real_type_tag)
|
|
{
|
|
if (end == itr_external) return false;
|
|
|
|
Iterator itr = itr_external;
|
|
|
|
T d = T(0);
|
|
|
|
bool negative = ('-' == (*itr));
|
|
|
|
if (negative || '+' == (*itr))
|
|
{
|
|
if (end == ++itr)
|
|
return false;
|
|
}
|
|
|
|
bool instate = false;
|
|
|
|
#define parse_digit_1(d) \
|
|
if ((digit = (*itr - '0')) < 10) { d = d * T(10) + digit; } else break; if (end == ++itr) break; \
|
|
|
|
#define parse_digit_2(d) \
|
|
if ((digit = (*itr - '0')) < 10) { d = d * T(10) + digit; } else break; ++itr; \
|
|
|
|
if ('.' != (*itr))
|
|
{
|
|
const Iterator curr = itr;
|
|
while ((end != itr) && ('0' == (*itr))) ++itr;
|
|
unsigned int digit;
|
|
|
|
while (end != itr)
|
|
{
|
|
// Note: For 'physical' superscalar architectures it
|
|
// is advised that the following loop be: 4xPD1 and 1xPD2
|
|
#ifdef exprtk_enable_superscalar
|
|
parse_digit_1(d)
|
|
parse_digit_1(d)
|
|
#endif
|
|
parse_digit_1(d)
|
|
parse_digit_1(d)
|
|
parse_digit_2(d)
|
|
}
|
|
|
|
if (curr != itr) instate = true;
|
|
}
|
|
|
|
int exponent = 0;
|
|
|
|
if (end != itr)
|
|
{
|
|
if ('.' == (*itr))
|
|
{
|
|
const Iterator curr = ++itr;
|
|
unsigned int digit;
|
|
T tmp_d = T(0);
|
|
|
|
while (end != itr)
|
|
{
|
|
#ifdef exprtk_enable_superscalar
|
|
parse_digit_1(tmp_d)
|
|
parse_digit_1(tmp_d)
|
|
parse_digit_1(tmp_d)
|
|
#endif
|
|
parse_digit_1(tmp_d)
|
|
parse_digit_1(tmp_d)
|
|
parse_digit_2(tmp_d)
|
|
}
|
|
|
|
if (curr != itr)
|
|
{
|
|
instate = true;
|
|
d += compute_pow10(tmp_d,-std::distance(curr,itr));
|
|
}
|
|
|
|
#undef parse_digit_1
|
|
#undef parse_digit_2
|
|
}
|
|
|
|
if (end != itr)
|
|
{
|
|
typename std::iterator_traits<Iterator>::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<T>((negative) ? -d : d);
|
|
return true;
|
|
}
|
|
|
|
template <typename T>
|
|
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<T>::type num_type;
|
|
return string_to_real(begin,end,t,num_type);
|
|
}
|
|
|
|
template <typename T>
|
|
struct functor_t
|
|
{
|
|
/*
|
|
Note: The following definitions for Type, may require tweaking
|
|
based on the compiler and target architecture. The benchmark
|
|
should provide enough information to make the right choice.
|
|
*/
|
|
//typedef T Type;
|
|
//typedef const T Type;
|
|
typedef const T& Type;
|
|
typedef T (*qfunc_t)(Type t0, Type t1, Type t2, Type t3);
|
|
typedef T (*tfunc_t)(Type t0, Type t1, Type t2);
|
|
typedef T (*bfunc_t)(Type t0, Type t1);
|
|
typedef T (*ufunc_t)(Type t0);
|
|
};
|
|
|
|
} // namespace details
|
|
|
|
namespace lexer
|
|
{
|
|
struct token
|
|
{
|
|
enum token_type
|
|
{
|
|
e_none = 0, e_error = 1, e_err_symbol = 2,
|
|
e_err_number = 3, e_err_string = 4, e_err_sfunc = 5,
|
|
e_eof = 6, e_number = 7, e_symbol = 8,
|
|
e_string = 9, e_assign = 10, e_addass = 11,
|
|
e_subass = 12, e_mulass = 13, e_divass = 14,
|
|
e_modass = 15, e_shr = 16, e_shl = 17,
|
|
e_lte = 18, e_ne = 19, e_gte = 20,
|
|
e_swap = 21, e_lt = '<', e_gt = '>',
|
|
e_eq = '=', e_rbracket = ')', e_lbracket = '(',
|
|
e_rsqrbracket = ']', e_lsqrbracket = '[', e_rcrlbracket = '}',
|
|
e_lcrlbracket = '{', e_comma = ',', e_add = '+',
|
|
e_sub = '-', e_div = '/', e_mul = '*',
|
|
e_mod = '%', e_pow = '^', e_colon = ':',
|
|
e_ternary = '?'
|
|
};
|
|
|
|
token()
|
|
: type(e_none),
|
|
value(""),
|
|
position(std::numeric_limits<std::size_t>::max())
|
|
{}
|
|
|
|
void clear()
|
|
{
|
|
type = e_none;
|
|
value = "";
|
|
position = std::numeric_limits<std::size_t>::max();
|
|
}
|
|
|
|
template <typename Iterator>
|
|
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 <typename Iterator>
|
|
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 <typename Iterator>
|
|
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 <typename Iterator>
|
|
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 <typename Iterator>
|
|
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_t> token_list_t;
|
|
typedef std::vector<token_t>::iterator token_list_itr_t;
|
|
|
|
generator()
|
|
: base_itr_(0),
|
|
s_itr_ (0),
|
|
s_end_ (0)
|
|
{
|
|
clear();
|
|
}
|
|
|
|
inline void clear()
|
|
{
|
|
base_itr_ = 0;
|
|
s_itr_ = 0;
|
|
s_end_ = 0;
|
|
token_list_.clear();
|
|
token_itr_ = token_list_.end();
|
|
store_token_itr_ = token_list_.end();
|
|
}
|
|
|
|
inline bool process(const std::string& str)
|
|
{
|
|
base_itr_ = str.data();
|
|
s_itr_ = str.data();
|
|
s_end_ = str.data() + str.size();
|
|
|
|
eof_token_.set_operator(token_t::e_eof,s_end_,s_end_,base_itr_);
|
|
token_list_.clear();
|
|
|
|
while (!is_end(s_itr_))
|
|
{
|
|
scan_token();
|
|
|
|
if (token_list_.empty())
|
|
return true;
|
|
else if (token_list_.back().is_error())
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
inline bool empty() const
|
|
{
|
|
return token_list_.empty();
|
|
}
|
|
|
|
inline std::size_t size() const
|
|
{
|
|
return token_list_.size();
|
|
}
|
|
|
|
inline void begin()
|
|
{
|
|
token_itr_ = token_list_.begin();
|
|
store_token_itr_ = token_list_.begin();
|
|
}
|
|
|
|
inline void store()
|
|
{
|
|
store_token_itr_ = token_itr_;
|
|
}
|
|
|
|
inline void restore()
|
|
{
|
|
token_itr_ = store_token_itr_;
|
|
}
|
|
|
|
inline token_t& next_token()
|
|
{
|
|
if (token_list_.end() != token_itr_)
|
|
{
|
|
return *token_itr_++;
|
|
}
|
|
else
|
|
return eof_token_;
|
|
}
|
|
|
|
inline token_t& peek_next_token()
|
|
{
|
|
if (token_list_.end() != token_itr_)
|
|
{
|
|
return *token_itr_;
|
|
}
|
|
else
|
|
return eof_token_;
|
|
}
|
|
|
|
inline token_t& operator[](const std::size_t& index)
|
|
{
|
|
if (index < token_list_.size())
|
|
return token_list_[index];
|
|
else
|
|
return eof_token_;
|
|
}
|
|
|
|
inline token_t operator[](const std::size_t& index) const
|
|
{
|
|
if (index < token_list_.size())
|
|
return token_list_[index];
|
|
else
|
|
return eof_token_;
|
|
}
|
|
|
|
inline bool finished() const
|
|
{
|
|
return (token_list_.end() == token_itr_);
|
|
}
|
|
|
|
inline void insert_front(token_t::token_type tk_type)
|
|
{
|
|
if (
|
|
!token_list_.empty() &&
|
|
(token_list_.end() != token_itr_)
|
|
)
|
|
{
|
|
token_t t = *token_itr_;
|
|
|
|
t.type = tk_type;
|
|
token_itr_ = token_list_.insert(token_itr_,t);
|
|
}
|
|
}
|
|
|
|
private:
|
|
|
|
inline bool is_end(const char* itr)
|
|
{
|
|
return (s_end_ == itr);
|
|
}
|
|
|
|
inline void skip_whitespace()
|
|
{
|
|
while (!is_end(s_itr_) && details::is_whitespace(*s_itr_))
|
|
{
|
|
++s_itr_;
|
|
}
|
|
}
|
|
|
|
inline void skip_comments()
|
|
{
|
|
#ifndef exprtk_disable_comments
|
|
// The following comment styles are supported:
|
|
// 1. // .... \n
|
|
// 2. # .... \n
|
|
// 3. /* .... */
|
|
struct test
|
|
{
|
|
static inline bool comment_start(const char c0, const char c1, int& mode, int& incr)
|
|
{
|
|
mode = 0;
|
|
if ('#' == c0) { mode = 1; incr = 1; }
|
|
else if ('/' == c0)
|
|
{
|
|
if ('/' == c1) { mode = 1; incr = 2; }
|
|
else if ('*' == c1) { mode = 2; incr = 2; }
|
|
}
|
|
return (0 != mode);
|
|
}
|
|
|
|
static inline bool comment_end(const char c0, const char c1, const int mode)
|
|
{
|
|
return (
|
|
((1 == mode) && ('\n' == c0)) ||
|
|
((2 == mode) && ( '*' == c0) && ('/' == c1))
|
|
);
|
|
}
|
|
};
|
|
|
|
int mode = 0;
|
|
int increment = 0;
|
|
|
|
if (is_end(s_itr_) || is_end((s_itr_ + 1)))
|
|
return;
|
|
else if (!test::comment_start(*s_itr_,*(s_itr_ + 1),mode,increment))
|
|
return;
|
|
|
|
s_itr_ += increment;
|
|
|
|
while (!is_end(s_itr_) && !test::comment_end(*s_itr_,*(s_itr_ + 1),mode))
|
|
{
|
|
++s_itr_;
|
|
}
|
|
|
|
if (!is_end(s_itr_))
|
|
{
|
|
s_itr_ += mode;
|
|
skip_whitespace();
|
|
skip_comments();
|
|
}
|
|
#endif
|
|
}
|
|
|
|
inline void scan_token()
|
|
{
|
|
skip_whitespace();
|
|
skip_comments();
|
|
if (is_end(s_itr_))
|
|
{
|
|
return;
|
|
}
|
|
else if (details::is_operator_char(*s_itr_))
|
|
{
|
|
scan_operator();
|
|
return;
|
|
}
|
|
else if (details::is_letter(*s_itr_))
|
|
{
|
|
scan_symbol();
|
|
return;
|
|
}
|
|
else if (details::is_digit((*s_itr_)) || ('.' == (*s_itr_)))
|
|
{
|
|
scan_number();
|
|
return;
|
|
}
|
|
else if ('$' == (*s_itr_))
|
|
{
|
|
scan_special_function();
|
|
return;
|
|
}
|
|
#ifndef exprtk_disable_string_capabilities
|
|
else if ('\'' == (*s_itr_))
|
|
{
|
|
scan_string();
|
|
return;
|
|
}
|
|
#endif
|
|
else if ('~' == (*s_itr_))
|
|
{
|
|
token_t t;
|
|
t.set_symbol(s_itr_,s_itr_ + 1,base_itr_);
|
|
token_list_.push_back(t);
|
|
++s_itr_;
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
token_t t;
|
|
t.set_error(token::e_error,s_itr_,s_itr_ + 2,base_itr_);
|
|
token_list_.push_back(t);
|
|
++s_itr_;
|
|
}
|
|
}
|
|
|
|
inline void scan_operator()
|
|
{
|
|
token_t t;
|
|
|
|
const char c0 = s_itr_[0];
|
|
|
|
if (!is_end(s_itr_ + 1))
|
|
{
|
|
const char c1 = s_itr_[1];
|
|
|
|
if (!is_end(s_itr_ + 2))
|
|
{
|
|
const char c2 = s_itr_[2];
|
|
|
|
if ((c0 == '<') && (c1 == '=') && (c2 == '>'))
|
|
{
|
|
t.set_operator(token_t::e_swap,s_itr_,s_itr_ + 3,base_itr_);
|
|
token_list_.push_back(t);
|
|
s_itr_ += 3;
|
|
return;
|
|
}
|
|
}
|
|
|
|
token_t::token_type ttype = token_t::e_none;
|
|
|
|
if ((c0 == '<') && (c1 == '=')) ttype = token_t::e_lte;
|
|
else if ((c0 == '>') && (c1 == '=')) ttype = token_t::e_gte;
|
|
else if ((c0 == '<') && (c1 == '>')) ttype = token_t::e_ne;
|
|
else if ((c0 == '!') && (c1 == '=')) ttype = token_t::e_ne;
|
|
else if ((c0 == '=') && (c1 == '=')) ttype = token_t::e_eq;
|
|
else if ((c0 == ':') && (c1 == '=')) ttype = token_t::e_assign;
|
|
else if ((c0 == '<') && (c1 == '<')) ttype = token_t::e_shl;
|
|
else if ((c0 == '>') && (c1 == '>')) ttype = token_t::e_shr;
|
|
else if ((c0 == '+') && (c1 == '=')) ttype = token_t::e_addass;
|
|
else if ((c0 == '-') && (c1 == '=')) ttype = token_t::e_subass;
|
|
else if ((c0 == '*') && (c1 == '=')) ttype = token_t::e_mulass;
|
|
else if ((c0 == '/') && (c1 == '=')) ttype = token_t::e_divass;
|
|
else if ((c0 == '%') && (c1 == '=')) ttype = token_t::e_modass;
|
|
|
|
if (token_t::e_none != ttype)
|
|
{
|
|
t.set_operator(ttype,s_itr_,s_itr_ + 2,base_itr_);
|
|
token_list_.push_back(t);
|
|
s_itr_ += 2;
|
|
return;
|
|
}
|
|
}
|
|
|
|
if ('<' == c0)
|
|
t.set_operator(token_t::e_lt ,s_itr_,s_itr_ + 1,base_itr_);
|
|
else if ('>' == c0)
|
|
t.set_operator(token_t::e_gt ,s_itr_,s_itr_ + 1,base_itr_);
|
|
else if (';' == c0)
|
|
t.set_operator(token_t::e_eof,s_itr_,s_itr_ + 1,base_itr_);
|
|
else if ('&' == c0)
|
|
t.set_symbol(s_itr_,s_itr_ + 1,base_itr_);
|
|
else if ('|' == c0)
|
|
t.set_symbol(s_itr_,s_itr_ + 1,base_itr_);
|
|
else
|
|
t.set_operator(token_t::token_type(c0),s_itr_,s_itr_ + 1,base_itr_);
|
|
|
|
token_list_.push_back(t);
|
|
++s_itr_;
|
|
}
|
|
|
|
inline void scan_symbol()
|
|
{
|
|
const char* initial_itr = s_itr_;
|
|
|
|
while (
|
|
(!is_end(s_itr_)) &&
|
|
(details::is_letter_or_digit(*s_itr_) || ((*s_itr_) == '_'))
|
|
)
|
|
{
|
|
++s_itr_;
|
|
}
|
|
|
|
token_t t;
|
|
t.set_symbol(initial_itr,s_itr_,base_itr_);
|
|
token_list_.push_back(t);
|
|
}
|
|
|
|
inline void scan_number()
|
|
{
|
|
/*
|
|
Attempt to match a valid numeric value in one of the following formats:
|
|
1. 123456
|
|
2. 123.456
|
|
3. 123.456e3
|
|
4. 123.456E3
|
|
5. 123.456e+3
|
|
6. 123.456E+3
|
|
7. 123.456e-3
|
|
8. 123.456E-3
|
|
*/
|
|
const char* initial_itr = s_itr_;
|
|
bool dot_found = false;
|
|
bool e_found = false;
|
|
bool post_e_sign_found = false;
|
|
token_t t;
|
|
|
|
while (!is_end(s_itr_))
|
|
{
|
|
if ('.' == (*s_itr_))
|
|
{
|
|
if (dot_found)
|
|
{
|
|
t.set_error(token::e_err_number,initial_itr,s_itr_,base_itr_);
|
|
token_list_.push_back(t);
|
|
return;
|
|
}
|
|
|
|
dot_found = true;
|
|
++s_itr_;
|
|
|
|
continue;
|
|
}
|
|
else if (details::imatch('e',(*s_itr_)))
|
|
{
|
|
const char& c = *(s_itr_ + 1);
|
|
|
|
if (is_end(s_itr_ + 1))
|
|
{
|
|
t.set_error(token::e_err_number,initial_itr,s_itr_,base_itr_);
|
|
token_list_.push_back(t);
|
|
|
|
return;
|
|
}
|
|
else if (
|
|
('+' != c) &&
|
|
('-' != c) &&
|
|
!details::is_digit(c)
|
|
)
|
|
{
|
|
t.set_error(token::e_err_number,initial_itr,s_itr_,base_itr_);
|
|
token_list_.push_back(t);
|
|
|
|
return;
|
|
}
|
|
|
|
e_found = true;
|
|
++s_itr_;
|
|
continue;
|
|
}
|
|
else if (e_found && details::is_sign(*s_itr_))
|
|
{
|
|
if (post_e_sign_found)
|
|
{
|
|
t.set_error(token::e_err_number,initial_itr,s_itr_,base_itr_);
|
|
token_list_.push_back(t);
|
|
|
|
return;
|
|
}
|
|
|
|
post_e_sign_found = true;
|
|
++s_itr_;
|
|
continue;
|
|
}
|
|
else if (('.' != (*s_itr_)) && !details::is_digit(*s_itr_))
|
|
break;
|
|
else
|
|
++s_itr_;
|
|
}
|
|
|
|
t.set_numeric(initial_itr,s_itr_,base_itr_);
|
|
token_list_.push_back(t);
|
|
|
|
return;
|
|
}
|
|
|
|
inline void scan_special_function()
|
|
{
|
|
const char* initial_itr = s_itr_;
|
|
token_t t;
|
|
|
|
// $fdd(x,x,x) = at least 11 chars
|
|
if (std::distance(s_itr_,s_end_) < 11)
|
|
{
|
|
t.set_error(token::e_err_sfunc,initial_itr,s_itr_,base_itr_);
|
|
token_list_.push_back(t);
|
|
|
|
return;
|
|
}
|
|
|
|
if (
|
|
!(('$' == *s_itr_) &&
|
|
(details::imatch ('f',*(s_itr_ + 1))) &&
|
|
(details::is_digit(*(s_itr_ + 2))) &&
|
|
(details::is_digit(*(s_itr_ + 3))))
|
|
)
|
|
{
|
|
t.set_error(token::e_err_sfunc,initial_itr,s_itr_,base_itr_);
|
|
token_list_.push_back(t);
|
|
|
|
return;
|
|
}
|
|
|
|
s_itr_ += 4; // $fdd = 4chars
|
|
|
|
t.set_symbol(initial_itr,s_itr_,base_itr_);
|
|
token_list_.push_back(t);
|
|
|
|
return;
|
|
}
|
|
|
|
#ifndef exprtk_disable_string_capabilities
|
|
inline void scan_string()
|
|
{
|
|
const char* initial_itr = s_itr_ + 1;
|
|
token_t t;
|
|
|
|
if (std::distance(s_itr_,s_end_) < 2)
|
|
{
|
|
t.set_error(token::e_err_string,s_itr_,s_end_,base_itr_);
|
|
token_list_.push_back(t);
|
|
return;
|
|
}
|
|
|
|
++s_itr_;
|
|
|
|
bool escaped_found = false;
|
|
bool escaped = false;
|
|
|
|
while (!is_end(s_itr_))
|
|
{
|
|
if ('\\' == *s_itr_)
|
|
{
|
|
escaped_found = true;
|
|
escaped = true;
|
|
++s_itr_;
|
|
|
|
continue;
|
|
}
|
|
else if (!escaped)
|
|
{
|
|
if ('\'' == *s_itr_)
|
|
break;
|
|
}
|
|
else if (escaped)
|
|
{
|
|
if (!is_end(s_itr_) && ('0' == *(s_itr_)))
|
|
{
|
|
if (
|
|
is_end(s_itr_ + 1) ||
|
|
is_end(s_itr_ + 2) ||
|
|
is_end(s_itr_ + 3) ||
|
|
(
|
|
('x' != *(s_itr_ + 1)) &&
|
|
('X' != *(s_itr_ + 1))
|
|
) ||
|
|
(!details::is_hex_digit(*(s_itr_ + 2))) ||
|
|
(!details::is_hex_digit(*(s_itr_ + 3)))
|
|
)
|
|
{
|
|
t.set_error(token::e_err_string,initial_itr,s_itr_,base_itr_);
|
|
token_list_.push_back(t);
|
|
return;
|
|
}
|
|
else
|
|
s_itr_ += 3;
|
|
}
|
|
|
|
escaped = false;
|
|
}
|
|
|
|
++s_itr_;
|
|
}
|
|
|
|
if (is_end(s_itr_))
|
|
{
|
|
t.set_error(token::e_err_string,initial_itr,s_itr_,base_itr_);
|
|
token_list_.push_back(t);
|
|
|
|
return;
|
|
}
|
|
|
|
if (!escaped_found)
|
|
t.set_string(initial_itr,s_itr_,base_itr_);
|
|
else
|
|
{
|
|
std::string parsed_string(initial_itr,s_itr_);
|
|
details::cleanup_escapes(parsed_string);
|
|
t.set_string(parsed_string, std::distance(base_itr_,initial_itr));
|
|
}
|
|
|
|
token_list_.push_back(t);
|
|
++s_itr_;
|
|
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
private:
|
|
|
|
token_list_t token_list_;
|
|
token_list_itr_t token_itr_;
|
|
token_list_itr_t store_token_itr_;
|
|
token_t eof_token_;
|
|
const char* base_itr_;
|
|
const char* s_itr_;
|
|
const char* s_end_;
|
|
|
|
friend class token_scanner;
|
|
friend class token_modifier;
|
|
friend class token_inserter;
|
|
friend class token_joiner;
|
|
};
|
|
|
|
class helper_interface
|
|
{
|
|
public:
|
|
|
|
virtual void init() { }
|
|
virtual void reset() { }
|
|
virtual bool result() { return true; }
|
|
virtual std::size_t process(generator&) { return 0; }
|
|
virtual ~helper_interface() { }
|
|
};
|
|
|
|
class token_scanner : public helper_interface
|
|
{
|
|
public:
|
|
|
|
virtual ~token_scanner()
|
|
{}
|
|
|
|
explicit token_scanner(const std::size_t& stride)
|
|
: stride_(stride)
|
|
{
|
|
if (stride > 4)
|
|
{
|
|
throw std::invalid_argument("token_scanner() - Invalid stride value");
|
|
}
|
|
}
|
|
|
|
inline std::size_t process(generator& g)
|
|
{
|
|
if (g.token_list_.size() >= stride_)
|
|
{
|
|
for (std::size_t i = 0; i < (g.token_list_.size() - stride_ + 1); ++i)
|
|
{
|
|
token t;
|
|
|
|
switch (stride_)
|
|
{
|
|
case 1 :
|
|
{
|
|
const token& t0 = g.token_list_[i];
|
|
|
|
if (!operator()(t0))
|
|
{
|
|
return i;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case 2 :
|
|
{
|
|
const token& t0 = g.token_list_[i ];
|
|
const token& t1 = g.token_list_[i + 1];
|
|
|
|
if (!operator()(t0,t1))
|
|
{
|
|
return i;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case 3 :
|
|
{
|
|
const token& t0 = g.token_list_[i ];
|
|
const token& t1 = g.token_list_[i + 1];
|
|
const token& t2 = g.token_list_[i + 2];
|
|
|
|
if (!operator()(t0,t1,t2))
|
|
{
|
|
return i;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case 4 :
|
|
{
|
|
const token& t0 = g.token_list_[i ];
|
|
const token& t1 = g.token_list_[i + 1];
|
|
const token& t2 = g.token_list_[i + 2];
|
|
const token& t3 = g.token_list_[i + 3];
|
|
|
|
if (!operator()(t0,t1,t2,t3))
|
|
{
|
|
return i;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return (g.token_list_.size() - stride_ + 1);
|
|
}
|
|
|
|
virtual bool operator()(const token&)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
virtual bool operator()(const token&, const token&)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
virtual bool operator()(const token&, const token&, const token&)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
virtual bool operator()(const token&, const token&, const token&, const token&)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
private:
|
|
|
|
std::size_t stride_;
|
|
};
|
|
|
|
class token_modifier : public helper_interface
|
|
{
|
|
public:
|
|
|
|
inline std::size_t process(generator& g)
|
|
{
|
|
std::size_t changes = 0;
|
|
|
|
for (std::size_t i = 0; i < g.token_list_.size(); ++i)
|
|
{
|
|
if (modify(g.token_list_[i])) changes++;
|
|
}
|
|
|
|
return changes;
|
|
}
|
|
|
|
virtual bool modify(token& t) = 0;
|
|
};
|
|
|
|
class token_inserter : public helper_interface
|
|
{
|
|
public:
|
|
|
|
explicit token_inserter(const std::size_t& stride)
|
|
: stride_(stride)
|
|
{
|
|
if (stride > 5)
|
|
{
|
|
throw std::invalid_argument("token_inserter() - Invalid stride value");
|
|
}
|
|
}
|
|
|
|
inline std::size_t process(generator& g)
|
|
{
|
|
if (g.token_list_.empty())
|
|
return 0;
|
|
else if (g.token_list_.size() < stride_)
|
|
return 0;
|
|
|
|
std::size_t changes = 0;
|
|
|
|
for (std::size_t i = 0; i < (g.token_list_.size() - stride_ + 1); ++i)
|
|
{
|
|
int insert_index = -1;
|
|
token t;
|
|
|
|
switch (stride_)
|
|
{
|
|
case 1 : insert_index = insert(g.token_list_[i],t);
|
|
break;
|
|
|
|
case 2 : insert_index = insert(g.token_list_[i],g.token_list_[i + 1],t);
|
|
break;
|
|
|
|
case 3 : insert_index = insert(g.token_list_[i],g.token_list_[i + 1],g.token_list_[i + 2],t);
|
|
break;
|
|
|
|
case 4 : insert_index = insert(g.token_list_[i],g.token_list_[i + 1],g.token_list_[i + 2],g.token_list_[i + 3],t);
|
|
break;
|
|
|
|
case 5 : insert_index = insert(g.token_list_[i],g.token_list_[i + 1],g.token_list_[i + 2],g.token_list_[i + 3],g.token_list_[i + 4],t);
|
|
break;
|
|
}
|
|
|
|
if ((insert_index >= 0) && (insert_index <= (static_cast<int>(stride_) + 1)))
|
|
{
|
|
g.token_list_.insert(g.token_list_.begin() + (i + insert_index),t);
|
|
changes++;
|
|
}
|
|
}
|
|
|
|
return changes;
|
|
}
|
|
|
|
inline virtual int insert(const token&, token& )
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
inline virtual int insert(const token&, const token&, token&)
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
inline virtual int insert(const token&, const token&, const token&, token&)
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
inline virtual int insert(const token&, const token&, const token&, const token&, token&)
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
inline virtual int insert(const token&, const token&, const token&, const token&, const token&, token&)
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
private:
|
|
|
|
std::size_t stride_;
|
|
};
|
|
|
|
class token_joiner : public helper_interface
|
|
{
|
|
public:
|
|
|
|
token_joiner(const std::size_t& stride)
|
|
: stride_(stride)
|
|
{}
|
|
|
|
inline std::size_t process(generator& g)
|
|
{
|
|
if (g.token_list_.empty())
|
|
return 0;
|
|
|
|
switch (stride_)
|
|
{
|
|
case 2 : return process_stride_2(g);
|
|
case 3 : return process_stride_3(g);
|
|
default : return 0;
|
|
}
|
|
}
|
|
|
|
virtual bool join(const token&, const token&, token&) { return false; }
|
|
virtual bool join(const token&, const token&, const token&, token&) { return false; }
|
|
|
|
private:
|
|
|
|
inline std::size_t process_stride_2(generator& g)
|
|
{
|
|
if (g.token_list_.size() < 2)
|
|
return 0;
|
|
|
|
std::size_t changes = 0;
|
|
|
|
for (std::size_t i = 0; i < g.token_list_.size() - 1; ++i)
|
|
{
|
|
token t;
|
|
|
|
while (join(g.token_list_[i],g.token_list_[i + 1],t))
|
|
{
|
|
g.token_list_[i] = t;
|
|
g.token_list_.erase(g.token_list_.begin() + (i + 1));
|
|
++changes;
|
|
}
|
|
}
|
|
|
|
return changes;
|
|
}
|
|
|
|
inline std::size_t process_stride_3(generator& g)
|
|
{
|
|
if (g.token_list_.size() < 3)
|
|
return 0;
|
|
|
|
std::size_t changes = 0;
|
|
|
|
for (std::size_t i = 0; i < g.token_list_.size() - 2; ++i)
|
|
{
|
|
token t;
|
|
|
|
while (join(g.token_list_[i],g.token_list_[i + 1],g.token_list_[i + 2],t))
|
|
{
|
|
g.token_list_[i] = t;
|
|
g.token_list_.erase(g.token_list_.begin() + (i + 1),
|
|
g.token_list_.begin() + (i + 3));
|
|
++changes;
|
|
}
|
|
}
|
|
|
|
return changes;
|
|
}
|
|
|
|
std::size_t stride_;
|
|
};
|
|
|
|
namespace helper
|
|
{
|
|
|
|
inline void dump(lexer::generator& generator)
|
|
{
|
|
for (std::size_t i = 0; i < generator.size(); ++i)
|
|
{
|
|
lexer::token t = generator[i];
|
|
printf("Token[%02d] @ %03d %6s --> '%s'\n",
|
|
static_cast<int>(i),
|
|
static_cast<int>(t.position),
|
|
t.to_str(t.type).c_str(),
|
|
t.value.c_str());
|
|
}
|
|
}
|
|
|
|
class commutative_inserter : public lexer::token_inserter
|
|
{
|
|
public:
|
|
|
|
commutative_inserter()
|
|
: lexer::token_inserter(2)
|
|
{}
|
|
|
|
inline void ignore_symbol(const std::string& symbol)
|
|
{
|
|
ignore_set_.insert(symbol);
|
|
}
|
|
|
|
inline int insert(const lexer::token& t0, const lexer::token& t1, lexer::token& new_token)
|
|
{
|
|
bool match = false;
|
|
new_token.type = lexer::token::e_mul;
|
|
new_token.value = "*";
|
|
new_token.position = t1.position;
|
|
|
|
if (t0.type == lexer::token::e_symbol)
|
|
{
|
|
if (ignore_set_.end() != ignore_set_.find(t0.value))
|
|
{
|
|
return -1;
|
|
}
|
|
else if (!t0.value.empty() && ('$' == t0.value[0]))
|
|
{
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
if (t1.type == lexer::token::e_symbol)
|
|
{
|
|
if (ignore_set_.end() != ignore_set_.find(t1.value))
|
|
{
|
|
return -1;
|
|
}
|
|
}
|
|
if ((t0.type == lexer::token::e_number ) && (t1.type == lexer::token::e_symbol )) match = true;
|
|
else if ((t0.type == lexer::token::e_number ) && (t1.type == lexer::token::e_lbracket )) match = true;
|
|
else if ((t0.type == lexer::token::e_number ) && (t1.type == lexer::token::e_lcrlbracket)) match = true;
|
|
else if ((t0.type == lexer::token::e_number ) && (t1.type == lexer::token::e_lsqrbracket)) match = true;
|
|
else if ((t0.type == lexer::token::e_symbol ) && (t1.type == lexer::token::e_number )) match = true;
|
|
else if ((t0.type == lexer::token::e_rbracket ) && (t1.type == lexer::token::e_number )) match = true;
|
|
else if ((t0.type == lexer::token::e_rcrlbracket) && (t1.type == lexer::token::e_number )) match = true;
|
|
else if ((t0.type == lexer::token::e_rsqrbracket) && (t1.type == lexer::token::e_number )) match = true;
|
|
else if ((t0.type == lexer::token::e_rbracket ) && (t1.type == lexer::token::e_symbol )) match = true;
|
|
else if ((t0.type == lexer::token::e_rcrlbracket) && (t1.type == lexer::token::e_symbol )) match = true;
|
|
else if ((t0.type == lexer::token::e_rsqrbracket) && (t1.type == lexer::token::e_symbol )) match = true;
|
|
|
|
return (match) ? 1 : -1;
|
|
}
|
|
|
|
private:
|
|
|
|
std::set<std::string,details::ilesscompare> 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<char>(t0.type) == '!') && (t1.type == lexer::token::e_eq))
|
|
{
|
|
t.type = lexer::token::e_ne;
|
|
t.value = "!=";
|
|
t.position = t0.position;
|
|
return true;
|
|
}
|
|
// '< >' --> '<>'
|
|
else if ((t0.type == lexer::token::e_lt) && (t1.type == lexer::token::e_gt))
|
|
{
|
|
t.type = lexer::token::e_ne;
|
|
t.value = "<>";
|
|
t.position = t0.position;
|
|
return true;
|
|
}
|
|
// '<= >' --> '<=>'
|
|
else if ((t0.type == lexer::token::e_lte) && (t1.type == lexer::token::e_gt))
|
|
{
|
|
t.type = lexer::token::e_swap;
|
|
t.value = "<=>";
|
|
t.position = t0.position;
|
|
return true;
|
|
}
|
|
else
|
|
return false;
|
|
}
|
|
|
|
inline bool join(const lexer::token& t0, const lexer::token& t1, const lexer::token& t2, lexer::token& t)
|
|
{
|
|
// '[ * ]' --> '[*]'
|
|
if (
|
|
(t0.type == lexer::token::e_lsqrbracket) &&
|
|
(t1.type == lexer::token::e_mul ) &&
|
|
(t2.type == lexer::token::e_rsqrbracket)
|
|
)
|
|
{
|
|
t.type = lexer::token::e_symbol;
|
|
t.value = "[*]";
|
|
t.position = t0.position;
|
|
|
|
return true;
|
|
}
|
|
else
|
|
return false;
|
|
}
|
|
};
|
|
|
|
class bracket_checker : public lexer::token_scanner
|
|
{
|
|
public:
|
|
|
|
bracket_checker()
|
|
: token_scanner(1),
|
|
state_(true)
|
|
{}
|
|
|
|
bool result()
|
|
{
|
|
if (!stack_.empty())
|
|
{
|
|
lexer::token t;
|
|
t.value = stack_.top().first;
|
|
t.position = stack_.top().second;
|
|
error_token_ = t;
|
|
state_ = false;
|
|
|
|
return false;
|
|
}
|
|
else
|
|
return state_;
|
|
}
|
|
|
|
lexer::token error_token()
|
|
{
|
|
return error_token_;
|
|
}
|
|
|
|
void reset()
|
|
{
|
|
// Why? because msvc doesn't support swap properly.
|
|
stack_ = std::stack<std::pair<char,std::size_t> >();
|
|
state_ = true;
|
|
error_token_.clear();
|
|
}
|
|
|
|
bool operator()(const lexer::token& t)
|
|
{
|
|
if (
|
|
!t.value.empty() &&
|
|
(lexer::token::e_string != t.type) &&
|
|
(lexer::token::e_symbol != t.type) &&
|
|
exprtk::details::is_bracket(t.value[0])
|
|
)
|
|
{
|
|
char c = t.value[0];
|
|
|
|
if (t.type == lexer::token::e_lbracket) stack_.push(std::make_pair(')',t.position));
|
|
else if (t.type == lexer::token::e_lcrlbracket) stack_.push(std::make_pair('}',t.position));
|
|
else if (t.type == lexer::token::e_lsqrbracket) stack_.push(std::make_pair(']',t.position));
|
|
else if (exprtk::details::is_right_bracket(c))
|
|
{
|
|
if (stack_.empty())
|
|
{
|
|
state_ = false;
|
|
error_token_ = t;
|
|
|
|
return false;
|
|
}
|
|
else if (c != stack_.top().first)
|
|
{
|
|
state_ = false;
|
|
error_token_ = t;
|
|
|
|
return false;
|
|
}
|
|
else
|
|
stack_.pop();
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
private:
|
|
|
|
bool state_;
|
|
std::stack<std::pair<char,std::size_t> > stack_;
|
|
lexer::token error_token_;
|
|
};
|
|
|
|
class numeric_checker : public lexer::token_scanner
|
|
{
|
|
public:
|
|
|
|
numeric_checker()
|
|
: token_scanner (1),
|
|
current_index_(0)
|
|
{}
|
|
|
|
bool result()
|
|
{
|
|
return error_list_.empty();
|
|
}
|
|
|
|
void reset()
|
|
{
|
|
error_list_.clear();
|
|
current_index_ = 0;
|
|
}
|
|
|
|
bool operator()(const lexer::token& t)
|
|
{
|
|
if (token::e_number == t.type)
|
|
{
|
|
double v;
|
|
|
|
if (!exprtk::details::string_to_real(t.value,v))
|
|
{
|
|
error_list_.push_back(current_index_);
|
|
}
|
|
}
|
|
|
|
++current_index_;
|
|
|
|
return true;
|
|
}
|
|
|
|
std::size_t error_count() const
|
|
{
|
|
return error_list_.size();
|
|
}
|
|
|
|
std::size_t error_index(const std::size_t& i)
|
|
{
|
|
if (i < error_list_.size())
|
|
return error_list_[i];
|
|
else
|
|
return std::numeric_limits<std::size_t>::max();
|
|
}
|
|
|
|
void clear_errors()
|
|
{
|
|
error_list_.clear();
|
|
}
|
|
|
|
private:
|
|
|
|
std::size_t current_index_;
|
|
std::vector<std::size_t> error_list_;
|
|
};
|
|
|
|
class symbol_replacer : public lexer::token_modifier
|
|
{
|
|
private:
|
|
|
|
typedef std::map<std::string,std::pair<std::string,token::token_type>,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<lexer::token::token_type,lexer::token::token_type> token_pair_t;
|
|
typedef std::set<token_pair_t> set_t;
|
|
|
|
public:
|
|
|
|
sequence_validator()
|
|
: lexer::token_scanner(2)
|
|
{
|
|
add_invalid(lexer::token::e_number ,lexer::token::e_number );
|
|
add_invalid(lexer::token::e_string ,lexer::token::e_string );
|
|
add_invalid(lexer::token::e_number ,lexer::token::e_string );
|
|
add_invalid(lexer::token::e_string ,lexer::token::e_number );
|
|
add_invalid(lexer::token::e_string ,lexer::token::e_colon );
|
|
add_invalid(lexer::token::e_string ,lexer::token::e_ternary);
|
|
add_invalid(lexer::token::e_colon ,lexer::token::e_string );
|
|
add_invalid(lexer::token::e_ternary,lexer::token::e_string );
|
|
add_invalid_set1(lexer::token::e_assign );
|
|
add_invalid_set1(lexer::token::e_shr );
|
|
add_invalid_set1(lexer::token::e_shl );
|
|
add_invalid_set1(lexer::token::e_lte );
|
|
add_invalid_set1(lexer::token::e_ne );
|
|
add_invalid_set1(lexer::token::e_gte );
|
|
add_invalid_set1(lexer::token::e_lt );
|
|
add_invalid_set1(lexer::token::e_gt );
|
|
add_invalid_set1(lexer::token::e_eq );
|
|
add_invalid_set1(lexer::token::e_comma );
|
|
add_invalid_set1(lexer::token::e_add );
|
|
add_invalid_set1(lexer::token::e_sub );
|
|
add_invalid_set1(lexer::token::e_div );
|
|
add_invalid_set1(lexer::token::e_mul );
|
|
add_invalid_set1(lexer::token::e_mod );
|
|
add_invalid_set1(lexer::token::e_pow );
|
|
add_invalid_set1(lexer::token::e_colon );
|
|
add_invalid_set1(lexer::token::e_ternary);
|
|
}
|
|
|
|
bool result()
|
|
{
|
|
return error_list_.empty();
|
|
}
|
|
|
|
bool operator()(const lexer::token& t0, const lexer::token& t1)
|
|
{
|
|
set_t::value_type p = std::make_pair(t0.type,t1.type);
|
|
|
|
if (invalid_bracket_check(t0.type,t1.type))
|
|
{
|
|
error_list_.push_back(std::make_pair(t0,t1));
|
|
}
|
|
else if (invalid_comb_.find(p) != invalid_comb_.end())
|
|
{
|
|
error_list_.push_back(std::make_pair(t0,t1));
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
std::size_t error_count()
|
|
{
|
|
return error_list_.size();
|
|
}
|
|
|
|
std::pair<lexer::token,lexer::token> 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<char>(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<char>(base)))
|
|
{
|
|
if (details::is_right_bracket(static_cast<char>(t)))
|
|
return false;
|
|
else if (details::is_left_bracket(static_cast<char>(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<char>(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<char>(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<std::pair<lexer::token,lexer::token> > 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<lexer::token_modifier*>(0);
|
|
bool result = true;
|
|
|
|
for (std::size_t i = 0; i < token_modifier_list.size(); ++i)
|
|
{
|
|
lexer::token_modifier& modifier = (*token_modifier_list[i]);
|
|
|
|
modifier.reset();
|
|
modifier.process(g);
|
|
|
|
if (!modifier.result())
|
|
{
|
|
error_token_modifier = token_modifier_list[i];
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
inline bool run_joiners(lexer::generator& g)
|
|
{
|
|
error_token_joiner = reinterpret_cast<lexer::token_joiner*>(0);
|
|
bool result = true;
|
|
|
|
for (std::size_t i = 0; i < token_joiner_list.size(); ++i)
|
|
{
|
|
lexer::token_joiner& joiner = (*token_joiner_list[i]);
|
|
|
|
joiner.reset();
|
|
joiner.process(g);
|
|
|
|
if (!joiner.result())
|
|
{
|
|
error_token_joiner = token_joiner_list[i];
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
inline bool run_inserters(lexer::generator& g)
|
|
{
|
|
error_token_inserter = reinterpret_cast<lexer::token_inserter*>(0);
|
|
bool result = true;
|
|
|
|
for (std::size_t i = 0; i < token_inserter_list.size(); ++i)
|
|
{
|
|
lexer::token_inserter& inserter = (*token_inserter_list[i]);
|
|
|
|
inserter.reset();
|
|
inserter.process(g);
|
|
|
|
if (!inserter.result())
|
|
{
|
|
error_token_inserter = token_inserter_list[i];
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
inline bool run_scanners(lexer::generator& g)
|
|
{
|
|
error_token_scanner = reinterpret_cast<lexer::token_scanner*>(0);
|
|
bool result = true;
|
|
|
|
for (std::size_t i = 0; i < token_scanner_list.size(); ++i)
|
|
{
|
|
lexer::token_scanner& scanner = (*token_scanner_list[i]);
|
|
|
|
scanner.reset();
|
|
scanner.process(g);
|
|
|
|
if (!scanner.result())
|
|
{
|
|
error_token_scanner = token_scanner_list[i];
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
std::vector<lexer::token_scanner*> token_scanner_list;
|
|
std::vector<lexer::token_modifier*> token_modifier_list;
|
|
std::vector<lexer::token_joiner*> token_joiner_list;
|
|
std::vector<lexer::token_inserter*> token_inserter_list;
|
|
|
|
lexer::token_scanner* error_token_scanner;
|
|
lexer::token_modifier* error_token_modifier;
|
|
lexer::token_joiner* error_token_joiner;
|
|
lexer::token_inserter* error_token_inserter;
|
|
};
|
|
}
|
|
}
|
|
|
|
template <typename T>
|
|
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<type_store>& pl)
|
|
: parameter_list_(pl)
|
|
{}
|
|
|
|
inline bool empty() const
|
|
{
|
|
return parameter_list_.empty();
|
|
}
|
|
|
|
inline std::size_t size() const
|
|
{
|
|
return parameter_list_.size();
|
|
}
|
|
|
|
inline type_store& operator[](const std::size_t& index)
|
|
{
|
|
return parameter_list_[index];
|
|
}
|
|
|
|
inline const type_store& operator[](const std::size_t& index) const
|
|
{
|
|
return parameter_list_[index];
|
|
}
|
|
|
|
inline type_store& front()
|
|
{
|
|
return parameter_list_[0];
|
|
}
|
|
|
|
inline const type_store& front() const
|
|
{
|
|
return parameter_list_[0];
|
|
}
|
|
|
|
inline type_store& back()
|
|
{
|
|
return parameter_list_[size() - 1];
|
|
}
|
|
|
|
inline const type_store& back() const
|
|
{
|
|
return parameter_list_[size() - 1];
|
|
}
|
|
|
|
private:
|
|
|
|
std::vector<type_store>& parameter_list_;
|
|
};
|
|
|
|
template <typename ViewType>
|
|
struct type_view
|
|
{
|
|
typedef type_store<T> type_store_t;
|
|
typedef ViewType value_t;
|
|
|
|
type_view(type_store_t& ts)
|
|
: ts_(ts),
|
|
data_(reinterpret_cast<value_t*>(ts_.data))
|
|
{}
|
|
|
|
inline std::size_t size() const
|
|
{
|
|
return ts_.size;
|
|
}
|
|
|
|
inline value_t& operator[](const std::size_t& i)
|
|
{
|
|
return data_[i];
|
|
}
|
|
|
|
inline const value_t& operator[](const std::size_t& i) const
|
|
{
|
|
return data_[i];
|
|
}
|
|
|
|
inline const value_t* begin() const { return data_; }
|
|
inline value_t* begin() { return data_; }
|
|
|
|
inline const value_t* end() const { return data_ + ts_.size; }
|
|
inline value_t* end() { return data_ + ts_.size; }
|
|
|
|
type_store_t& ts_;
|
|
value_t* data_;
|
|
};
|
|
|
|
typedef type_view<T> vector_view;
|
|
typedef type_view<char> string_view;
|
|
|
|
struct scalar_view
|
|
{
|
|
typedef type_store<T> type_store_t;
|
|
typedef T value_t;
|
|
|
|
scalar_view(type_store_t& ts)
|
|
: v_(*reinterpret_cast<value_t*>(ts.data))
|
|
{}
|
|
|
|
value_t& operator()()
|
|
{
|
|
return v_;
|
|
}
|
|
|
|
const value_t& operator()() const
|
|
{
|
|
return v_;
|
|
}
|
|
|
|
T& v_;
|
|
};
|
|
};
|
|
|
|
template <typename StringView>
|
|
inline std::string to_str(const StringView& view)
|
|
{
|
|
return std::string(view.begin(),view.size());
|
|
}
|
|
|
|
namespace details
|
|
{
|
|
enum operator_type
|
|
{
|
|
e_default , e_null , e_add , e_sub ,
|
|
e_mul , e_div , e_mod , e_pow ,
|
|
e_atan2 , e_min , e_max , e_avg ,
|
|
e_sum , e_prod , e_lt , e_lte ,
|
|
e_eq , e_equal , e_ne , e_nequal ,
|
|
e_gte , e_gt , e_and , e_nand ,
|
|
e_or , e_nor , e_xor , e_xnor ,
|
|
e_mand , e_mor , e_scand , e_scor ,
|
|
e_shr , e_shl , e_abs , e_acos ,
|
|
e_acosh , e_asin , e_asinh , e_atan ,
|
|
e_atanh , e_ceil , e_cos , e_cosh ,
|
|
e_exp , e_expm1 , e_floor , e_log ,
|
|
e_log10 , e_log2 , e_log1p , e_logn ,
|
|
e_neg , e_pos , e_round , e_roundn ,
|
|
e_root , e_sqrt , e_sin , e_sinc ,
|
|
e_sinh , e_sec , e_csc , e_tan ,
|
|
e_tanh , e_cot , e_clamp , e_iclamp ,
|
|
e_inrange , e_sgn , e_r2d , e_d2r ,
|
|
e_d2g , e_g2d , e_hypot , e_notl ,
|
|
e_erf , e_erfc , e_ncdf , e_frac ,
|
|
e_trunc , e_assign , e_addass , e_subass ,
|
|
e_mulass , e_divass , e_modass , e_in ,
|
|
e_like , e_ilike , e_multi , e_swap ,
|
|
|
|
// Do not add new functions/operators after this point.
|
|
e_sf00 = 1000, e_sf01 = 1001, e_sf02 = 1002, e_sf03 = 1003,
|
|
e_sf04 = 1004, e_sf05 = 1005, e_sf06 = 1006, e_sf07 = 1007,
|
|
e_sf08 = 1008, e_sf09 = 1009, e_sf10 = 1010, e_sf11 = 1011,
|
|
e_sf12 = 1012, e_sf13 = 1013, e_sf14 = 1014, e_sf15 = 1015,
|
|
e_sf16 = 1016, e_sf17 = 1017, e_sf18 = 1018, e_sf19 = 1019,
|
|
e_sf20 = 1020, e_sf21 = 1021, e_sf22 = 1022, e_sf23 = 1023,
|
|
e_sf24 = 1024, e_sf25 = 1025, e_sf26 = 1026, e_sf27 = 1027,
|
|
e_sf28 = 1028, e_sf29 = 1029, e_sf30 = 1030, e_sf31 = 1031,
|
|
e_sf32 = 1032, e_sf33 = 1033, e_sf34 = 1034, e_sf35 = 1035,
|
|
e_sf36 = 1036, e_sf37 = 1037, e_sf38 = 1038, e_sf39 = 1039,
|
|
e_sf40 = 1040, e_sf41 = 1041, e_sf42 = 1042, e_sf43 = 1043,
|
|
e_sf44 = 1044, e_sf45 = 1045, e_sf46 = 1046, e_sf47 = 1047,
|
|
e_sf48 = 1048, e_sf49 = 1049, e_sf50 = 1050, e_sf51 = 1051,
|
|
e_sf52 = 1052, e_sf53 = 1053, e_sf54 = 1054, e_sf55 = 1055,
|
|
e_sf56 = 1056, e_sf57 = 1057, e_sf58 = 1058, e_sf59 = 1059,
|
|
e_sf60 = 1060, e_sf61 = 1061, e_sf62 = 1062, e_sf63 = 1063,
|
|
e_sf64 = 1064, e_sf65 = 1065, e_sf66 = 1066, e_sf67 = 1067,
|
|
e_sf68 = 1068, e_sf69 = 1069, e_sf70 = 1070, e_sf71 = 1071,
|
|
e_sf72 = 1072, e_sf73 = 1073, e_sf74 = 1074, e_sf75 = 1075,
|
|
e_sf76 = 1076, e_sf77 = 1077, e_sf78 = 1078, e_sf79 = 1079,
|
|
e_sf80 = 1080, e_sf81 = 1081, e_sf82 = 1082, e_sf83 = 1083,
|
|
e_sf84 = 1084, e_sf85 = 1085, e_sf86 = 1086, e_sf87 = 1087,
|
|
e_sf88 = 1088, e_sf89 = 1089, e_sf90 = 1090, e_sf91 = 1091,
|
|
e_sf92 = 1092, e_sf93 = 1093, e_sf94 = 1094, e_sf95 = 1095,
|
|
e_sf96 = 1096, e_sf97 = 1097, e_sf98 = 1098, e_sf99 = 1099,
|
|
e_sffinal = 1100,
|
|
e_sf4ext00 = 2000, e_sf4ext01 = 2001, e_sf4ext02 = 2002, e_sf4ext03 = 2003,
|
|
e_sf4ext04 = 2004, e_sf4ext05 = 2005, e_sf4ext06 = 2006, e_sf4ext07 = 2007,
|
|
e_sf4ext08 = 2008, e_sf4ext09 = 2009, e_sf4ext10 = 2010, e_sf4ext11 = 2011,
|
|
e_sf4ext12 = 2012, e_sf4ext13 = 2013, e_sf4ext14 = 2014, e_sf4ext15 = 2015,
|
|
e_sf4ext16 = 2016, e_sf4ext17 = 2017, e_sf4ext18 = 2018, e_sf4ext19 = 2019,
|
|
e_sf4ext20 = 2020, e_sf4ext21 = 2021, e_sf4ext22 = 2022, e_sf4ext23 = 2023,
|
|
e_sf4ext24 = 2024, e_sf4ext25 = 2025, e_sf4ext26 = 2026, e_sf4ext27 = 2027,
|
|
e_sf4ext28 = 2028, e_sf4ext29 = 2029, e_sf4ext30 = 2030, e_sf4ext31 = 2031,
|
|
e_sf4ext32 = 2032, e_sf4ext33 = 2033, e_sf4ext34 = 2034, e_sf4ext35 = 2035,
|
|
e_sf4ext36 = 2036, e_sf4ext37 = 2037, e_sf4ext38 = 2038, e_sf4ext39 = 2039,
|
|
e_sf4ext40 = 2040, e_sf4ext41 = 2041, e_sf4ext42 = 2042, e_sf4ext43 = 2043,
|
|
e_sf4ext44 = 2044, e_sf4ext45 = 2045, e_sf4ext46 = 2046, e_sf4ext47 = 2047,
|
|
e_sf4ext48 = 2048, e_sf4ext49 = 2049, e_sf4ext50 = 2050, e_sf4ext51 = 2051,
|
|
e_sf4ext52 = 2052, e_sf4ext53 = 2053, e_sf4ext54 = 2054, e_sf4ext55 = 2055,
|
|
e_sf4ext56 = 2056, e_sf4ext57 = 2057, e_sf4ext58 = 2058, e_sf4ext59 = 2059
|
|
};
|
|
|
|
struct base_operation_t
|
|
{
|
|
base_operation_t(const operator_type t, const unsigned int& np)
|
|
: type(t),
|
|
num_params(np)
|
|
{}
|
|
|
|
operator_type type;
|
|
unsigned int num_params;
|
|
};
|
|
|
|
namespace numeric
|
|
{
|
|
namespace details
|
|
{
|
|
template <typename T>
|
|
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<T>::quiet_NaN();
|
|
}
|
|
}
|
|
|
|
template <typename T>
|
|
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<T>(arg0,arg1);
|
|
case e_pow : return pow<T>(arg0,arg1);
|
|
case e_atan2 : return atan2<T>(arg0,arg1);
|
|
case e_min : return std::min<T>(arg0,arg1);
|
|
case e_max : return std::max<T>(arg0,arg1);
|
|
case e_logn : return logn<T>(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<T>()(arg0,arg1) ? T(1) : T(0);
|
|
case e_ne : return std::not_equal_to<T>()(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<T> (arg0,arg1);
|
|
case e_nand : return nand_opr<T>(arg0,arg1);
|
|
case e_or : return or_opr<T> (arg0,arg1);
|
|
case e_nor : return nor_opr<T> (arg0,arg1);
|
|
case e_xor : return xor_opr<T> (arg0,arg1);
|
|
case e_xnor : return xnor_opr<T>(arg0,arg1);
|
|
case e_root : return root<T> (arg0,arg1);
|
|
case e_roundn : return roundn<T> (arg0,arg1);
|
|
case e_equal : return equal<T> (arg0,arg1);
|
|
case e_nequal : return nequal<T> (arg0,arg1);
|
|
case e_hypot : return hypot<T> (arg0,arg1);
|
|
case e_shr : return shr<T> (arg0,arg1);
|
|
case e_shl : return shl<T> (arg0,arg1);
|
|
default : return std::numeric_limits<T>::quiet_NaN();
|
|
}
|
|
}
|
|
|
|
template <typename T>
|
|
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<T>(arg0,arg1);
|
|
case e_min : return std::min<T>(arg0,arg1);
|
|
case e_max : return std::max<T>(arg0,arg1);
|
|
case e_logn : return logn<T>(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<T>(arg0,arg1);
|
|
case e_equal : return arg0 == arg1;
|
|
case e_nequal : return arg0 != arg1;
|
|
case e_hypot : return hypot<T>(arg0,arg1);
|
|
case e_shr : return arg0 >> arg1;
|
|
case e_shl : return arg0 << arg1;
|
|
default : return std::numeric_limits<T>::quiet_NaN();
|
|
}
|
|
}
|
|
}
|
|
|
|
template <typename T>
|
|
inline T process(const operator_type operation, const T arg)
|
|
{
|
|
return exprtk::details::numeric::details::process_impl(operation,arg);
|
|
}
|
|
|
|
template <typename T>
|
|
inline T process(const operator_type operation, const T arg0, const T arg1)
|
|
{
|
|
return exprtk::details::numeric::details::process_impl(operation,arg0,arg1);
|
|
}
|
|
}
|
|
|
|
template <typename T>
|
|
class expression_node
|
|
{
|
|
public:
|
|
|
|
enum node_type
|
|
{
|
|
e_none , e_null , e_constant , e_unary ,
|
|
e_binary , e_binary_ext , e_trinary , e_quaternary ,
|
|
e_quinary , e_senary , e_vararg , e_conditional ,
|
|
e_while , e_repeat , e_for , e_switch ,
|
|
e_mswitch , e_variable , e_stringvar , e_stringconst ,
|
|
e_stringvarrng , e_cstringvarrng, e_strgenrange , e_strconcat ,
|
|
e_stringvarsize, e_strswap , e_stringsize , e_function ,
|
|
e_vafunction , e_genfunction , e_strfunction , e_add ,
|
|
e_sub , e_mul , e_div , e_mod ,
|
|
e_pow , e_lt , e_lte , e_gt ,
|
|
e_gte , e_eq , e_ne , e_and ,
|
|
e_nand , e_or , e_nor , e_xor ,
|
|
e_xnor , e_in , e_like , e_ilike ,
|
|
e_inranges , e_ipow , e_ipowinv , e_abs ,
|
|
e_acos , e_acosh , e_asin , e_asinh ,
|
|
e_atan , e_atanh , e_ceil , e_cos ,
|
|
e_cosh , e_exp , e_expm1 , e_floor ,
|
|
e_log , e_log10 , e_log2 , e_log1p ,
|
|
e_neg , e_pos , e_round , e_sin ,
|
|
e_sinc , e_sinh , e_sqrt , e_tan ,
|
|
e_tanh , e_cot , e_sec , e_csc ,
|
|
e_r2d , e_d2r , e_d2g , e_g2d ,
|
|
e_notl , e_sgn , e_erf , e_erfc ,
|
|
e_ncdf , e_frac , e_trunc , e_uvouv ,
|
|
e_vov , e_cov , e_voc , e_vob ,
|
|
e_bov , e_cob , e_boc , e_vovov ,
|
|
e_vovoc , e_vocov , e_covov , e_covoc ,
|
|
e_vovovov , e_vovovoc , e_vovocov , e_vocovov ,
|
|
e_covovov , e_covocov , e_vocovoc , e_covovoc ,
|
|
e_vococov , e_sf3ext , e_sf4ext , e_nulleq ,
|
|
e_strass , e_vector , e_vecelem , e_vecdefass ,
|
|
e_vecvalass , e_vecvecass , e_vecopvalass , e_vecopvecass ,
|
|
e_vecfunc , e_vecvecswap , e_vecvecineq , e_vecvalineq ,
|
|
e_valvecineq , e_vecvecarith , e_vecvalarith , e_valvecarith ,
|
|
e_vecunaryop , e_break , e_continue , e_swap
|
|
};
|
|
|
|
typedef T value_type;
|
|
typedef expression_node<T>* expression_ptr;
|
|
|
|
virtual ~expression_node()
|
|
{}
|
|
|
|
inline virtual T value() const
|
|
{
|
|
return std::numeric_limits<T>::quiet_NaN();
|
|
}
|
|
|
|
inline virtual expression_node<T>* branch(const std::size_t& index = 0) const
|
|
{
|
|
return reinterpret_cast<expression_ptr>(index * 0);
|
|
}
|
|
|
|
inline virtual node_type type() const
|
|
{
|
|
return e_none;
|
|
}
|
|
};
|
|
|
|
template <typename T>
|
|
inline bool is_generally_string_node(const expression_node<T>* node);
|
|
|
|
inline bool is_true(const double v)
|
|
{
|
|
return std::not_equal_to<double>()(0.0,v);
|
|
}
|
|
|
|
inline bool is_true(const long double v)
|
|
{
|
|
return std::not_equal_to<long double>()(0.0L,v);
|
|
}
|
|
|
|
inline bool is_true(const float v)
|
|
{
|
|
return std::not_equal_to<float>()(0.0f,v);
|
|
}
|
|
|
|
template <typename T>
|
|
inline bool is_true(const expression_node<T>* node)
|
|
{
|
|
return std::not_equal_to<T>()(T(0),node->value());
|
|
}
|
|
|
|
template <typename T>
|
|
inline bool is_false(const expression_node<T>* node)
|
|
{
|
|
return std::equal_to<T>()(T(0),node->value());
|
|
}
|
|
|
|
template <typename T>
|
|
inline bool is_unary_node(const expression_node<T>* node)
|
|
{
|
|
return node && (details::expression_node<T>::e_unary == node->type());
|
|
}
|
|
|
|
template <typename T>
|
|
inline bool is_neg_unary_node(const expression_node<T>* node)
|
|
{
|
|
return node && (details::expression_node<T>::e_neg == node->type());
|
|
}
|
|
|
|
template <typename T>
|
|
inline bool is_binary_node(const expression_node<T>* node)
|
|
{
|
|
return node && (details::expression_node<T>::e_binary == node->type());
|
|
}
|
|
|
|
template <typename T>
|
|
inline bool is_variable_node(const expression_node<T>* node)
|
|
{
|
|
return node && (details::expression_node<T>::e_variable == node->type());
|
|
}
|
|
|
|
template <typename T>
|
|
inline bool is_ivariable_node(const expression_node<T>* node)
|
|
{
|
|
return node &&
|
|
(
|
|
details::expression_node<T>::e_variable == node->type() ||
|
|
details::expression_node<T>::e_vecelem == node->type()
|
|
);
|
|
}
|
|
|
|
template <typename T>
|
|
inline bool is_vector_elem_node(const expression_node<T>* node)
|
|
{
|
|
return node && (details::expression_node<T>::e_vecelem == node->type());
|
|
}
|
|
|
|
template <typename T>
|
|
inline bool is_vector_node(const expression_node<T>* node)
|
|
{
|
|
return node && (details::expression_node<T>::e_vector == node->type());
|
|
}
|
|
|
|
template <typename T>
|
|
inline bool is_ivector_node(const expression_node<T>* node)
|
|
{
|
|
if (node)
|
|
{
|
|
switch (node->type())
|
|
{
|
|
case details::expression_node<T>::e_vector :
|
|
case details::expression_node<T>::e_vecvalass :
|
|
case details::expression_node<T>::e_vecvecass :
|
|
case details::expression_node<T>::e_vecopvalass :
|
|
case details::expression_node<T>::e_vecopvecass :
|
|
case details::expression_node<T>::e_vecvecswap :
|
|
case details::expression_node<T>::e_vecvecarith :
|
|
case details::expression_node<T>::e_vecvalarith :
|
|
case details::expression_node<T>::e_valvecarith :
|
|
case details::expression_node<T>::e_vecunaryop : return true;
|
|
default : return false;
|
|
}
|
|
}
|
|
else
|
|
return false;
|
|
}
|
|
|
|
template <typename T>
|
|
inline bool is_constant_node(const expression_node<T>* node)
|
|
{
|
|
return node && (details::expression_node<T>::e_constant == node->type());
|
|
}
|
|
|
|
template <typename T>
|
|
inline bool is_null_node(const expression_node<T>* node)
|
|
{
|
|
return node && (details::expression_node<T>::e_null == node->type());
|
|
}
|
|
|
|
template <typename T>
|
|
inline bool is_break_node(const expression_node<T>* node)
|
|
{
|
|
return node && (details::expression_node<T>::e_break == node->type());
|
|
}
|
|
|
|
template <typename T>
|
|
inline bool is_continue_node(const expression_node<T>* node)
|
|
{
|
|
return node && (details::expression_node<T>::e_continue == node->type());
|
|
}
|
|
|
|
template <typename T>
|
|
inline bool is_swap_node(const expression_node<T>* node)
|
|
{
|
|
return node && (details::expression_node<T>::e_swap == node->type());
|
|
}
|
|
|
|
template <typename T>
|
|
inline bool is_function(const expression_node<T>* node)
|
|
{
|
|
return node && (details::expression_node<T>::e_function == node->type());
|
|
}
|
|
|
|
template <typename T> class unary_node;
|
|
|
|
template <typename T>
|
|
inline bool is_negate_node(const expression_node<T>* node)
|
|
{
|
|
if (node && is_unary_node(node))
|
|
{
|
|
return (details::e_neg == static_cast<const unary_node<T>*>(node)->operation());
|
|
}
|
|
else
|
|
return false;
|
|
}
|
|
|
|
template <typename T>
|
|
inline bool branch_deletable(expression_node<T>* node)
|
|
{
|
|
return !is_variable_node(node) &&
|
|
!is_string_node (node) ;
|
|
}
|
|
|
|
template <std::size_t N, typename T>
|
|
inline bool all_nodes_valid(expression_node<T>* (&b)[N])
|
|
{
|
|
for (std::size_t i = 0; i < N; ++i)
|
|
{
|
|
if (0 == b[i]) return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
template <typename T,
|
|
typename Allocator,
|
|
template <typename,typename> class Sequence>
|
|
inline bool all_nodes_valid(const Sequence<expression_node<T>*,Allocator>& b)
|
|
{
|
|
for (std::size_t i = 0; i < b.size(); ++i)
|
|
{
|
|
if (0 == b[i]) return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
template <std::size_t N, typename T>
|
|
inline bool all_nodes_variables(expression_node<T>* (&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 <typename T,
|
|
typename Allocator,
|
|
template <typename,typename> class Sequence>
|
|
inline bool all_nodes_variables(Sequence<expression_node<T>*,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 <typename NodeAllocator, typename T, std::size_t N>
|
|
inline void free_all_nodes(NodeAllocator& node_allocator, expression_node<T>* (&b)[N])
|
|
{
|
|
for (std::size_t i = 0; i < N; ++i)
|
|
{
|
|
free_node(node_allocator,b[i]);
|
|
}
|
|
}
|
|
|
|
template <typename NodeAllocator,
|
|
typename T,
|
|
typename Allocator,
|
|
template <typename,typename> class Sequence>
|
|
inline void free_all_nodes(NodeAllocator& node_allocator, Sequence<expression_node<T>*,Allocator>& b)
|
|
{
|
|
for (std::size_t i = 0; i < b.size(); ++i)
|
|
{
|
|
free_node(node_allocator,b[i]);
|
|
}
|
|
|
|
b.clear();
|
|
}
|
|
|
|
template <typename NodeAllocator, typename T>
|
|
inline void free_node(NodeAllocator& node_allocator, expression_node<T>*& 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 <typename Type>
|
|
class vector_holder
|
|
{
|
|
private:
|
|
|
|
typedef Type value_type;
|
|
typedef value_type* value_ptr;
|
|
typedef const value_ptr const_value_ptr;
|
|
|
|
class vector_holder_base
|
|
{
|
|
public:
|
|
|
|
virtual ~vector_holder_base(){}
|
|
|
|
inline value_ptr operator[](const std::size_t& index) const
|
|
{
|
|
return value_at(index);
|
|
}
|
|
|
|
inline std::size_t size() const
|
|
{
|
|
return vector_size();
|
|
}
|
|
|
|
protected:
|
|
|
|
virtual value_ptr value_at(const std::size_t&) const = 0;
|
|
virtual std::size_t vector_size() const = 0;
|
|
};
|
|
|
|
class array_vector_impl : public vector_holder_base
|
|
{
|
|
public:
|
|
|
|
array_vector_impl(const Type* vec, const std::size_t& vec_size)
|
|
: vec_(vec),
|
|
size_(vec_size)
|
|
{}
|
|
|
|
protected:
|
|
|
|
value_ptr value_at(const std::size_t& index) const
|
|
{
|
|
if (index < size_)
|
|
return const_cast<const_value_ptr>(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 <typename Allocator,
|
|
template <typename,typename> class Sequence>
|
|
class sequence_vector_impl : public vector_holder_base
|
|
{
|
|
public:
|
|
|
|
typedef Sequence<Type,Allocator> sequence_t;
|
|
|
|
sequence_vector_impl(sequence_t& seq)
|
|
: sequence_(seq)
|
|
{}
|
|
|
|
protected:
|
|
|
|
value_ptr value_at(const std::size_t& index) const
|
|
{
|
|
return (index < sequence_.size()) ? (&sequence_[index]) : const_value_ptr(0);
|
|
}
|
|
|
|
std::size_t vector_size() const
|
|
{
|
|
return sequence_.size();
|
|
}
|
|
|
|
private:
|
|
|
|
sequence_vector_impl operator=(const sequence_vector_impl&);
|
|
|
|
sequence_t& sequence_;
|
|
};
|
|
|
|
public:
|
|
|
|
vector_holder(Type* vec, const std::size_t& vec_size)
|
|
: vector_holder_base_(new(buffer)array_vector_impl(vec,vec_size))
|
|
{}
|
|
|
|
template <typename Allocator>
|
|
vector_holder(std::vector<Type,Allocator>& vec)
|
|
: vector_holder_base_(new(buffer)sequence_vector_impl<Allocator,std::vector>(vec))
|
|
{}
|
|
|
|
template <typename Allocator>
|
|
vector_holder(std::deque<Type,Allocator>& deq)
|
|
: vector_holder_base_(new(buffer)sequence_vector_impl<Allocator,std::deque>(deq))
|
|
{}
|
|
|
|
inline value_ptr operator[](const std::size_t& index) const
|
|
{
|
|
return (*vector_holder_base_)[index];
|
|
}
|
|
|
|
inline std::size_t size() const
|
|
{
|
|
return vector_holder_base_->size();
|
|
}
|
|
|
|
private:
|
|
|
|
mutable vector_holder_base* vector_holder_base_;
|
|
unsigned char buffer[64];
|
|
};
|
|
|
|
template <typename T>
|
|
class null_node : public expression_node<T>
|
|
{
|
|
public:
|
|
|
|
inline T value() const
|
|
{
|
|
return std::numeric_limits<T>::quiet_NaN();
|
|
}
|
|
|
|
inline typename expression_node<T>::node_type type() const
|
|
{
|
|
return expression_node<T>::e_null;
|
|
}
|
|
};
|
|
|
|
template <typename T>
|
|
class null_eq_node : public expression_node<T>
|
|
{
|
|
public:
|
|
|
|
typedef expression_node<T>* expression_ptr;
|
|
|
|
null_eq_node(expression_ptr brnch, const bool equality = true)
|
|
: branch_(brnch),
|
|
branch_deletable_(branch_deletable(branch_)),
|
|
equality_(equality)
|
|
{}
|
|
|
|
~null_eq_node()
|
|
{
|
|
if (branch_ && branch_deletable_)
|
|
{
|
|
delete branch_;
|
|
branch_ = 0;
|
|
}
|
|
}
|
|
|
|
inline T value() const
|
|
{
|
|
const T v = branch_->value();
|
|
const bool result = details::numeric::is_nan(v);
|
|
|
|
if (result)
|
|
return (equality_) ? T(1) : T(0);
|
|
else
|
|
return (equality_) ? T(0) : T(1);
|
|
}
|
|
|
|
inline typename expression_node<T>::node_type type() const
|
|
{
|
|
return expression_node<T>::e_nulleq;
|
|
}
|
|
|
|
inline operator_type operation() const
|
|
{
|
|
return details::e_eq;
|
|
}
|
|
|
|
inline expression_node<T>* branch(const std::size_t&) const
|
|
{
|
|
return branch_;
|
|
}
|
|
|
|
private:
|
|
|
|
expression_ptr branch_;
|
|
bool branch_deletable_;
|
|
bool equality_;
|
|
};
|
|
|
|
template <typename T>
|
|
class literal_node : public expression_node<T>
|
|
{
|
|
public:
|
|
|
|
explicit literal_node(const T& v)
|
|
: value_(v)
|
|
{}
|
|
|
|
inline T value() const
|
|
{
|
|
return value_;
|
|
}
|
|
|
|
inline typename expression_node<T>::node_type type() const
|
|
{
|
|
return expression_node<T>::e_constant;
|
|
}
|
|
|
|
inline expression_node<T>* branch(const std::size_t&) const
|
|
{
|
|
return reinterpret_cast<expression_node<T>*>(0);
|
|
}
|
|
|
|
private:
|
|
|
|
literal_node(literal_node<T>&) {}
|
|
literal_node<T>& operator=(literal_node<T>&) { return *this; }
|
|
|
|
const T value_;
|
|
};
|
|
|
|
template <typename T>
|
|
struct range_pack;
|
|
|
|
template <typename T>
|
|
struct range_data_type;
|
|
|
|
template <typename T>
|
|
class range_interface
|
|
{
|
|
public:
|
|
|
|
typedef range_pack<T> range_t;
|
|
|
|
virtual range_t& range_ref() = 0;
|
|
|
|
virtual const range_t& range_ref() const = 0;
|
|
};
|
|
|
|
template <typename T>
|
|
class string_base_node
|
|
{
|
|
public:
|
|
|
|
typedef range_data_type<T> range_data_type_t;
|
|
|
|
virtual std::string str () const = 0;
|
|
|
|
virtual const char* base() const = 0;
|
|
|
|
virtual std::size_t size() const = 0;
|
|
};
|
|
|
|
template <typename T>
|
|
class string_literal_node : public expression_node <T>,
|
|
public string_base_node<T>,
|
|
public range_interface <T>
|
|
{
|
|
public:
|
|
|
|
typedef range_pack<T> range_t;
|
|
|
|
explicit string_literal_node(const std::string& v)
|
|
: value_(v)
|
|
{
|
|
rp_.n0_c = std::make_pair<bool,std::size_t>(true,0);
|
|
rp_.n1_c = std::make_pair<bool,std::size_t>(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<T>::quiet_NaN();
|
|
}
|
|
|
|
inline typename expression_node<T>::node_type type() const
|
|
{
|
|
return expression_node<T>::e_stringconst;
|
|
}
|
|
|
|
inline expression_node<T>* branch(const std::size_t&) const
|
|
{
|
|
return reinterpret_cast<expression_node<T>*>(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<T>&);
|
|
string_literal_node<T>& operator=(const string_literal_node<T>&);
|
|
|
|
const std::string value_;
|
|
range_t rp_;
|
|
};
|
|
|
|
template <typename T>
|
|
class unary_node : public expression_node<T>
|
|
{
|
|
public:
|
|
|
|
typedef expression_node<T>* expression_ptr;
|
|
|
|
unary_node(const operator_type& opr,
|
|
expression_ptr brnch)
|
|
: operation_(opr),
|
|
branch_(brnch),
|
|
branch_deletable_(branch_deletable(branch_))
|
|
{}
|
|
|
|
~unary_node()
|
|
{
|
|
if (branch_ && branch_deletable_)
|
|
{
|
|
delete branch_;
|
|
branch_ = 0;
|
|
}
|
|
}
|
|
|
|
inline T value() const
|
|
{
|
|
const T arg = branch_->value();
|
|
return numeric::process<T>(operation_,arg);
|
|
}
|
|
|
|
inline typename expression_node<T>::node_type type() const
|
|
{
|
|
return expression_node<T>::e_unary;
|
|
}
|
|
|
|
inline operator_type operation() const
|
|
{
|
|
return operation_;
|
|
}
|
|
|
|
inline expression_node<T>* 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 <typename T, std::size_t D, bool B>
|
|
struct construct_branch_pair
|
|
{
|
|
template <std::size_t N>
|
|
static inline void process(std::pair<expression_node<T>*,bool> (&)[N], expression_node<T>*)
|
|
{}
|
|
};
|
|
|
|
template <typename T, std::size_t D>
|
|
struct construct_branch_pair<T,D,true>
|
|
{
|
|
template <std::size_t N>
|
|
static inline void process(std::pair<expression_node<T>*,bool> (&branch)[N], expression_node<T>* b)
|
|
{
|
|
if (b)
|
|
{
|
|
branch[D] = std::make_pair(b,branch_deletable(b));
|
|
}
|
|
}
|
|
};
|
|
|
|
template <std::size_t N, typename T>
|
|
inline void init_branches(std::pair<expression_node<T>*,bool> (&branch)[N],
|
|
expression_node<T>* b0,
|
|
expression_node<T>* b1 = reinterpret_cast<expression_node<T>*>(0),
|
|
expression_node<T>* b2 = reinterpret_cast<expression_node<T>*>(0),
|
|
expression_node<T>* b3 = reinterpret_cast<expression_node<T>*>(0),
|
|
expression_node<T>* b4 = reinterpret_cast<expression_node<T>*>(0),
|
|
expression_node<T>* b5 = reinterpret_cast<expression_node<T>*>(0),
|
|
expression_node<T>* b6 = reinterpret_cast<expression_node<T>*>(0),
|
|
expression_node<T>* b7 = reinterpret_cast<expression_node<T>*>(0),
|
|
expression_node<T>* b8 = reinterpret_cast<expression_node<T>*>(0),
|
|
expression_node<T>* b9 = reinterpret_cast<expression_node<T>*>(0))
|
|
{
|
|
construct_branch_pair<T,0,(N > 0)>::process(branch,b0);
|
|
construct_branch_pair<T,1,(N > 1)>::process(branch,b1);
|
|
construct_branch_pair<T,2,(N > 2)>::process(branch,b2);
|
|
construct_branch_pair<T,3,(N > 3)>::process(branch,b3);
|
|
construct_branch_pair<T,4,(N > 4)>::process(branch,b4);
|
|
construct_branch_pair<T,5,(N > 5)>::process(branch,b5);
|
|
construct_branch_pair<T,6,(N > 6)>::process(branch,b6);
|
|
construct_branch_pair<T,7,(N > 7)>::process(branch,b7);
|
|
construct_branch_pair<T,8,(N > 8)>::process(branch,b8);
|
|
construct_branch_pair<T,9,(N > 9)>::process(branch,b9);
|
|
}
|
|
|
|
struct cleanup_branches
|
|
{
|
|
template <typename T, std::size_t N>
|
|
static inline void execute(std::pair<expression_node<T>*,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 <typename T,
|
|
typename Allocator,
|
|
template <typename,typename> class Sequence>
|
|
static inline void execute(Sequence<std::pair<expression_node<T>*,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 <typename T>
|
|
class binary_node : public expression_node<T>
|
|
{
|
|
public:
|
|
|
|
typedef expression_node<T>* expression_ptr;
|
|
typedef std::pair<expression_ptr,bool> 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<T,2>(branch_);
|
|
}
|
|
|
|
inline T value() const
|
|
{
|
|
const T arg0 = branch_[0].first->value();
|
|
const T arg1 = branch_[1].first->value();
|
|
return numeric::process<T>(operation_,arg0,arg1);
|
|
}
|
|
|
|
inline typename expression_node<T>::node_type type() const
|
|
{
|
|
return expression_node<T>::e_binary;
|
|
}
|
|
|
|
inline operator_type operation()
|
|
{
|
|
return operation_;
|
|
}
|
|
|
|
inline expression_node<T>* 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<expression_ptr>(0);
|
|
}
|
|
|
|
protected:
|
|
|
|
operator_type operation_;
|
|
branch_t branch_[2];
|
|
};
|
|
|
|
template <typename T, typename Operation>
|
|
class binary_ext_node : public expression_node<T>
|
|
{
|
|
public:
|
|
|
|
typedef expression_node<T>* expression_ptr;
|
|
typedef std::pair<expression_ptr,bool> branch_t;
|
|
|
|
binary_ext_node(expression_ptr branch0, expression_ptr branch1)
|
|
{
|
|
init_branches<2>(branch_,branch0,branch1);
|
|
}
|
|
|
|
~binary_ext_node()
|
|
{
|
|
cleanup_branches::execute<T,2>(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<T>::node_type type() const
|
|
{
|
|
return expression_node<T>::e_binary_ext;
|
|
}
|
|
|
|
inline operator_type operation()
|
|
{
|
|
return Operation::operation();
|
|
}
|
|
|
|
inline expression_node<T>* 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<expression_ptr>(0);
|
|
}
|
|
|
|
protected:
|
|
|
|
branch_t branch_[2];
|
|
};
|
|
|
|
template <typename T>
|
|
class trinary_node : public expression_node<T>
|
|
{
|
|
public:
|
|
|
|
typedef expression_node<T>* expression_ptr;
|
|
typedef std::pair<expression_ptr,bool> 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<T,3>(branch_);
|
|
}
|
|
|
|
inline T value() const
|
|
{
|
|
const T arg0 = branch_[0].first->value();
|
|
const T arg1 = branch_[1].first->value();
|
|
const T arg2 = branch_[2].first->value();
|
|
|
|
switch (operation_)
|
|
{
|
|
case e_inrange : return (arg1 < arg0) ? T(0) : ((arg1 > arg2) ? T(0) : T(1));
|
|
case e_min : return std::min<T>(std::min<T>(arg0,arg1),arg2);
|
|
case e_max : return std::max<T>(std::max<T>(arg0,arg1),arg2);
|
|
case e_clamp : return (arg1 < arg0) ? arg0 : (arg1 > arg2 ? arg2 : arg1);
|
|
case e_iclamp : if ((arg1 <= arg0) || (arg1 >= arg2))
|
|
return arg1;
|
|
else
|
|
return ((T(2) * arg1 <= (arg2 + arg0)) ? arg0 : arg2);
|
|
default : return std::numeric_limits<T>::quiet_NaN();
|
|
}
|
|
}
|
|
|
|
inline typename expression_node<T>::node_type type() const
|
|
{
|
|
return expression_node<T>::e_trinary;
|
|
}
|
|
|
|
protected:
|
|
|
|
operator_type operation_;
|
|
branch_t branch_[3];
|
|
};
|
|
|
|
template <typename T>
|
|
class quaternary_node : public expression_node<T>
|
|
{
|
|
public:
|
|
|
|
typedef expression_node<T>* expression_ptr;
|
|
typedef std::pair<expression_ptr,bool> 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<T,4>(branch_);
|
|
}
|
|
|
|
inline T value() const
|
|
{
|
|
const T arg0 = branch_[0].first->value();
|
|
const T arg1 = branch_[1].first->value();
|
|
const T arg2 = branch_[2].first->value();
|
|
const T arg3 = branch_[3].first->value();
|
|
|
|
switch (operation_)
|
|
{
|
|
case e_min : return std::min<T>(std::min<T>(arg0,arg1),std::min<T>(arg2,arg3));
|
|
case e_max : return std::max<T>(std::max<T>(arg0,arg1),std::max<T>(arg2,arg3));
|
|
default : return std::numeric_limits<T>::quiet_NaN();
|
|
}
|
|
}
|
|
|
|
inline typename expression_node<T>::node_type type() const
|
|
{
|
|
return expression_node<T>::e_quaternary;
|
|
}
|
|
|
|
protected:
|
|
|
|
operator_type operation_;
|
|
branch_t branch_[4];
|
|
};
|
|
|
|
template <typename T>
|
|
class quinary_node : public expression_node<T>
|
|
{
|
|
public:
|
|
|
|
typedef expression_node<T>* expression_ptr;
|
|
typedef std::pair<expression_ptr,bool> branch_t;
|
|
|
|
quinary_node(const operator_type& opr,
|
|
expression_ptr branch0,
|
|
expression_ptr branch1,
|
|
expression_ptr branch2,
|
|
expression_ptr branch3,
|
|
expression_ptr branch4)
|
|
: operation_(opr)
|
|
{
|
|
init_branches<5>(branch_,branch0,branch1,branch2,branch3,branch4);
|
|
}
|
|
|
|
~quinary_node()
|
|
{
|
|
cleanup_branches::execute<T,5>(branch_);
|
|
}
|
|
|
|
inline T value() const
|
|
{
|
|
const T arg0 = branch_[0].first->value();
|
|
const T arg1 = branch_[1].first->value();
|
|
const T arg2 = branch_[2].first->value();
|
|
const T arg3 = branch_[3].first->value();
|
|
const T arg4 = branch_[4].first->value();
|
|
|
|
switch (operation_)
|
|
{
|
|
case e_min : return std::min<T>(std::min<T>(std::min<T>(arg0,arg1),std::min<T>(arg2,arg3)),arg4);
|
|
case e_max : return std::max<T>(std::max<T>(std::max<T>(arg0,arg1),std::max<T>(arg2,arg3)),arg4);
|
|
default : return std::numeric_limits<T>::quiet_NaN();
|
|
}
|
|
}
|
|
|
|
inline typename expression_node<T>::node_type type() const
|
|
{
|
|
return expression_node<T>::e_quinary;
|
|
}
|
|
|
|
private:
|
|
|
|
operator_type operation_;
|
|
branch_t branch_[5];
|
|
};
|
|
|
|
template <typename T>
|
|
class senary_node : public expression_node<T>
|
|
{
|
|
public:
|
|
|
|
typedef expression_node<T>* expression_ptr;
|
|
typedef std::pair<expression_ptr,bool> branch_t;
|
|
|
|
senary_node(const operator_type& opr,
|
|
expression_ptr branch0,
|
|
expression_ptr branch1,
|
|
expression_ptr branch2,
|
|
expression_ptr branch3,
|
|
expression_ptr branch4,
|
|
expression_ptr branch5)
|
|
: operation_(opr)
|
|
{
|
|
init_branches<6>(branch_,branch0,branch1,branch2,branch3,branch4,branch5);
|
|
}
|
|
|
|
~senary_node()
|
|
{
|
|
cleanup_branches::execute<T,6>(branch_);
|
|
}
|
|
|
|
inline T value() const
|
|
{
|
|
const T arg0 = branch_[0].first->value();
|
|
const T arg1 = branch_[1].first->value();
|
|
const T arg2 = branch_[2].first->value();
|
|
const T arg3 = branch_[3].first->value();
|
|
const T arg4 = branch_[4].first->value();
|
|
const T arg5 = branch_[5].first->value();
|
|
|
|
switch (operation_)
|
|
{
|
|
case e_min : return std::min<T>(std::min<T>(std::min<T>(arg0,arg1),std::min<T>(arg2,arg3)),std::min<T>(arg4,arg5));
|
|
case e_max : return std::max<T>(std::max<T>(std::max<T>(arg0,arg1),std::max<T>(arg2,arg3)),std::max<T>(arg4,arg5));
|
|
case e_default :
|
|
default : return std::numeric_limits<T>::quiet_NaN();
|
|
}
|
|
}
|
|
|
|
inline typename expression_node<T>::node_type type() const
|
|
{
|
|
return expression_node<T>::e_senary;
|
|
}
|
|
|
|
private:
|
|
|
|
operator_type operation_;
|
|
branch_t branch_[6];
|
|
};
|
|
|
|
template <typename T>
|
|
class conditional_node : public expression_node<T>
|
|
{
|
|
public:
|
|
|
|
typedef expression_node<T>* 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<T>::node_type type() const
|
|
{
|
|
return expression_node<T>::e_conditional;
|
|
}
|
|
|
|
private:
|
|
|
|
expression_ptr test_;
|
|
expression_ptr consequent_;
|
|
expression_ptr alternative_;
|
|
bool test_deletable_;
|
|
bool consequent_deletable_;
|
|
bool alternative_deletable_;
|
|
};
|
|
|
|
template <typename T>
|
|
class cons_conditional_node : public expression_node<T>
|
|
{
|
|
public:
|
|
|
|
// Consequent only conditional statement node
|
|
typedef expression_node<T>* 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<T>::quiet_NaN();
|
|
}
|
|
|
|
inline typename expression_node<T>::node_type type() const
|
|
{
|
|
return expression_node<T>::e_conditional;
|
|
}
|
|
|
|
private:
|
|
|
|
expression_ptr test_;
|
|
expression_ptr consequent_;
|
|
bool test_deletable_;
|
|
bool consequent_deletable_;
|
|
};
|
|
|
|
#ifndef exprtk_disable_break_continue
|
|
template <typename T>
|
|
class break_exception : public std::exception
|
|
{
|
|
public:
|
|
|
|
break_exception(const T& v)
|
|
: value(v)
|
|
{}
|
|
|
|
T value;
|
|
};
|
|
|
|
class continue_exception : public std::exception
|
|
{};
|
|
|
|
template <typename T>
|
|
class break_node : public expression_node<T>
|
|
{
|
|
public:
|
|
|
|
typedef expression_node<T>* 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<T>(return_ ? return_->value() : std::numeric_limits<T>::quiet_NaN());
|
|
#ifndef _MSC_VER
|
|
return std::numeric_limits<T>::quiet_NaN();
|
|
#endif
|
|
}
|
|
|
|
inline typename expression_node<T>::node_type type() const
|
|
{
|
|
return expression_node<T>::e_break;
|
|
}
|
|
|
|
private:
|
|
|
|
expression_ptr return_;
|
|
bool return_deletable_;
|
|
};
|
|
|
|
template <typename T>
|
|
class continue_node : public expression_node<T>
|
|
{
|
|
public:
|
|
|
|
inline T value() const
|
|
{
|
|
throw continue_exception();
|
|
#ifndef _MSC_VER
|
|
return std::numeric_limits<T>::quiet_NaN();
|
|
#endif
|
|
}
|
|
|
|
inline typename expression_node<T>::node_type type() const
|
|
{
|
|
return expression_node<T>::e_break;
|
|
}
|
|
};
|
|
#endif
|
|
|
|
template <typename T>
|
|
class while_loop_node : public expression_node<T>
|
|
{
|
|
public:
|
|
|
|
typedef expression_node<T>* 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<T>::node_type type() const
|
|
{
|
|
return expression_node<T>::e_while;
|
|
}
|
|
|
|
private:
|
|
|
|
expression_ptr condition_;
|
|
expression_ptr loop_body_;
|
|
bool condition_deletable_;
|
|
bool loop_body_deletable_;
|
|
};
|
|
|
|
template <typename T>
|
|
class repeat_until_loop_node : public expression_node<T>
|
|
{
|
|
public:
|
|
|
|
typedef expression_node<T>* 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<T>::node_type type() const
|
|
{
|
|
return expression_node<T>::e_repeat;
|
|
}
|
|
|
|
private:
|
|
|
|
expression_ptr condition_;
|
|
expression_ptr loop_body_;
|
|
bool condition_deletable_;
|
|
bool loop_body_deletable_;
|
|
};
|
|
|
|
template <typename T>
|
|
class for_loop_node : public expression_node<T>
|
|
{
|
|
public:
|
|
|
|
typedef expression_node<T>* 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<T>::node_type type() const
|
|
{
|
|
return expression_node<T>::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 <typename T>
|
|
class while_loop_bc_node : public expression_node<T>
|
|
{
|
|
public:
|
|
|
|
typedef expression_node<T>* 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<T>& e)
|
|
{
|
|
return e.value;
|
|
}
|
|
catch(const continue_exception&)
|
|
{}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
inline typename expression_node<T>::node_type type() const
|
|
{
|
|
return expression_node<T>::e_while;
|
|
}
|
|
|
|
private:
|
|
|
|
expression_ptr condition_;
|
|
expression_ptr loop_body_;
|
|
bool condition_deletable_;
|
|
bool loop_body_deletable_;
|
|
};
|
|
|
|
template <typename T>
|
|
class repeat_until_loop_bc_node : public expression_node<T>
|
|
{
|
|
public:
|
|
|
|
typedef expression_node<T>* 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<T>& e)
|
|
{
|
|
return e.value;
|
|
}
|
|
catch(const continue_exception&)
|
|
{}
|
|
}
|
|
while (is_false(condition_));
|
|
|
|
return result;
|
|
}
|
|
|
|
inline typename expression_node<T>::node_type type() const
|
|
{
|
|
return expression_node<T>::e_repeat;
|
|
}
|
|
|
|
private:
|
|
|
|
expression_ptr condition_;
|
|
expression_ptr loop_body_;
|
|
bool condition_deletable_;
|
|
bool loop_body_deletable_;
|
|
};
|
|
|
|
template <typename T>
|
|
class for_loop_bc_node : public expression_node<T>
|
|
{
|
|
public:
|
|
|
|
typedef expression_node<T>* 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<T>& e)
|
|
{
|
|
return e.value;
|
|
}
|
|
catch(const continue_exception&)
|
|
{}
|
|
|
|
incrementor_->value();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
while (is_true(condition_))
|
|
{
|
|
try
|
|
{
|
|
result = loop_body_->value();
|
|
}
|
|
catch(const break_exception<T>& e)
|
|
{
|
|
return e.value;
|
|
}
|
|
catch(const continue_exception&)
|
|
{}
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
inline typename expression_node<T>::node_type type() const
|
|
{
|
|
return expression_node<T>::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 <typename T>
|
|
class switch_node : public expression_node<T>
|
|
{
|
|
public:
|
|
|
|
typedef expression_node<T>* expression_ptr;
|
|
|
|
template <typename Allocator,
|
|
template <typename,typename> class Sequence>
|
|
switch_node(const Sequence<expression_ptr,Allocator>& 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<unsigned char>(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<T>::quiet_NaN();
|
|
}
|
|
|
|
inline typename expression_node<T>::node_type type() const
|
|
{
|
|
return expression_node<T>::e_switch;
|
|
}
|
|
|
|
private:
|
|
|
|
std::vector<expression_ptr> arg_list_;
|
|
std::vector<unsigned char> delete_branch_;
|
|
};
|
|
|
|
template <typename T>
|
|
class multi_switch_node : public expression_node<T>
|
|
{
|
|
public:
|
|
|
|
typedef expression_node<T>* expression_ptr;
|
|
|
|
template <typename Allocator,
|
|
template <typename,typename> class Sequence>
|
|
multi_switch_node(const Sequence<expression_ptr,Allocator>& 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<unsigned char>(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<T>::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<T>::node_type type() const
|
|
{
|
|
return expression_node<T>::e_mswitch;
|
|
}
|
|
|
|
private:
|
|
|
|
std::vector<expression_ptr> arg_list_;
|
|
std::vector<unsigned char> delete_branch_;
|
|
};
|
|
|
|
template <typename T>
|
|
class ivariable
|
|
{
|
|
public:
|
|
|
|
virtual T& ref() = 0;
|
|
virtual const T& ref() const = 0;
|
|
};
|
|
|
|
template <typename T>
|
|
class variable_node : public expression_node<T>,
|
|
public ivariable<T>
|
|
{
|
|
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<T>& 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<T>::node_type type() const
|
|
{
|
|
return expression_node<T>::e_variable;
|
|
}
|
|
|
|
inline bool& delete_value()
|
|
{
|
|
return delete_value_;
|
|
}
|
|
|
|
private:
|
|
|
|
T* value_;
|
|
bool delete_value_;
|
|
};
|
|
|
|
template <typename T>
|
|
T variable_node<T>::null_value = T(std::numeric_limits<T>::quiet_NaN());
|
|
|
|
template <typename T>
|
|
struct range_pack
|
|
{
|
|
typedef expression_node<T>* expression_node_ptr;
|
|
typedef std::pair<std::size_t,std::size_t> 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<std::size_t>::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<std::size_t>(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<std::size_t>(details::numeric::to_int64(r1_value));
|
|
}
|
|
else
|
|
return false;
|
|
|
|
if (
|
|
(std::numeric_limits<std::size_t>::max() != size) &&
|
|
(std::numeric_limits<std::size_t>::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<bool,expression_node_ptr> n0_e;
|
|
std::pair<bool,expression_node_ptr> n1_e;
|
|
std::pair<bool,std::size_t > n0_c;
|
|
std::pair<bool,std::size_t > n1_c;
|
|
mutable cached_range_t cache;
|
|
};
|
|
|
|
template <typename T>
|
|
class string_base_node;
|
|
|
|
template <typename T>
|
|
struct range_data_type
|
|
{
|
|
typedef range_pack<T> range_t;
|
|
typedef string_base_node<T>* 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 <typename T> class vector_node;
|
|
|
|
template <typename T>
|
|
class vector_interface
|
|
{
|
|
public:
|
|
|
|
typedef vector_node<T>* vector_node_ptr;
|
|
|
|
virtual ~vector_interface()
|
|
{}
|
|
|
|
virtual vector_node_ptr vec() const = 0;
|
|
|
|
virtual vector_node_ptr vec() = 0;
|
|
|
|
virtual std::size_t size() const = 0;
|
|
};
|
|
|
|
template <typename T>
|
|
class vector_node : public expression_node<T>,
|
|
public vector_interface<T>
|
|
{
|
|
public:
|
|
|
|
typedef expression_node<T>* expression_ptr;
|
|
typedef vector_holder<T> vector_holder_t;
|
|
typedef vector_node<T>* vector_node_ptr;
|
|
|
|
vector_node(vector_holder_t* vh)
|
|
: vector_holder_(vh)
|
|
{}
|
|
|
|
inline T value() const
|
|
{
|
|
return *(ref()[0]);
|
|
}
|
|
|
|
inline const vector_holder_t& ref() const
|
|
{
|
|
return (*vector_holder_);
|
|
}
|
|
|
|
inline vector_holder_t& ref()
|
|
{
|
|
return (*vector_holder_);
|
|
}
|
|
|
|
vector_node_ptr vec() const
|
|
{
|
|
return const_cast<vector_node_ptr>(this);
|
|
}
|
|
|
|
vector_node_ptr vec()
|
|
{
|
|
return this;
|
|
}
|
|
|
|
inline typename expression_node<T>::node_type type() const
|
|
{
|
|
return expression_node<T>::e_vector;
|
|
}
|
|
|
|
std::size_t size() const
|
|
{
|
|
return ref().size();
|
|
}
|
|
|
|
private:
|
|
|
|
vector_holder_t* vector_holder_;
|
|
};
|
|
|
|
template <typename T>
|
|
class vector_elem_node : public expression_node<T>,
|
|
public ivariable<T>
|
|
{
|
|
public:
|
|
|
|
typedef expression_node<T>* expression_ptr;
|
|
|
|
vector_elem_node(expression_ptr index, T* vector_base)
|
|
: index_(index),
|
|
vector_base_(vector_base),
|
|
index_deletable_(branch_deletable(index_))
|
|
{}
|
|
|
|
~vector_elem_node()
|
|
{
|
|
if (index_ && index_deletable_)
|
|
{
|
|
delete index_;
|
|
}
|
|
}
|
|
|
|
inline T value() const
|
|
{
|
|
return *(vector_base_ + static_cast<std::size_t>(details::numeric::to_int64(index_->value())));
|
|
}
|
|
|
|
inline T& ref()
|
|
{
|
|
return *(vector_base_ + static_cast<std::size_t>(details::numeric::to_int64(index_->value())));
|
|
}
|
|
|
|
inline const T& ref() const
|
|
{
|
|
return *(vector_base_ + static_cast<std::size_t>(details::numeric::to_int64(index_->value())));
|
|
}
|
|
|
|
inline typename expression_node<T>::node_type type() const
|
|
{
|
|
return expression_node<T>::e_vecelem;
|
|
}
|
|
|
|
private:
|
|
|
|
expression_ptr index_;
|
|
T* vector_base_;
|
|
bool index_deletable_;
|
|
};
|
|
|
|
template <typename T>
|
|
class vector_assignment_node : public expression_node<T>
|
|
{
|
|
public:
|
|
|
|
typedef expression_node<T>* expression_ptr;
|
|
|
|
vector_assignment_node(T* vector_base,
|
|
const std::size_t& size,
|
|
const std::vector<expression_ptr>& 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<T>::node_type type() const
|
|
{
|
|
return expression_node<T>::e_vecdefass;
|
|
}
|
|
|
|
private:
|
|
|
|
vector_assignment_node<T>& operator=(const vector_assignment_node<T>&);
|
|
|
|
mutable T* vector_base_;
|
|
std::vector<expression_ptr> initialiser_list_;
|
|
const std::size_t size_;
|
|
const bool single_value_initialse_;
|
|
};
|
|
|
|
template <typename T>
|
|
class swap_node : public expression_node<T>
|
|
{
|
|
public:
|
|
|
|
typedef expression_node<T>* expression_ptr;
|
|
typedef variable_node<T>* 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<T>::node_type type() const
|
|
{
|
|
return expression_node<T>::e_swap;
|
|
}
|
|
|
|
private:
|
|
|
|
variable_node_ptr var0_;
|
|
variable_node_ptr var1_;
|
|
};
|
|
|
|
template <typename T>
|
|
class swap_generic_node : public binary_node<T>
|
|
{
|
|
public:
|
|
|
|
typedef expression_node<T>* expression_ptr;
|
|
typedef ivariable<T>* ivariable_ptr;
|
|
|
|
swap_generic_node(expression_ptr var0, expression_ptr var1)
|
|
: binary_node<T>(details::e_swap,var0,var1),
|
|
var0_(dynamic_cast<ivariable_ptr>(var0)),
|
|
var1_(dynamic_cast<ivariable_ptr>(var1))
|
|
{}
|
|
|
|
inline T value() const
|
|
{
|
|
std::swap(var0_->ref(),var1_->ref());
|
|
return var1_->ref();
|
|
}
|
|
|
|
inline typename expression_node<T>::node_type type() const
|
|
{
|
|
return expression_node<T>::e_swap;
|
|
}
|
|
|
|
private:
|
|
|
|
ivariable_ptr var0_;
|
|
ivariable_ptr var1_;
|
|
};
|
|
|
|
template <typename T>
|
|
class swap_vecvec_node : public binary_node<T>,
|
|
public vector_interface<T>
|
|
{
|
|
public:
|
|
|
|
typedef expression_node<T>* expression_ptr;
|
|
typedef vector_node<T>* vector_node_ptr;
|
|
|
|
swap_vecvec_node(expression_ptr branch0,
|
|
expression_ptr branch1)
|
|
: binary_node<T>(details::e_swap,branch0,branch1),
|
|
vec0_node_ptr_(0),
|
|
vec1_node_ptr_(0),
|
|
vec_size_ (0)
|
|
{
|
|
if (is_ivector_node(binary_node<T>::branch_[0].first))
|
|
{
|
|
vector_interface<T>* vi = reinterpret_cast<vector_interface<T>*>(0);
|
|
|
|
if ((vi = dynamic_cast<vector_interface<T>*>(binary_node<T>::branch_[0].first)))
|
|
{
|
|
vec0_node_ptr_ = vi->vec();
|
|
}
|
|
}
|
|
|
|
if (is_ivector_node(binary_node<T>::branch_[1].first))
|
|
{
|
|
vector_interface<T>* vi = reinterpret_cast<vector_interface<T>*>(0);
|
|
|
|
if ((vi = dynamic_cast<vector_interface<T>*>(binary_node<T>::branch_[1].first)))
|
|
{
|
|
vec1_node_ptr_ = vi->vec();
|
|
}
|
|
}
|
|
|
|
if (vec0_node_ptr_ && vec1_node_ptr_)
|
|
{
|
|
vec_size_ = std::min(vec0_node_ptr_->ref().size(),
|
|
vec1_node_ptr_->ref().size());
|
|
}
|
|
}
|
|
|
|
inline T value() const
|
|
{
|
|
if (vec0_node_ptr_ && vec1_node_ptr_)
|
|
{
|
|
binary_node<T>::branch_[0].first->value();
|
|
binary_node<T>::branch_[1].first->value();
|
|
|
|
vector_holder<T>& vec0 = vec0_node_ptr_->ref();
|
|
vector_holder<T>& vec1 = vec1_node_ptr_->ref();
|
|
|
|
for (std::size_t i = 0; i < vec_size_; ++i)
|
|
{
|
|
std::swap((*vec0[i]),(*vec1[i]));
|
|
}
|
|
|
|
return vec1_node_ptr_->value();
|
|
}
|
|
else
|
|
return std::numeric_limits<T>::quiet_NaN();
|
|
}
|
|
|
|
vector_node_ptr vec() const
|
|
{
|
|
return vec0_node_ptr_;
|
|
}
|
|
|
|
vector_node_ptr vec()
|
|
{
|
|
return vec0_node_ptr_;
|
|
}
|
|
|
|
inline typename expression_node<T>::node_type type() const
|
|
{
|
|
return expression_node<T>::e_vecvecswap;
|
|
}
|
|
|
|
std::size_t size() const
|
|
{
|
|
return vec_size_;
|
|
}
|
|
|
|
private:
|
|
|
|
vector_node<T>* vec0_node_ptr_;
|
|
vector_node<T>* vec1_node_ptr_;
|
|
std::size_t vec_size_;
|
|
};
|
|
|
|
#ifndef exprtk_disable_string_capabilities
|
|
template <typename T>
|
|
class stringvar_node : public expression_node <T>,
|
|
public string_base_node<T>,
|
|
public range_interface <T>
|
|
{
|
|
public:
|
|
|
|
typedef range_pack<T> range_t;
|
|
|
|
static std::string null_value;
|
|
|
|
explicit stringvar_node()
|
|
: value_(&null_value)
|
|
{}
|
|
|
|
explicit stringvar_node(std::string& v)
|
|
: value_(&v)
|
|
{
|
|
rp_.n0_c = std::make_pair<bool,std::size_t>(true,0);
|
|
rp_.n1_c = std::make_pair<bool,std::size_t>(true,v.size() - 1);
|
|
rp_.cache.first = rp_.n0_c.second;
|
|
rp_.cache.second = rp_.n1_c.second;
|
|
}
|
|
|
|
inline bool operator <(const stringvar_node<T>& 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<T>::quiet_NaN();
|
|
}
|
|
|
|
std::string str() const
|
|
{
|
|
return ref();
|
|
}
|
|
|
|
const char* base() const
|
|
{
|
|
return (*value_).data();
|
|
}
|
|
|
|
std::size_t size() const
|
|
{
|
|
return ref().size();
|
|
}
|
|
|
|
std::string& ref()
|
|
{
|
|
return (*value_);
|
|
}
|
|
|
|
const std::string& ref() const
|
|
{
|
|
return (*value_);
|
|
}
|
|
|
|
range_t& range_ref()
|
|
{
|
|
return rp_;
|
|
}
|
|
|
|
const range_t& range_ref() const
|
|
{
|
|
return rp_;
|
|
}
|
|
|
|
inline typename expression_node<T>::node_type type() const
|
|
{
|
|
return expression_node<T>::e_stringvar;
|
|
}
|
|
|
|
private:
|
|
|
|
std::string* value_;
|
|
mutable range_t rp_;
|
|
};
|
|
|
|
template <typename T>
|
|
std::string stringvar_node<T>::null_value = std::string("");
|
|
|
|
template <typename T>
|
|
class string_range_node : public expression_node <T>,
|
|
public string_base_node<T>,
|
|
public range_interface <T>
|
|
{
|
|
public:
|
|
|
|
typedef range_pack<T> range_t;
|
|
|
|
static std::string null_value;
|
|
|
|
explicit string_range_node(std::string& v, range_t rp)
|
|
: value_(&v),
|
|
rp_(rp)
|
|
{}
|
|
|
|
~string_range_node()
|
|
{
|
|
rp_.free();
|
|
}
|
|
|
|
inline bool operator <(const string_range_node<T>& v) const
|
|
{
|
|
return this < (&v);
|
|
}
|
|
|
|
inline T value() const
|
|
{
|
|
return std::numeric_limits<T>::quiet_NaN();
|
|
}
|
|
|
|
inline std::string str() const
|
|
{
|
|
return (*value_);
|
|
}
|
|
|
|
const char* base() const
|
|
{
|
|
return (*value_).data();
|
|
}
|
|
|
|
std::size_t size() const
|
|
{
|
|
return ref().size();
|
|
}
|
|
|
|
inline range_t range() const
|
|
{
|
|
return rp_;
|
|
}
|
|
|
|
inline virtual std::string& ref()
|
|
{
|
|
return (*value_);
|
|
}
|
|
|
|
inline virtual const std::string& ref() const
|
|
{
|
|
return (*value_);
|
|
}
|
|
|
|
inline range_t& range_ref()
|
|
{
|
|
return rp_;
|
|
}
|
|
|
|
inline const range_t& range_ref() const
|
|
{
|
|
return rp_;
|
|
}
|
|
|
|
inline typename expression_node<T>::node_type type() const
|
|
{
|
|
return expression_node<T>::e_stringvarrng;
|
|
}
|
|
|
|
private:
|
|
|
|
std::string* value_;
|
|
range_t rp_;
|
|
};
|
|
|
|
template <typename T>
|
|
std::string string_range_node<T>::null_value = std::string("");
|
|
|
|
template <typename T>
|
|
class const_string_range_node : public expression_node <T>,
|
|
public string_base_node<T>,
|
|
public range_interface <T>
|
|
{
|
|
public:
|
|
|
|
typedef range_pack<T> range_t;
|
|
|
|
explicit const_string_range_node(const std::string& v, range_t rp)
|
|
: value_(v),
|
|
rp_(rp)
|
|
{}
|
|
|
|
~const_string_range_node()
|
|
{
|
|
rp_.free();
|
|
}
|
|
|
|
inline T value() const
|
|
{
|
|
return std::numeric_limits<T>::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<T>::node_type type() const
|
|
{
|
|
return expression_node<T>::e_cstringvarrng;
|
|
}
|
|
|
|
private:
|
|
|
|
const_string_range_node<T>& operator=(const const_string_range_node<T>&);
|
|
|
|
const std::string value_;
|
|
range_t rp_;
|
|
};
|
|
|
|
template <typename T>
|
|
class generic_string_range_node : public expression_node <T>,
|
|
public string_base_node<T>,
|
|
public range_interface <T>
|
|
{
|
|
public:
|
|
|
|
typedef expression_node <T>* expression_ptr;
|
|
typedef stringvar_node <T>* strvar_node_ptr;
|
|
typedef string_base_node<T>* str_base_ptr;
|
|
typedef range_pack <T> range_t;
|
|
typedef range_t* range_ptr;
|
|
typedef range_interface<T> irange_t;
|
|
typedef irange_t* irange_ptr;
|
|
typedef typename range_t::cached_range_t cached_range_t;
|
|
|
|
generic_string_range_node(expression_ptr str_branch, range_t brange)
|
|
: initialised_(false),
|
|
branch_(str_branch),
|
|
branch_deletable_(branch_deletable(branch_)),
|
|
str_base_ptr_ (0),
|
|
str_range_ptr_(0),
|
|
base_range_(brange)
|
|
{
|
|
range_.n0_c = std::make_pair<bool,std::size_t>(true,0);
|
|
range_.n1_c = std::make_pair<bool,std::size_t>(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<str_base_ptr>(branch_);
|
|
|
|
if (0 == str_base_ptr_)
|
|
return;
|
|
|
|
str_range_ptr_ = dynamic_cast<irange_ptr>(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<T>::quiet_NaN();
|
|
}
|
|
|
|
std::string str() const
|
|
{
|
|
return value_;
|
|
}
|
|
|
|
const char* base() const
|
|
{
|
|
return value_.data();
|
|
}
|
|
|
|
std::size_t size() const
|
|
{
|
|
return value_.size();
|
|
}
|
|
|
|
range_t& range_ref()
|
|
{
|
|
return range_;
|
|
}
|
|
|
|
const range_t& range_ref() const
|
|
{
|
|
return range_;
|
|
}
|
|
|
|
inline typename expression_node<T>::node_type type() const
|
|
{
|
|
return expression_node<T>::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 <typename T>
|
|
class string_concat_node : public binary_node <T>,
|
|
public string_base_node<T>,
|
|
public range_interface <T>
|
|
{
|
|
public:
|
|
|
|
typedef expression_node <T>* expression_ptr;
|
|
typedef stringvar_node <T>* strvar_node_ptr;
|
|
typedef string_base_node<T>* str_base_ptr;
|
|
typedef range_pack <T> range_t;
|
|
typedef range_t* range_ptr;
|
|
typedef range_interface<T> irange_t;
|
|
typedef irange_t* irange_ptr;
|
|
typedef typename range_t::cached_range_t cached_range_t;
|
|
|
|
string_concat_node(const operator_type& opr,
|
|
expression_ptr branch0,
|
|
expression_ptr branch1)
|
|
: binary_node<T>(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<bool,std::size_t>(true,0);
|
|
range_.n1_c = std::make_pair<bool,std::size_t>(true,0);
|
|
range_.cache.first = range_.n0_c.second;
|
|
range_.cache.second = range_.n1_c.second;
|
|
|
|
if (is_generally_string_node(binary_node<T>::branch_[0].first))
|
|
{
|
|
str0_base_ptr_ = dynamic_cast<str_base_ptr>(binary_node<T>::branch_[0].first);
|
|
|
|
if (0 == str0_base_ptr_)
|
|
return;
|
|
|
|
str0_range_ptr_ = dynamic_cast<irange_ptr>(binary_node<T>::branch_[0].first);
|
|
|
|
if (0 == str0_range_ptr_)
|
|
return;
|
|
}
|
|
|
|
if (is_generally_string_node(binary_node<T>::branch_[1].first))
|
|
{
|
|
str1_base_ptr_ = dynamic_cast<str_base_ptr>(binary_node<T>::branch_[1].first);
|
|
|
|
if (0 == str1_base_ptr_)
|
|
return;
|
|
|
|
str1_range_ptr_ = dynamic_cast<irange_ptr>(binary_node<T>::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<T>::branch_[0].first->value();
|
|
binary_node<T>::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<T>::quiet_NaN();
|
|
}
|
|
|
|
std::string str() const
|
|
{
|
|
return value_;
|
|
}
|
|
|
|
const char* base() const
|
|
{
|
|
return value_.data();
|
|
}
|
|
|
|
std::size_t size() const
|
|
{
|
|
return value_.size();
|
|
}
|
|
|
|
range_t& range_ref()
|
|
{
|
|
return range_;
|
|
}
|
|
|
|
const range_t& range_ref() const
|
|
{
|
|
return range_;
|
|
}
|
|
|
|
inline typename expression_node<T>::node_type type() const
|
|
{
|
|
return expression_node<T>::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 <typename T>
|
|
class swap_string_node : public binary_node <T>,
|
|
public string_base_node<T>,
|
|
public range_interface <T>
|
|
{
|
|
public:
|
|
|
|
typedef expression_node <T>* expression_ptr;
|
|
typedef stringvar_node <T>* strvar_node_ptr;
|
|
typedef string_base_node<T>* str_base_ptr;
|
|
typedef range_pack <T> range_t;
|
|
typedef range_t* range_ptr;
|
|
typedef range_interface<T> irange_t;
|
|
typedef irange_t* irange_ptr;
|
|
typedef typename range_t::cached_range_t cached_range_t;
|
|
|
|
swap_string_node(expression_ptr branch0, expression_ptr branch1)
|
|
: binary_node<T>(details::e_swap,branch0,branch1),
|
|
initialised_(false),
|
|
str0_node_ptr_(0),
|
|
str1_node_ptr_(0)
|
|
{
|
|
if (is_string_node(binary_node<T>::branch_[0].first))
|
|
{
|
|
str0_node_ptr_ = static_cast<strvar_node_ptr>(binary_node<T>::branch_[0].first);
|
|
}
|
|
|
|
if (is_string_node(binary_node<T>::branch_[1].first))
|
|
{
|
|
str1_node_ptr_ = static_cast<strvar_node_ptr>(binary_node<T>::branch_[1].first);
|
|
}
|
|
|
|
initialised_ = (str0_node_ptr_ && str1_node_ptr_);
|
|
}
|
|
|
|
inline T value() const
|
|
{
|
|
if (initialised_)
|
|
{
|
|
binary_node<T>::branch_[0].first->value();
|
|
binary_node<T>::branch_[1].first->value();
|
|
|
|
std::swap(str0_node_ptr_->ref(),str1_node_ptr_->ref());
|
|
}
|
|
|
|
return std::numeric_limits<T>::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<T>::node_type type() const
|
|
{
|
|
return expression_node<T>::e_strswap;
|
|
}
|
|
|
|
private:
|
|
|
|
bool initialised_;
|
|
strvar_node_ptr str0_node_ptr_;
|
|
strvar_node_ptr str1_node_ptr_;
|
|
};
|
|
|
|
template <typename T>
|
|
class stringvar_size_node : public expression_node<T>
|
|
{
|
|
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<T>::node_type type() const
|
|
{
|
|
return expression_node<T>::e_stringvarsize;
|
|
}
|
|
|
|
private:
|
|
|
|
std::string* value_;
|
|
};
|
|
|
|
template <typename T>
|
|
std::string stringvar_size_node<T>::null_value = std::string("");
|
|
|
|
template <typename T>
|
|
class string_size_node : public expression_node<T>
|
|
{
|
|
public:
|
|
|
|
typedef expression_node <T>* expression_ptr;
|
|
typedef string_base_node<T>* 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<str_base_ptr>(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<T>::quiet_NaN();
|
|
|
|
if (str_base_ptr_)
|
|
{
|
|
branch_->value();
|
|
result = T(str_base_ptr_->size());
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
inline typename expression_node<T>::node_type type() const
|
|
{
|
|
return expression_node<T>::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 <typename T, typename AssignmentProcess = asn_assignment>
|
|
class assignment_string_node : public binary_node <T>,
|
|
public string_base_node<T>,
|
|
public range_interface <T>
|
|
{
|
|
public:
|
|
|
|
typedef expression_node <T>* expression_ptr;
|
|
typedef stringvar_node <T>* strvar_node_ptr;
|
|
typedef string_base_node<T>* str_base_ptr;
|
|
typedef range_pack <T> range_t;
|
|
typedef range_t* range_ptr;
|
|
typedef range_interface<T> irange_t;
|
|
typedef irange_t* irange_ptr;
|
|
typedef typename range_t::cached_range_t cached_range_t;
|
|
|
|
assignment_string_node(const operator_type& opr,
|
|
expression_ptr branch0,
|
|
expression_ptr branch1)
|
|
: binary_node<T>(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<T>::branch_[0].first))
|
|
{
|
|
str0_node_ptr_ = static_cast<strvar_node_ptr>(binary_node<T>::branch_[0].first);
|
|
|
|
str0_base_ptr_ = dynamic_cast<str_base_ptr>(binary_node<T>::branch_[0].first);
|
|
}
|
|
|
|
if (is_generally_string_node(binary_node<T>::branch_[1].first))
|
|
{
|
|
str1_base_ptr_ = dynamic_cast<str_base_ptr>(binary_node<T>::branch_[1].first);
|
|
|
|
if (0 == str1_base_ptr_)
|
|
return;
|
|
|
|
irange_ptr range_ptr = dynamic_cast<irange_ptr>(binary_node<T>::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<T>::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<T>::branch_[0].first->value();
|
|
}
|
|
}
|
|
|
|
return std::numeric_limits<T>::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<T>::node_type type() const
|
|
{
|
|
return expression_node<T>::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 <typename T, typename AssignmentProcess = asn_assignment>
|
|
class assignment_string_range_node : public binary_node <T>,
|
|
public string_base_node<T>,
|
|
public range_interface <T>
|
|
{
|
|
public:
|
|
|
|
typedef expression_node <T>* expression_ptr;
|
|
typedef stringvar_node <T>* strvar_node_ptr;
|
|
typedef string_base_node<T>* str_base_ptr;
|
|
typedef range_pack <T> range_t;
|
|
typedef range_t* range_ptr;
|
|
typedef range_interface<T> irange_t;
|
|
typedef irange_t* irange_ptr;
|
|
typedef typename range_t::cached_range_t cached_range_t;
|
|
|
|
assignment_string_range_node(const operator_type& opr,
|
|
expression_ptr branch0,
|
|
expression_ptr branch1)
|
|
: binary_node<T>(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<T>::branch_[0].first))
|
|
{
|
|
str0_node_ptr_ = static_cast<strvar_node_ptr>(binary_node<T>::branch_[0].first);
|
|
|
|
str0_base_ptr_ = dynamic_cast<str_base_ptr>(binary_node<T>::branch_[0].first);
|
|
|
|
irange_ptr range_ptr = dynamic_cast<irange_ptr>(binary_node<T>::branch_[0].first);
|
|
|
|
if (0 == range_ptr)
|
|
return;
|
|
|
|
str0_range_ptr_ = &(range_ptr->range_ref());
|
|
}
|
|
|
|
if (is_generally_string_node(binary_node<T>::branch_[1].first))
|
|
{
|
|
str1_base_ptr_ = dynamic_cast<str_base_ptr>(binary_node<T>::branch_[1].first);
|
|
|
|
if (0 == str1_base_ptr_)
|
|
return;
|
|
|
|
irange_ptr range_ptr = dynamic_cast<irange_ptr>(binary_node<T>::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<T>::branch_[0].first->value();
|
|
binary_node<T>::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<char*>(base() + s0_r0));
|
|
}
|
|
}
|
|
|
|
return std::numeric_limits<T>::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<T>::node_type type() const
|
|
{
|
|
return expression_node<T>::e_strass;
|
|
}
|
|
|
|
private:
|
|
|
|
bool initialised_;
|
|
str_base_ptr str0_base_ptr_;
|
|
str_base_ptr str1_base_ptr_;
|
|
strvar_node_ptr str0_node_ptr_;
|
|
range_ptr str0_range_ptr_;
|
|
range_ptr str1_range_ptr_;
|
|
};
|
|
#endif
|
|
|
|
template <typename T, std::size_t N>
|
|
inline T axn(T a, T x)
|
|
{
|
|
// a*x^n
|
|
return a * exprtk::details::numeric::fast_exp<T,N>::result(x);
|
|
}
|
|
|
|
template <typename T, std::size_t N>
|
|
inline T axnb(T a, T x, T b)
|
|
{
|
|
// a*x^n+b
|
|
return a * exprtk::details::numeric::fast_exp<T,N>::result(x) + b;
|
|
}
|
|
|
|
template <typename T>
|
|
struct sf_base
|
|
{
|
|
typedef typename details::functor_t<T>::Type Type;
|
|
typedef typename details::functor_t<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 <typename T> \
|
|
struct sf##NN##_op : public sf_base<T> \
|
|
{ \
|
|
typedef typename sf_base<T>::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<T,2>(x,y,z))," ")
|
|
define_sfop3(32,(axnb<T,3>(x,y,z))," ")
|
|
define_sfop3(33,(axnb<T,4>(x,y,z))," ")
|
|
define_sfop3(34,(axnb<T,5>(x,y,z))," ")
|
|
define_sfop3(35,(axnb<T,6>(x,y,z))," ")
|
|
define_sfop3(36,(axnb<T,7>(x,y,z))," ")
|
|
define_sfop3(37,(axnb<T,8>(x,y,z))," ")
|
|
define_sfop3(38,(axnb<T,9>(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 <typename T> \
|
|
struct sf##NN##_op : public sf_base<T> \
|
|
{ \
|
|
typedef typename sf_base<T>::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<T,2>(x,y) + axn<T,2>(z,w)),"")
|
|
define_sfop4(85,(axn<T,3>(x,y) + axn<T,3>(z,w)),"")
|
|
define_sfop4(86,(axn<T,4>(x,y) + axn<T,4>(z,w)),"")
|
|
define_sfop4(87,(axn<T,5>(x,y) + axn<T,5>(z,w)),"")
|
|
define_sfop4(88,(axn<T,6>(x,y) + axn<T,6>(z,w)),"")
|
|
define_sfop4(89,(axn<T,7>(x,y) + axn<T,7>(z,w)),"")
|
|
define_sfop4(90,(axn<T,8>(x,y) + axn<T,8>(z,w)),"")
|
|
define_sfop4(91,(axn<T,9>(x,y) + axn<T,9>(z,w)),"")
|
|
define_sfop4(92,((details::is_true(x) && details::is_true(y)) ? z : w),"")
|
|
define_sfop4(93,((details::is_true(x) || details::is_true(y)) ? z : w),"")
|
|
define_sfop4(94,((x < y) ? z : w),"")
|
|
define_sfop4(95,((x <= y) ? z : w),"")
|
|
define_sfop4(96,((x > y) ? z : w),"")
|
|
define_sfop4(97,((x >= y) ? z : w),"")
|
|
define_sfop4(98,(details::is_true(numeric::equal(x,y)) ? z : w),"")
|
|
define_sfop4(99,(x * numeric::sin(y) + z * numeric::cos(w)),"")
|
|
|
|
define_sfop4(ext00,((x + y) - (z * w)),"(t+t)-(t*t)")
|
|
define_sfop4(ext01,((x + y) - (z / w)),"(t+t)-(t/t)")
|
|
define_sfop4(ext02,((x + y) + (z * w)),"(t+t)+(t*t)")
|
|
define_sfop4(ext03,((x + y) + (z / w)),"(t+t)+(t/t)")
|
|
define_sfop4(ext04,((x - y) + (z * w)),"(t-t)+(t*t)")
|
|
define_sfop4(ext05,((x - y) + (z / w)),"(t-t)+(t/t)")
|
|
define_sfop4(ext06,((x - y) - (z * w)),"(t-t)-(t*t)")
|
|
define_sfop4(ext07,((x - y) - (z / w)),"(t-t)-(t/t)")
|
|
define_sfop4(ext08,((x + y) - (z - w)),"(t+t)-(t-t)")
|
|
define_sfop4(ext09,((x + y) + (z - w)),"(t+t)+(t-t)")
|
|
define_sfop4(ext10,((x + y) * (z - w)),"(t+t)*(t-t)")
|
|
define_sfop4(ext11,((x + y) / (z - w)),"(t+t)/(t-t)")
|
|
define_sfop4(ext12,((x - y) - (z + w)),"(t-t)-(t+t)")
|
|
define_sfop4(ext13,((x - y) + (z + w)),"(t-t)+(t+t)")
|
|
define_sfop4(ext14,((x - y) * (z + w)),"(t-t)*(t+t)")
|
|
define_sfop4(ext15,((x - y) / (z + w)),"(t-t)/(t+t)")
|
|
define_sfop4(ext16,((x * y) - (z + w)),"(t*t)-(t+t)")
|
|
define_sfop4(ext17,((x / y) - (z + w)),"(t/t)-(t+t)")
|
|
define_sfop4(ext18,((x * y) + (z + w)),"(t*t)+(t+t)")
|
|
define_sfop4(ext19,((x / y) + (z + w)),"(t/t)+(t+t)")
|
|
define_sfop4(ext20,((x * y) + (z - w)),"(t*t)+(t-t)")
|
|
define_sfop4(ext21,((x / y) + (z - w)),"(t/t)+(t-t)")
|
|
define_sfop4(ext22,((x * y) - (z - w)),"(t*t)-(t-t)")
|
|
define_sfop4(ext23,((x / y) - (z - w)),"(t/t)-(t-t)")
|
|
define_sfop4(ext24,((x + y) * (z * w)),"(t+t)*(t*t)")
|
|
define_sfop4(ext25,((x + y) * (z / w)),"(t+t)*(t/t)")
|
|
define_sfop4(ext26,((x + y) / (z * w)),"(t+t)/(t*t)")
|
|
define_sfop4(ext27,((x + y) / (z / w)),"(t+t)/(t/t)")
|
|
define_sfop4(ext28,((x - y) / (z * w)),"(t-t)/(t*t)")
|
|
define_sfop4(ext29,((x - y) / (z / w)),"(t-t)/(t/t)")
|
|
define_sfop4(ext30,((x - y) * (z * w)),"(t-t)*(t*t)")
|
|
define_sfop4(ext31,((x - y) * (z / w)),"(t-t)*(t/t)")
|
|
define_sfop4(ext32,((x * y) * (z + w)),"(t*t)*(t+t)")
|
|
define_sfop4(ext33,((x / y) * (z + w)),"(t/t)*(t+t)")
|
|
define_sfop4(ext34,((x * y) / (z + w)),"(t*t)/(t+t)")
|
|
define_sfop4(ext35,((x / y) / (z + w)),"(t/t)/(t+t)")
|
|
define_sfop4(ext36,((x * y) / (z - w)),"(t*t)/(t-t)")
|
|
define_sfop4(ext37,((x / y) / (z - w)),"(t/t)/(t-t)")
|
|
define_sfop4(ext38,((x * y) * (z - w)),"(t*t)*(t-t)")
|
|
define_sfop4(ext39,((x * y) / (z * w)),"(t*t)/(t*t)")
|
|
define_sfop4(ext40,((x / y) * (z / w)),"(t/t)*(t/t)")
|
|
define_sfop4(ext41,((x / y) * (z - w)),"(t/t)*(t-t)")
|
|
define_sfop4(ext42,((x * y) * (z * w)),"(t*t)*(t*t)")
|
|
define_sfop4(ext43,(x + (y * (z / w))),"t+(t*(t/t))")
|
|
define_sfop4(ext44,(x - (y * (z / w))),"t-(t*(t/t))")
|
|
define_sfop4(ext45,(x + (y / (z * w))),"t+(t/(t*t))")
|
|
define_sfop4(ext46,(x - (y / (z * w))),"t-(t/(t*t))")
|
|
define_sfop4(ext47,(((x - y) - z) * w),"((t-t)-t)*t")
|
|
define_sfop4(ext48,(((x - y) - z) / w),"((t-t)-t)/t")
|
|
define_sfop4(ext49,(((x - y) + z) * w),"((t-t)+t)*t")
|
|
define_sfop4(ext50,(((x - y) + z) / w),"((t-t)+t)/t")
|
|
define_sfop4(ext51,((x + (y - z)) * w),"(t+(t-t))*t")
|
|
define_sfop4(ext52,((x + (y - z)) / w),"(t+(t-t))/t")
|
|
define_sfop4(ext53,((x + y) / (z + w)),"(t+t)/(t+t)")
|
|
define_sfop4(ext54,((x - y) / (z - w)),"(t-t)/(t-t)")
|
|
define_sfop4(ext55,((x + y) * (z + w)),"(t+t)*(t+t)")
|
|
define_sfop4(ext56,((x - y) * (z - w)),"(t-t)*(t-t)")
|
|
define_sfop4(ext57,((x - y) + (z - w)),"(t-t)+(t-t)")
|
|
define_sfop4(ext58,((x - y) - (z - w)),"(t-t)-(t-t)")
|
|
define_sfop4(ext59,((x / y) + (z * w)),"(t/t)+(t*t)")
|
|
|
|
#undef define_sfop3
|
|
#undef define_sfop4
|
|
|
|
template <typename T, typename SpecialFunction>
|
|
class sf3_node : public trinary_node<T>
|
|
{
|
|
public:
|
|
|
|
typedef expression_node<T>* expression_ptr;
|
|
|
|
sf3_node(const operator_type& opr,
|
|
expression_ptr branch0,
|
|
expression_ptr branch1,
|
|
expression_ptr branch2)
|
|
: trinary_node<T>(opr,branch0,branch1,branch2)
|
|
{}
|
|
|
|
inline T value() const
|
|
{
|
|
const T x = trinary_node<T>::branch_[0].first->value();
|
|
const T y = trinary_node<T>::branch_[1].first->value();
|
|
const T z = trinary_node<T>::branch_[2].first->value();
|
|
|
|
return SpecialFunction::process(x,y,z);
|
|
}
|
|
};
|
|
|
|
template <typename T, typename SpecialFunction>
|
|
class sf4_node : public quaternary_node<T>
|
|
{
|
|
public:
|
|
|
|
typedef expression_node<T>* expression_ptr;
|
|
|
|
sf4_node(const operator_type& opr,
|
|
expression_ptr branch0,
|
|
expression_ptr branch1,
|
|
expression_ptr branch2,
|
|
expression_ptr branch3)
|
|
: quaternary_node<T>(opr,branch0,branch1,branch2,branch3)
|
|
{}
|
|
|
|
inline T value() const
|
|
{
|
|
const T x = quaternary_node<T>::branch_[0].first->value();
|
|
const T y = quaternary_node<T>::branch_[1].first->value();
|
|
const T z = quaternary_node<T>::branch_[2].first->value();
|
|
const T w = quaternary_node<T>::branch_[3].first->value();
|
|
|
|
return SpecialFunction::process(x,y,z,w);
|
|
}
|
|
};
|
|
|
|
template <typename T, typename SpecialFunction>
|
|
class sf3_var_node : public expression_node<T>
|
|
{
|
|
public:
|
|
|
|
typedef expression_node<T>* 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<T>::node_type type() const
|
|
{
|
|
return expression_node<T>::e_trinary;
|
|
}
|
|
|
|
private:
|
|
|
|
sf3_var_node(sf3_var_node<T,SpecialFunction>&);
|
|
sf3_var_node<T,SpecialFunction>& operator=(sf3_var_node<T,SpecialFunction>&);
|
|
|
|
const T& v0_;
|
|
const T& v1_;
|
|
const T& v2_;
|
|
};
|
|
|
|
template <typename T, typename SpecialFunction>
|
|
class sf4_var_node : public expression_node<T>
|
|
{
|
|
public:
|
|
|
|
typedef expression_node<T>* 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<T>::node_type type() const
|
|
{
|
|
return expression_node<T>::e_trinary;
|
|
}
|
|
|
|
private:
|
|
|
|
sf4_var_node(sf4_var_node<T,SpecialFunction>&);
|
|
sf4_var_node<T,SpecialFunction>& operator=(sf4_var_node<T,SpecialFunction>&);
|
|
|
|
const T& v0_;
|
|
const T& v1_;
|
|
const T& v2_;
|
|
const T& v3_;
|
|
};
|
|
|
|
template <typename T, typename VarArgFunction>
|
|
class vararg_node : public expression_node<T>
|
|
{
|
|
public:
|
|
|
|
typedef expression_node<T>* expression_ptr;
|
|
|
|
template <typename Allocator,
|
|
template <typename,typename> class Sequence>
|
|
vararg_node(const Sequence<expression_ptr,Allocator>& 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<unsigned char>(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<T>::quiet_NaN();
|
|
}
|
|
|
|
inline typename expression_node<T>::node_type type() const
|
|
{
|
|
return expression_node<T>::e_vararg;
|
|
}
|
|
|
|
private:
|
|
|
|
std::vector<expression_ptr> arg_list_;
|
|
std::vector<unsigned char> delete_branch_;
|
|
};
|
|
|
|
template <typename T, typename VarArgFunction>
|
|
class vararg_varnode : public expression_node<T>
|
|
{
|
|
public:
|
|
|
|
typedef expression_node<T>* expression_ptr;
|
|
|
|
template <typename Allocator,
|
|
template <typename,typename> class Sequence>
|
|
vararg_varnode(const Sequence<expression_ptr,Allocator>& 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<T>* var_node_ptr = static_cast<variable_node<T>*>(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<T>::quiet_NaN();
|
|
}
|
|
|
|
inline typename expression_node<T>::node_type type() const
|
|
{
|
|
return expression_node<T>::e_vararg;
|
|
}
|
|
|
|
private:
|
|
|
|
std::vector<const T*> arg_list_;
|
|
};
|
|
|
|
template <typename T, typename VecFunction>
|
|
class vectorize_node : public expression_node<T>
|
|
{
|
|
public:
|
|
|
|
typedef expression_node<T>* 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<vector_interface<T>*>(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<T>::quiet_NaN();
|
|
}
|
|
|
|
inline typename expression_node<T>::node_type type() const
|
|
{
|
|
return expression_node<T>::e_vecfunc;
|
|
}
|
|
|
|
private:
|
|
|
|
vector_interface<T>* ivec_ptr_;
|
|
expression_ptr v_;
|
|
bool v_deletable_;
|
|
};
|
|
|
|
template <typename T>
|
|
class assignment_node : public binary_node<T>
|
|
{
|
|
public:
|
|
|
|
typedef expression_node<T>* expression_ptr;
|
|
|
|
assignment_node(const operator_type& opr,
|
|
expression_ptr branch0,
|
|
expression_ptr branch1)
|
|
: binary_node<T>(opr,branch0,branch1),
|
|
var_node_ptr_(0)
|
|
{
|
|
if (is_variable_node(binary_node<T>::branch_[0].first))
|
|
{
|
|
var_node_ptr_ = static_cast<variable_node<T>*>(binary_node<T>::branch_[0].first);
|
|
}
|
|
}
|
|
|
|
inline T value() const
|
|
{
|
|
if (var_node_ptr_)
|
|
{
|
|
T& result = var_node_ptr_->ref();
|
|
result = binary_node<T>::branch_[1].first->value();
|
|
|
|
return result;
|
|
}
|
|
else
|
|
return std::numeric_limits<T>::quiet_NaN();
|
|
}
|
|
|
|
private:
|
|
|
|
variable_node<T>* var_node_ptr_;
|
|
};
|
|
|
|
template <typename T>
|
|
class assignment_vec_elem_node : public binary_node<T>
|
|
{
|
|
public:
|
|
|
|
typedef expression_node<T>* expression_ptr;
|
|
|
|
assignment_vec_elem_node(const operator_type& opr,
|
|
expression_ptr branch0,
|
|
expression_ptr branch1)
|
|
: binary_node<T>(opr,branch0,branch1),
|
|
vec_node_ptr_(0)
|
|
{
|
|
if (is_vector_elem_node(binary_node<T>::branch_[0].first))
|
|
{
|
|
vec_node_ptr_ = static_cast<vector_elem_node<T>*>(binary_node<T>::branch_[0].first);
|
|
}
|
|
}
|
|
|
|
inline T value() const
|
|
{
|
|
if (vec_node_ptr_)
|
|
{
|
|
T& result = vec_node_ptr_->ref();
|
|
result = binary_node<T>::branch_[1].first->value();
|
|
|
|
return result;
|
|
}
|
|
else
|
|
return std::numeric_limits<T>::quiet_NaN();
|
|
}
|
|
|
|
private:
|
|
|
|
vector_elem_node<T>* vec_node_ptr_;
|
|
};
|
|
|
|
template <typename T>
|
|
class assignment_vec_node : public binary_node<T>,
|
|
public vector_interface<T>
|
|
{
|
|
public:
|
|
|
|
typedef expression_node<T>* expression_ptr;
|
|
typedef vector_node<T>* vector_node_ptr;
|
|
|
|
assignment_vec_node(const operator_type& opr,
|
|
expression_ptr branch0,
|
|
expression_ptr branch1)
|
|
: binary_node<T>(opr,branch0,branch1),
|
|
vec_node_ptr_(0),
|
|
vec_size_ (0)
|
|
{
|
|
if (is_vector_node(binary_node<T>::branch_[0].first))
|
|
{
|
|
vec_node_ptr_ = static_cast<vector_node<T>*>(binary_node<T>::branch_[0].first);
|
|
vec_size_ = vec_node_ptr_->ref().size();
|
|
}
|
|
}
|
|
|
|
inline T value() const
|
|
{
|
|
if (vec_node_ptr_)
|
|
{
|
|
vector_holder<T>& vec_hldr = vec_node_ptr_->ref();
|
|
const T v = binary_node<T>::branch_[1].first->value();
|
|
|
|
for (std::size_t i = 0; i < vec_size_; ++i)
|
|
{
|
|
(*vec_hldr[i]) = v;
|
|
}
|
|
|
|
return vec_node_ptr_->value();
|
|
}
|
|
else
|
|
return std::numeric_limits<T>::quiet_NaN();
|
|
}
|
|
|
|
vector_node_ptr vec() const
|
|
{
|
|
return vec_node_ptr_;
|
|
}
|
|
|
|
vector_node_ptr vec()
|
|
{
|
|
return vec_node_ptr_;
|
|
}
|
|
|
|
inline typename expression_node<T>::node_type type() const
|
|
{
|
|
return expression_node<T>::e_vecvalass;
|
|
}
|
|
|
|
std::size_t size() const
|
|
{
|
|
return vec_size_;
|
|
}
|
|
|
|
private:
|
|
|
|
vector_node<T>* vec_node_ptr_;
|
|
std::size_t vec_size_;
|
|
};
|
|
|
|
template <typename T>
|
|
class assignment_vecvec_node : public binary_node<T>,
|
|
public vector_interface<T>
|
|
{
|
|
public:
|
|
|
|
typedef expression_node<T>* expression_ptr;
|
|
typedef vector_node<T>* vector_node_ptr;
|
|
|
|
assignment_vecvec_node(const operator_type& opr,
|
|
expression_ptr branch0,
|
|
expression_ptr branch1)
|
|
: binary_node<T>(opr,branch0,branch1),
|
|
vec0_node_ptr_(0),
|
|
vec1_node_ptr_(0),
|
|
vec_size_ (0)
|
|
{
|
|
if (is_vector_node(binary_node<T>::branch_[0].first))
|
|
{
|
|
vec0_node_ptr_ = static_cast<vector_node<T>*>(binary_node<T>::branch_[0].first);
|
|
}
|
|
|
|
if (is_vector_node(binary_node<T>::branch_[1].first))
|
|
{
|
|
vec1_node_ptr_ = static_cast<vector_node<T>*>(binary_node<T>::branch_[1].first);
|
|
}
|
|
else if (is_ivector_node(binary_node<T>::branch_[1].first))
|
|
{
|
|
vector_interface<T>* vi = reinterpret_cast<vector_interface<T>*>(0);
|
|
|
|
if ((vi = dynamic_cast<vector_interface<T>*>(binary_node<T>::branch_[1].first)))
|
|
{
|
|
vec1_node_ptr_ = vi->vec();
|
|
}
|
|
}
|
|
|
|
if (vec0_node_ptr_ && vec1_node_ptr_)
|
|
{
|
|
vec_size_ = std::min(vec0_node_ptr_->ref().size(),
|
|
vec1_node_ptr_->ref().size());
|
|
}
|
|
}
|
|
|
|
inline T value() const
|
|
{
|
|
binary_node<T>::branch_[1].first->value();
|
|
|
|
if (vec0_node_ptr_ && vec1_node_ptr_)
|
|
{
|
|
vector_holder<T>& vec0 = vec0_node_ptr_->ref();
|
|
vector_holder<T>& vec1 = vec1_node_ptr_->ref();
|
|
|
|
for (std::size_t i = 0; i < vec_size_; ++i)
|
|
{
|
|
(*vec0[i]) = (*vec1[i]);
|
|
}
|
|
|
|
return vec0_node_ptr_->value();
|
|
}
|
|
else
|
|
return std::numeric_limits<T>::quiet_NaN();
|
|
}
|
|
|
|
vector_node_ptr vec() const
|
|
{
|
|
return vec0_node_ptr_;
|
|
}
|
|
|
|
vector_node_ptr vec()
|
|
{
|
|
return vec0_node_ptr_;
|
|
}
|
|
|
|
inline typename expression_node<T>::node_type type() const
|
|
{
|
|
return expression_node<T>::e_vecvecass;
|
|
}
|
|
|
|
std::size_t size() const
|
|
{
|
|
return vec_size_;
|
|
}
|
|
|
|
private:
|
|
|
|
vector_node<T>* vec0_node_ptr_;
|
|
vector_node<T>* vec1_node_ptr_;
|
|
std::size_t vec_size_;
|
|
};
|
|
|
|
template <typename T, typename Operation>
|
|
class assignment_op_node : public binary_node<T>
|
|
{
|
|
public:
|
|
|
|
typedef expression_node<T>* expression_ptr;
|
|
|
|
assignment_op_node(const operator_type& opr,
|
|
expression_ptr branch0,
|
|
expression_ptr branch1)
|
|
: binary_node<T>(opr,branch0,branch1),
|
|
var_node_ptr_(0)
|
|
{
|
|
if (is_variable_node(binary_node<T>::branch_[0].first))
|
|
{
|
|
var_node_ptr_ = static_cast<variable_node<T>*>(binary_node<T>::branch_[0].first);
|
|
}
|
|
}
|
|
|
|
inline T value() const
|
|
{
|
|
if (var_node_ptr_)
|
|
{
|
|
T& v = var_node_ptr_->ref();
|
|
v = Operation::process(v,binary_node<T>::branch_[1].first->value());
|
|
|
|
return v;
|
|
}
|
|
else
|
|
return std::numeric_limits<T>::quiet_NaN();
|
|
}
|
|
|
|
private:
|
|
|
|
variable_node<T>* var_node_ptr_;
|
|
};
|
|
|
|
template <typename T, typename Operation>
|
|
class assignment_vec_elem_op_node : public binary_node<T>
|
|
{
|
|
public:
|
|
|
|
typedef expression_node<T>* expression_ptr;
|
|
|
|
assignment_vec_elem_op_node(const operator_type& opr,
|
|
expression_ptr branch0,
|
|
expression_ptr branch1)
|
|
: binary_node<T>(opr,branch0,branch1),
|
|
vec_node_ptr_(0)
|
|
{
|
|
if (is_vector_elem_node(binary_node<T>::branch_[0].first))
|
|
{
|
|
vec_node_ptr_ = static_cast<vector_elem_node<T>*>(binary_node<T>::branch_[0].first);
|
|
}
|
|
}
|
|
|
|
inline T value() const
|
|
{
|
|
if (vec_node_ptr_)
|
|
{
|
|
T& v = vec_node_ptr_->ref();
|
|
v = Operation::process(v,binary_node<T>::branch_[1].first->value());
|
|
|
|
return v;
|
|
}
|
|
else
|
|
return std::numeric_limits<T>::quiet_NaN();
|
|
}
|
|
|
|
private:
|
|
|
|
vector_elem_node<T>* vec_node_ptr_;
|
|
};
|
|
|
|
template <typename T, typename Operation>
|
|
class assignment_vec_op_node : public binary_node<T>,
|
|
public vector_interface<T>
|
|
{
|
|
public:
|
|
|
|
typedef expression_node<T>* expression_ptr;
|
|
typedef vector_node<T>* vector_node_ptr;
|
|
|
|
assignment_vec_op_node(const operator_type& opr,
|
|
expression_ptr branch0,
|
|
expression_ptr branch1)
|
|
: binary_node<T>(opr,branch0,branch1),
|
|
vec_node_ptr_(0),
|
|
vec_size_ (0)
|
|
{
|
|
if (is_vector_node(binary_node<T>::branch_[0].first))
|
|
{
|
|
vec_node_ptr_ = static_cast<vector_node<T>*>(binary_node<T>::branch_[0].first);
|
|
vec_size_ = vec_node_ptr_->ref().size();
|
|
}
|
|
}
|
|
|
|
inline T value() const
|
|
{
|
|
if (vec_node_ptr_)
|
|
{
|
|
vector_holder<T>& vec_hldr = vec_node_ptr_->ref();
|
|
const T v = binary_node<T>::branch_[1].first->value();
|
|
|
|
for (std::size_t i = 0; i < vec_size_; ++i)
|
|
{
|
|
T& vec_i = *vec_hldr[i];
|
|
vec_i = Operation::process(vec_i,v);
|
|
}
|
|
|
|
return vec_node_ptr_->value();
|
|
}
|
|
else
|
|
return std::numeric_limits<T>::quiet_NaN();
|
|
}
|
|
|
|
vector_node_ptr vec() const
|
|
{
|
|
return vec_node_ptr_;
|
|
}
|
|
|
|
vector_node_ptr vec()
|
|
{
|
|
return vec_node_ptr_;
|
|
}
|
|
|
|
inline typename expression_node<T>::node_type type() const
|
|
{
|
|
return expression_node<T>::e_vecopvalass;
|
|
}
|
|
|
|
std::size_t size() const
|
|
{
|
|
return vec_size_;
|
|
}
|
|
|
|
private:
|
|
|
|
vector_node<T>* vec_node_ptr_;
|
|
std::size_t vec_size_;
|
|
};
|
|
|
|
template <typename T, typename Operation>
|
|
class assignment_vecvec_op_node : public binary_node<T>,
|
|
public vector_interface<T>
|
|
{
|
|
public:
|
|
|
|
typedef expression_node<T>* expression_ptr;
|
|
typedef vector_node<T>* vector_node_ptr;
|
|
|
|
assignment_vecvec_op_node(const operator_type& opr,
|
|
expression_ptr branch0,
|
|
expression_ptr branch1)
|
|
: binary_node<T>(opr,branch0,branch1),
|
|
vec0_node_ptr_(0),
|
|
vec1_node_ptr_(0),
|
|
vec_size_ (0)
|
|
{
|
|
if (is_vector_node(binary_node<T>::branch_[0].first))
|
|
{
|
|
vec0_node_ptr_ = static_cast<vector_node<T>*>(binary_node<T>::branch_[0].first);
|
|
}
|
|
|
|
if (is_vector_node(binary_node<T>::branch_[1].first))
|
|
{
|
|
vec1_node_ptr_ = static_cast<vector_node<T>*>(binary_node<T>::branch_[1].first);
|
|
}
|
|
else if (is_ivector_node(binary_node<T>::branch_[1].first))
|
|
{
|
|
vector_interface<T>* vi = reinterpret_cast<vector_interface<T>*>(0);
|
|
|
|
if ((vi = dynamic_cast<vector_interface<T>*>(binary_node<T>::branch_[1].first)))
|
|
{
|
|
vec1_node_ptr_ = vi->vec();
|
|
}
|
|
}
|
|
|
|
if (vec0_node_ptr_ && vec1_node_ptr_)
|
|
{
|
|
vec_size_ = std::min(vec0_node_ptr_->ref().size(),
|
|
vec1_node_ptr_->ref().size());
|
|
}
|
|
}
|
|
|
|
inline T value() const
|
|
{
|
|
if (vec0_node_ptr_ && vec1_node_ptr_)
|
|
{
|
|
binary_node<T>::branch_[0].first->value();
|
|
binary_node<T>::branch_[1].first->value();
|
|
|
|
vector_holder<T>& vec0 = vec0_node_ptr_->ref();
|
|
vector_holder<T>& vec1 = vec1_node_ptr_->ref();
|
|
|
|
for (std::size_t i = 0; i < vec_size_; ++i)
|
|
{
|
|
T& vec0_i = *vec0[i];
|
|
T& vec1_i = *vec1[i];
|
|
vec0_i = Operation::process(vec0_i,vec1_i);
|
|
}
|
|
|
|
return vec0_node_ptr_->value();
|
|
}
|
|
else
|
|
return std::numeric_limits<T>::quiet_NaN();
|
|
}
|
|
|
|
vector_node_ptr vec() const
|
|
{
|
|
return vec0_node_ptr_;
|
|
}
|
|
|
|
vector_node_ptr vec()
|
|
{
|
|
return vec0_node_ptr_;
|
|
}
|
|
|
|
inline typename expression_node<T>::node_type type() const
|
|
{
|
|
return expression_node<T>::e_vecopvecass;
|
|
}
|
|
|
|
std::size_t size() const
|
|
{
|
|
return vec_size_;
|
|
}
|
|
|
|
private:
|
|
|
|
vector_node<T>* vec0_node_ptr_;
|
|
vector_node<T>* vec1_node_ptr_;
|
|
std::size_t vec_size_;
|
|
};
|
|
|
|
template <typename T, typename Operation>
|
|
class eqineq_vecvec_node : public binary_node<T>,
|
|
public vector_interface<T>
|
|
{
|
|
public:
|
|
|
|
typedef expression_node<T>* expression_ptr;
|
|
typedef vector_node<T>* vector_node_ptr;
|
|
|
|
eqineq_vecvec_node(const operator_type& opr,
|
|
expression_ptr branch0,
|
|
expression_ptr branch1)
|
|
: binary_node<T>(opr,branch0,branch1),
|
|
vec0_node_ptr_(0),
|
|
vec1_node_ptr_(0),
|
|
vec_size_ (0)
|
|
{
|
|
|
|
if (is_vector_node(binary_node<T>::branch_[0].first))
|
|
{
|
|
vec0_node_ptr_ = static_cast<vector_node<T>*>(binary_node<T>::branch_[0].first);
|
|
}
|
|
else if (is_ivector_node(binary_node<T>::branch_[0].first))
|
|
{
|
|
vector_interface<T>* vi = reinterpret_cast<vector_interface<T>*>(0);
|
|
|
|
if ((vi = dynamic_cast<vector_interface<T>*>(binary_node<T>::branch_[0].first)))
|
|
{
|
|
vec0_node_ptr_ = vi->vec();
|
|
}
|
|
}
|
|
|
|
if (is_vector_node(binary_node<T>::branch_[1].first))
|
|
{
|
|
vec1_node_ptr_ = static_cast<vector_node<T>*>(binary_node<T>::branch_[1].first);
|
|
}
|
|
else if (is_ivector_node(binary_node<T>::branch_[1].first))
|
|
{
|
|
vector_interface<T>* vi = reinterpret_cast<vector_interface<T>*>(0);
|
|
|
|
if ((vi = dynamic_cast<vector_interface<T>*>(binary_node<T>::branch_[1].first)))
|
|
{
|
|
vec1_node_ptr_ = vi->vec();
|
|
}
|
|
}
|
|
|
|
if (vec0_node_ptr_ && vec1_node_ptr_)
|
|
{
|
|
vec_size_ = std::min(vec0_node_ptr_->ref().size(),
|
|
vec1_node_ptr_->ref().size());
|
|
}
|
|
}
|
|
|
|
inline T value() const
|
|
{
|
|
if (vec0_node_ptr_ && vec1_node_ptr_)
|
|
{
|
|
binary_node<T>::branch_[0].first->value();
|
|
binary_node<T>::branch_[1].first->value();
|
|
|
|
vector_holder<T>& vec0 = vec0_node_ptr_->ref();
|
|
vector_holder<T>& vec1 = vec1_node_ptr_->ref();
|
|
|
|
for (std::size_t i = 0; i < vec_size_; ++i)
|
|
{
|
|
if (std::equal_to<T>()(T(0),Operation::process(*vec0[i],*vec1[i])))
|
|
{
|
|
return T(0);
|
|
}
|
|
}
|
|
|
|
return T(1);
|
|
}
|
|
else
|
|
return std::numeric_limits<T>::quiet_NaN();
|
|
}
|
|
|
|
vector_node_ptr vec() const
|
|
{
|
|
return vec0_node_ptr_;
|
|
}
|
|
|
|
vector_node_ptr vec()
|
|
{
|
|
return vec0_node_ptr_;
|
|
}
|
|
|
|
inline typename expression_node<T>::node_type type() const
|
|
{
|
|
return expression_node<T>::e_vecvecineq;
|
|
}
|
|
|
|
std::size_t size() const
|
|
{
|
|
return vec_size_;
|
|
}
|
|
|
|
private:
|
|
|
|
vector_node<T>* vec0_node_ptr_;
|
|
vector_node<T>* vec1_node_ptr_;
|
|
std::size_t vec_size_;
|
|
};
|
|
|
|
template <typename T, typename Operation>
|
|
class eqineq_vecval_node : public binary_node<T>,
|
|
public vector_interface<T>
|
|
{
|
|
public:
|
|
|
|
typedef expression_node<T>* expression_ptr;
|
|
typedef vector_node<T>* vector_node_ptr;
|
|
|
|
eqineq_vecval_node(const operator_type& opr,
|
|
expression_ptr branch0,
|
|
expression_ptr branch1)
|
|
: binary_node<T>(opr,branch0,branch1),
|
|
vec_node_ptr_(0),
|
|
vec_size_ (0)
|
|
{
|
|
if (is_vector_node(binary_node<T>::branch_[0].first))
|
|
{
|
|
vec_node_ptr_ = static_cast<vector_node_ptr>(binary_node<T>::branch_[0].first);
|
|
}
|
|
else if (is_ivector_node(binary_node<T>::branch_[0].first))
|
|
{
|
|
vector_interface<T>* vi = reinterpret_cast<vector_interface<T>*>(0);
|
|
|
|
if ((vi = dynamic_cast<vector_interface<T>*>(binary_node<T>::branch_[0].first)))
|
|
{
|
|
vec_node_ptr_ = vi->vec();
|
|
}
|
|
}
|
|
|
|
if (vec_node_ptr_)
|
|
{
|
|
vec_size_ = vec_node_ptr_->ref().size();
|
|
}
|
|
}
|
|
|
|
inline T value() const
|
|
{
|
|
if (vec_node_ptr_)
|
|
{
|
|
binary_node<T>::branch_[0].first->value();
|
|
T v = binary_node<T>::branch_[1].first->value();
|
|
|
|
vector_holder<T>& vec_hldr = vec_node_ptr_->ref();
|
|
|
|
for (std::size_t i = 0; i < vec_size_; ++i)
|
|
{
|
|
if (std::equal_to<T>()(T(0),Operation::process(*vec_hldr[i],v)))
|
|
{
|
|
return T(0);
|
|
}
|
|
}
|
|
|
|
return T(1);
|
|
}
|
|
else
|
|
return std::numeric_limits<T>::quiet_NaN();
|
|
}
|
|
|
|
vector_node_ptr vec() const
|
|
{
|
|
return vec_node_ptr_;
|
|
}
|
|
|
|
vector_node_ptr vec()
|
|
{
|
|
return vec_node_ptr_;
|
|
}
|
|
|
|
inline typename expression_node<T>::node_type type() const
|
|
{
|
|
return expression_node<T>::e_vecvalineq;
|
|
}
|
|
|
|
std::size_t size() const
|
|
{
|
|
return vec_size_;
|
|
}
|
|
|
|
private:
|
|
|
|
vector_node<T>* vec_node_ptr_;
|
|
std::size_t vec_size_;
|
|
};
|
|
|
|
template <typename T, typename Operation>
|
|
class eqineq_valvec_node : public binary_node<T>,
|
|
public vector_interface<T>
|
|
{
|
|
public:
|
|
|
|
typedef expression_node<T>* expression_ptr;
|
|
typedef vector_node<T>* vector_node_ptr;
|
|
|
|
eqineq_valvec_node(const operator_type& opr,
|
|
expression_ptr branch0,
|
|
expression_ptr branch1)
|
|
: binary_node<T>(opr,branch0,branch1),
|
|
vec_node_ptr_(0),
|
|
vec_size_ (0)
|
|
{
|
|
if (is_vector_node(binary_node<T>::branch_[1].first))
|
|
{
|
|
vec_node_ptr_ = static_cast<vector_node_ptr>(binary_node<T>::branch_[1].first);
|
|
}
|
|
else if (is_ivector_node(binary_node<T>::branch_[1].first))
|
|
{
|
|
vector_interface<T>* vi = reinterpret_cast<vector_interface<T>*>(0);
|
|
|
|
if ((vi = dynamic_cast<vector_interface<T>*>(binary_node<T>::branch_[1].first)))
|
|
{
|
|
vec_node_ptr_ = vi->vec();
|
|
}
|
|
}
|
|
|
|
if (vec_node_ptr_)
|
|
{
|
|
vec_size_ = vec_node_ptr_->ref().size();
|
|
}
|
|
}
|
|
|
|
inline T value() const
|
|
{
|
|
if (vec_node_ptr_)
|
|
{
|
|
T v = binary_node<T>::branch_[0].first->value();
|
|
binary_node<T>::branch_[1].first->value();
|
|
|
|
vector_holder<T>& vec_hldr = vec_node_ptr_->ref();
|
|
|
|
for (std::size_t i = 0; i < vec_size_; ++i)
|
|
{
|
|
if (std::equal_to<T>()(T(0),Operation::process(v,*vec_hldr[i])))
|
|
{
|
|
return T(0);
|
|
}
|
|
}
|
|
|
|
return T(1);
|
|
}
|
|
else
|
|
return std::numeric_limits<T>::quiet_NaN();
|
|
}
|
|
|
|
vector_node_ptr vec() const
|
|
{
|
|
return vec_node_ptr_;
|
|
}
|
|
|
|
vector_node_ptr vec()
|
|
{
|
|
return vec_node_ptr_;
|
|
}
|
|
|
|
inline typename expression_node<T>::node_type type() const
|
|
{
|
|
return expression_node<T>::e_valvecineq;
|
|
}
|
|
|
|
std::size_t size() const
|
|
{
|
|
return vec_size_;
|
|
}
|
|
|
|
private:
|
|
|
|
vector_node<T>* vec_node_ptr_;
|
|
std::size_t vec_size_;
|
|
};
|
|
|
|
template <typename T, typename Operation>
|
|
class vecarith_vecvec_node : public binary_node<T>,
|
|
public vector_interface<T>
|
|
{
|
|
public:
|
|
|
|
typedef expression_node<T>* expression_ptr;
|
|
typedef vector_node<T>* vector_node_ptr;
|
|
typedef vector_holder<T>* vector_holder_ptr;
|
|
|
|
vecarith_vecvec_node(const operator_type& opr,
|
|
expression_ptr branch0,
|
|
expression_ptr branch1)
|
|
: binary_node<T>(opr,branch0,branch1),
|
|
vec0_node_ptr_(0),
|
|
vec1_node_ptr_(0),
|
|
vec_size_ (0),
|
|
data_ (0),
|
|
temp_ (0),
|
|
temp_vec_node_(0)
|
|
{
|
|
if (is_vector_node(binary_node<T>::branch_[0].first))
|
|
{
|
|
vec0_node_ptr_ = static_cast<vector_node_ptr>(binary_node<T>::branch_[0].first);
|
|
}
|
|
else if (is_ivector_node(binary_node<T>::branch_[0].first))
|
|
{
|
|
vector_interface<T>* vi = reinterpret_cast<vector_interface<T>*>(0);
|
|
|
|
if ((vi = dynamic_cast<vector_interface<T>*>(binary_node<T>::branch_[0].first)))
|
|
{
|
|
vec0_node_ptr_ = vi->vec();
|
|
}
|
|
}
|
|
|
|
if (is_vector_node(binary_node<T>::branch_[1].first))
|
|
{
|
|
vec1_node_ptr_ = static_cast<vector_node_ptr>(binary_node<T>::branch_[1].first);
|
|
}
|
|
else if (is_ivector_node(binary_node<T>::branch_[1].first))
|
|
{
|
|
vector_interface<T>* vi = reinterpret_cast<vector_interface<T>*>(0);
|
|
|
|
if ((vi = dynamic_cast<vector_interface<T>*>(binary_node<T>::branch_[1].first)))
|
|
{
|
|
vec1_node_ptr_ = vi->vec();
|
|
}
|
|
}
|
|
|
|
if (vec0_node_ptr_ && vec1_node_ptr_)
|
|
{
|
|
vector_holder<T>& vec0 = vec0_node_ptr_->ref();
|
|
vector_holder<T>& vec1 = vec1_node_ptr_->ref();
|
|
|
|
vec_size_ = std::min(vec0.size(),vec1.size());
|
|
data_ = new T[vec_size_];
|
|
temp_ = new vector_holder<T>(data_,vec_size_);
|
|
temp_vec_node_ = new vector_node<T> (temp_);
|
|
}
|
|
}
|
|
|
|
~vecarith_vecvec_node()
|
|
{
|
|
delete[] data_;
|
|
delete temp_;
|
|
delete temp_vec_node_;
|
|
}
|
|
|
|
inline T value() const
|
|
{
|
|
if (vec0_node_ptr_ && vec1_node_ptr_)
|
|
{
|
|
binary_node<T>::branch_[0].first->value();
|
|
binary_node<T>::branch_[1].first->value();
|
|
|
|
vector_holder<T>& vec0 = vec0_node_ptr_->ref();
|
|
vector_holder<T>& vec1 = vec1_node_ptr_->ref();
|
|
vector_holder<T>& vec2 = *temp_;
|
|
|
|
for (std::size_t i = 0; i < vec_size_; ++i)
|
|
{
|
|
|
|
T& vec0_i = *vec0[i];
|
|
T& vec1_i = *vec1[i];
|
|
T& vec2_i = *vec2[i];
|
|
|
|
vec2_i = Operation::process(vec0_i,vec1_i);
|
|
}
|
|
|
|
return *vec2[0];
|
|
}
|
|
else
|
|
return std::numeric_limits<T>::quiet_NaN();
|
|
}
|
|
|
|
vector_node_ptr vec() const
|
|
{
|
|
return temp_vec_node_;
|
|
}
|
|
|
|
vector_node_ptr vec()
|
|
{
|
|
return temp_vec_node_;
|
|
}
|
|
|
|
inline typename expression_node<T>::node_type type() const
|
|
{
|
|
return expression_node<T>::e_vecvecarith;
|
|
}
|
|
|
|
std::size_t size() const
|
|
{
|
|
return vec_size_;
|
|
}
|
|
|
|
private:
|
|
|
|
vector_node_ptr vec0_node_ptr_;
|
|
vector_node_ptr vec1_node_ptr_;
|
|
std::size_t vec_size_;
|
|
T* data_;
|
|
vector_holder_ptr temp_;
|
|
vector_node_ptr temp_vec_node_;
|
|
};
|
|
|
|
template <typename T, typename Operation>
|
|
class vecarith_vecval_node : public binary_node<T>,
|
|
public vector_interface<T>
|
|
{
|
|
public:
|
|
|
|
typedef expression_node<T>* expression_ptr;
|
|
typedef vector_node<T>* vector_node_ptr;
|
|
typedef vector_holder<T>* vector_holder_ptr;
|
|
|
|
vecarith_vecval_node(const operator_type& opr,
|
|
expression_ptr branch0,
|
|
expression_ptr branch1)
|
|
: binary_node<T>(opr,branch0,branch1),
|
|
vec0_node_ptr_(0),
|
|
vec_size_ (0),
|
|
data_ (0),
|
|
temp_ (0),
|
|
temp_vec_node_(0)
|
|
{
|
|
if (is_vector_node(binary_node<T>::branch_[0].first))
|
|
{
|
|
vec0_node_ptr_ = static_cast<vector_node_ptr>(binary_node<T>::branch_[0].first);
|
|
}
|
|
else if (is_ivector_node(binary_node<T>::branch_[0].first))
|
|
{
|
|
vector_interface<T>* vi = reinterpret_cast<vector_interface<T>*>(0);
|
|
|
|
if ((vi = dynamic_cast<vector_interface<T>*>(binary_node<T>::branch_[0].first)))
|
|
{
|
|
vec0_node_ptr_ = vi->vec();
|
|
}
|
|
}
|
|
|
|
if (vec0_node_ptr_)
|
|
{
|
|
vector_holder<T>& vec0 = vec0_node_ptr_->ref();
|
|
|
|
vec_size_ = vec0.size();
|
|
data_ = new T[vec_size_];
|
|
temp_ = new vector_holder<T>(data_,vec_size_);
|
|
temp_vec_node_ = new vector_node<T> (temp_);
|
|
}
|
|
}
|
|
|
|
~vecarith_vecval_node()
|
|
{
|
|
delete[] data_;
|
|
delete temp_;
|
|
delete temp_vec_node_;
|
|
}
|
|
|
|
inline T value() const
|
|
{
|
|
if (vec0_node_ptr_)
|
|
{
|
|
binary_node<T>::branch_[0].first->value();
|
|
const T v = binary_node<T>::branch_[1].first->value();
|
|
|
|
vector_holder<T>& vec0 = vec0_node_ptr_->ref();
|
|
vector_holder<T>& vec1 = *temp_;
|
|
|
|
for (std::size_t i = 0; i < vec_size_; ++i)
|
|
{
|
|
T& vec0_i = *vec0[i];
|
|
T& vec1_i = *vec1[i];
|
|
|
|
vec1_i = Operation::process(vec0_i,v);
|
|
}
|
|
|
|
return *vec1[0];
|
|
}
|
|
else
|
|
return std::numeric_limits<T>::quiet_NaN();
|
|
}
|
|
|
|
vector_node_ptr vec() const
|
|
{
|
|
return temp_vec_node_;
|
|
}
|
|
|
|
vector_node_ptr vec()
|
|
{
|
|
return temp_vec_node_;
|
|
}
|
|
|
|
inline typename expression_node<T>::node_type type() const
|
|
{
|
|
return expression_node<T>::e_vecvalarith;
|
|
}
|
|
|
|
std::size_t size() const
|
|
{
|
|
return vec_size_;
|
|
}
|
|
|
|
private:
|
|
|
|
vector_node_ptr vec0_node_ptr_;
|
|
std::size_t vec_size_;
|
|
T* data_;
|
|
vector_holder_ptr temp_;
|
|
vector_node_ptr temp_vec_node_;
|
|
};
|
|
|
|
template <typename T, typename Operation>
|
|
class vecarith_valvec_node : public binary_node<T>,
|
|
public vector_interface<T>
|
|
{
|
|
public:
|
|
|
|
typedef expression_node<T>* expression_ptr;
|
|
typedef vector_node<T>* vector_node_ptr;
|
|
typedef vector_holder<T>* vector_holder_ptr;
|
|
|
|
vecarith_valvec_node(const operator_type& opr,
|
|
expression_ptr branch0,
|
|
expression_ptr branch1)
|
|
: binary_node<T>(opr,branch0,branch1),
|
|
vec1_node_ptr_(0),
|
|
vec_size_ (0),
|
|
data_ (0),
|
|
temp_ (0),
|
|
temp_vec_node_(0)
|
|
{
|
|
if (is_vector_node(binary_node<T>::branch_[1].first))
|
|
{
|
|
vec1_node_ptr_ = static_cast<vector_node_ptr>(binary_node<T>::branch_[1].first);
|
|
}
|
|
else if (is_ivector_node(binary_node<T>::branch_[1].first))
|
|
{
|
|
vector_interface<T>* vi = reinterpret_cast<vector_interface<T>*>(0);
|
|
|
|
if ((vi = dynamic_cast<vector_interface<T>*>(binary_node<T>::branch_[1].first)))
|
|
{
|
|
vec1_node_ptr_ = vi->vec();
|
|
}
|
|
}
|
|
|
|
if (vec1_node_ptr_)
|
|
{
|
|
vector_holder<T>& vec0 = vec1_node_ptr_->ref();
|
|
|
|
vec_size_ = vec0.size();
|
|
data_ = new T[vec_size_];
|
|
temp_ = new vector_holder<T>(data_,vec_size_);
|
|
temp_vec_node_ = new vector_node<T> (temp_);
|
|
}
|
|
}
|
|
|
|
~vecarith_valvec_node()
|
|
{
|
|
delete[] data_;
|
|
delete temp_;
|
|
delete temp_vec_node_;
|
|
}
|
|
|
|
inline T value() const
|
|
{
|
|
if (vec1_node_ptr_)
|
|
{
|
|
const T v = binary_node<T>::branch_[0].first->value();
|
|
binary_node<T>::branch_[1].first->value();
|
|
|
|
vector_holder<T>& vec1 = vec1_node_ptr_->ref();
|
|
vector_holder<T>& vec2 = *temp_;
|
|
|
|
for (std::size_t i = 0; i < vec_size_; ++i)
|
|
{
|
|
T& vec1_i = *vec1[i];
|
|
T& vec2_i = *vec2[i];
|
|
|
|
vec2_i = Operation::process(v,vec1_i);
|
|
}
|
|
|
|
return *vec2[0];
|
|
}
|
|
else
|
|
return std::numeric_limits<T>::quiet_NaN();
|
|
}
|
|
|
|
vector_node_ptr vec() const
|
|
{
|
|
return temp_vec_node_;
|
|
}
|
|
|
|
vector_node_ptr vec()
|
|
{
|
|
return temp_vec_node_;
|
|
}
|
|
|
|
inline typename expression_node<T>::node_type type() const
|
|
{
|
|
return expression_node<T>::e_vecvalarith;
|
|
}
|
|
|
|
std::size_t size() const
|
|
{
|
|
return vec_size_;
|
|
}
|
|
|
|
private:
|
|
|
|
vector_node_ptr vec1_node_ptr_;
|
|
std::size_t vec_size_;
|
|
T* data_;
|
|
vector_holder_ptr temp_;
|
|
vector_node_ptr temp_vec_node_;
|
|
};
|
|
|
|
template <typename T, typename Operation>
|
|
class unary_vector_node : public unary_node<T>,
|
|
public vector_interface<T>
|
|
{
|
|
public:
|
|
|
|
typedef expression_node<T>* expression_ptr;
|
|
typedef vector_node<T>* vector_node_ptr;
|
|
typedef vector_holder<T>* vector_holder_ptr;
|
|
|
|
unary_vector_node(const operator_type& opr, expression_ptr branch0)
|
|
: unary_node<T>(opr,branch0),
|
|
vec0_node_ptr_(0),
|
|
vec_size_ (0),
|
|
data_ (0),
|
|
temp_ (0),
|
|
temp_vec_node_(0)
|
|
{
|
|
if (is_vector_node(unary_node<T>::branch_))
|
|
{
|
|
vec0_node_ptr_ = static_cast<vector_node_ptr>(unary_node<T>::branch_);
|
|
}
|
|
else if (is_ivector_node(unary_node<T>::branch_))
|
|
{
|
|
vector_interface<T>* vi = reinterpret_cast<vector_interface<T>*>(0);
|
|
|
|
if ((vi = dynamic_cast<vector_interface<T>*>(unary_node<T>::branch_)))
|
|
{
|
|
vec0_node_ptr_ = vi->vec();
|
|
}
|
|
}
|
|
|
|
if (vec0_node_ptr_)
|
|
{
|
|
vector_holder<T>& vec0 = vec0_node_ptr_->ref();
|
|
|
|
vec_size_ = vec0.size();
|
|
data_ = new T[vec_size_];
|
|
temp_ = new vector_holder<T>(data_,vec_size_);
|
|
temp_vec_node_ = new vector_node<T> (temp_);
|
|
}
|
|
}
|
|
|
|
~unary_vector_node()
|
|
{
|
|
delete[] data_;
|
|
delete temp_;
|
|
delete temp_vec_node_;
|
|
}
|
|
|
|
inline T value() const
|
|
{
|
|
unary_node<T>::branch_->value();
|
|
|
|
if (vec0_node_ptr_)
|
|
{
|
|
vector_holder<T>& vec0 = vec0_node_ptr_->ref();
|
|
vector_holder<T>& vec1 = *temp_;
|
|
|
|
for (std::size_t i = 0; i < vec_size_; ++i)
|
|
{
|
|
T& vec0_i = *vec0[i];
|
|
T& vec1_i = *vec1[i];
|
|
|
|
vec1_i = Operation::process(vec0_i);
|
|
}
|
|
|
|
return *vec1[0];
|
|
}
|
|
else
|
|
return std::numeric_limits<T>::quiet_NaN();
|
|
}
|
|
|
|
vector_node_ptr vec() const
|
|
{
|
|
return temp_vec_node_;
|
|
}
|
|
|
|
vector_node_ptr vec()
|
|
{
|
|
return temp_vec_node_;
|
|
}
|
|
|
|
inline typename expression_node<T>::node_type type() const
|
|
{
|
|
return expression_node<T>::e_vecunaryop;
|
|
}
|
|
|
|
std::size_t size() const
|
|
{
|
|
return vec_size_;
|
|
}
|
|
|
|
private:
|
|
|
|
vector_node_ptr vec0_node_ptr_;
|
|
std::size_t vec_size_;
|
|
T* data_;
|
|
vector_holder_ptr temp_;
|
|
vector_node_ptr temp_vec_node_;
|
|
};
|
|
|
|
template <typename T>
|
|
class scand_node : public binary_node<T>
|
|
{
|
|
public:
|
|
|
|
typedef expression_node<T>* expression_ptr;
|
|
|
|
scand_node(const operator_type& opr,
|
|
expression_ptr branch0,
|
|
expression_ptr branch1)
|
|
: binary_node<T>(opr,branch0,branch1)
|
|
{}
|
|
|
|
inline T value() const
|
|
{
|
|
return (
|
|
std::not_equal_to<T>()
|
|
(T(0),binary_node<T>::branch_[0].first->value()) &&
|
|
std::not_equal_to<T>()
|
|
(T(0),binary_node<T>::branch_[1].first->value())
|
|
) ? T(1) : T(0);
|
|
}
|
|
};
|
|
|
|
template <typename T>
|
|
class scor_node : public binary_node<T>
|
|
{
|
|
public:
|
|
|
|
typedef expression_node<T>* expression_ptr;
|
|
|
|
scor_node(const operator_type& opr,
|
|
expression_ptr branch0,
|
|
expression_ptr branch1)
|
|
: binary_node<T>(opr,branch0,branch1)
|
|
{}
|
|
|
|
inline T value() const
|
|
{
|
|
return (
|
|
std::not_equal_to<T>()
|
|
(T(0),binary_node<T>::branch_[0].first->value()) ||
|
|
std::not_equal_to<T>()
|
|
(T(0),binary_node<T>::branch_[1].first->value())
|
|
) ? T(1) : T(0);
|
|
}
|
|
};
|
|
|
|
template <typename T, typename IFunction, std::size_t N>
|
|
class function_N_node : public expression_node<T>
|
|
{
|
|
public:
|
|
|
|
// Function of N paramters.
|
|
typedef expression_node<T>* expression_ptr;
|
|
typedef std::pair<expression_ptr,bool> branch_t;
|
|
typedef IFunction ifunction;
|
|
|
|
function_N_node(ifunction* func)
|
|
: function_((N == func->param_count) ? func : reinterpret_cast<ifunction*>(0)),
|
|
parameter_count_(func->param_count)
|
|
{}
|
|
|
|
~function_N_node()
|
|
{
|
|
cleanup_branches::execute<T,N>(branch_);
|
|
}
|
|
|
|
template <std::size_t NumBranches>
|
|
bool init_branches(expression_ptr (&b)[NumBranches])
|
|
{
|
|
// Needed for incompetent and broken msvc compiler versions
|
|
#ifdef _MSC_VER
|
|
#pragma warning(push)
|
|
#pragma warning(disable: 4127)
|
|
#endif
|
|
if (N != NumBranches)
|
|
return false;
|
|
else
|
|
{
|
|
for (std::size_t i = 0; i < NumBranches; ++i)
|
|
{
|
|
if (b[i])
|
|
branch_[i] = std::make_pair(b[i],branch_deletable(b[i]));
|
|
else
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
#ifdef _MSC_VER
|
|
#pragma warning(pop)
|
|
#endif
|
|
}
|
|
|
|
inline bool operator <(const function_N_node<T,IFunction,N>& 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<T>::quiet_NaN();
|
|
else
|
|
{
|
|
T v[N];
|
|
evaluate_branches<T,N>::execute(v,branch_);
|
|
return invoke<T,N>::execute(*function_,v);
|
|
}
|
|
#ifdef _MSC_VER
|
|
#pragma warning(pop)
|
|
#endif
|
|
}
|
|
|
|
template <typename T_, std::size_t BranchCount>
|
|
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 <typename T_>
|
|
struct evaluate_branches <T_,5>
|
|
{
|
|
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 <typename T_>
|
|
struct evaluate_branches <T_,4>
|
|
{
|
|
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 <typename T_>
|
|
struct evaluate_branches <T_,3>
|
|
{
|
|
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 <typename T_>
|
|
struct evaluate_branches <T_,2>
|
|
{
|
|
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 <typename T_>
|
|
struct evaluate_branches <T_,1>
|
|
{
|
|
static inline void execute(T_ (&v)[1], const branch_t (&b)[1])
|
|
{
|
|
v[0] = b[0].first->value();
|
|
}
|
|
};
|
|
|
|
template <typename T_, std::size_t ParamCount>
|
|
struct invoke { static inline T execute(ifunction&, branch_t (&)[ParamCount]) { return std::numeric_limits<T_>::quiet_NaN(); } };
|
|
|
|
template <typename T_>
|
|
struct invoke<T_,20>
|
|
{
|
|
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 <typename T_>
|
|
struct invoke<T_,19>
|
|
{
|
|
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 <typename T_>
|
|
struct invoke<T_,18>
|
|
{
|
|
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 <typename T_>
|
|
struct invoke<T_,17>
|
|
{
|
|
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 <typename T_>
|
|
struct invoke<T_,16>
|
|
{
|
|
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 <typename T_>
|
|
struct invoke<T_,15>
|
|
{
|
|
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 <typename T_>
|
|
struct invoke<T_,14>
|
|
{
|
|
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 <typename T_>
|
|
struct invoke<T_,13>
|
|
{
|
|
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 <typename T_>
|
|
struct invoke<T_,12>
|
|
{
|
|
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 <typename T_>
|
|
struct invoke<T_,11>
|
|
{
|
|
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 <typename T_>
|
|
struct invoke<T_,10>
|
|
{
|
|
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 <typename T_>
|
|
struct invoke<T_,9>
|
|
{
|
|
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 <typename T_>
|
|
struct invoke<T_,8>
|
|
{
|
|
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 <typename T_>
|
|
struct invoke<T_,7>
|
|
{
|
|
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 <typename T_>
|
|
struct invoke<T_,6>
|
|
{
|
|
static inline T_ execute(ifunction& f, T_ (&v)[6])
|
|
{ return f(v[0],v[1],v[2],v[3],v[4],v[5]); }
|
|
};
|
|
|
|
template <typename T_>
|
|
struct invoke<T_,5>
|
|
{
|
|
static inline T_ execute(ifunction& f, T_ (&v)[5])
|
|
{ return f(v[0],v[1],v[2],v[3],v[4]); }
|
|
};
|
|
|
|
template <typename T_>
|
|
struct invoke<T_,4>
|
|
{
|
|
static inline T_ execute(ifunction& f, T_ (&v)[4])
|
|
{ return f(v[0],v[1],v[2],v[3]); }
|
|
};
|
|
|
|
template <typename T_>
|
|
struct invoke<T_,3>
|
|
{
|
|
static inline T_ execute(ifunction& f, T_ (&v)[3])
|
|
{ return f(v[0],v[1],v[2]); }
|
|
};
|
|
|
|
template <typename T_>
|
|
struct invoke<T_,2>
|
|
{
|
|
static inline T_ execute(ifunction& f, T_ (&v)[2])
|
|
{ return f(v[0],v[1]); }
|
|
};
|
|
|
|
template <typename T_>
|
|
struct invoke<T_,1>
|
|
{
|
|
static inline T_ execute(ifunction& f, T_ (&v)[1])
|
|
{ return f(v[0]); }
|
|
};
|
|
|
|
inline typename expression_node<T>::node_type type() const
|
|
{
|
|
return expression_node<T>::e_function;
|
|
}
|
|
|
|
private:
|
|
|
|
ifunction* function_;
|
|
std::size_t parameter_count_;
|
|
branch_t branch_[N];
|
|
};
|
|
|
|
template <typename T, typename IFunction>
|
|
class function_N_node<T,IFunction,0> : public expression_node<T>
|
|
{
|
|
public:
|
|
|
|
typedef expression_node<T>* expression_ptr;
|
|
typedef IFunction ifunction;
|
|
|
|
function_N_node(ifunction* func)
|
|
: function_((0 == func->param_count) ? func : reinterpret_cast<ifunction*>(0))
|
|
{}
|
|
|
|
inline bool operator <(const function_N_node<T,IFunction,0>& fn) const
|
|
{
|
|
return this < (&fn);
|
|
}
|
|
|
|
inline T value() const
|
|
{
|
|
if (function_)
|
|
return (*function_)();
|
|
else
|
|
return std::numeric_limits<T>::quiet_NaN();
|
|
}
|
|
|
|
inline typename expression_node<T>::node_type type() const
|
|
{
|
|
return expression_node<T>::e_function;
|
|
}
|
|
|
|
private:
|
|
|
|
ifunction* function_;
|
|
};
|
|
|
|
template <typename T, typename VarArgFunction>
|
|
class vararg_function_node : public expression_node<T>
|
|
{
|
|
public:
|
|
|
|
typedef expression_node<T>* expression_ptr;
|
|
|
|
vararg_function_node(VarArgFunction* func,
|
|
const std::vector<expression_ptr>& arg_list)
|
|
: function_(func),
|
|
arg_list_(arg_list)
|
|
{
|
|
value_list_.resize(arg_list.size(),std::numeric_limits<T>::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<T,VarArgFunction>& fn) const
|
|
{
|
|
return this < (&fn);
|
|
}
|
|
|
|
inline T value() const
|
|
{
|
|
if (function_)
|
|
{
|
|
populate_value_list();
|
|
return (*function_)(value_list_);
|
|
}
|
|
else
|
|
return std::numeric_limits<T>::quiet_NaN();
|
|
}
|
|
|
|
inline typename expression_node<T>::node_type type() const
|
|
{
|
|
return expression_node<T>::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<expression_ptr> arg_list_;
|
|
mutable std::vector<T> value_list_;
|
|
};
|
|
|
|
template <typename T, typename GenericFunction>
|
|
class generic_function_node : public expression_node<T>
|
|
{
|
|
public:
|
|
|
|
typedef type_store<T> type_store_t;
|
|
typedef expression_node<T>* expression_ptr;
|
|
typedef variable_node<T> variable_node_t;
|
|
typedef vector_elem_node<T> vector_elem_node_t;
|
|
typedef vector_node<T> vector_node_t;
|
|
typedef variable_node_t* variable_node_ptr_t;
|
|
typedef vector_elem_node_t* vector_elem_node_ptr_t;
|
|
typedef vector_node_t* vector_node_ptr_t;
|
|
typedef range_interface<T> range_interface_t;
|
|
typedef range_data_type<T> range_data_type_t;
|
|
typedef range_pack<T> range_t;
|
|
typedef std::pair<expression_ptr,bool> branch_t;
|
|
typedef std::pair<void*,std::size_t> void_t;
|
|
typedef std::vector<T> tmp_vs_t;
|
|
typedef std::vector<type_store_t> typestore_list_t;
|
|
typedef std::vector<range_data_type_t> range_list_t;
|
|
|
|
generic_function_node(GenericFunction* func,
|
|
const std::vector<expression_ptr>& arg_list)
|
|
: function_(func),
|
|
arg_list_(arg_list)
|
|
{}
|
|
|
|
~generic_function_node()
|
|
{
|
|
cleanup_branches::execute(branch_);
|
|
}
|
|
|
|
virtual bool init_branches()
|
|
{
|
|
expr_as_vec1_store_.resize(arg_list_.size(),T(0) );
|
|
typestore_list_ .resize(arg_list_.size(),type_store_t() );
|
|
range_list_ .resize(arg_list_.size(),range_data_type_t());
|
|
branch_ .resize(arg_list_.size(),branch_t((expression_ptr)0,false));
|
|
|
|
for (std::size_t i = 0; i < arg_list_.size(); ++i)
|
|
{
|
|
type_store_t& ts = typestore_list_[i];
|
|
|
|
if (0 == arg_list_[i])
|
|
return false;
|
|
else if (is_ivector_node(arg_list_[i]))
|
|
{
|
|
vector_interface<T>* vi = reinterpret_cast<vector_interface<T>*>(0);
|
|
|
|
if (0 == (vi = dynamic_cast<vector_interface<T>*>(arg_list_[i])))
|
|
return false;
|
|
|
|
ts.size = vi->size();
|
|
ts.data = vi->vec()->ref()[0];
|
|
ts.type = type_store_t::e_vector;
|
|
}
|
|
else if (is_generally_string_node(arg_list_[i]))
|
|
{
|
|
string_base_node<T>* sbn = reinterpret_cast<string_base_node<T>*>(0);
|
|
|
|
if (0 == (sbn = dynamic_cast<string_base_node<T>*>(arg_list_[i])))
|
|
return false;
|
|
|
|
ts.size = sbn->size();
|
|
ts.data = reinterpret_cast<void*>(const_cast<char*>(sbn->base()));
|
|
ts.type = type_store_t::e_string;
|
|
|
|
range_list_[i].data = ts.data;
|
|
range_list_[i].size = ts.size;
|
|
range_list_[i].type_size = sizeof(char);
|
|
range_list_[i].str_node = sbn;
|
|
|
|
if (is_generally_string_node(arg_list_[i]))
|
|
{
|
|
range_interface_t* ri = reinterpret_cast<range_interface_t*>(0);
|
|
|
|
if (0 == (ri = dynamic_cast<range_interface_t*>(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<char*>(ts.data) + rp.n0_c.second;
|
|
range_list_[i].range = reinterpret_cast<range_t*>(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<variable_node_ptr_t>(arg_list_[i])))
|
|
return false;
|
|
|
|
ts.size = 1;
|
|
ts.data = &var->ref();
|
|
ts.type = type_store_t::e_scalar;
|
|
}
|
|
else if (is_vector_elem_node(arg_list_[i]))
|
|
{
|
|
vector_elem_node_ptr_t var = vector_elem_node_ptr_t(0);
|
|
|
|
if (0 == (var = dynamic_cast<vector_elem_node_ptr_t>(arg_list_[i])))
|
|
return false;
|
|
|
|
ts.size = 1;
|
|
ts.data = reinterpret_cast<void*>(&var->ref());
|
|
ts.type = type_store_t::e_scalar;
|
|
}
|
|
else
|
|
{
|
|
ts.size = 1;
|
|
ts.data = reinterpret_cast<void*>(&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<T,GenericFunction>& 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<T>::quiet_NaN();
|
|
}
|
|
|
|
inline typename expression_node<T>::node_type type() const
|
|
{
|
|
return expression_node<T>::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<char*>(rdt.str_node->base()) + rp.cache.first;
|
|
else
|
|
ts.data = static_cast<char*>(rdt.data) + (rp.cache.first * rdt.type_size);
|
|
}
|
|
else
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
GenericFunction* function_;
|
|
mutable typestore_list_t typestore_list_;
|
|
|
|
private:
|
|
|
|
std::vector<expression_ptr> arg_list_;
|
|
std::vector<branch_t> branch_;
|
|
mutable tmp_vs_t expr_as_vec1_store_;
|
|
mutable range_list_t range_list_;
|
|
};
|
|
|
|
template <typename T, typename StringFunction>
|
|
class string_function_node : public generic_function_node<T,StringFunction>,
|
|
public string_base_node<T>,
|
|
public range_interface <T>
|
|
{
|
|
public:
|
|
|
|
typedef generic_function_node<T, StringFunction> gen_function_t;
|
|
typedef range_pack<T> range_t;
|
|
|
|
string_function_node(StringFunction* func,
|
|
const std::vector<typename gen_function_t::expression_ptr>& arg_list)
|
|
: gen_function_t(func,arg_list)
|
|
{
|
|
range_.n0_c = std::make_pair<bool,std::size_t>(true,0);
|
|
range_.n1_c = std::make_pair<bool,std::size_t>(true,0);
|
|
range_.cache.first = range_.n0_c.second;
|
|
range_.cache.second = range_.n1_c.second;
|
|
}
|
|
|
|
inline bool operator <(const string_function_node<T,StringFunction>& fn) const
|
|
{
|
|
return this < (&fn);
|
|
}
|
|
|
|
inline T value() const
|
|
{
|
|
T result = std::numeric_limits<T>::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<T>::node_type type() const
|
|
{
|
|
return expression_node<T>::e_strfunction;
|
|
}
|
|
|
|
std::string str() const
|
|
{
|
|
return ret_string_;
|
|
}
|
|
|
|
const char* base() const
|
|
{
|
|
return ret_string_.data();
|
|
}
|
|
|
|
std::size_t size() const
|
|
{
|
|
return ret_string_.size();
|
|
}
|
|
|
|
range_t& range_ref()
|
|
{
|
|
return range_;
|
|
}
|
|
|
|
const range_t& range_ref() const
|
|
{
|
|
return range_;
|
|
}
|
|
|
|
protected:
|
|
|
|
mutable range_t range_;
|
|
mutable std::string ret_string_;
|
|
};
|
|
|
|
template <typename T, typename GenericFunction>
|
|
class multimode_genfunction_node : public generic_function_node<T,GenericFunction>
|
|
{
|
|
public:
|
|
|
|
typedef generic_function_node<T, GenericFunction> gen_function_t;
|
|
typedef range_pack<T> range_t;
|
|
|
|
multimode_genfunction_node(GenericFunction* func,
|
|
const std::size_t& param_seq_index,
|
|
const std::vector<typename gen_function_t::expression_ptr>& arg_list)
|
|
: gen_function_t(func,arg_list),
|
|
param_seq_index_(param_seq_index)
|
|
{}
|
|
|
|
inline T value() const
|
|
{
|
|
T result = std::numeric_limits<T>::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<T>::node_type type() const
|
|
{
|
|
return expression_node<T>::e_genfunction;
|
|
}
|
|
|
|
private:
|
|
|
|
std::size_t param_seq_index_;
|
|
};
|
|
|
|
template <typename T, typename StringFunction>
|
|
class multimode_strfunction_node : public string_function_node<T,StringFunction>
|
|
{
|
|
public:
|
|
|
|
typedef string_function_node<T, StringFunction> str_function_t;
|
|
typedef range_pack<T> range_t;
|
|
|
|
multimode_strfunction_node(StringFunction* func,
|
|
const std::size_t& param_seq_index,
|
|
const std::vector<typename str_function_t::expression_ptr>& arg_list)
|
|
: str_function_t(func,arg_list),
|
|
param_seq_index_(param_seq_index)
|
|
{}
|
|
|
|
inline T value() const
|
|
{
|
|
T result = std::numeric_limits<T>::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<T>::node_type type() const
|
|
{
|
|
return expression_node<T>::e_strfunction;
|
|
}
|
|
|
|
private:
|
|
|
|
std::size_t param_seq_index_;
|
|
};
|
|
|
|
#define exprtk_define_unary_op(OpName) \
|
|
template <typename T> \
|
|
struct OpName##_op \
|
|
{ \
|
|
typedef typename functor_t<T>::Type Type; \
|
|
\
|
|
static inline T process(Type v) \
|
|
{ \
|
|
return numeric:: OpName (v); \
|
|
} \
|
|
\
|
|
static inline typename expression_node<T>::node_type type() \
|
|
{ \
|
|
return expression_node<T>::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 <typename T>
|
|
struct opr_base
|
|
{
|
|
typedef typename details::functor_t<T>::Type Type;
|
|
typedef typename details::functor_t<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 <typename T>
|
|
struct add_op : public opr_base<T>
|
|
{
|
|
typedef typename opr_base<T>::Type Type;
|
|
static inline T process(Type t1, Type t2) { return t1 + t2; }
|
|
static inline T process(Type t1, Type t2, Type t3) { return t1 + t2 + t3; }
|
|
static inline typename expression_node<T>::node_type type() { return expression_node<T>::e_add; }
|
|
static inline details::operator_type operation() { return details::e_add; }
|
|
};
|
|
|
|
template <typename T>
|
|
struct mul_op : public opr_base<T>
|
|
{
|
|
typedef typename opr_base<T>::Type Type;
|
|
static inline T process(Type t1, Type t2) { return t1 * t2; }
|
|
static inline T process(Type t1, Type t2, Type t3) { return t1 * t2 * t3; }
|
|
static inline typename expression_node<T>::node_type type() { return expression_node<T>::e_mul; }
|
|
static inline details::operator_type operation() { return details::e_mul; }
|
|
};
|
|
|
|
template <typename T>
|
|
struct sub_op : public opr_base<T>
|
|
{
|
|
typedef typename opr_base<T>::Type Type;
|
|
static inline T process(Type t1, Type t2) { return t1 - t2; }
|
|
static inline T process(Type t1, Type t2, Type t3) { return t1 - t2 - t3; }
|
|
static inline typename expression_node<T>::node_type type() { return expression_node<T>::e_sub; }
|
|
static inline details::operator_type operation() { return details::e_sub; }
|
|
};
|
|
|
|
template <typename T>
|
|
struct div_op : public opr_base<T>
|
|
{
|
|
typedef typename opr_base<T>::Type Type;
|
|
static inline T process(Type t1, Type t2) { return t1 / t2; }
|
|
static inline T process(Type t1, Type t2, Type t3) { return t1 / t2 / t3; }
|
|
static inline typename expression_node<T>::node_type type() { return expression_node<T>::e_div; }
|
|
static inline details::operator_type operation() { return details::e_div; }
|
|
};
|
|
|
|
template <typename T>
|
|
struct mod_op : public opr_base<T>
|
|
{
|
|
typedef typename opr_base<T>::Type Type;
|
|
static inline T process(Type t1, Type t2) { return numeric::modulus<T>(t1,t2); }
|
|
static inline typename expression_node<T>::node_type type() { return expression_node<T>::e_mod; }
|
|
static inline details::operator_type operation() { return details::e_mod; }
|
|
};
|
|
|
|
template <typename T>
|
|
struct pow_op : public opr_base<T>
|
|
{
|
|
typedef typename opr_base<T>::Type Type;
|
|
static inline T process(Type t1, Type t2) { return numeric::pow<T>(t1,t2); }
|
|
static inline typename expression_node<T>::node_type type() { return expression_node<T>::e_pow; }
|
|
static inline details::operator_type operation() { return details::e_pow; }
|
|
};
|
|
|
|
template <typename T>
|
|
struct lt_op : public opr_base<T>
|
|
{
|
|
typedef typename opr_base<T>::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<T>::node_type type() { return expression_node<T>::e_lt; }
|
|
static inline details::operator_type operation() { return details::e_lt; }
|
|
};
|
|
|
|
template <typename T>
|
|
struct lte_op : public opr_base<T>
|
|
{
|
|
typedef typename opr_base<T>::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<T>::node_type type() { return expression_node<T>::e_lte; }
|
|
static inline details::operator_type operation() { return details::e_lte; }
|
|
};
|
|
|
|
template <typename T>
|
|
struct gt_op : public opr_base<T>
|
|
{
|
|
typedef typename opr_base<T>::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<T>::node_type type() { return expression_node<T>::e_gt; }
|
|
static inline details::operator_type operation() { return details::e_gt; }
|
|
};
|
|
|
|
template <typename T>
|
|
struct gte_op : public opr_base<T>
|
|
{
|
|
typedef typename opr_base<T>::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<T>::node_type type() { return expression_node<T>::e_gte; }
|
|
static inline details::operator_type operation() { return details::e_gte; }
|
|
};
|
|
|
|
template <typename T>
|
|
struct eq_op : public opr_base<T>
|
|
{
|
|
typedef typename opr_base<T>::Type Type;
|
|
static inline T process(Type t1, Type t2) { return (std::equal_to<T>()(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<T>::node_type type() { return expression_node<T>::e_eq; }
|
|
static inline details::operator_type operation() { return details::e_eq; }
|
|
};
|
|
|
|
template <typename T>
|
|
struct ne_op : public opr_base<T>
|
|
{
|
|
typedef typename opr_base<T>::Type Type;
|
|
static inline T process(Type t1, Type t2) { return (std::not_equal_to<T>()(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<T>::node_type type() { return expression_node<T>::e_ne; }
|
|
static inline details::operator_type operation() { return details::e_ne; }
|
|
};
|
|
|
|
template <typename T>
|
|
struct and_op : public opr_base<T>
|
|
{
|
|
typedef typename opr_base<T>::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<T>::node_type type() { return expression_node<T>::e_and; }
|
|
static inline details::operator_type operation() { return details::e_and; }
|
|
};
|
|
|
|
template <typename T>
|
|
struct nand_op : public opr_base<T>
|
|
{
|
|
typedef typename opr_base<T>::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<T>::node_type type() { return expression_node<T>::e_nand; }
|
|
static inline details::operator_type operation() { return details::e_nand; }
|
|
};
|
|
|
|
template <typename T>
|
|
struct or_op : public opr_base<T>
|
|
{
|
|
typedef typename opr_base<T>::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<T>::node_type type() { return expression_node<T>::e_or; }
|
|
static inline details::operator_type operation() { return details::e_or; }
|
|
};
|
|
|
|
template <typename T>
|
|
struct nor_op : public opr_base<T>
|
|
{
|
|
typedef typename opr_base<T>::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<T>::node_type type() { return expression_node<T>::e_nor; }
|
|
static inline details::operator_type operation() { return details::e_nor; }
|
|
};
|
|
|
|
template <typename T>
|
|
struct xor_op : public opr_base<T>
|
|
{
|
|
typedef typename opr_base<T>::Type Type;
|
|
static inline T process(Type t1, Type t2) { return numeric::xor_opr<T>(t1,t2); }
|
|
static inline typename expression_node<T>::node_type type() { return expression_node<T>::e_nor; }
|
|
static inline details::operator_type operation() { return details::e_xor; }
|
|
};
|
|
|
|
template <typename T>
|
|
struct xnor_op : public opr_base<T>
|
|
{
|
|
typedef typename opr_base<T>::Type Type;
|
|
static inline T process(Type t1, Type t2) { return numeric::xnor_opr<T>(t1,t2); }
|
|
static inline typename expression_node<T>::node_type type() { return expression_node<T>::e_nor; }
|
|
static inline details::operator_type operation() { return details::e_xnor; }
|
|
};
|
|
|
|
template <typename T>
|
|
struct in_op : public opr_base<T>
|
|
{
|
|
typedef typename opr_base<T>::Type Type;
|
|
static inline T process(const T&, const T&) { return std::numeric_limits<T>::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<T>::node_type type() { return expression_node<T>::e_in; }
|
|
static inline details::operator_type operation() { return details::e_in; }
|
|
};
|
|
|
|
template <typename T>
|
|
struct like_op : public opr_base<T>
|
|
{
|
|
typedef typename opr_base<T>::Type Type;
|
|
static inline T process(const T&, const T&) { return std::numeric_limits<T>::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<T>::node_type type() { return expression_node<T>::e_like; }
|
|
static inline details::operator_type operation() { return details::e_like; }
|
|
};
|
|
|
|
template <typename T>
|
|
struct ilike_op : public opr_base<T>
|
|
{
|
|
typedef typename opr_base<T>::Type Type;
|
|
static inline T process(const T&, const T&) { return std::numeric_limits<T>::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<T>::node_type type() { return expression_node<T>::e_ilike; }
|
|
static inline details::operator_type operation() { return details::e_ilike; }
|
|
};
|
|
|
|
template <typename T>
|
|
struct inrange_op : public opr_base<T>
|
|
{
|
|
typedef typename opr_base<T>::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<T>::node_type type() { return expression_node<T>::e_inranges; }
|
|
static inline details::operator_type operation() { return details::e_inrange; }
|
|
};
|
|
|
|
template <typename T>
|
|
inline T value(details::expression_node<T>* n)
|
|
{
|
|
return n->value();
|
|
}
|
|
|
|
template <typename T>
|
|
inline T value(T* t)
|
|
{
|
|
return (*t);
|
|
}
|
|
|
|
template <typename T>
|
|
struct vararg_add_op : public opr_base<T>
|
|
{
|
|
typedef typename opr_base<T>::Type Type;
|
|
|
|
template <typename Type,
|
|
typename Allocator,
|
|
template <typename,typename> class Sequence>
|
|
static inline T process(const Sequence<Type,Allocator>& arg_list)
|
|
{
|
|
switch (arg_list.size())
|
|
{
|
|
case 0 : return T(0);
|
|
case 1 : return process_1(arg_list);
|
|
case 2 : return process_2(arg_list);
|
|
case 3 : return process_3(arg_list);
|
|
case 4 : return process_4(arg_list);
|
|
case 5 : return process_5(arg_list);
|
|
default :
|
|
{
|
|
T result = T(0);
|
|
|
|
for (std::size_t i = 0; i < arg_list.size(); ++i)
|
|
{
|
|
result += value(arg_list[i]);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
}
|
|
}
|
|
|
|
template <typename Sequence>
|
|
static inline T process_1(const Sequence& arg_list)
|
|
{
|
|
return value(arg_list[0]);
|
|
}
|
|
|
|
template <typename Sequence>
|
|
static inline T process_2(const Sequence& arg_list)
|
|
{
|
|
return value(arg_list[0]) + value(arg_list[1]);
|
|
}
|
|
|
|
template <typename Sequence>
|
|
static inline T process_3(const Sequence& arg_list)
|
|
{
|
|
return value(arg_list[0]) + value(arg_list[1]) +
|
|
value(arg_list[2]);
|
|
}
|
|
|
|
template <typename Sequence>
|
|
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 <typename Sequence>
|
|
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 <typename T>
|
|
struct vararg_mul_op : public opr_base<T>
|
|
{
|
|
typedef typename opr_base<T>::Type Type;
|
|
|
|
template <typename Type,
|
|
typename Allocator,
|
|
template <typename,typename> class Sequence>
|
|
static inline T process(const Sequence<Type,Allocator>& arg_list)
|
|
{
|
|
switch (arg_list.size())
|
|
{
|
|
case 0 : return T(0);
|
|
case 1 : return process_1(arg_list);
|
|
case 2 : return process_2(arg_list);
|
|
case 3 : return process_3(arg_list);
|
|
case 4 : return process_4(arg_list);
|
|
case 5 : return process_5(arg_list);
|
|
default :
|
|
{
|
|
T result = T(value(arg_list[0]));
|
|
|
|
for (std::size_t i = 1; i < arg_list.size(); ++i)
|
|
{
|
|
result *= value(arg_list[i]);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
}
|
|
}
|
|
|
|
template <typename Sequence>
|
|
static inline T process_1(const Sequence& arg_list)
|
|
{
|
|
return value(arg_list[0]);
|
|
}
|
|
|
|
template <typename Sequence>
|
|
static inline T process_2(const Sequence& arg_list)
|
|
{
|
|
return value(arg_list[0]) * value(arg_list[1]);
|
|
}
|
|
|
|
template <typename Sequence>
|
|
static inline T process_3(const Sequence& arg_list)
|
|
{
|
|
return value(arg_list[0]) * value(arg_list[1]) *
|
|
value(arg_list[2]);
|
|
}
|
|
|
|
template <typename Sequence>
|
|
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 <typename Sequence>
|
|
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 <typename T>
|
|
struct vararg_avg_op : public opr_base<T>
|
|
{
|
|
typedef typename opr_base<T>::Type Type;
|
|
|
|
template <typename Type,
|
|
typename Allocator,
|
|
template <typename,typename> class Sequence>
|
|
static inline T process(const Sequence<Type,Allocator>& 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<T>::process(arg_list) / arg_list.size();
|
|
}
|
|
}
|
|
|
|
template <typename Sequence>
|
|
static inline T process_1(const Sequence& arg_list)
|
|
{
|
|
return value(arg_list[0]);
|
|
}
|
|
|
|
template <typename Sequence>
|
|
static inline T process_2(const Sequence& arg_list)
|
|
{
|
|
return (value(arg_list[0]) + value(arg_list[1])) / T(2);
|
|
}
|
|
|
|
template <typename Sequence>
|
|
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 <typename Sequence>
|
|
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 <typename Sequence>
|
|
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 <typename T>
|
|
struct vararg_min_op : public opr_base<T>
|
|
{
|
|
typedef typename opr_base<T>::Type Type;
|
|
|
|
template <typename Type,
|
|
typename Allocator,
|
|
template <typename,typename> class Sequence>
|
|
static inline T process(const Sequence<Type,Allocator>& 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 <typename Sequence>
|
|
static inline T process_1(const Sequence& arg_list)
|
|
{
|
|
return value(arg_list[0]);
|
|
}
|
|
|
|
template <typename Sequence>
|
|
static inline T process_2(const Sequence& arg_list)
|
|
{
|
|
return std::min<T>(value(arg_list[0]),value(arg_list[1]));
|
|
}
|
|
|
|
template <typename Sequence>
|
|
static inline T process_3(const Sequence& arg_list)
|
|
{
|
|
return std::min<T>(std::min<T>(value(arg_list[0]),value(arg_list[1])),value(arg_list[2]));
|
|
}
|
|
|
|
template <typename Sequence>
|
|
static inline T process_4(const Sequence& arg_list)
|
|
{
|
|
return std::min<T>(
|
|
std::min<T>(value(arg_list[0]),value(arg_list[1])),
|
|
std::min<T>(value(arg_list[2]),value(arg_list[3])));
|
|
}
|
|
|
|
template <typename Sequence>
|
|
static inline T process_5(const Sequence& arg_list)
|
|
{
|
|
return std::min<T>(
|
|
std::min<T>(std::min<T>(value(arg_list[0]),value(arg_list[1])),
|
|
std::min<T>(value(arg_list[2]),value(arg_list[3]))),
|
|
value(arg_list[4]));
|
|
}
|
|
};
|
|
|
|
template <typename T>
|
|
struct vararg_max_op : public opr_base<T>
|
|
{
|
|
typedef typename opr_base<T>::Type Type;
|
|
|
|
template <typename Type,
|
|
typename Allocator,
|
|
template <typename,typename> class Sequence>
|
|
static inline T process(const Sequence<Type,Allocator>& 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 <typename Sequence>
|
|
static inline T process_1(const Sequence& arg_list)
|
|
{
|
|
return value(arg_list[0]);
|
|
}
|
|
|
|
template <typename Sequence>
|
|
static inline T process_2(const Sequence& arg_list)
|
|
{
|
|
return std::max<T>(value(arg_list[0]),value(arg_list[1]));
|
|
}
|
|
|
|
template <typename Sequence>
|
|
static inline T process_3(const Sequence& arg_list)
|
|
{
|
|
return std::max<T>(std::max<T>(value(arg_list[0]),value(arg_list[1])),value(arg_list[2]));
|
|
}
|
|
|
|
template <typename Sequence>
|
|
static inline T process_4(const Sequence& arg_list)
|
|
{
|
|
return std::max<T>(
|
|
std::max<T>(value(arg_list[0]),value(arg_list[1])),
|
|
std::max<T>(value(arg_list[2]),value(arg_list[3])));
|
|
}
|
|
|
|
template <typename Sequence>
|
|
static inline T process_5(const Sequence& arg_list)
|
|
{
|
|
return std::max<T>(
|
|
std::max<T>(std::max<T>(value(arg_list[0]),value(arg_list[1])),
|
|
std::max<T>(value(arg_list[2]),value(arg_list[3]))),
|
|
value(arg_list[4]));
|
|
}
|
|
};
|
|
|
|
template <typename T>
|
|
struct vararg_mand_op : public opr_base<T>
|
|
{
|
|
typedef typename opr_base<T>::Type Type;
|
|
|
|
template <typename Type,
|
|
typename Allocator,
|
|
template <typename,typename> class Sequence>
|
|
static inline T process(const Sequence<Type,Allocator>& 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>()(T(0),value(arg_list[i])))
|
|
return T(0);
|
|
}
|
|
|
|
return T(1);
|
|
}
|
|
}
|
|
}
|
|
|
|
template <typename Sequence>
|
|
static inline T process_1(const Sequence& arg_list)
|
|
{
|
|
return std::not_equal_to<T>()
|
|
(T(0),value(arg_list[0])) ? T(1) : T(0);
|
|
}
|
|
|
|
template <typename Sequence>
|
|
static inline T process_2(const Sequence& arg_list)
|
|
{
|
|
return (
|
|
std::not_equal_to<T>()(T(0),value(arg_list[0])) &&
|
|
std::not_equal_to<T>()(T(0),value(arg_list[1]))
|
|
) ? T(1) : T(0);
|
|
}
|
|
|
|
template <typename Sequence>
|
|
static inline T process_3(const Sequence& arg_list)
|
|
{
|
|
return (
|
|
std::not_equal_to<T>()(T(0),value(arg_list[0])) &&
|
|
std::not_equal_to<T>()(T(0),value(arg_list[1])) &&
|
|
std::not_equal_to<T>()(T(0),value(arg_list[2]))
|
|
) ? T(1) : T(0);
|
|
}
|
|
|
|
template <typename Sequence>
|
|
static inline T process_4(const Sequence& arg_list)
|
|
{
|
|
return (
|
|
std::not_equal_to<T>()(T(0),value(arg_list[0])) &&
|
|
std::not_equal_to<T>()(T(0),value(arg_list[1])) &&
|
|
std::not_equal_to<T>()(T(0),value(arg_list[2])) &&
|
|
std::not_equal_to<T>()(T(0),value(arg_list[3]))
|
|
) ? T(1) : T(0);
|
|
}
|
|
|
|
template <typename Sequence>
|
|
static inline T process_5(const Sequence& arg_list)
|
|
{
|
|
return (
|
|
std::not_equal_to<T>()(T(0),value(arg_list[0])) &&
|
|
std::not_equal_to<T>()(T(0),value(arg_list[1])) &&
|
|
std::not_equal_to<T>()(T(0),value(arg_list[2])) &&
|
|
std::not_equal_to<T>()(T(0),value(arg_list[3])) &&
|
|
std::not_equal_to<T>()(T(0),value(arg_list[4]))
|
|
) ? T(1) : T(0);
|
|
}
|
|
};
|
|
|
|
template <typename T>
|
|
struct vararg_mor_op : public opr_base<T>
|
|
{
|
|
typedef typename opr_base<T>::Type Type;
|
|
|
|
template <typename Type,
|
|
typename Allocator,
|
|
template <typename,typename> class Sequence>
|
|
static inline T process(const Sequence<Type,Allocator>& 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>()(T(0),value(arg_list[i])))
|
|
return T(1);
|
|
}
|
|
|
|
return T(0);
|
|
}
|
|
}
|
|
}
|
|
|
|
template <typename Sequence>
|
|
static inline T process_1(const Sequence& arg_list)
|
|
{
|
|
return std::not_equal_to<T>()
|
|
(T(0),value(arg_list[0])) ? T(1) : T(0);
|
|
}
|
|
|
|
template <typename Sequence>
|
|
static inline T process_2(const Sequence& arg_list)
|
|
{
|
|
return (
|
|
std::not_equal_to<T>()(T(0),value(arg_list[0])) ||
|
|
std::not_equal_to<T>()(T(0),value(arg_list[1]))
|
|
) ? T(1) : T(0);
|
|
}
|
|
|
|
template <typename Sequence>
|
|
static inline T process_3(const Sequence& arg_list)
|
|
{
|
|
return (
|
|
std::not_equal_to<T>()(T(0),value(arg_list[0])) ||
|
|
std::not_equal_to<T>()(T(0),value(arg_list[1])) ||
|
|
std::not_equal_to<T>()(T(0),value(arg_list[2]))
|
|
) ? T(1) : T(0);
|
|
}
|
|
|
|
template <typename Sequence>
|
|
static inline T process_4(const Sequence& arg_list)
|
|
{
|
|
return (
|
|
std::not_equal_to<T>()(T(0),value(arg_list[0])) ||
|
|
std::not_equal_to<T>()(T(0),value(arg_list[1])) ||
|
|
std::not_equal_to<T>()(T(0),value(arg_list[2])) ||
|
|
std::not_equal_to<T>()(T(0),value(arg_list[3]))
|
|
) ? T(1) : T(0);
|
|
}
|
|
|
|
template <typename Sequence>
|
|
static inline T process_5(const Sequence& arg_list)
|
|
{
|
|
return (
|
|
std::not_equal_to<T>()(T(0),value(arg_list[0])) ||
|
|
std::not_equal_to<T>()(T(0),value(arg_list[1])) ||
|
|
std::not_equal_to<T>()(T(0),value(arg_list[2])) ||
|
|
std::not_equal_to<T>()(T(0),value(arg_list[3])) ||
|
|
std::not_equal_to<T>()(T(0),value(arg_list[4]))
|
|
) ? T(1) : T(0);
|
|
}
|
|
};
|
|
|
|
template <typename T>
|
|
struct vararg_multi_op : public opr_base<T>
|
|
{
|
|
typedef typename opr_base<T>::Type Type;
|
|
|
|
template <typename Type,
|
|
typename Allocator,
|
|
template <typename,typename> class Sequence>
|
|
static inline T process(const Sequence<Type,Allocator>& arg_list)
|
|
{
|
|
switch (arg_list.size())
|
|
{
|
|
case 0 : return std::numeric_limits<T>::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 <typename Sequence>
|
|
static inline T process_1(const Sequence& arg_list)
|
|
{
|
|
return value(arg_list[0]);
|
|
}
|
|
|
|
template <typename Sequence>
|
|
static inline T process_2(const Sequence& arg_list)
|
|
{
|
|
value(arg_list[0]);
|
|
return value(arg_list[1]);
|
|
}
|
|
|
|
template <typename Sequence>
|
|
static inline T process_3(const Sequence& arg_list)
|
|
{
|
|
value(arg_list[0]);
|
|
value(arg_list[1]);
|
|
return value(arg_list[2]);
|
|
}
|
|
|
|
template <typename Sequence>
|
|
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 <typename Sequence>
|
|
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 <typename Sequence>
|
|
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 <typename Sequence>
|
|
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 <typename Sequence>
|
|
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 <typename T>
|
|
struct vec_add_op
|
|
{
|
|
typedef vector_interface<T>* ivector_ptr;
|
|
|
|
static inline T process(const ivector_ptr v)
|
|
{
|
|
vector_holder<T>& vec = v->vec()->ref();
|
|
|
|
T result = T(0);
|
|
|
|
for (std::size_t i = 0; i < vec.size(); ++i)
|
|
{
|
|
result += (*vec[i]);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
};
|
|
|
|
template <typename T>
|
|
struct vec_mul_op
|
|
{
|
|
typedef vector_interface<T>* ivector_ptr;
|
|
|
|
static inline T process(const ivector_ptr v)
|
|
{
|
|
vector_holder<T>& vec = v->vec()->ref();
|
|
|
|
T result = (*vec[0]);
|
|
|
|
for (std::size_t i = 1; i < vec.size(); ++i)
|
|
{
|
|
result *= (*vec[i]);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
};
|
|
|
|
template <typename T>
|
|
struct vec_avg_op
|
|
{
|
|
typedef vector_interface<T>* ivector_ptr;
|
|
|
|
static inline T process(const ivector_ptr v)
|
|
{
|
|
vector_holder<T>& vec = v->vec()->ref();
|
|
|
|
T result = T(0);
|
|
|
|
for (std::size_t i = 0; i < vec.size(); ++i)
|
|
{
|
|
result += (*vec[i]);
|
|
}
|
|
|
|
return result / vec.size();
|
|
}
|
|
};
|
|
|
|
template <typename T>
|
|
struct vec_min_op
|
|
{
|
|
typedef vector_interface<T>* ivector_ptr;
|
|
|
|
static inline T process(const ivector_ptr v)
|
|
{
|
|
vector_holder<T>& vec = v->vec()->ref();
|
|
|
|
T result = (*vec[0]);
|
|
|
|
for (std::size_t i = 1; i < vec.size(); ++i)
|
|
{
|
|
T v_i = (*vec[i]);
|
|
|
|
if (v_i < result)
|
|
result = v_i;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
};
|
|
|
|
template <typename T>
|
|
struct vec_max_op
|
|
{
|
|
typedef vector_interface<T>* ivector_ptr;
|
|
|
|
static inline T process(const ivector_ptr v)
|
|
{
|
|
vector_holder<T>& vec = v->vec()->ref();
|
|
|
|
T result = (*vec[0]);
|
|
|
|
for (std::size_t i = 1; i < vec.size(); ++i)
|
|
{
|
|
T v_i = (*vec[i]);
|
|
if (v_i > result)
|
|
result = v_i;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
};
|
|
|
|
template <typename T>
|
|
class vov_base_node : public expression_node<T>
|
|
{
|
|
public:
|
|
|
|
inline virtual operator_type operation() const
|
|
{
|
|
return details::e_default;
|
|
}
|
|
|
|
virtual const T& v0() const = 0;
|
|
|
|
virtual const T& v1() const = 0;
|
|
};
|
|
|
|
template <typename T>
|
|
class cov_base_node : public expression_node<T>
|
|
{
|
|
public:
|
|
|
|
inline virtual operator_type operation() const
|
|
{
|
|
return details::e_default;
|
|
}
|
|
|
|
virtual const T c() const = 0;
|
|
|
|
virtual const T& v() const = 0;
|
|
};
|
|
|
|
template <typename T>
|
|
class voc_base_node : public expression_node<T>
|
|
{
|
|
public:
|
|
|
|
inline virtual operator_type operation() const
|
|
{
|
|
return details::e_default;
|
|
}
|
|
|
|
virtual const T c() const = 0;
|
|
|
|
virtual const T& v() const = 0;
|
|
};
|
|
|
|
template <typename T>
|
|
class vob_base_node : public expression_node<T>
|
|
{
|
|
public:
|
|
|
|
virtual const T& v() const = 0;
|
|
};
|
|
|
|
template <typename T>
|
|
class bov_base_node : public expression_node<T>
|
|
{
|
|
public:
|
|
|
|
virtual const T& v() const = 0;
|
|
};
|
|
|
|
template <typename T>
|
|
class cob_base_node : public expression_node<T>
|
|
{
|
|
public:
|
|
|
|
inline virtual operator_type operation() const
|
|
{
|
|
return details::e_default;
|
|
}
|
|
|
|
virtual const T c() const = 0;
|
|
|
|
virtual void set_c(const T) = 0;
|
|
|
|
virtual expression_node<T>* move_branch(const std::size_t& index) = 0;
|
|
};
|
|
|
|
template <typename T>
|
|
class boc_base_node : public expression_node<T>
|
|
{
|
|
public:
|
|
|
|
inline virtual operator_type operation() const
|
|
{
|
|
return details::e_default;
|
|
}
|
|
|
|
virtual const T c() const = 0;
|
|
|
|
virtual void set_c(const T) = 0;
|
|
|
|
virtual expression_node<T>* move_branch(const std::size_t& index) = 0;
|
|
};
|
|
|
|
template <typename T>
|
|
class uv_base_node : public expression_node<T>
|
|
{
|
|
public:
|
|
|
|
inline virtual operator_type operation() const
|
|
{
|
|
return details::e_default;
|
|
}
|
|
|
|
virtual const T& v() const = 0;
|
|
};
|
|
|
|
template <typename T>
|
|
class sos_base_node : public expression_node<T>
|
|
{
|
|
public:
|
|
|
|
inline virtual operator_type operation() const
|
|
{
|
|
return details::e_default;
|
|
}
|
|
};
|
|
|
|
template <typename T>
|
|
class sosos_base_node : public expression_node<T>
|
|
{
|
|
public:
|
|
|
|
inline virtual operator_type operation() const
|
|
{
|
|
return details::e_default;
|
|
}
|
|
};
|
|
|
|
template <typename T>
|
|
class T0oT1oT2_base_node : public expression_node<T>
|
|
{
|
|
public:
|
|
|
|
virtual std::string type_id() const = 0;
|
|
};
|
|
|
|
template <typename T>
|
|
class T0oT1oT2oT3_base_node : public expression_node<T>
|
|
{
|
|
public:
|
|
|
|
virtual std::string type_id() const = 0;
|
|
};
|
|
|
|
template <typename T, typename Operation>
|
|
class unary_variable_node : public uv_base_node<T>
|
|
{
|
|
public:
|
|
|
|
typedef expression_node<T>* 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<T>::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<T,Operation>&);
|
|
unary_variable_node<T,Operation>& operator=(unary_variable_node<T,Operation>&);
|
|
|
|
const T& v_;
|
|
};
|
|
|
|
template <typename T>
|
|
class uvouv_node : public expression_node<T>
|
|
{
|
|
public:
|
|
|
|
// UOpr1(v0) Op UOpr2(v1)
|
|
|
|
typedef expression_node<T>* expression_ptr;
|
|
typedef typename details::functor_t<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<T>::node_type type() const
|
|
{
|
|
return expression_node<T>::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<T>&);
|
|
uvouv_node<T>& operator=(uvouv_node<T>&);
|
|
|
|
const T& v0_;
|
|
const T& v1_;
|
|
const ufunc_t u0_;
|
|
const ufunc_t u1_;
|
|
const bfunc_t f_;
|
|
};
|
|
|
|
template <typename T, typename Operation>
|
|
class unary_branch_node : public expression_node<T>
|
|
{
|
|
public:
|
|
|
|
typedef expression_node<T>* expression_ptr;
|
|
typedef Operation operation_t;
|
|
|
|
explicit unary_branch_node(expression_ptr brnch)
|
|
: branch_(brnch),
|
|
branch_deletable_(branch_deletable(branch_))
|
|
{}
|
|
|
|
~unary_branch_node()
|
|
{
|
|
if (branch_ && branch_deletable_)
|
|
{
|
|
delete branch_;
|
|
branch_ = 0;
|
|
}
|
|
}
|
|
|
|
inline T value() const
|
|
{
|
|
return Operation::process(branch_->value());
|
|
}
|
|
|
|
inline typename expression_node<T>::node_type type() const
|
|
{
|
|
return Operation::type();
|
|
}
|
|
|
|
inline operator_type operation() const
|
|
{
|
|
return Operation::operation();
|
|
}
|
|
|
|
inline expression_node<T>* branch(const std::size_t&) const
|
|
{
|
|
return branch_;
|
|
}
|
|
|
|
inline void release()
|
|
{
|
|
branch_deletable_ = false;
|
|
}
|
|
|
|
private:
|
|
|
|
unary_branch_node(unary_branch_node<T,Operation>&);
|
|
unary_branch_node<T,Operation>& operator=(unary_branch_node<T,Operation>&);
|
|
|
|
expression_ptr branch_;
|
|
bool branch_deletable_;
|
|
};
|
|
|
|
template <typename T> struct is_const { enum {result = 0}; };
|
|
template <typename T> struct is_const <const T> { enum {result = 1}; };
|
|
template <typename T> struct is_const_ref { enum {result = 0}; };
|
|
template <typename T> struct is_const_ref <const T&> { enum {result = 1}; };
|
|
template <typename T> struct is_ref { enum {result = 0}; };
|
|
template <typename T> struct is_ref<T&> { enum {result = 1}; };
|
|
template <typename T> struct is_ref<const T&> { enum {result = 0}; };
|
|
|
|
template <std::size_t State>
|
|
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<is_const_ref< Type >::result>::result() \
|
|
|
|
template <typename T>
|
|
struct T0oT1oT2process
|
|
{
|
|
typedef typename details::functor_t<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 <typename T0, typename T1, typename T2>
|
|
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 <typename T0, typename T1, typename T2>
|
|
static inline std::string id()
|
|
{
|
|
static const std::string result = "(" + exprtk_crtype(T0) + ")o(" +
|
|
exprtk_crtype(T1) + "o" +
|
|
exprtk_crtype(T2) + ")" ;
|
|
return result;
|
|
}
|
|
};
|
|
};
|
|
|
|
template <typename T>
|
|
struct T0oT1oT20T3process
|
|
{
|
|
typedef typename details::functor_t<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 <typename T0, typename T1, typename T2, typename T3>
|
|
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 <typename T0, typename T1, typename T2, typename T3>
|
|
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 <typename T0, typename T1, typename T2, typename T3>
|
|
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 <typename T0, typename T1, typename T2, typename T3>
|
|
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 <typename T0, typename T1, typename T2, typename T3>
|
|
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 <typename T, typename T0, typename T1>
|
|
struct nodetype_T0oT1 { static const typename expression_node<T>::node_type result; };
|
|
template <typename T, typename T0, typename T1>
|
|
const typename expression_node<T>::node_type nodetype_T0oT1<T,T0,T1>::result = expression_node<T>::e_none;
|
|
|
|
#define synthesis_node_type_define(T0_,T1_,v_) \
|
|
template <typename T, typename T0, typename T1> \
|
|
struct nodetype_T0oT1<T,T0_,T1_> { static const typename expression_node<T>::node_type result; }; \
|
|
template <typename T, typename T0, typename T1> \
|
|
const typename expression_node<T>::node_type nodetype_T0oT1<T,T0_,T1_>::result = expression_node<T>:: 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 <typename T, typename T0, typename T1, typename T2>
|
|
struct nodetype_T0oT1oT2 { static const typename expression_node<T>::node_type result; };
|
|
template <typename T, typename T0, typename T1, typename T2>
|
|
const typename expression_node<T>::node_type nodetype_T0oT1oT2<T,T0,T1,T2>::result = expression_node<T>::e_none;
|
|
|
|
#define synthesis_node_type_define(T0_,T1_,T2_,v_) \
|
|
template <typename T, typename T0, typename T1, typename T2> \
|
|
struct nodetype_T0oT1oT2<T,T0_,T1_,T2_> { static const typename expression_node<T>::node_type result; }; \
|
|
template <typename T, typename T0, typename T1, typename T2> \
|
|
const typename expression_node<T>::node_type nodetype_T0oT1oT2<T,T0_,T1_,T2_>::result = expression_node<T>:: 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 <typename T, typename T0, typename T1, typename T2, typename T3>
|
|
struct nodetype_T0oT1oT2oT3 { static const typename expression_node<T>::node_type result; };
|
|
template <typename T, typename T0, typename T1, typename T2, typename T3>
|
|
const typename expression_node<T>::node_type nodetype_T0oT1oT2oT3<T,T0,T1,T2,T3>::result = expression_node<T>::e_none;
|
|
|
|
#define synthesis_node_type_define(T0_,T1_,T2_,T3_,v_) \
|
|
template <typename T, typename T0, typename T1, typename T2, typename T3> \
|
|
struct nodetype_T0oT1oT2oT3<T,T0_,T1_,T2_,T3_> { static const typename expression_node<T>::node_type result; }; \
|
|
template <typename T, typename T0, typename T1, typename T2, typename T3> \
|
|
const typename expression_node<T>::node_type nodetype_T0oT1oT2oT3<T,T0_,T1_,T2_,T3_>::result = expression_node<T>:: 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 <typename T, typename T0, typename T1>
|
|
class T0oT1 : public expression_node<T>
|
|
{
|
|
public:
|
|
|
|
typedef typename details::functor_t<T> functor_t;
|
|
typedef typename functor_t::bfunc_t bfunc_t;
|
|
typedef T value_type;
|
|
typedef T0oT1<T,T0,T1> node_type;
|
|
|
|
T0oT1(T0 p0, T1 p1, const bfunc_t p2)
|
|
: t0_(p0),
|
|
t1_(p1),
|
|
f_ (p2)
|
|
{}
|
|
|
|
inline typename expression_node<T>::node_type type() const
|
|
{
|
|
static const typename expression_node<T>::node_type result = nodetype_T0oT1<T,T0,T1>::result;
|
|
return result;
|
|
}
|
|
|
|
inline operator_type operation() const
|
|
{
|
|
return e_default;
|
|
}
|
|
|
|
inline T value() const
|
|
{
|
|
return f_(t0_,t1_);
|
|
}
|
|
|
|
inline T0 t0() const
|
|
{
|
|
return t0_;
|
|
}
|
|
|
|
inline T1 t1() const
|
|
{
|
|
return t1_;
|
|
}
|
|
|
|
inline bfunc_t f() const
|
|
{
|
|
return f_;
|
|
}
|
|
|
|
template <typename Allocator>
|
|
static inline expression_node<T>* allocate(Allocator& allocator,
|
|
T0 p0, T1 p1,
|
|
bfunc_t p2)
|
|
{
|
|
return allocator.template allocate_type<node_type,T0,T1,bfunc_t&>(p0,p1,p2);
|
|
}
|
|
|
|
private:
|
|
|
|
T0oT1(T0oT1<T,T0,T1>&) {}
|
|
T0oT1<T,T0,T1>& operator=(T0oT1<T,T0,T1>&) { return *this; }
|
|
|
|
T0 t0_;
|
|
T1 t1_;
|
|
const bfunc_t f_;
|
|
};
|
|
|
|
template <typename T, typename T0, typename T1, typename T2, typename ProcessMode>
|
|
class T0oT1oT2 : public T0oT1oT2_base_node<T>
|
|
{
|
|
public:
|
|
|
|
typedef typename details::functor_t<T> functor_t;
|
|
typedef typename functor_t::bfunc_t bfunc_t;
|
|
typedef T value_type;
|
|
typedef T0oT1oT2<T,T0,T1,T2,ProcessMode> 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<T>::node_type type() const
|
|
{
|
|
static const typename expression_node<T>::node_type result = nodetype_T0oT1oT2<T,T0,T1,T2>::result;
|
|
return result;
|
|
}
|
|
|
|
inline operator_type operation() const
|
|
{
|
|
return e_default;
|
|
}
|
|
|
|
inline T value() const
|
|
{
|
|
return ProcessMode::process(t0_,t1_,t2_,f0_,f1_);
|
|
}
|
|
|
|
inline T0 t0() const
|
|
{
|
|
return t0_;
|
|
}
|
|
|
|
inline T1 t1() const
|
|
{
|
|
return t1_;
|
|
}
|
|
|
|
inline T2 t2() const
|
|
{
|
|
return t2_;
|
|
}
|
|
|
|
bfunc_t f0() const
|
|
{
|
|
return f0_;
|
|
}
|
|
|
|
bfunc_t f1() const
|
|
{
|
|
return f1_;
|
|
}
|
|
|
|
std::string type_id() const
|
|
{
|
|
return id();
|
|
}
|
|
|
|
static inline std::string id()
|
|
{
|
|
return process_mode_t::template id<T0,T1,T2>();
|
|
}
|
|
|
|
template <typename Allocator>
|
|
static inline expression_node<T>* allocate(Allocator& allocator, T0 p0, T1 p1, T2 p2, bfunc_t p3, bfunc_t p4)
|
|
{
|
|
return allocator.template allocate_type<node_type,T0,T1,T2,bfunc_t,bfunc_t>(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 <typename T, typename T0_, typename T1_, typename T2_, typename T3_, typename ProcessMode>
|
|
class T0oT1oT2oT3 : public T0oT1oT2oT3_base_node<T>
|
|
{
|
|
public:
|
|
|
|
typedef typename details::functor_t<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<T,T0,T1,T2,T3,ProcessMode> 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<T0,T1,T2,T3>();
|
|
}
|
|
|
|
template <typename Allocator>
|
|
static inline expression_node<T>* 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<node_type,T0,T1,T2,T3,bfunc_t,bfunc_t>(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 <typename T, typename T0, typename T1, typename T2>
|
|
class T0oT1oT2_sf3 : public T0oT1oT2_base_node<T>
|
|
{
|
|
public:
|
|
|
|
typedef typename details::functor_t<T> functor_t;
|
|
typedef typename functor_t::tfunc_t tfunc_t;
|
|
typedef T value_type;
|
|
typedef T0oT1oT2_sf3<T,T0,T1,T2> 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<T>::node_type type() const
|
|
{
|
|
static const typename expression_node<T>::node_type result = nodetype_T0oT1oT2<T,T0,T1,T2>::result;
|
|
return result;
|
|
}
|
|
|
|
inline operator_type operation() const
|
|
{
|
|
return e_default;
|
|
}
|
|
|
|
inline T value() const
|
|
{
|
|
return f_(t0_,t1_,t2_);
|
|
}
|
|
|
|
inline T0 t0() const
|
|
{
|
|
return t0_;
|
|
}
|
|
|
|
inline T1 t1() const
|
|
{
|
|
return t1_;
|
|
}
|
|
|
|
inline T2 t2() const
|
|
{
|
|
return t2_;
|
|
}
|
|
|
|
tfunc_t f() const
|
|
{
|
|
return f_;
|
|
}
|
|
|
|
std::string type_id() const
|
|
{
|
|
return id();
|
|
}
|
|
|
|
static inline std::string id()
|
|
{
|
|
return "sf3";
|
|
}
|
|
|
|
template <typename Allocator>
|
|
static inline expression_node<T>* allocate(Allocator& allocator, T0 p0, T1 p1, T2 p2, tfunc_t p3)
|
|
{
|
|
return allocator.template allocate_type<node_type,T0,T1,T2,tfunc_t>(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 <typename T, typename T0, typename T1, typename T2>
|
|
class sf3ext_type_node : public T0oT1oT2_base_node<T>
|
|
{
|
|
public:
|
|
|
|
virtual T0 t0() const = 0;
|
|
|
|
virtual T1 t1() const = 0;
|
|
|
|
virtual T2 t2() const = 0;
|
|
};
|
|
|
|
template <typename T, typename T0, typename T1, typename T2, typename SF3Operation>
|
|
class T0oT1oT2_sf3ext : public sf3ext_type_node<T,T0,T1,T2>
|
|
{
|
|
public:
|
|
|
|
typedef typename details::functor_t<T> functor_t;
|
|
typedef typename functor_t::tfunc_t tfunc_t;
|
|
typedef T value_type;
|
|
typedef T0oT1oT2_sf3ext<T,T0,T1,T2,SF3Operation> node_type;
|
|
|
|
T0oT1oT2_sf3ext(T0 p0, T1 p1, T2 p2)
|
|
: t0_(p0),
|
|
t1_(p1),
|
|
t2_(p2)
|
|
{}
|
|
|
|
inline typename expression_node<T>::node_type type() const
|
|
{
|
|
static const typename expression_node<T>::node_type result = nodetype_T0oT1oT2<T,T0,T1,T2>::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 <typename Allocator>
|
|
static inline expression_node<T>* allocate(Allocator& allocator, T0 p0, T1 p1, T2 p2)
|
|
{
|
|
return allocator.template allocate_type<node_type,T0,T1,T2>(p0,p1,p2);
|
|
}
|
|
|
|
private:
|
|
|
|
T0oT1oT2_sf3ext(node_type&) {}
|
|
node_type& operator=(node_type&) { return *this; }
|
|
|
|
T0 t0_;
|
|
T1 t1_;
|
|
T2 t2_;
|
|
};
|
|
|
|
template <typename T>
|
|
inline bool is_sf3ext_node(const expression_node<T>* n)
|
|
{
|
|
switch (n->type())
|
|
{
|
|
case expression_node<T>::e_vovov : return true;
|
|
case expression_node<T>::e_vovoc : return true;
|
|
case expression_node<T>::e_vocov : return true;
|
|
case expression_node<T>::e_covov : return true;
|
|
case expression_node<T>::e_covoc : return true;
|
|
default : return false;
|
|
}
|
|
}
|
|
|
|
template <typename T, typename T0, typename T1, typename T2, typename T3>
|
|
class T0oT1oT2oT3_sf4 : public T0oT1oT2_base_node<T>
|
|
{
|
|
public:
|
|
|
|
typedef typename details::functor_t<T> functor_t;
|
|
typedef typename functor_t::qfunc_t qfunc_t;
|
|
typedef T value_type;
|
|
typedef T0oT1oT2oT3_sf4<T,T0,T1,T2,T3> 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<T>::node_type type() const
|
|
{
|
|
static const typename expression_node<T>::node_type result = nodetype_T0oT1oT2oT3<T,T0,T1,T2,T3>::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 <typename Allocator>
|
|
static inline expression_node<T>* allocate(Allocator& allocator, T0 p0, T1 p1, T2 p2, T3 p3, qfunc_t p4)
|
|
{
|
|
return allocator.template allocate_type<node_type,T0,T1,T2,T3,qfunc_t>(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 <typename T, typename T0, typename T1, typename T2, typename T3, typename SF4Operation>
|
|
class T0oT1oT2oT3_sf4ext : public T0oT1oT2oT3_base_node<T>
|
|
{
|
|
public:
|
|
|
|
typedef typename details::functor_t<T> functor_t;
|
|
typedef typename functor_t::tfunc_t tfunc_t;
|
|
typedef T value_type;
|
|
typedef T0oT1oT2oT3_sf4ext<T,T0,T1,T2,T3,SF4Operation> node_type;
|
|
|
|
T0oT1oT2oT3_sf4ext(T0 p0, T1 p1, T2 p2, T3 p3)
|
|
: t0_(p0),
|
|
t1_(p1),
|
|
t2_(p2),
|
|
t3_(p3)
|
|
{}
|
|
|
|
inline typename expression_node<T>::node_type type() const
|
|
{
|
|
static const typename expression_node<T>::node_type result = nodetype_T0oT1oT2oT3<T,T0,T1,T2,T3>::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 <typename Allocator>
|
|
static inline expression_node<T>* allocate(Allocator& allocator, T0 p0, T1 p1, T2 p2, T3 p3)
|
|
{
|
|
return allocator.template allocate_type<node_type,T0,T1,T2,T3>(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 <typename T>
|
|
inline bool is_sf4ext_node(const expression_node<T>* n)
|
|
{
|
|
switch (n->type())
|
|
{
|
|
case expression_node<T>::e_vovovov : return true;
|
|
case expression_node<T>::e_vovovoc : return true;
|
|
case expression_node<T>::e_vovocov : return true;
|
|
case expression_node<T>::e_vocovov : return true;
|
|
case expression_node<T>::e_covovov : return true;
|
|
case expression_node<T>::e_covocov : return true;
|
|
case expression_node<T>::e_vocovoc : return true;
|
|
case expression_node<T>::e_covovoc : return true;
|
|
case expression_node<T>::e_vococov : return true;
|
|
default : return false;
|
|
}
|
|
}
|
|
|
|
template <typename T, typename T0, typename T1>
|
|
struct T0oT1_define
|
|
{
|
|
typedef details::T0oT1<T,T0,T1> type0;
|
|
};
|
|
|
|
template <typename T, typename T0, typename T1, typename T2>
|
|
struct T0oT1oT2_define
|
|
{
|
|
typedef details::T0oT1oT2<T,T0,T1,T2,typename T0oT1oT2process<T>::mode0> type0;
|
|
typedef details::T0oT1oT2<T,T0,T1,T2,typename T0oT1oT2process<T>::mode1> type1;
|
|
typedef details::T0oT1oT2_sf3<T,T0,T1,T2> sf3_type;
|
|
typedef details::sf3ext_type_node<T,T0,T1,T2> sf3_type_node;
|
|
};
|
|
|
|
template <typename T, typename T0, typename T1, typename T2, typename T3>
|
|
struct T0oT1oT2oT3_define
|
|
{
|
|
typedef details::T0oT1oT2oT3<T,T0,T1,T2,T3,typename T0oT1oT20T3process<T>::mode0> type0;
|
|
typedef details::T0oT1oT2oT3<T,T0,T1,T2,T3,typename T0oT1oT20T3process<T>::mode1> type1;
|
|
typedef details::T0oT1oT2oT3<T,T0,T1,T2,T3,typename T0oT1oT20T3process<T>::mode2> type2;
|
|
typedef details::T0oT1oT2oT3<T,T0,T1,T2,T3,typename T0oT1oT20T3process<T>::mode3> type3;
|
|
typedef details::T0oT1oT2oT3<T,T0,T1,T2,T3,typename T0oT1oT20T3process<T>::mode4> type4;
|
|
typedef details::T0oT1oT2oT3_sf4<T,T0,T1,T2,T3> sf4_type;
|
|
};
|
|
|
|
template <typename T, typename Operation>
|
|
class vov_node : public vov_base_node<T>
|
|
{
|
|
public:
|
|
|
|
typedef expression_node<T>* 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<T>::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<T,Operation>&);
|
|
vov_node<T,Operation>& operator=(vov_node<T,Operation>&);
|
|
};
|
|
|
|
template <typename T, typename Operation>
|
|
class cov_node : public cov_base_node<T>
|
|
{
|
|
public:
|
|
|
|
typedef expression_node<T>* 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<T>::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<T,Operation>&);
|
|
cov_node<T,Operation>& operator=(const cov_node<T,Operation>&);
|
|
};
|
|
|
|
template <typename T, typename Operation>
|
|
class voc_node : public voc_base_node<T>
|
|
{
|
|
public:
|
|
|
|
typedef expression_node<T>* 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<T,Operation>&);
|
|
voc_node<T,Operation>& operator=(const voc_node<T,Operation>&);
|
|
};
|
|
|
|
template <typename T, typename Operation>
|
|
class vob_node : public vob_base_node<T>
|
|
{
|
|
public:
|
|
|
|
typedef expression_node<T>* expression_ptr;
|
|
typedef std::pair<expression_ptr,bool> 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<T,1>(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<T>* branch(const std::size_t&) const
|
|
{
|
|
return branch_[0].first;
|
|
}
|
|
|
|
private:
|
|
|
|
vob_node(const vob_node<T,Operation>&);
|
|
vob_node<T,Operation>& operator=(const vob_node<T,Operation>&);
|
|
|
|
const T& v_;
|
|
branch_t branch_[1];
|
|
};
|
|
|
|
template <typename T, typename Operation>
|
|
class bov_node : public bov_base_node<T>
|
|
{
|
|
public:
|
|
|
|
typedef expression_node<T>* expression_ptr;
|
|
typedef std::pair<expression_ptr,bool> 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<T,1>(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<T>* branch(const std::size_t&) const
|
|
{
|
|
return branch_[0].first;
|
|
}
|
|
|
|
private:
|
|
|
|
bov_node(const bov_node<T,Operation>&);
|
|
bov_node<T,Operation>& operator=(const bov_node<T,Operation>&);
|
|
|
|
const T& v_;
|
|
branch_t branch_[1];
|
|
};
|
|
|
|
template <typename T, typename Operation>
|
|
class cob_node : public cob_base_node<T>
|
|
{
|
|
public:
|
|
|
|
typedef expression_node<T>* expression_ptr;
|
|
typedef std::pair<expression_ptr,bool> 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<T,1>(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<T*>(&c_)) = new_c;
|
|
}
|
|
|
|
inline expression_node<T>* branch(const std::size_t&) const
|
|
{
|
|
return branch_[0].first;
|
|
}
|
|
|
|
inline expression_node<T>* move_branch(const std::size_t&)
|
|
{
|
|
branch_[0].second = false;
|
|
return branch_[0].first;
|
|
}
|
|
|
|
private:
|
|
|
|
cob_node(const cob_node<T,Operation>&);
|
|
cob_node<T,Operation>& operator=(const cob_node<T,Operation>&);
|
|
|
|
const T c_;
|
|
branch_t branch_[1];
|
|
};
|
|
|
|
template <typename T, typename Operation>
|
|
class boc_node : public boc_base_node<T>
|
|
{
|
|
public:
|
|
|
|
typedef expression_node<T>* expression_ptr;
|
|
typedef std::pair<expression_ptr,bool> 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<T,1>(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<T*>(&c_)) = new_c;
|
|
}
|
|
|
|
inline expression_node<T>* branch(const std::size_t&) const
|
|
{
|
|
return branch_[0].first;
|
|
}
|
|
|
|
inline expression_node<T>* move_branch(const std::size_t&)
|
|
{
|
|
branch_[0].second = false;
|
|
return branch_[0].first;
|
|
}
|
|
|
|
private:
|
|
|
|
boc_node(const boc_node<T,Operation>&);
|
|
boc_node<T,Operation>& operator=(const boc_node<T,Operation>&);
|
|
|
|
const T c_;
|
|
branch_t branch_[1];
|
|
};
|
|
|
|
#ifndef exprtk_disable_string_capabilities
|
|
template <typename T, typename SType0, typename SType1, typename Operation>
|
|
class sos_node : public sos_base_node<T>
|
|
{
|
|
public:
|
|
|
|
typedef expression_node<T>* 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<T>::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<T,SType0,SType1,Operation>&);
|
|
sos_node<T,SType0,SType1,Operation>& operator=(sos_node<T,SType0,SType1,Operation>&);
|
|
};
|
|
|
|
template <typename T, typename SType0, typename SType1, typename RangePack, typename Operation>
|
|
class str_xrox_node : public sos_base_node<T>
|
|
{
|
|
public:
|
|
|
|
typedef expression_node<T>* 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<T>::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<T,SType0,SType1,RangePack,Operation>&);
|
|
str_xrox_node<T,SType0,SType1,RangePack,Operation>& operator=(str_xrox_node<T,SType0,SType1,RangePack,Operation>&);
|
|
};
|
|
|
|
template <typename T, typename SType0, typename SType1, typename RangePack, typename Operation>
|
|
class str_xoxr_node : public sos_base_node<T>
|
|
{
|
|
public:
|
|
|
|
typedef expression_node<T>* 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<T>::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<T,SType0,SType1,RangePack,Operation>&);
|
|
str_xoxr_node<T,SType0,SType1,RangePack,Operation>& operator=(str_xoxr_node<T,SType0,SType1,RangePack,Operation>&);
|
|
};
|
|
|
|
template <typename T, typename SType0, typename SType1, typename RangePack, typename Operation>
|
|
class str_xroxr_node : public sos_base_node<T>
|
|
{
|
|
public:
|
|
|
|
typedef expression_node<T>* 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<T>::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<T,SType0,SType1,RangePack,Operation>&);
|
|
str_xroxr_node<T,SType0,SType1,RangePack,Operation>& operator=(str_xroxr_node<T,SType0,SType1,RangePack,Operation>&);
|
|
};
|
|
|
|
template <typename T, typename Operation>
|
|
class str_sogens_node : public binary_node<T>
|
|
{
|
|
public:
|
|
|
|
typedef expression_node <T>* expression_ptr;
|
|
typedef string_base_node<T>* str_base_ptr;
|
|
typedef range_pack <T> range_t;
|
|
typedef range_t* range_ptr;
|
|
typedef range_interface<T> irange_t;
|
|
typedef irange_t* irange_ptr;
|
|
|
|
str_sogens_node(const operator_type& opr,
|
|
expression_ptr branch0,
|
|
expression_ptr branch1)
|
|
: binary_node<T>(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<T>::branch_[0].first))
|
|
{
|
|
str0_base_ptr_ = dynamic_cast<str_base_ptr>(binary_node<T>::branch_[0].first);
|
|
|
|
if (0 == str0_base_ptr_)
|
|
return;
|
|
|
|
irange_ptr range_ptr = dynamic_cast<irange_ptr>(binary_node<T>::branch_[0].first);
|
|
|
|
if (0 == range_ptr)
|
|
return;
|
|
|
|
str0_range_ptr_ = &(range_ptr->range_ref());
|
|
}
|
|
|
|
if (is_generally_string_node(binary_node<T>::branch_[1].first))
|
|
{
|
|
str1_base_ptr_ = dynamic_cast<str_base_ptr>(binary_node<T>::branch_[1].first);
|
|
|
|
if (0 == str1_base_ptr_)
|
|
return;
|
|
|
|
irange_ptr range_ptr = dynamic_cast<irange_ptr>(binary_node<T>::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<T>::branch_[0].first->value();
|
|
binary_node<T>::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<T>::quiet_NaN();
|
|
}
|
|
|
|
inline typename expression_node<T>::node_type type() const
|
|
{
|
|
return Operation::type();
|
|
}
|
|
|
|
inline operator_type operation() const
|
|
{
|
|
return Operation::operation();
|
|
}
|
|
|
|
private:
|
|
|
|
str_sogens_node(str_sogens_node<T,Operation>&);
|
|
str_sogens_node<T,Operation>& operator=(str_sogens_node<T,Operation>&);
|
|
|
|
str_base_ptr str0_base_ptr_;
|
|
str_base_ptr str1_base_ptr_;
|
|
range_ptr str0_range_ptr_;
|
|
range_ptr str1_range_ptr_;
|
|
};
|
|
|
|
template <typename T, typename SType0, typename SType1, typename SType2, typename Operation>
|
|
class sosos_node : public sosos_base_node<T>
|
|
{
|
|
public:
|
|
|
|
typedef expression_node<T>* 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<T>::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<T,SType0,SType1,SType2,Operation>&);
|
|
sosos_node<T,SType0,SType1,SType2,Operation>& operator=(sosos_node<T,SType0,SType1,SType2,Operation>&);
|
|
};
|
|
#endif
|
|
|
|
template <typename T, typename PowOp>
|
|
class ipow_node : public expression_node<T>
|
|
{
|
|
public:
|
|
|
|
typedef expression_node<T>* 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<T>::node_type type() const
|
|
{
|
|
return expression_node<T>::e_ipow;
|
|
}
|
|
|
|
private:
|
|
|
|
ipow_node(const ipow_node<T,PowOp>&);
|
|
ipow_node<T,PowOp>& operator=(const ipow_node<T,PowOp>&);
|
|
|
|
const T& v_;
|
|
};
|
|
|
|
template <typename T, typename PowOp>
|
|
class ipowinv_node : public expression_node<T>
|
|
{
|
|
public:
|
|
|
|
typedef expression_node<T>* 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<T>::node_type type() const
|
|
{
|
|
return expression_node<T>::e_ipowinv;
|
|
}
|
|
|
|
private:
|
|
|
|
ipowinv_node(const ipowinv_node<T,PowOp>&);
|
|
ipowinv_node<T,PowOp>& operator=(const ipowinv_node<T,PowOp>&);
|
|
|
|
const T& v_;
|
|
};
|
|
|
|
template <typename T>
|
|
inline bool is_vov_node(const expression_node<T>* node)
|
|
{
|
|
return (0 != dynamic_cast<const vov_base_node<T>*>(node));
|
|
}
|
|
|
|
template <typename T>
|
|
inline bool is_cov_node(const expression_node<T>* node)
|
|
{
|
|
return (0 != dynamic_cast<const cov_base_node<T>*>(node));
|
|
}
|
|
|
|
template <typename T>
|
|
inline bool is_voc_node(const expression_node<T>* node)
|
|
{
|
|
return (0 != dynamic_cast<const voc_base_node<T>*>(node));
|
|
}
|
|
|
|
template <typename T>
|
|
inline bool is_cob_node(const expression_node<T>* node)
|
|
{
|
|
return (0 != dynamic_cast<const cob_base_node<T>*>(node));
|
|
}
|
|
|
|
template <typename T>
|
|
inline bool is_boc_node(const expression_node<T>* node)
|
|
{
|
|
return (0 != dynamic_cast<const boc_base_node<T>*>(node));
|
|
}
|
|
|
|
template <typename T>
|
|
inline bool is_t0ot1ot2_node(const expression_node<T>* node)
|
|
{
|
|
return (0 != dynamic_cast<const T0oT1oT2_base_node<T>*>(node));
|
|
}
|
|
|
|
template <typename T>
|
|
inline bool is_t0ot1ot2ot3_node(const expression_node<T>* node)
|
|
{
|
|
return (0 != dynamic_cast<const T0oT1oT2oT3_base_node<T>*>(node));
|
|
}
|
|
|
|
template <typename T>
|
|
inline bool is_uv_node(const expression_node<T>* node)
|
|
{
|
|
return (0 != dynamic_cast<const uv_base_node<T>*>(node));
|
|
}
|
|
|
|
template <typename T>
|
|
inline bool is_string_node(const expression_node<T>* node)
|
|
{
|
|
return node && (expression_node<T>::e_stringvar == node->type());
|
|
}
|
|
|
|
template <typename T>
|
|
inline bool is_string_range_node(const expression_node<T>* node)
|
|
{
|
|
return node && (expression_node<T>::e_stringvarrng == node->type());
|
|
}
|
|
|
|
template <typename T>
|
|
inline bool is_const_string_node(const expression_node<T>* node)
|
|
{
|
|
return node && (expression_node<T>::e_stringconst == node->type());
|
|
}
|
|
|
|
template <typename T>
|
|
inline bool is_const_string_range_node(const expression_node<T>* node)
|
|
{
|
|
return node && (expression_node<T>::e_cstringvarrng == node->type());
|
|
}
|
|
|
|
template <typename T>
|
|
inline bool is_string_assignment_node(const expression_node<T>* node)
|
|
{
|
|
return node && (expression_node<T>::e_strass == node->type());
|
|
}
|
|
|
|
template <typename T>
|
|
inline bool is_string_concat_node(const expression_node<T>* node)
|
|
{
|
|
return node && (expression_node<T>::e_strconcat == node->type());
|
|
}
|
|
|
|
template <typename T>
|
|
inline bool is_string_function_node(const expression_node<T>* node)
|
|
{
|
|
return node && (expression_node<T>::e_strfunction == node->type());
|
|
}
|
|
|
|
template <typename T>
|
|
inline bool is_genricstring_range_node(const expression_node<T>* node)
|
|
{
|
|
return node && (expression_node<T>::e_strgenrange == node->type());
|
|
}
|
|
|
|
template <typename T>
|
|
inline bool is_generally_string_node(const expression_node<T>* node)
|
|
{
|
|
if (node)
|
|
{
|
|
switch (node->type())
|
|
{
|
|
case expression_node<T>::e_stringvar :
|
|
case expression_node<T>::e_stringconst :
|
|
case expression_node<T>::e_stringvarrng :
|
|
case expression_node<T>::e_cstringvarrng :
|
|
case expression_node<T>::e_strgenrange :
|
|
case expression_node<T>::e_strass :
|
|
case expression_node<T>::e_strconcat :
|
|
case expression_node<T>::e_strfunction : return true;
|
|
default : return false;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
class node_allocator
|
|
{
|
|
public:
|
|
|
|
template <typename ResultNode, typename OpType, typename ExprNode>
|
|
inline expression_node<typename ResultNode::value_type>* allocate(OpType& operation, ExprNode (&branch)[1])
|
|
{
|
|
return allocate<ResultNode>(operation,branch[0]);
|
|
}
|
|
|
|
template <typename ResultNode, typename OpType, typename ExprNode>
|
|
inline expression_node<typename ResultNode::value_type>* allocate(OpType& operation, ExprNode (&branch)[2])
|
|
{
|
|
return allocate<ResultNode>(operation,branch[0],branch[1]);
|
|
}
|
|
|
|
template <typename ResultNode, typename OpType, typename ExprNode>
|
|
inline expression_node<typename ResultNode::value_type>* allocate(OpType& operation, ExprNode (&branch)[3])
|
|
{
|
|
return allocate<ResultNode>(operation,branch[0],branch[1],branch[2]);
|
|
}
|
|
|
|
template <typename ResultNode, typename OpType, typename ExprNode>
|
|
inline expression_node<typename ResultNode::value_type>* allocate(OpType& operation, ExprNode (&branch)[4])
|
|
{
|
|
return allocate<ResultNode>(operation,branch[0],branch[1],branch[2],branch[3]);
|
|
}
|
|
|
|
template <typename ResultNode, typename OpType, typename ExprNode>
|
|
inline expression_node<typename ResultNode::value_type>* allocate(OpType& operation, ExprNode (&branch)[5])
|
|
{
|
|
return allocate<ResultNode>(operation,branch[0],branch[1],branch[2],branch[3],branch[4]);
|
|
}
|
|
|
|
template <typename ResultNode, typename OpType, typename ExprNode>
|
|
inline expression_node<typename ResultNode::value_type>* allocate(OpType& operation, ExprNode (&branch)[6])
|
|
{
|
|
return allocate<ResultNode>(operation,branch[0],branch[1],branch[2],branch[3],branch[4],branch[5]);
|
|
}
|
|
|
|
template <typename node_type>
|
|
inline expression_node<typename node_type::value_type>* allocate() const
|
|
{
|
|
return new node_type();
|
|
}
|
|
|
|
template <typename node_type,
|
|
typename Type,
|
|
typename Allocator,
|
|
template <typename,typename> class Sequence>
|
|
inline expression_node<typename node_type::value_type>* allocate(const Sequence<Type,Allocator>& seq) const
|
|
{
|
|
return new node_type(seq);
|
|
}
|
|
|
|
template <typename node_type, typename T1>
|
|
inline expression_node<typename node_type::value_type>* allocate(T1& t1) const
|
|
{
|
|
return new node_type(t1);
|
|
}
|
|
|
|
template <typename node_type, typename T1>
|
|
inline expression_node<typename node_type::value_type>* allocate_c(const T1& t1) const
|
|
{
|
|
return new node_type(t1);
|
|
}
|
|
|
|
template <typename node_type,
|
|
typename T1, typename T2>
|
|
inline expression_node<typename node_type::value_type>* allocate(const T1& t1, const T2& t2) const
|
|
{
|
|
return new node_type(t1,t2);
|
|
}
|
|
|
|
template <typename node_type,
|
|
typename T1, typename T2>
|
|
inline expression_node<typename node_type::value_type>* allocate_cr(const T1& t1, T2& t2) const
|
|
{
|
|
return new node_type(t1,t2);
|
|
}
|
|
|
|
template <typename node_type,
|
|
typename T1, typename T2>
|
|
inline expression_node<typename node_type::value_type>* allocate_rc(T1& t1, const T2& t2) const
|
|
{
|
|
return new node_type(t1,t2);
|
|
}
|
|
|
|
template <typename node_type,
|
|
typename T1, typename T2>
|
|
inline expression_node<typename node_type::value_type>* allocate_rr(T1& t1, T2& t2) const
|
|
{
|
|
return new node_type(t1,t2);
|
|
}
|
|
|
|
template <typename node_type,
|
|
typename T1, typename T2>
|
|
inline expression_node<typename node_type::value_type>* allocate_tt(T1 t1, T2 t2) const
|
|
{
|
|
return new node_type(t1,t2);
|
|
}
|
|
|
|
template <typename node_type,
|
|
typename T1, typename T2, typename T3>
|
|
inline expression_node<typename node_type::value_type>* allocate_ttt(T1 t1, T2 t2, T3 t3) const
|
|
{
|
|
return new node_type(t1,t2,t3);
|
|
}
|
|
|
|
template <typename node_type,
|
|
typename T1, typename T2, typename T3, typename T4>
|
|
inline expression_node<typename node_type::value_type>* allocate_tttt(T1 t1, T2 t2, T3 t3, T4 t4) const
|
|
{
|
|
return new node_type(t1,t2,t3,t4);
|
|
}
|
|
|
|
template <typename node_type,
|
|
typename T1, typename T2, typename T3>
|
|
inline expression_node<typename node_type::value_type>* allocate_rrr(T1& t1, T2& t2, T3& t3) const
|
|
{
|
|
return new node_type(t1,t2,t3);
|
|
}
|
|
|
|
template <typename node_type,
|
|
typename T1, typename T2, typename T3, typename T4>
|
|
inline expression_node<typename node_type::value_type>* allocate_rrrr(T1& t1, T2& t2, T3& t3, T4& t4) const
|
|
{
|
|
return new node_type(t1,t2,t3,t4);
|
|
}
|
|
|
|
template <typename node_type,
|
|
typename T1, typename T2, typename T3, typename T4, typename T5>
|
|
inline expression_node<typename node_type::value_type>* allocate_rrrrr(T1& t1, T2& t2, T3& t3, T4& t4, T5& t5) const
|
|
{
|
|
return new node_type(t1,t2,t3,t4,t5);
|
|
}
|
|
|
|
template <typename node_type,
|
|
typename T1, typename T2, typename T3>
|
|
inline expression_node<typename node_type::value_type>* allocate(const T1& t1, const T2& t2,
|
|
const T3& t3) const
|
|
{
|
|
return new node_type(t1,t2,t3);
|
|
}
|
|
|
|
template <typename node_type,
|
|
typename T1, typename T2,
|
|
typename T3, typename T4>
|
|
inline expression_node<typename node_type::value_type>* allocate(const T1& t1, const T2& t2,
|
|
const T3& t3, const T4& t4) const
|
|
{
|
|
return new node_type(t1,t2,t3,t4);
|
|
}
|
|
|
|
template <typename node_type,
|
|
typename T1, typename T2,
|
|
typename T3, typename T4, typename T5>
|
|
inline expression_node<typename node_type::value_type>* 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 <typename node_type,
|
|
typename T1, typename T2,
|
|
typename T3, typename T4, typename T5, typename T6>
|
|
inline expression_node<typename node_type::value_type>* 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 <typename node_type,
|
|
typename T1, typename T2,
|
|
typename T3, typename T4,
|
|
typename T5, typename T6, typename T7>
|
|
inline expression_node<typename node_type::value_type>* 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 <typename node_type,
|
|
typename T1, typename T2,
|
|
typename T3, typename T4,
|
|
typename T5, typename T6,
|
|
typename T7, typename T8>
|
|
inline expression_node<typename node_type::value_type>* 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 <typename node_type,
|
|
typename T1, typename T2,
|
|
typename T3, typename T4,
|
|
typename T5, typename T6,
|
|
typename T7, typename T8, typename T9>
|
|
inline expression_node<typename node_type::value_type>* 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 <typename node_type,
|
|
typename T1, typename T2,
|
|
typename T3, typename T4,
|
|
typename T5, typename T6,
|
|
typename T7, typename T8,
|
|
typename T9, typename T10>
|
|
inline expression_node<typename node_type::value_type>* 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 <typename node_type,
|
|
typename T1, typename T2, typename T3>
|
|
inline expression_node<typename node_type::value_type>* allocate_type(T1 t1, T2 t2, T3 t3) const
|
|
{
|
|
return new node_type(t1,t2,t3);
|
|
}
|
|
|
|
template <typename node_type,
|
|
typename T1, typename T2,
|
|
typename T3, typename T4>
|
|
inline expression_node<typename node_type::value_type>* allocate_type(T1 t1, T2 t2,
|
|
T3 t3, T4 t4) const
|
|
{
|
|
return new node_type(t1,t2,t3,t4);
|
|
}
|
|
|
|
template <typename node_type,
|
|
typename T1, typename T2,
|
|
typename T3, typename T4,
|
|
typename T5>
|
|
inline expression_node<typename node_type::value_type>* allocate_type(T1 t1, T2 t2,
|
|
T3 t3, T4 t4,
|
|
T5 t5) const
|
|
{
|
|
return new node_type(t1,t2,t3,t4,t5);
|
|
}
|
|
|
|
template <typename node_type,
|
|
typename T1, typename T2,
|
|
typename T3, typename T4,
|
|
typename T5, typename T6, typename T7>
|
|
inline expression_node<typename node_type::value_type>* 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 <typename T>
|
|
void inline free(expression_node<T>*& e) const
|
|
{
|
|
delete e;
|
|
e = 0;
|
|
}
|
|
};
|
|
|
|
inline void load_operations_map(std::multimap<std::string,details::base_operation_t,details::ilesscompare>& m)
|
|
{
|
|
#define register_op(Symbol,Type,Args) \
|
|
m.insert(std::make_pair(std::string(Symbol),details::base_operation_t(Type,Args))); \
|
|
|
|
register_op( "abs",e_abs , 1)
|
|
register_op( "acos",e_acos , 1)
|
|
register_op( "acosh",e_acosh , 1)
|
|
register_op( "asin",e_asin , 1)
|
|
register_op( "asinh",e_asinh , 1)
|
|
register_op( "atan",e_atan , 1)
|
|
register_op( "atanh",e_atanh , 1)
|
|
register_op( "ceil",e_ceil , 1)
|
|
register_op( "cos",e_cos , 1)
|
|
register_op( "cosh",e_cosh , 1)
|
|
register_op( "exp",e_exp , 1)
|
|
register_op( "expm1",e_expm1 , 1)
|
|
register_op( "floor",e_floor , 1)
|
|
register_op( "log",e_log , 1)
|
|
register_op( "log10",e_log10 , 1)
|
|
register_op( "log2",e_log2 , 1)
|
|
register_op( "log1p",e_log1p , 1)
|
|
register_op( "round",e_round , 1)
|
|
register_op( "sin",e_sin , 1)
|
|
register_op( "sinc",e_sinc , 1)
|
|
register_op( "sinh",e_sinh , 1)
|
|
register_op( "sec",e_sec , 1)
|
|
register_op( "csc",e_csc , 1)
|
|
register_op( "sqrt",e_sqrt , 1)
|
|
register_op( "tan",e_tan , 1)
|
|
register_op( "tanh",e_tanh , 1)
|
|
register_op( "cot",e_cot , 1)
|
|
register_op( "rad2deg",e_r2d , 1)
|
|
register_op( "deg2rad",e_d2r , 1)
|
|
register_op( "deg2grad",e_d2g , 1)
|
|
register_op( "grad2deg",e_g2d , 1)
|
|
register_op( "sgn",e_sgn , 1)
|
|
register_op( "not",e_notl , 1)
|
|
register_op( "erf",e_erf , 1)
|
|
register_op( "erfc",e_erfc , 1)
|
|
register_op( "ncdf",e_ncdf , 1)
|
|
register_op( "frac",e_frac , 1)
|
|
register_op( "trunc",e_trunc , 1)
|
|
register_op( "atan2",e_atan2 , 2)
|
|
register_op( "mod",e_mod , 2)
|
|
register_op( "logn",e_logn , 2)
|
|
register_op( "pow",e_pow , 2)
|
|
register_op( "root",e_root , 2)
|
|
register_op( "roundn",e_roundn , 2)
|
|
register_op( "equal",e_equal , 2)
|
|
register_op("not_equal",e_nequal , 2)
|
|
register_op( "hypot",e_hypot , 2)
|
|
register_op( "shr",e_shr , 2)
|
|
register_op( "shl",e_shl , 2)
|
|
register_op( "clamp",e_clamp , 3)
|
|
register_op( "iclamp",e_iclamp , 3)
|
|
register_op( "inrange",e_inrange , 3)
|
|
#undef register_op
|
|
}
|
|
|
|
} // namespace details
|
|
|
|
template <typename T>
|
|
class ifunction
|
|
{
|
|
public:
|
|
|
|
explicit ifunction(const std::size_t& pc, const bool hse = true)
|
|
: param_count(pc),
|
|
has_side_effects(hse)
|
|
{}
|
|
|
|
virtual ~ifunction()
|
|
{}
|
|
|
|
inline virtual T operator()()
|
|
{
|
|
return std::numeric_limits<T>::quiet_NaN();
|
|
}
|
|
|
|
inline virtual T operator()(const T&)
|
|
{
|
|
return std::numeric_limits<T>::quiet_NaN();
|
|
}
|
|
|
|
inline virtual T operator()(const T&,const T&)
|
|
{
|
|
return std::numeric_limits<T>::quiet_NaN();
|
|
}
|
|
|
|
inline virtual T operator()(const T&, const T&, const T&)
|
|
{
|
|
return std::numeric_limits<T>::quiet_NaN();
|
|
}
|
|
|
|
inline virtual T operator()(const T&, const T&, const T&, const T&)
|
|
{
|
|
return std::numeric_limits<T>::quiet_NaN();
|
|
}
|
|
|
|
inline virtual T operator()(const T&, const T&, const T&, const T&, const T&)
|
|
{
|
|
return std::numeric_limits<T>::quiet_NaN();
|
|
}
|
|
|
|
inline virtual T operator()(const T&, const T&, const T&, const T&, const T&, const T&)
|
|
{
|
|
return std::numeric_limits<T>::quiet_NaN();
|
|
}
|
|
|
|
inline virtual T operator()(const T&, const T&, const T&, const T&, const T&, const T&, const T&)
|
|
{
|
|
return std::numeric_limits<T>::quiet_NaN();
|
|
}
|
|
|
|
inline virtual T operator()(const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&)
|
|
{
|
|
return std::numeric_limits<T>::quiet_NaN();
|
|
}
|
|
|
|
inline virtual T operator()(const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&)
|
|
{
|
|
return std::numeric_limits<T>::quiet_NaN();
|
|
}
|
|
|
|
inline virtual T operator()(const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&)
|
|
{
|
|
return std::numeric_limits<T>::quiet_NaN();
|
|
}
|
|
|
|
inline virtual T operator()(const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&,
|
|
const T&)
|
|
{
|
|
return std::numeric_limits<T>::quiet_NaN();
|
|
}
|
|
|
|
inline virtual T operator()(const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&,
|
|
const T&, const T&)
|
|
{
|
|
return std::numeric_limits<T>::quiet_NaN();
|
|
}
|
|
|
|
inline virtual T operator()(const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&,
|
|
const T&, const T&, const T&)
|
|
{
|
|
return std::numeric_limits<T>::quiet_NaN();
|
|
}
|
|
|
|
inline virtual T operator()(const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&,
|
|
const T&, const T&, const T&, const T&)
|
|
{
|
|
return std::numeric_limits<T>::quiet_NaN();
|
|
}
|
|
|
|
inline virtual T operator()(const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&,
|
|
const T&, const T&, const T&, const T&, const T&)
|
|
{
|
|
return std::numeric_limits<T>::quiet_NaN();
|
|
}
|
|
|
|
inline virtual T operator()(const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&,
|
|
const T&, const T&, const T&, const T&, const T&, const T&)
|
|
{
|
|
return std::numeric_limits<T>::quiet_NaN();
|
|
}
|
|
|
|
inline virtual T operator()(const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&,
|
|
const T&, const T&, const T&, const T&, const T&, const T&, const T&)
|
|
{
|
|
return std::numeric_limits<T>::quiet_NaN();
|
|
}
|
|
|
|
inline virtual T operator()(const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&,
|
|
const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&)
|
|
{
|
|
return std::numeric_limits<T>::quiet_NaN();
|
|
}
|
|
|
|
inline virtual T operator()(const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&,
|
|
const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&)
|
|
{
|
|
return std::numeric_limits<T>::quiet_NaN();
|
|
}
|
|
|
|
inline virtual T operator()(const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&,
|
|
const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&, const T&)
|
|
{
|
|
return std::numeric_limits<T>::quiet_NaN();
|
|
}
|
|
|
|
std::size_t param_count;
|
|
bool has_side_effects;
|
|
};
|
|
|
|
template <typename T>
|
|
class ivararg_function
|
|
{
|
|
public:
|
|
|
|
ivararg_function(const bool hse = true)
|
|
: has_side_effects(hse)
|
|
{}
|
|
|
|
virtual ~ivararg_function()
|
|
{}
|
|
|
|
inline virtual T operator()(const std::vector<T>&)
|
|
{
|
|
exprtk_debug(("ivararg_function::operator() - Operator has not been overriden.\n"));
|
|
return std::numeric_limits<T>::quiet_NaN();
|
|
}
|
|
|
|
bool has_side_effects;
|
|
};
|
|
|
|
template <typename T>
|
|
class igeneric_function
|
|
{
|
|
public:
|
|
|
|
typedef T type;
|
|
typedef type_store<T> generic_type;
|
|
typedef typename generic_type::parameter_list parameter_list_t;
|
|
|
|
igeneric_function(const std::string& param_seq = "",
|
|
const bool hse = true)
|
|
: has_side_effects(hse),
|
|
parameter_sequence(param_seq)
|
|
{}
|
|
|
|
virtual ~igeneric_function()
|
|
{}
|
|
|
|
// f(i_0,i_1,....,i_N) --> Number
|
|
inline virtual T operator()(parameter_list_t)
|
|
{
|
|
exprtk_debug(("igeneric_function::operator() - Operator has not been overriden. [1]\n"));
|
|
return std::numeric_limits<T>::quiet_NaN();
|
|
}
|
|
|
|
// f(i_0,i_1,....,i_N) --> String
|
|
inline virtual T operator()(std::string&, parameter_list_t)
|
|
{
|
|
exprtk_debug(("igeneric_function::operator() - Operator has not been overriden. [2]\n"));
|
|
return std::numeric_limits<T>::quiet_NaN();
|
|
}
|
|
|
|
// f(psi,i_0,i_1,....,i_N) --> Number
|
|
inline virtual T operator()(const std::size_t&, parameter_list_t)
|
|
{
|
|
exprtk_debug(("igeneric_function::operator() - Operator has not been overriden. [3]\n"));
|
|
return std::numeric_limits<T>::quiet_NaN();
|
|
}
|
|
|
|
// f(psi,i_0,i_1,....,i_N) --> String
|
|
inline virtual T operator()(const std::size_t&, std::string&, parameter_list_t)
|
|
{
|
|
exprtk_debug(("igeneric_function::operator() - Operator has not been overriden. [4]\n"));
|
|
return std::numeric_limits<T>::quiet_NaN();
|
|
}
|
|
|
|
bool has_side_effects;
|
|
std::string parameter_sequence;
|
|
};
|
|
|
|
template <typename T> class parser;
|
|
template <typename T> class expression_helper;
|
|
|
|
template <typename T>
|
|
class symbol_table
|
|
{
|
|
protected:
|
|
|
|
template <typename Type> class parser;
|
|
|
|
protected:
|
|
|
|
template <typename Type, typename RawType>
|
|
struct type_store
|
|
{
|
|
typedef details::expression_node<T>* expression_ptr;
|
|
typedef typename details::variable_node<T> variable_node_t;
|
|
typedef ifunction<T> ifunction_t;
|
|
typedef ivararg_function<T> ivararg_function_t;
|
|
typedef igeneric_function<T> igeneric_function_t;
|
|
typedef details::vector_holder<T> vector_t;
|
|
#ifndef exprtk_disable_string_capabilities
|
|
typedef typename details::stringvar_node<T> stringvar_node_t;
|
|
#endif
|
|
|
|
typedef Type type_t;
|
|
typedef type_t* type_ptr;
|
|
typedef std::pair<bool,type_ptr> type_pair_t;
|
|
typedef std::map<std::string,type_pair_t,details::ilesscompare> 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 <typename PtrType>
|
|
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 <typename Tie, typename RType>
|
|
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<bool,vector_t*> make(std::pair<T*,std::size_t> v, const bool is_const = false)
|
|
{
|
|
return std::make_pair(is_const,new vector_t(v.first,v.second));
|
|
}
|
|
};
|
|
|
|
struct tie_stdvec
|
|
{
|
|
template <typename Allocator>
|
|
static inline std::pair<bool,vector_t*> make(std::vector<T,Allocator>& v, const bool is_const = false)
|
|
{
|
|
return std::make_pair(is_const,new vector_t(v));
|
|
}
|
|
};
|
|
|
|
struct tie_stddeq
|
|
{
|
|
template <typename Allocator>
|
|
static inline std::pair<bool,vector_t*> make(std::deque<T,Allocator>& v, const bool is_const = false)
|
|
{
|
|
return std::make_pair(is_const,new vector_t(v));
|
|
}
|
|
};
|
|
|
|
template <std::size_t v_size>
|
|
inline bool add(const std::string& symbol_name, T (&v)[v_size], const bool is_const = false)
|
|
{
|
|
return add_impl<tie_array,std::pair<T*,std::size_t> >(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<tie_array,std::pair<T*,std::size_t> >(symbol_name,std::make_pair(v,v_size),is_const);
|
|
}
|
|
|
|
template <typename Allocator>
|
|
inline bool add(const std::string& symbol_name, std::vector<T,Allocator>& v, const bool is_const = false)
|
|
{
|
|
return add_impl<tie_stdvec,std::vector<T,Allocator>&>(symbol_name,v,is_const);
|
|
}
|
|
|
|
template <typename Allocator>
|
|
inline bool add(const std::string& symbol_name, std::deque<T,Allocator>& v, const bool is_const = false)
|
|
{
|
|
return add_impl<tie_stddeq,std::deque<T,Allocator>&>(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<bool,variable_node_t*> 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<bool,stringvar_node_t*> 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<bool,function_t*> make(function_t& t, const bool is_constant = false)
|
|
{
|
|
return std::make_pair(is_constant,&t);
|
|
}
|
|
|
|
static inline std::pair<bool,vararg_function_t*> make(vararg_function_t& t, const bool is_const = false)
|
|
{
|
|
return std::make_pair(is_const,&t);
|
|
}
|
|
|
|
static inline std::pair<bool,generic_function_t*> make(generic_function_t& t, const bool is_constant = false)
|
|
{
|
|
return std::make_pair(is_constant,&t);
|
|
}
|
|
};
|
|
|
|
if (symbol_name.size() > 1)
|
|
{
|
|
for (std::size_t i = 0; i < details::reserved_symbols_size; ++i)
|
|
{
|
|
if (details::imatch(symbol_name,details::reserved_symbols[i]))
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
tm_itr_t itr = map.find(symbol_name);
|
|
|
|
if (map.end() == itr)
|
|
{
|
|
map[symbol_name] = tie::make(t,is_const);
|
|
++size;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
inline type_ptr get(const std::string& symbol_name) const
|
|
{
|
|
tm_const_itr_t itr = map.find(symbol_name);
|
|
|
|
if (map.end() == itr)
|
|
return reinterpret_cast<type_ptr>(0);
|
|
else
|
|
return itr->second.second;
|
|
}
|
|
|
|
template <typename TType, typename TRawType, typename PtrType>
|
|
struct ptr_match
|
|
{
|
|
static inline bool test(const PtrType, const void*)
|
|
{
|
|
return false;
|
|
}
|
|
};
|
|
|
|
template <typename TType, typename TRawType>
|
|
struct ptr_match<TType,TRawType,variable_node_t*>
|
|
{
|
|
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<Type,RawType,type_ptr>::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<bool,variable_node_t*>& n) { delete n.second; }
|
|
static inline void process(std::pair<bool,vector_t*>& n) { delete n.second; }
|
|
#ifndef exprtk_disable_string_capabilities
|
|
static inline void process(std::pair<bool,stringvar_node_t*>& n) { delete n.second; }
|
|
#endif
|
|
static inline void process(std::pair<bool,function_t*>&) { }
|
|
};
|
|
|
|
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<bool,variable_node_t*>& n) { delete n.second; }
|
|
static inline void process(std::pair<bool,vector_t*>& n) { delete n.second; }
|
|
static inline void process(std::pair<bool,function_t*>&) { }
|
|
#ifndef exprtk_disable_string_capabilities
|
|
static inline void process(std::pair<bool,stringvar_node_t*>& 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 <typename Allocator,
|
|
template <typename, typename> class Sequence>
|
|
inline std::size_t get_list(Sequence<std::pair<std::string,RawType>,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 <typename Allocator,
|
|
template <typename, typename> class Sequence>
|
|
inline std::size_t get_list(Sequence<std::string,Allocator>& 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<T>* expression_ptr;
|
|
typedef typename details::variable_node<T> variable_t;
|
|
typedef typename details::vector_holder<T> vector_holder_t;
|
|
typedef variable_t* variable_ptr;
|
|
#ifndef exprtk_disable_string_capabilities
|
|
typedef typename details::stringvar_node<T> stringvar_t;
|
|
typedef stringvar_t* stringvar_ptr;
|
|
#endif
|
|
typedef ifunction<T> function_t;
|
|
typedef ivararg_function<T> vararg_function_t;
|
|
typedef igeneric_function<T> generic_function_t;
|
|
typedef function_t* function_ptr;
|
|
typedef vararg_function_t* vararg_function_ptr;
|
|
typedef generic_function_t* generic_function_ptr;
|
|
|
|
static const std::size_t lut_size = 256;
|
|
|
|
// Symbol Table Holder
|
|
struct st_holder
|
|
{
|
|
struct st_data
|
|
{
|
|
type_store<typename details::variable_node<T>,T> variable_store;
|
|
#ifndef exprtk_disable_string_capabilities
|
|
type_store<typename details::stringvar_node<T>,std::string> stringvar_store;
|
|
#endif
|
|
type_store<ifunction<T>,ifunction<T> > function_store;
|
|
type_store<ivararg_function<T>,ivararg_function<T> > vararg_function_store;
|
|
type_store<igeneric_function<T>,igeneric_function<T> > generic_function_store;
|
|
type_store<igeneric_function<T>,igeneric_function<T> > string_function_store;
|
|
type_store<vector_holder_t,vector_holder_t> vector_store;
|
|
|
|
st_data()
|
|
{
|
|
for (std::size_t i = 0; i < details::reserved_words_size; ++i)
|
|
{
|
|
reserved_symbol_table_.insert(details::reserved_words[i]);
|
|
}
|
|
|
|
for (std::size_t i = 0; i < details::reserved_symbols_size; ++i)
|
|
{
|
|
reserved_symbol_table_.insert(details::reserved_symbols[i]);
|
|
}
|
|
}
|
|
|
|
inline bool is_reserved_symbol(const std::string& symbol) const
|
|
{
|
|
return (reserved_symbol_table_.end() != reserved_symbol_table_.find(symbol));
|
|
}
|
|
|
|
std::list<T> local_symbol_list_;
|
|
std::list<std::string> local_stringvar_list_;
|
|
std::set<std::string> reserved_symbol_table_;
|
|
};
|
|
|
|
st_holder()
|
|
: ref_count(1),
|
|
data_(new st_data)
|
|
{}
|
|
|
|
st_holder(st_data* data)
|
|
: ref_count(1),
|
|
data_(data)
|
|
{}
|
|
|
|
~st_holder()
|
|
{
|
|
if (data_ && (0 == ref_count))
|
|
{
|
|
delete data_;
|
|
data_ = 0;
|
|
}
|
|
}
|
|
|
|
std::size_t ref_count;
|
|
st_data* data_;
|
|
};
|
|
|
|
public:
|
|
|
|
symbol_table()
|
|
: holder_(new st_holder)
|
|
{
|
|
clear();
|
|
}
|
|
|
|
~symbol_table()
|
|
{
|
|
if (holder_)
|
|
{
|
|
if (0 == --holder_->ref_count)
|
|
{
|
|
clear();
|
|
delete holder_;
|
|
}
|
|
}
|
|
}
|
|
|
|
symbol_table(const symbol_table<T>& st)
|
|
{
|
|
holder_ = st.holder_;
|
|
holder_->ref_count++;
|
|
}
|
|
|
|
inline symbol_table<T>& operator=(const symbol_table<T>& st)
|
|
{
|
|
if (holder_)
|
|
{
|
|
if (0 == --holder_->ref_count)
|
|
{
|
|
delete holder_;
|
|
}
|
|
|
|
holder_ = 0;
|
|
}
|
|
|
|
holder_ = st.holder_;
|
|
holder_->ref_count++;
|
|
|
|
return *this;
|
|
}
|
|
|
|
inline bool operator==(const symbol_table<T>& st)
|
|
{
|
|
return (this == &st) || (holder_ == st.holder_);
|
|
}
|
|
|
|
inline void clear_variables(const bool delete_node = true)
|
|
{
|
|
local_data().variable_store.clear(delete_node);
|
|
}
|
|
|
|
inline void clear_functions()
|
|
{
|
|
local_data().function_store.clear();
|
|
}
|
|
|
|
inline void clear_strings()
|
|
{
|
|
#ifndef exprtk_disable_string_capabilities
|
|
local_data().stringvar_store.clear();
|
|
#endif
|
|
}
|
|
|
|
inline void clear_vectors()
|
|
{
|
|
local_data().vector_store.clear();
|
|
}
|
|
|
|
inline void clear()
|
|
{
|
|
if (!valid()) return;
|
|
clear_variables();
|
|
clear_functions();
|
|
clear_strings ();
|
|
clear_vectors ();
|
|
}
|
|
|
|
inline std::size_t variable_count() const
|
|
{
|
|
if (valid())
|
|
return local_data().variable_store.size;
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
#ifndef exprtk_disable_string_capabilities
|
|
inline std::size_t stringvar_count() const
|
|
{
|
|
if (valid())
|
|
return local_data().stringvar_store.size;
|
|
else
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
inline std::size_t function_count() const
|
|
{
|
|
if (valid())
|
|
return local_data().function_store.size;
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
inline std::size_t vector_count() const
|
|
{
|
|
if (valid())
|
|
return local_data().vector_store.size;
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
inline variable_ptr get_variable(const std::string& variable_name) const
|
|
{
|
|
if (!valid())
|
|
return reinterpret_cast<variable_ptr>(0);
|
|
else if (!valid_symbol(variable_name))
|
|
return reinterpret_cast<variable_ptr>(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<variable_ptr>(0);
|
|
else
|
|
return local_data().variable_store.get_from_varptr(
|
|
reinterpret_cast<const void*>(&var_ref));
|
|
}
|
|
|
|
#ifndef exprtk_disable_string_capabilities
|
|
inline stringvar_ptr get_stringvar(const std::string& string_name) const
|
|
{
|
|
if (!valid())
|
|
return reinterpret_cast<stringvar_ptr>(0);
|
|
else if (!valid_symbol(string_name))
|
|
return reinterpret_cast<stringvar_ptr>(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<function_ptr>(0);
|
|
else if (!valid_symbol(function_name))
|
|
return reinterpret_cast<function_ptr>(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<vararg_function_ptr>(0);
|
|
else if (!valid_symbol(vararg_function_name))
|
|
return reinterpret_cast<vararg_function_ptr>(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<generic_function_ptr>(0);
|
|
else if (!valid_symbol(function_name))
|
|
return reinterpret_cast<generic_function_ptr>(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<generic_function_ptr>(0);
|
|
else if (!valid_symbol(function_name))
|
|
return reinterpret_cast<generic_function_ptr>(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<vector_holder_ptr>(0);
|
|
else if (!valid_symbol(vector_name))
|
|
return reinterpret_cast<vector_holder_ptr>(0);
|
|
else
|
|
return local_data().vector_store.get(vector_name);
|
|
}
|
|
|
|
inline T& variable_ref(const std::string& symbol_name)
|
|
{
|
|
static T null_var = T(0);
|
|
if (!valid())
|
|
return null_var;
|
|
else if (!valid_symbol(symbol_name))
|
|
return null_var;
|
|
else
|
|
return local_data().variable_store.type_ref(symbol_name);
|
|
}
|
|
|
|
#ifndef exprtk_disable_string_capabilities
|
|
inline std::string& stringvar_ref(const std::string& symbol_name)
|
|
{
|
|
static std::string null_stringvar;
|
|
if (!valid())
|
|
return null_stringvar;
|
|
else if (!valid_symbol(symbol_name))
|
|
return null_stringvar;
|
|
else
|
|
return local_data().stringvar_store.type_ref(symbol_name);
|
|
}
|
|
#endif
|
|
|
|
inline bool is_constant_node(const std::string& symbol_name) const
|
|
{
|
|
if (!valid())
|
|
return false;
|
|
else if (!valid_symbol(symbol_name))
|
|
return false;
|
|
else
|
|
return local_data().variable_store.is_constant(symbol_name);
|
|
}
|
|
|
|
#ifndef exprtk_disable_string_capabilities
|
|
inline bool is_constant_string(const std::string& symbol_name) const
|
|
{
|
|
if (!valid())
|
|
return false;
|
|
else if (!valid_symbol(symbol_name))
|
|
return false;
|
|
else if (!local_data().stringvar_store.symbol_exists(symbol_name))
|
|
return false;
|
|
else
|
|
return local_data().stringvar_store.is_constant(symbol_name);
|
|
}
|
|
#endif
|
|
|
|
inline bool create_variable(const std::string& variable_name, const T& value = T(0))
|
|
{
|
|
if (!valid())
|
|
return false;
|
|
else if (!valid_symbol(variable_name))
|
|
return false;
|
|
else if (symbol_exists(variable_name))
|
|
return false;
|
|
|
|
local_data().local_symbol_list_.push_back(value);
|
|
T& t = local_data().local_symbol_list_.back();
|
|
|
|
return add_variable(variable_name,t);
|
|
}
|
|
|
|
#ifndef exprtk_disable_string_capabilities
|
|
inline bool create_stringvar(const std::string& stringvar_name, const std::string& value = std::string(""))
|
|
{
|
|
if (!valid())
|
|
return false;
|
|
else if (!valid_symbol(stringvar_name))
|
|
return false;
|
|
else if (symbol_exists(stringvar_name))
|
|
return false;
|
|
|
|
local_data().local_stringvar_list_.push_back(value);
|
|
std::string& s = local_data().local_stringvar_list_.back();
|
|
|
|
return add_stringvar(stringvar_name,s);
|
|
}
|
|
#endif
|
|
|
|
inline bool add_variable(const std::string& variable_name, T& t, const bool is_constant = false)
|
|
{
|
|
if (!valid())
|
|
return false;
|
|
else if (!valid_symbol(variable_name))
|
|
return false;
|
|
else if (symbol_exists(variable_name))
|
|
return false;
|
|
else
|
|
return local_data().variable_store.add(variable_name,t,is_constant);
|
|
}
|
|
|
|
inline bool add_constant(const std::string& constant_name, const T& value)
|
|
{
|
|
if (!valid())
|
|
return false;
|
|
else if (!valid_symbol(constant_name))
|
|
return false;
|
|
else if (symbol_exists(constant_name))
|
|
return false;
|
|
|
|
local_data().local_symbol_list_.push_back(value);
|
|
T& t = local_data().local_symbol_list_.back();
|
|
|
|
return add_variable(constant_name,t,true);
|
|
}
|
|
|
|
#ifndef exprtk_disable_string_capabilities
|
|
inline bool add_stringvar(const std::string& stringvar_name, std::string& s, const bool is_constant = false)
|
|
{
|
|
if (!valid())
|
|
return false;
|
|
else if (!valid_symbol(stringvar_name))
|
|
return false;
|
|
else if (symbol_exists(stringvar_name))
|
|
return false;
|
|
else
|
|
return local_data().stringvar_store.add(stringvar_name,s,is_constant);
|
|
}
|
|
#endif
|
|
|
|
inline bool add_function(const std::string& function_name, function_t& function)
|
|
{
|
|
if (!valid())
|
|
return false;
|
|
else if (!valid_symbol(function_name))
|
|
return false;
|
|
else if (symbol_exists(function_name))
|
|
return false;
|
|
else
|
|
return local_data().function_store.add(function_name,function);
|
|
}
|
|
|
|
inline bool add_function(const std::string& vararg_function_name, vararg_function_t& vararg_function)
|
|
{
|
|
if (!valid())
|
|
return false;
|
|
else if (!valid_symbol(vararg_function_name))
|
|
return false;
|
|
else if (symbol_exists(vararg_function_name))
|
|
return false;
|
|
else
|
|
return local_data().vararg_function_store.add(vararg_function_name,vararg_function);
|
|
}
|
|
|
|
enum func_type
|
|
{
|
|
e_ft_unknown = 0,
|
|
e_ft_basicfunc = 1,
|
|
e_ft_strfunc = 2
|
|
};
|
|
|
|
inline bool add_function(const std::string& function_name, generic_function_t& function, const func_type ft = e_ft_basicfunc)
|
|
{
|
|
if (!valid())
|
|
return false;
|
|
else if (!valid_symbol(function_name))
|
|
return false;
|
|
else if (symbol_exists(function_name))
|
|
return false;
|
|
else if (std::string::npos != function.parameter_sequence.find_first_not_of("STV*?|"))
|
|
return false;
|
|
else if (e_ft_basicfunc == ft)
|
|
return local_data().generic_function_store.add(function_name,function);
|
|
else if (e_ft_strfunc == ft)
|
|
return local_data().string_function_store.add(function_name, function);
|
|
else
|
|
return false;
|
|
}
|
|
|
|
template <std::size_t N>
|
|
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 <typename Allocator>
|
|
inline bool add_vector(const std::string& vector_name, std::vector<T,Allocator>& v)
|
|
{
|
|
if (!valid())
|
|
return false;
|
|
else if (!valid_symbol(vector_name))
|
|
return false;
|
|
else if (symbol_exists(vector_name))
|
|
return false;
|
|
else
|
|
return local_data().vector_store.add(vector_name,v);
|
|
}
|
|
|
|
template <typename Allocator>
|
|
inline bool add_vector(const std::string& vector_name, std::deque<T,Allocator>& 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<T>::value();
|
|
return add_constant("epsilon",local_epsilon);
|
|
}
|
|
|
|
inline bool add_infinity()
|
|
{
|
|
static const T local_infinity = std::numeric_limits<T>::infinity();
|
|
return add_constant("inf",local_infinity);
|
|
}
|
|
|
|
template <typename Allocator,
|
|
template <typename, typename> class Sequence>
|
|
inline std::size_t get_variable_list(Sequence<std::pair<std::string,T>,Allocator>& vlist) const
|
|
{
|
|
if (!valid())
|
|
return 0;
|
|
else
|
|
return local_data().variable_store.get_list(vlist);
|
|
}
|
|
|
|
template <typename Allocator,
|
|
template <typename, typename> class Sequence>
|
|
inline std::size_t get_variable_list(Sequence<std::string,Allocator>& vlist) const
|
|
{
|
|
if (!valid())
|
|
return 0;
|
|
else
|
|
return local_data().variable_store.get_list(vlist);
|
|
}
|
|
|
|
#ifndef exprtk_disable_string_capabilities
|
|
template <typename Allocator,
|
|
template <typename, typename> class Sequence>
|
|
inline std::size_t get_stringvar_list(Sequence<std::pair<std::string,std::string>,Allocator>& svlist) const
|
|
{
|
|
if (!valid())
|
|
return 0;
|
|
else
|
|
return local_data().stringvar_store.get_list(svlist);
|
|
}
|
|
|
|
template <typename Allocator,
|
|
template <typename, typename> class Sequence>
|
|
inline std::size_t get_stringvar_list(Sequence<std::string,Allocator>& svlist) const
|
|
{
|
|
if (!valid())
|
|
return 0;
|
|
else
|
|
return local_data().stringvar_store.get_list(svlist);
|
|
}
|
|
#endif
|
|
|
|
template <typename Allocator,
|
|
template <typename, typename> class Sequence>
|
|
inline std::size_t get_vector_list(Sequence<std::string,Allocator>& vlist) const
|
|
{
|
|
if (!valid())
|
|
return 0;
|
|
else
|
|
return local_data().vector_store.get_list(vlist);
|
|
}
|
|
|
|
inline bool symbol_exists(const std::string& symbol_name) const
|
|
{
|
|
/*
|
|
Will return true if symbol_name exists as either a reserved symbol,
|
|
variable, stringvar or function name in any of the type stores.
|
|
*/
|
|
if (!valid())
|
|
return false;
|
|
else if (local_data().variable_store.symbol_exists(symbol_name))
|
|
return true;
|
|
#ifndef exprtk_disable_string_capabilities
|
|
else if (local_data().stringvar_store.symbol_exists(symbol_name))
|
|
return true;
|
|
#endif
|
|
else if (local_data().function_store.symbol_exists(symbol_name))
|
|
return true;
|
|
else if (local_data().is_reserved_symbol(symbol_name))
|
|
return true;
|
|
else
|
|
return false;
|
|
}
|
|
|
|
inline bool is_variable(const std::string& variable_name) const
|
|
{
|
|
if (!valid())
|
|
return false;
|
|
else
|
|
return local_data().variable_store.symbol_exists(variable_name);
|
|
}
|
|
|
|
#ifndef exprtk_disable_string_capabilities
|
|
inline bool is_stringvar(const std::string& stringvar_name) const
|
|
{
|
|
if (!valid())
|
|
return false;
|
|
else
|
|
return local_data().stringvar_store.symbol_exists(stringvar_name);
|
|
}
|
|
|
|
inline bool is_conststr_stringvar(const std::string& symbol_name) const
|
|
{
|
|
if (!valid())
|
|
return false;
|
|
else if (!valid_symbol(symbol_name))
|
|
return false;
|
|
else if (!local_data().stringvar_store.symbol_exists(symbol_name))
|
|
return false;
|
|
|
|
return (
|
|
local_data().stringvar_store.symbol_exists(symbol_name) ||
|
|
local_data().stringvar_store.is_constant (symbol_name)
|
|
);
|
|
}
|
|
#endif
|
|
|
|
inline bool is_function(const std::string& function_name) const
|
|
{
|
|
if (!valid())
|
|
return false;
|
|
else
|
|
return local_data().function_store.symbol_exists(function_name);
|
|
}
|
|
|
|
inline bool is_vararg_function(const std::string& vararg_function_name) const
|
|
{
|
|
if (!valid())
|
|
return false;
|
|
else
|
|
return local_data().vararg_function_store.symbol_exists(vararg_function_name);
|
|
}
|
|
|
|
inline bool is_vector(const std::string& vector_name) const
|
|
{
|
|
if (!valid())
|
|
return false;
|
|
else
|
|
return local_data().vector_store.symbol_exists(vector_name);
|
|
}
|
|
|
|
inline std::string get_variable_name(const expression_ptr& ptr) const
|
|
{
|
|
return local_data().variable_store.entity_name(ptr);
|
|
}
|
|
|
|
inline std::string get_vector_name(const vector_holder_ptr& ptr) const
|
|
{
|
|
return local_data().vector_store.entity_name(ptr);
|
|
}
|
|
|
|
#ifndef exprtk_disable_string_capabilities
|
|
inline std::string get_stringvar_name(const expression_ptr& ptr) const
|
|
{
|
|
return local_data().stringvar_store.entity_name(ptr);
|
|
}
|
|
|
|
inline std::string get_conststr_stringvar_name(const expression_ptr& ptr) const
|
|
{
|
|
return local_data().stringvar_store.entity_name(ptr);
|
|
}
|
|
#endif
|
|
|
|
inline bool valid() const
|
|
{
|
|
// Symbol table sanity check.
|
|
return holder_ && holder_->data_;
|
|
}
|
|
|
|
inline void load_from(const symbol_table<T>& st)
|
|
{
|
|
{
|
|
std::vector<std::string> 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<T>& ifunc = *st.get_function(name_list[i]);
|
|
add_function(name_list[i],ifunc);
|
|
}
|
|
}
|
|
}
|
|
|
|
{
|
|
std::vector<std::string> 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<T>& ivafunc = *st.get_vararg_function(name_list[i]);
|
|
add_function(name_list[i],ivafunc);
|
|
}
|
|
}
|
|
}
|
|
|
|
{
|
|
std::vector<std::string> 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<T>& ifunc = *st.get_generic_function(name_list[i]);
|
|
add_function(name_list[i],ifunc);
|
|
}
|
|
}
|
|
}
|
|
|
|
{
|
|
std::vector<std::string> 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<T>& ifunc = *st.get_string_function(name_list[i]);
|
|
add_function(name_list[i],ifunc,e_ft_strfunc);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private:
|
|
|
|
inline bool valid_symbol(const std::string& symbol) const
|
|
{
|
|
if (symbol.empty())
|
|
return false;
|
|
if (!details::is_letter(symbol[0]))
|
|
return false;
|
|
else if (symbol.size() > 1)
|
|
{
|
|
for (std::size_t i = 1; i < symbol.size(); ++i)
|
|
{
|
|
if (
|
|
(!details::is_letter(symbol[i])) &&
|
|
(!details:: is_digit(symbol[i])) &&
|
|
('_' != symbol[i])
|
|
)
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
return (!local_data().is_reserved_symbol(symbol));
|
|
}
|
|
|
|
inline typename st_holder::st_data& local_data()
|
|
{
|
|
return *(holder_->data_);
|
|
}
|
|
|
|
inline const typename st_holder::st_data& local_data() const
|
|
{
|
|
return *(holder_->data_);
|
|
}
|
|
|
|
st_holder* holder_;
|
|
};
|
|
|
|
template <typename T>
|
|
class function_compositor;
|
|
|
|
template <typename T>
|
|
class expression
|
|
{
|
|
private:
|
|
|
|
typedef details::expression_node<T>* expression_ptr;
|
|
typedef details::vector_holder<T>* vector_holder_ptr;
|
|
|
|
struct expression_holder
|
|
{
|
|
enum data_type
|
|
{
|
|
e_unknown ,
|
|
e_expr ,
|
|
e_vecholder,
|
|
e_data ,
|
|
e_vecdata ,
|
|
e_string
|
|
};
|
|
|
|
struct data_pack
|
|
{
|
|
data_pack()
|
|
: pointer(0),
|
|
type(e_unknown),
|
|
size(0)
|
|
{}
|
|
|
|
data_pack(void* ptr, data_type dt, std::size_t sz = 0)
|
|
: pointer(ptr),
|
|
type(dt),
|
|
size(sz)
|
|
{}
|
|
|
|
void* pointer;
|
|
data_type type;
|
|
std::size_t size;
|
|
};
|
|
|
|
typedef std::vector<data_pack> local_data_list_t;
|
|
|
|
expression_holder()
|
|
: ref_count(0),
|
|
expr(0)
|
|
{}
|
|
|
|
expression_holder(expression_ptr e)
|
|
: ref_count(1),
|
|
expr(e)
|
|
{}
|
|
|
|
~expression_holder()
|
|
{
|
|
if (expr && details::branch_deletable(expr))
|
|
{
|
|
delete expr;
|
|
}
|
|
|
|
if (!local_data_list.empty())
|
|
{
|
|
for (std::size_t i = 0; i < local_data_list.size(); ++i)
|
|
{
|
|
switch (local_data_list[i].type)
|
|
{
|
|
case e_expr : delete reinterpret_cast<expression_ptr>(local_data_list[i].pointer);
|
|
break;
|
|
|
|
case e_vecholder : delete reinterpret_cast<vector_holder_ptr>(local_data_list[i].pointer);
|
|
break;
|
|
|
|
case e_data : delete (T*)(local_data_list[i].pointer);
|
|
break;
|
|
|
|
case e_vecdata : delete [] (T*)(local_data_list[i].pointer);
|
|
break;
|
|
|
|
case e_string : delete (std::string*)(local_data_list[i].pointer);
|
|
break;
|
|
|
|
default : break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
std::size_t ref_count;
|
|
expression_ptr expr;
|
|
local_data_list_t local_data_list;
|
|
|
|
friend class function_compositor<T>;
|
|
};
|
|
|
|
public:
|
|
|
|
expression()
|
|
: expression_holder_(0)
|
|
{
|
|
set_expression(new details::null_node<T>());
|
|
}
|
|
|
|
expression(const expression<T>& e)
|
|
: expression_holder_(e.expression_holder_),
|
|
symbol_table_(e.symbol_table_)
|
|
{
|
|
expression_holder_->ref_count++;
|
|
}
|
|
|
|
inline expression<T>& operator=(const expression<T>& e)
|
|
{
|
|
if (this != &e)
|
|
{
|
|
if (expression_holder_)
|
|
{
|
|
if (0 == --expression_holder_->ref_count)
|
|
{
|
|
delete expression_holder_;
|
|
}
|
|
|
|
expression_holder_ = 0;
|
|
}
|
|
|
|
expression_holder_ = e.expression_holder_;
|
|
expression_holder_->ref_count++;
|
|
symbol_table_ = e.symbol_table_;
|
|
}
|
|
|
|
return *this;
|
|
}
|
|
|
|
inline bool operator==(const expression<T>& e)
|
|
{
|
|
return (this == &e);
|
|
}
|
|
|
|
inline bool operator!() const
|
|
{
|
|
return (
|
|
(0 == expression_holder_ ) ||
|
|
(0 == expression_holder_->expr)
|
|
);
|
|
}
|
|
|
|
inline expression<T>& release()
|
|
{
|
|
if (expression_holder_)
|
|
{
|
|
if (0 == --expression_holder_->ref_count)
|
|
{
|
|
delete expression_holder_;
|
|
}
|
|
|
|
expression_holder_ = 0;
|
|
}
|
|
|
|
return *this;
|
|
}
|
|
|
|
~expression()
|
|
{
|
|
if (expression_holder_)
|
|
{
|
|
if (0 == --expression_holder_->ref_count)
|
|
{
|
|
delete expression_holder_;
|
|
}
|
|
}
|
|
}
|
|
|
|
inline T value() const
|
|
{
|
|
return expression_holder_->expr->value();
|
|
}
|
|
|
|
inline T operator()() const
|
|
{
|
|
return value();
|
|
}
|
|
|
|
inline operator T() const
|
|
{
|
|
return value();
|
|
}
|
|
|
|
inline operator bool() const
|
|
{
|
|
return details::is_true(value());
|
|
}
|
|
|
|
inline void register_symbol_table(symbol_table<T>& st)
|
|
{
|
|
symbol_table_ = st;
|
|
}
|
|
|
|
inline const symbol_table<T>& get_symbol_table() const
|
|
{
|
|
return symbol_table_;
|
|
}
|
|
|
|
inline symbol_table<T>& get_symbol_table()
|
|
{
|
|
return symbol_table_;
|
|
}
|
|
|
|
private:
|
|
|
|
inline void set_expression(const expression_ptr expr)
|
|
{
|
|
if (expr)
|
|
{
|
|
if (expression_holder_)
|
|
{
|
|
if (0 == --expression_holder_->ref_count)
|
|
{
|
|
delete expression_holder_;
|
|
}
|
|
}
|
|
|
|
expression_holder_ = new expression_holder(expr);
|
|
}
|
|
}
|
|
|
|
inline void register_local_var(expression_ptr expr)
|
|
{
|
|
if (expr)
|
|
{
|
|
if (expression_holder_)
|
|
{
|
|
expression_holder_->
|
|
local_data_list.push_back(
|
|
typename expression<T>::expression_holder::
|
|
data_pack(reinterpret_cast<void*>(expr),
|
|
expression_holder::e_expr));
|
|
}
|
|
}
|
|
}
|
|
|
|
inline void register_local_var(vector_holder_ptr vec_holder)
|
|
{
|
|
if (vec_holder)
|
|
{
|
|
if (expression_holder_)
|
|
{
|
|
expression_holder_->
|
|
local_data_list.push_back(
|
|
typename expression<T>::expression_holder::
|
|
data_pack(reinterpret_cast<void*>(vec_holder),
|
|
expression_holder::e_vecholder));
|
|
}
|
|
}
|
|
}
|
|
|
|
inline void register_local_data(void* data, const std::size_t& size = 0, const bool vectype = false)
|
|
{
|
|
if (data)
|
|
{
|
|
if (expression_holder_)
|
|
{
|
|
expression_holder_->
|
|
local_data_list.push_back(
|
|
typename expression<T>::expression_holder::
|
|
data_pack(reinterpret_cast<void*>(data),
|
|
vectype ? expression_holder::e_vecdata :
|
|
expression_holder::e_data,
|
|
size));
|
|
}
|
|
}
|
|
}
|
|
|
|
inline const typename expression_holder::local_data_list_t& local_data_list()
|
|
{
|
|
if (expression_holder_)
|
|
{
|
|
return expression_holder_->local_data_list;
|
|
}
|
|
else
|
|
{
|
|
static typename expression_holder::local_data_list_t null_local_data_list;
|
|
return null_local_data_list;
|
|
}
|
|
}
|
|
|
|
expression_holder* expression_holder_;
|
|
symbol_table<T> symbol_table_;
|
|
|
|
friend class parser<T>;
|
|
friend class expression_helper<T>;
|
|
friend class function_compositor<T>;
|
|
};
|
|
|
|
template <typename T>
|
|
class expression_helper
|
|
{
|
|
public:
|
|
|
|
static inline bool is_constant(const expression<T>& expr)
|
|
{
|
|
return details::is_constant_node(expr.expression_holder_->expr);
|
|
}
|
|
|
|
static inline bool is_variable(const expression<T>& expr)
|
|
{
|
|
return details::is_variable_node(expr.expression_holder_->expr);
|
|
}
|
|
|
|
static inline bool is_unary(const expression<T>& expr)
|
|
{
|
|
return details::is_unary_node(expr.expression_holder_->expr);
|
|
}
|
|
|
|
static inline bool is_binary(const expression<T>& expr)
|
|
{
|
|
return details::is_binary_node(expr.expression_holder_->expr);
|
|
}
|
|
|
|
static inline bool is_function(const expression<T>& expr)
|
|
{
|
|
return details::is_function(expr.expression_holder_->expr);
|
|
}
|
|
};
|
|
|
|
namespace parser_error
|
|
{
|
|
enum error_mode
|
|
{
|
|
e_unknown = 0,
|
|
e_syntax = 1,
|
|
e_token = 2,
|
|
e_numeric = 4,
|
|
e_symtab = 5,
|
|
e_lexer = 6,
|
|
e_helper = 7
|
|
};
|
|
|
|
struct type
|
|
{
|
|
type()
|
|
: mode(parser_error::e_unknown),
|
|
line_no (0),
|
|
column_no(0)
|
|
{}
|
|
|
|
lexer::token token;
|
|
error_mode mode;
|
|
std::string diagnostic;
|
|
std::string error_line;
|
|
std::size_t line_no;
|
|
std::size_t column_no;
|
|
};
|
|
|
|
inline type make_error(error_mode mode, const std::string& diagnostic = "")
|
|
{
|
|
type t;
|
|
t.mode = mode;
|
|
t.token.type = lexer::token::e_error;
|
|
t.diagnostic = diagnostic;
|
|
exprtk_debug(((diagnostic + "\n").c_str()));
|
|
return t;
|
|
}
|
|
|
|
inline type make_error(error_mode mode, const lexer::token& tk, const std::string& diagnostic = "")
|
|
{
|
|
type t;
|
|
t.mode = mode;
|
|
t.token = tk;
|
|
t.diagnostic = diagnostic;
|
|
exprtk_debug(((diagnostic + "\n").c_str()));
|
|
return t;
|
|
}
|
|
|
|
inline std::string to_str(error_mode mode)
|
|
{
|
|
switch (mode)
|
|
{
|
|
case e_unknown : return std::string("Unknown Error");
|
|
case e_syntax : return std::string("Syntax Error" );
|
|
case e_token : return std::string("Token Error" );
|
|
case e_numeric : return std::string("Numeric Error");
|
|
case e_symtab : return std::string("Symbol Error" );
|
|
case e_lexer : return std::string("Lexer Error" );
|
|
case e_helper : return std::string("Helper Error" );
|
|
default : return std::string("Unknown Error");
|
|
}
|
|
}
|
|
|
|
inline bool update_error(type& error, const std::string& expression)
|
|
{
|
|
if (
|
|
expression.empty() ||
|
|
(error.token.position > expression.size()) ||
|
|
(std::numeric_limits<std::size_t>::max() == error.token.position)
|
|
)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
std::size_t error_line_start = 0;
|
|
|
|
for (std::size_t i = error.token.position; i > 0; --i)
|
|
{
|
|
const char c = expression[i];
|
|
|
|
if (('\n' == c) || ('\r' == c))
|
|
{
|
|
error_line_start = i + 1;
|
|
break;
|
|
}
|
|
}
|
|
|
|
std::size_t next_nl_position = std::min(expression.size(),
|
|
expression.find_first_of('\n',error.token.position + 1));
|
|
|
|
error.column_no = error.token.position - error_line_start;
|
|
error.error_line = expression.substr(error_line_start,
|
|
next_nl_position - error_line_start);
|
|
|
|
error.line_no = 0;
|
|
|
|
for (std::size_t i = 0; i < next_nl_position; ++i)
|
|
{
|
|
if ('\n' == expression[i])
|
|
++error.line_no;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
inline void dump_error(const type& error)
|
|
{
|
|
printf("Position: %02d Type: [%s] Msg: %s\n",
|
|
static_cast<int>(error.token.position),
|
|
exprtk::parser_error::to_str(error.mode).c_str(),
|
|
error.diagnostic.c_str());
|
|
}
|
|
}
|
|
|
|
template <typename T>
|
|
class parser
|
|
{
|
|
private:
|
|
|
|
enum precedence_level
|
|
{
|
|
e_level00,
|
|
e_level01,
|
|
e_level02,
|
|
e_level03,
|
|
e_level04,
|
|
e_level05,
|
|
e_level06,
|
|
e_level07,
|
|
e_level08,
|
|
e_level09,
|
|
e_level10,
|
|
e_level11,
|
|
e_level12,
|
|
e_level13,
|
|
e_level14
|
|
};
|
|
|
|
typedef const T& cref_t;
|
|
typedef const T const_t;
|
|
typedef ifunction <T> F;
|
|
typedef ivararg_function <T> VAF;
|
|
typedef igeneric_function <T> GF;
|
|
typedef ifunction <T> ifunction_t;
|
|
typedef ivararg_function <T> ivararg_function_t;
|
|
typedef igeneric_function <T> igeneric_function_t;
|
|
typedef details::expression_node <T> expression_node_t;
|
|
typedef details::literal_node <T> literal_node_t;
|
|
typedef details::unary_node <T> unary_node_t;
|
|
typedef details::binary_node <T> binary_node_t;
|
|
typedef details::trinary_node <T> trinary_node_t;
|
|
typedef details::quaternary_node <T> quaternary_node_t;
|
|
typedef details::quinary_node <T> quinary_node_t;
|
|
typedef details::senary_node <T> senary_node_t;
|
|
typedef details::conditional_node<T> conditional_node_t;
|
|
typedef details::cons_conditional_node<T> cons_conditional_node_t;
|
|
typedef details::while_loop_node <T> while_loop_node_t;
|
|
typedef details::repeat_until_loop_node<T> repeat_until_loop_node_t;
|
|
typedef details::for_loop_node <T> for_loop_node_t;
|
|
#ifndef exprtk_disable_break_continue
|
|
typedef details::while_loop_bc_node <T> while_loop_bc_node_t;
|
|
typedef details::repeat_until_loop_bc_node<T> repeat_until_loop_bc_node_t;
|
|
typedef details::for_loop_bc_node<T> for_loop_bc_node_t;
|
|
#endif
|
|
typedef details::switch_node <T> switch_node_t;
|
|
typedef details::variable_node <T> variable_node_t;
|
|
typedef details::vector_elem_node<T> vector_elem_node_t;
|
|
typedef details::vector_node <T> vector_node_t;
|
|
#ifndef exprtk_disable_string_capabilities
|
|
typedef details::range_pack <T> range_t;
|
|
typedef details::stringvar_node <T> stringvar_node_t;
|
|
typedef details::string_literal_node<T> string_literal_node_t;
|
|
typedef details::string_range_node <T> string_range_node_t;
|
|
typedef details::const_string_range_node<T> const_string_range_node_t;
|
|
typedef details::generic_string_range_node<T> generic_string_range_node_t;
|
|
typedef details::string_concat_node <T> string_concat_node_t;
|
|
typedef details::assignment_string_node<T> assignment_string_node_t;
|
|
typedef details::assignment_string_range_node<T> assignment_string_range_node_t;
|
|
#endif
|
|
typedef details::assignment_node<T> assignment_node_t;
|
|
typedef details::assignment_vec_elem_node<T> assignment_vec_elem_node_t;
|
|
typedef details::assignment_vec_node <T> assignment_vec_node_t;
|
|
typedef details::assignment_vecvec_node <T> assignment_vecvec_node_t;
|
|
typedef details::scand_node<T> scand_node_t;
|
|
typedef details::scor_node<T> scor_node_t;
|
|
typedef lexer::token token_t;
|
|
typedef expression_node_t* expression_node_ptr;
|
|
typedef symbol_table<T> symbol_table_t;
|
|
typedef details::vector_holder<T>* vector_holder_ptr;
|
|
|
|
typedef typename details::functor_t<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<operator_t, unary_functor_t> unary_op_map_t;
|
|
typedef std::map<operator_t, binary_functor_t> binary_op_map_t;
|
|
typedef std::map<operator_t,trinary_functor_t> trinary_op_map_t;
|
|
|
|
typedef std::map<std::string,std::pair<trinary_functor_t ,operator_t> > sf3_map_t;
|
|
typedef std::map<std::string,std::pair<quaternary_functor_t,operator_t> > sf4_map_t;
|
|
|
|
typedef std::map<binary_functor_t,operator_t> inv_binary_op_map_t;
|
|
typedef std::multimap<std::string,details::base_operation_t,details::ilesscompare> base_ops_map_t;
|
|
|
|
typedef details::T0oT1_define<T, cref_t, cref_t> vov_t;
|
|
typedef details::T0oT1_define<T,const_t, cref_t> cov_t;
|
|
typedef details::T0oT1_define<T, cref_t,const_t> voc_t;
|
|
|
|
typedef details::T0oT1oT2_define<T, cref_t, cref_t, cref_t> vovov_t;
|
|
typedef details::T0oT1oT2_define<T, cref_t, cref_t,const_t> vovoc_t;
|
|
typedef details::T0oT1oT2_define<T, cref_t,const_t, cref_t> vocov_t;
|
|
typedef details::T0oT1oT2_define<T,const_t, cref_t, cref_t> covov_t;
|
|
typedef details::T0oT1oT2_define<T,const_t, cref_t,const_t> covoc_t;
|
|
typedef details::T0oT1oT2_define<T,const_t,const_t, cref_t> cocov_t;
|
|
typedef details::T0oT1oT2_define<T,cref_t,const_t, const_t> vococ_t;
|
|
|
|
typedef details::T0oT1oT2oT3_define<T, cref_t, cref_t, cref_t, cref_t> vovovov_t;
|
|
typedef details::T0oT1oT2oT3_define<T, cref_t, cref_t, cref_t,const_t> vovovoc_t;
|
|
typedef details::T0oT1oT2oT3_define<T, cref_t, cref_t,const_t, cref_t> vovocov_t;
|
|
typedef details::T0oT1oT2oT3_define<T, cref_t,const_t, cref_t, cref_t> vocovov_t;
|
|
typedef details::T0oT1oT2oT3_define<T,const_t, cref_t, cref_t, cref_t> covovov_t;
|
|
|
|
typedef details::T0oT1oT2oT3_define<T,const_t, cref_t,const_t, cref_t> covocov_t;
|
|
typedef details::T0oT1oT2oT3_define<T, cref_t,const_t, cref_t,const_t> vocovoc_t;
|
|
typedef details::T0oT1oT2oT3_define<T,const_t, cref_t, cref_t,const_t> covovoc_t;
|
|
typedef details::T0oT1oT2oT3_define<T, cref_t,const_t,const_t, cref_t> vococov_t;
|
|
|
|
struct scope_element
|
|
{
|
|
enum element_type
|
|
{
|
|
e_none ,
|
|
e_variable,
|
|
e_vector ,
|
|
e_vecelem ,
|
|
e_string
|
|
};
|
|
|
|
typedef variable_node_t* variable_node_ptr;
|
|
typedef details::vector_holder<T> vector_holder_t;
|
|
typedef vector_holder_t* vector_holder_ptr;
|
|
|
|
scope_element()
|
|
: name("???"),
|
|
size (std::numeric_limits<std::size_t>::max()),
|
|
index(std::numeric_limits<std::size_t>::max()),
|
|
depth(std::numeric_limits<std::size_t>::max()),
|
|
ref_count(0),
|
|
ip_index (0),
|
|
type (e_none),
|
|
active(false),
|
|
data (0),
|
|
var_node(0),
|
|
vec_node(0)
|
|
{}
|
|
|
|
bool operator < (const scope_element& se) const
|
|
{
|
|
if (ip_index < se.ip_index)
|
|
return true;
|
|
else if (ip_index > se.ip_index)
|
|
return false;
|
|
else if (depth < se.depth)
|
|
return true;
|
|
else if (depth > se.depth)
|
|
return false;
|
|
else if (index < se.index)
|
|
return true;
|
|
else if (index > se.index)
|
|
return false;
|
|
else
|
|
return (name < se.name);
|
|
}
|
|
|
|
std::string name;
|
|
std::size_t size;
|
|
std::size_t index;
|
|
std::size_t depth;
|
|
std::size_t ref_count;
|
|
std::size_t ip_index;
|
|
element_type type;
|
|
bool active;
|
|
void* data;
|
|
variable_node_ptr var_node;
|
|
vector_holder_ptr vec_node;
|
|
};
|
|
|
|
class scope_element_manager
|
|
{
|
|
public:
|
|
|
|
typedef variable_node_t* variable_node_ptr;
|
|
typedef parser<T> parser_t;
|
|
|
|
scope_element_manager(parser<T>& 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<std::size_t>::max())
|
|
{
|
|
for (std::size_t i = 0; i < element_.size(); ++i)
|
|
{
|
|
scope_element& se = element_[i];
|
|
|
|
if (se.depth > parser_.scope_depth_)
|
|
return null_element_;
|
|
else if (
|
|
(se.name == var_name) &&
|
|
(se.index == index)
|
|
)
|
|
return se;
|
|
}
|
|
|
|
return null_element_;
|
|
}
|
|
|
|
inline bool add_element(const scope_element& se)
|
|
{
|
|
for (std::size_t j = 0; j < element_.size(); ++j)
|
|
{
|
|
if (
|
|
(element_[j].name == se.name ) &&
|
|
(element_[j].depth <= se.depth) &&
|
|
(element_[j].index == se.index) &&
|
|
(element_[j].size == se.size )
|
|
)
|
|
return false;
|
|
}
|
|
|
|
element_.push_back(se);
|
|
std::sort(element_.begin(),element_.end());
|
|
|
|
return true;
|
|
}
|
|
|
|
inline void deactivate(const std::size_t& scope_depth)
|
|
{
|
|
for (std::size_t j = 0; j < element_.size(); ++j)
|
|
{
|
|
if (element_[j].depth >= scope_depth)
|
|
{
|
|
element_[j].active = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
void cleanup()
|
|
{
|
|
for (std::size_t i = 0; i < element_.size(); ++i)
|
|
{
|
|
if (element_[i].var_node)
|
|
{
|
|
delete element_[i].var_node;
|
|
}
|
|
|
|
if (element_[i].vec_node)
|
|
{
|
|
delete element_[i].vec_node;
|
|
}
|
|
|
|
T* data = (T*)(element_[i].data);
|
|
|
|
switch (element_[i].type)
|
|
{
|
|
case scope_element::e_variable : delete data; break;
|
|
case scope_element::e_vector : delete [] data; break;
|
|
default : break;
|
|
}
|
|
}
|
|
|
|
element_.clear();
|
|
|
|
input_param_cnt_ = 0;
|
|
}
|
|
|
|
inline std::size_t next_ip_index()
|
|
{
|
|
return ++input_param_cnt_;
|
|
}
|
|
|
|
inline variable_node_ptr get_variable(const T& v)
|
|
{
|
|
for (std::size_t i = 0; i < element_.size(); ++i)
|
|
{
|
|
scope_element& se = element_[i];
|
|
|
|
if (se.active && se.var_node)
|
|
{
|
|
if (&se.var_node->ref() == (&v))
|
|
{
|
|
return se.var_node;
|
|
}
|
|
}
|
|
}
|
|
|
|
return variable_node_ptr(0);
|
|
}
|
|
|
|
private:
|
|
|
|
scope_element_manager& operator=(const scope_element_manager&);
|
|
|
|
parser_t& parser_;
|
|
std::vector<scope_element> element_;
|
|
scope_element null_element_;
|
|
std::size_t input_param_cnt_;
|
|
};
|
|
|
|
class scope_handler
|
|
{
|
|
public:
|
|
|
|
typedef parser<T> parser_t;
|
|
|
|
scope_handler(parser<T>& p)
|
|
: parser_(p)
|
|
{
|
|
parser_.scope_depth_++;
|
|
#ifdef exprtk_enable_debugging
|
|
std::string depth(2 * parser_.scope_depth_,'-');
|
|
exprtk_debug(("%s> Scope Depth: %02d\n",depth.c_str(),static_cast<int>(parser_.scope_depth_)));
|
|
#endif
|
|
}
|
|
|
|
~scope_handler()
|
|
{
|
|
parser_.scope_depth_--;
|
|
parser_.sem_.deactivate(parser_.scope_depth_);
|
|
#ifdef exprtk_enable_debugging
|
|
std::string depth(2 * parser_.scope_depth_,'-');
|
|
exprtk_debug(("<%s Scope Depth: %02d\n",depth.c_str(),static_cast<int>(parser_.scope_depth_)));
|
|
#endif
|
|
}
|
|
|
|
private:
|
|
|
|
scope_handler& operator=(const scope_handler&);
|
|
|
|
parser_t& parser_;
|
|
};
|
|
|
|
public:
|
|
|
|
enum compilation_options
|
|
{
|
|
e_unknown = 0,
|
|
e_replacer = 1,
|
|
e_joiner = 2,
|
|
e_numeric_check = 4,
|
|
e_bracket_check = 8,
|
|
e_sequence_check = 16,
|
|
e_commutative_check = 32,
|
|
e_strength_reduction = 64,
|
|
e_disable_vardef = 128,
|
|
e_collect_vars = 256,
|
|
e_collect_funcs = 512,
|
|
e_collect_assings = 1024
|
|
};
|
|
|
|
struct unknown_symbol_resolver
|
|
{
|
|
|
|
enum usr_symbol_type
|
|
{
|
|
e_usr_variable_type = 0,
|
|
e_usr_constant_type = 1
|
|
};
|
|
|
|
virtual ~unknown_symbol_resolver()
|
|
{}
|
|
|
|
virtual bool process(const std::string& /*unknown_symbol*/,
|
|
usr_symbol_type& st,
|
|
T& default_value,
|
|
std::string& error_message)
|
|
{
|
|
st = e_usr_variable_type;
|
|
default_value = T(0);
|
|
error_message = "";
|
|
|
|
return true;
|
|
}
|
|
};
|
|
|
|
enum collect_type
|
|
{
|
|
e_ct_none = 0,
|
|
e_ct_variables = 1,
|
|
e_ct_functions = 2,
|
|
e_ct_assignments = 4
|
|
};
|
|
|
|
enum symbol_type
|
|
{
|
|
e_st_unknown = 0,
|
|
e_st_variable = 1,
|
|
e_st_vector = 2,
|
|
e_st_string = 3,
|
|
e_st_function = 4,
|
|
e_st_local_variable = 5,
|
|
e_st_local_vector = 6,
|
|
e_st_local_string = 7
|
|
};
|
|
|
|
class dependent_entity_collector
|
|
{
|
|
public:
|
|
|
|
typedef std::pair<std::string,symbol_type> symbol_t;
|
|
typedef std::vector<symbol_t> symbol_list_t;
|
|
|
|
dependent_entity_collector(const std::size_t options = e_ct_none)
|
|
: options_(options),
|
|
collect_variables_ ((options_ & e_ct_variables ) == e_ct_variables ),
|
|
collect_functions_ ((options_ & e_ct_functions ) == e_ct_functions ),
|
|
collect_assignments_((options_ & e_ct_assignments) == e_ct_assignments)
|
|
{}
|
|
|
|
template <typename Allocator,
|
|
template <typename,typename> class Sequence>
|
|
inline std::size_t symbols(Sequence<symbol_t,Allocator>& symbols_list)
|
|
{
|
|
if (!collect_variables_ && !collect_functions_)
|
|
return 0;
|
|
else if (symbol_name_list_.empty())
|
|
return 0;
|
|
|
|
for (std::size_t i = 0; i < symbol_name_list_.size(); ++i)
|
|
{
|
|
std::string& s = symbol_name_list_[i].first;
|
|
std::transform(s.begin(),s.end(),s.begin(),static_cast<int(*)(int)>(std::tolower));
|
|
}
|
|
|
|
std::sort(symbol_name_list_.begin(),symbol_name_list_.end());
|
|
std::unique_copy(symbol_name_list_.begin(),
|
|
symbol_name_list_.end(),
|
|
std::back_inserter(symbols_list));
|
|
|
|
return symbols_list.size();
|
|
}
|
|
|
|
template <typename Allocator,
|
|
template <typename,typename> class Sequence>
|
|
inline std::size_t assignment_symbols(Sequence<symbol_t,Allocator>& assignment_list)
|
|
{
|
|
if (!collect_assignments_)
|
|
return 0;
|
|
else if (assignment_name_list_.empty())
|
|
return 0;
|
|
|
|
for (std::size_t i = 0; i < assignment_name_list_.size(); ++i)
|
|
{
|
|
std::string& s = assignment_name_list_[i].first;
|
|
std::transform(s.begin(),s.end(),s.begin(),static_cast<int(*)(int)>(std::tolower));
|
|
}
|
|
|
|
std::sort(assignment_name_list_.begin(),assignment_name_list_.end());
|
|
std::unique_copy(assignment_name_list_.begin(),
|
|
assignment_name_list_.end(),
|
|
std::back_inserter(assignment_list));
|
|
|
|
return assignment_list.size();
|
|
}
|
|
|
|
void clear()
|
|
{
|
|
symbol_name_list_ .clear();
|
|
assignment_name_list_.clear();
|
|
}
|
|
|
|
bool& collect_variables()
|
|
{
|
|
return collect_variables_;
|
|
}
|
|
|
|
bool& collect_functions()
|
|
{
|
|
return collect_functions_;
|
|
}
|
|
|
|
bool& collect_assignments()
|
|
{
|
|
return collect_assignments_;
|
|
}
|
|
|
|
private:
|
|
|
|
inline void add_symbol(const std::string& symbol, const symbol_type st)
|
|
{
|
|
switch (st)
|
|
{
|
|
case e_st_variable :
|
|
case e_st_vector :
|
|
case e_st_string :
|
|
case e_st_local_variable :
|
|
case e_st_local_vector :
|
|
case e_st_local_string :
|
|
case e_st_function :
|
|
if (collect_variables_ || collect_functions_)
|
|
symbol_name_list_.push_back(std::make_pair(symbol,st));
|
|
break;
|
|
|
|
default : return;
|
|
}
|
|
}
|
|
|
|
inline void add_assignment(const std::string& symbol, const symbol_type st)
|
|
{
|
|
switch (st)
|
|
{
|
|
case e_st_variable :
|
|
case e_st_vector :
|
|
case e_st_string :
|
|
if (collect_assignments_)
|
|
assignment_name_list_.push_back(std::make_pair(symbol,st));
|
|
break;
|
|
|
|
default : return;
|
|
}
|
|
}
|
|
|
|
std::size_t options_;
|
|
bool collect_variables_;
|
|
bool collect_functions_;
|
|
bool collect_assignments_;
|
|
symbol_list_t symbol_name_list_;
|
|
symbol_list_t assignment_name_list_;
|
|
|
|
friend class parser<T>;
|
|
};
|
|
|
|
static const std::size_t compile_all_opts = e_replacer +
|
|
e_joiner +
|
|
e_numeric_check +
|
|
e_bracket_check +
|
|
e_sequence_check +
|
|
e_commutative_check +
|
|
e_strength_reduction;
|
|
|
|
parser(const std::size_t compile_options = compile_all_opts)
|
|
: compile_options_(compile_options),
|
|
resolve_unknown_symbol_(false),
|
|
vardef_disabled_((compile_options & e_disable_vardef) == e_disable_vardef),
|
|
scope_depth_(0),
|
|
unknown_symbol_resolver_(reinterpret_cast<unknown_symbol_resolver*>(0)),
|
|
#ifdef _MSC_VER
|
|
#pragma warning(push)
|
|
#pragma warning (disable:4355)
|
|
#endif
|
|
sem_(*this),
|
|
#ifdef _MSC_VER
|
|
#pragma warning(pop)
|
|
#endif
|
|
operator_joiner_2_(2),
|
|
operator_joiner_3_(3)
|
|
{
|
|
init_precompilation();
|
|
|
|
load_operations_map(base_ops_map_);
|
|
load_unary_operations_map(unary_op_map_);
|
|
load_binary_operations_map(binary_op_map_);
|
|
load_inv_binary_operations_map(inv_binary_op_map_);
|
|
load_sf3_map(sf3_map_);
|
|
load_sf4_map(sf4_map_);
|
|
|
|
expression_generator_.init_synthesize_map();
|
|
expression_generator_.set_parser(*this);
|
|
expression_generator_.set_uom(unary_op_map_);
|
|
expression_generator_.set_bom(binary_op_map_);
|
|
expression_generator_.set_ibom(inv_binary_op_map_);
|
|
expression_generator_.set_sf3m(sf3_map_);
|
|
expression_generator_.set_sf4m(sf4_map_);
|
|
expression_generator_.set_strength_reduction_state(strength_reduction_enabled());
|
|
}
|
|
|
|
~parser()
|
|
{}
|
|
|
|
inline void init_precompilation()
|
|
{
|
|
if (collect_variables_enabled())
|
|
dec_.collect_variables() = true;
|
|
|
|
if (collect_functions_enabled())
|
|
dec_.collect_functions() = true;
|
|
|
|
if (collect_assignments_enabled())
|
|
dec_.collect_assignments() = true;
|
|
|
|
if (replacer_enabled())
|
|
{
|
|
symbol_replacer_.clear();
|
|
symbol_replacer_.add_replace("true" ,"1",lexer::token::e_number);
|
|
symbol_replacer_.add_replace("false","0",lexer::token::e_number);
|
|
helper_assembly_.token_modifier_list.clear();
|
|
helper_assembly_.register_modifier(&symbol_replacer_);
|
|
}
|
|
|
|
if (commutative_check_enabled())
|
|
{
|
|
for (std::size_t i = 0; i < details::reserved_words_size; ++i)
|
|
{
|
|
commutative_inserter_.ignore_symbol(details::reserved_words[i]);
|
|
}
|
|
|
|
helper_assembly_.token_inserter_list.clear();
|
|
helper_assembly_.register_inserter(&commutative_inserter_);
|
|
}
|
|
|
|
if (joiner_enabled())
|
|
{
|
|
helper_assembly_.token_joiner_list.clear();
|
|
helper_assembly_.register_joiner(&operator_joiner_2_);
|
|
helper_assembly_.register_joiner(&operator_joiner_3_);
|
|
}
|
|
|
|
if (
|
|
numeric_check_enabled () ||
|
|
bracket_check_enabled () ||
|
|
sequence_check_enabled()
|
|
)
|
|
{
|
|
helper_assembly_.token_scanner_list.clear();
|
|
|
|
if (numeric_check_enabled())
|
|
{
|
|
helper_assembly_.register_scanner(&numeric_checker_);
|
|
}
|
|
|
|
if (bracket_check_enabled())
|
|
{
|
|
helper_assembly_.register_scanner(&bracket_checker_);
|
|
}
|
|
|
|
if (sequence_check_enabled())
|
|
{
|
|
helper_assembly_.register_scanner(&sequence_validator_);
|
|
}
|
|
}
|
|
}
|
|
|
|
inline bool compile(const std::string& expression_string, expression<T>& expr)
|
|
{
|
|
error_list_ .clear();
|
|
brkcnt_list_ .clear();
|
|
synthesis_error_.clear();
|
|
sem_ .cleanup();
|
|
|
|
expression_generator_.set_allocator(node_allocator_);
|
|
|
|
scope_depth_ = 0;
|
|
|
|
if (expression_string.empty())
|
|
{
|
|
set_error(
|
|
make_error(parser_error::e_syntax,
|
|
"ERR00 - Empty expression!"));
|
|
|
|
return false;
|
|
}
|
|
|
|
if (!lexer_.process(expression_string))
|
|
{
|
|
process_lexer_errors();
|
|
return false;
|
|
}
|
|
|
|
if (lexer_.empty())
|
|
{
|
|
set_error(
|
|
make_error(parser_error::e_syntax,
|
|
"ERR01 - Empty expression!"));
|
|
|
|
return false;
|
|
}
|
|
|
|
if (!run_assemblies())
|
|
{
|
|
return false;
|
|
}
|
|
|
|
symbol_table_ = expr.get_symbol_table();
|
|
dec_.clear();
|
|
|
|
lexer_.begin();
|
|
next_token();
|
|
|
|
expression_node_ptr e = parse_corpus();
|
|
|
|
if ((0 != e) && (token_t::e_eof == current_token_.type))
|
|
{
|
|
expr.set_expression(e);
|
|
register_local_vars(expr);
|
|
|
|
return !(!expr);
|
|
}
|
|
else
|
|
{
|
|
if (error_list_.empty())
|
|
{
|
|
set_error(
|
|
make_error(parser_error::e_syntax,
|
|
current_token_,
|
|
"ERR02 - Invalid expression encountered"));
|
|
}
|
|
|
|
dec_.clear ();
|
|
sem_.cleanup();
|
|
|
|
if (0 != e)
|
|
{
|
|
delete e;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
}
|
|
|
|
void process_lexer_errors()
|
|
{
|
|
for (std::size_t i = 0; i < lexer_.size(); ++i)
|
|
{
|
|
if (lexer_[i].is_error())
|
|
{
|
|
std::string diagnostic = "ERR03 - ";
|
|
|
|
switch (lexer_[i].type)
|
|
{
|
|
case lexer::token::e_error : diagnostic += "General token error";
|
|
break;
|
|
|
|
case lexer::token::e_err_symbol : diagnostic += "Symbol error";
|
|
break;
|
|
|
|
case lexer::token::e_err_number : diagnostic += "Invalid numeric token";
|
|
break;
|
|
|
|
case lexer::token::e_err_string : diagnostic += "Invalid string token";
|
|
break;
|
|
|
|
case lexer::token::e_err_sfunc : diagnostic += "Invalid special function token";
|
|
break;
|
|
|
|
default : diagnostic += "Unknown compiler error";
|
|
}
|
|
|
|
set_error(
|
|
make_error(parser_error::e_lexer,
|
|
lexer_[i],
|
|
diagnostic + ": " + lexer_[i].value));
|
|
}
|
|
}
|
|
}
|
|
|
|
inline bool replacer_enabled() const
|
|
{
|
|
return ((compile_options_ & e_replacer) == e_replacer);
|
|
}
|
|
|
|
inline bool commutative_check_enabled() const
|
|
{
|
|
return ((compile_options_ & e_commutative_check) == e_commutative_check);
|
|
}
|
|
|
|
inline bool joiner_enabled() const
|
|
{
|
|
return ((compile_options_ & e_joiner) == e_joiner);
|
|
}
|
|
|
|
inline bool numeric_check_enabled() const
|
|
{
|
|
return ((compile_options_ & e_numeric_check) == e_numeric_check);
|
|
}
|
|
|
|
inline bool bracket_check_enabled() const
|
|
{
|
|
return ((compile_options_ & e_bracket_check) == e_bracket_check);
|
|
}
|
|
|
|
inline bool sequence_check_enabled() const
|
|
{
|
|
return ((compile_options_ & e_sequence_check) == e_sequence_check);
|
|
}
|
|
|
|
inline bool strength_reduction_enabled() const
|
|
{
|
|
return ((compile_options_ & e_strength_reduction) == e_strength_reduction);
|
|
}
|
|
|
|
inline bool collect_variables_enabled() const
|
|
{
|
|
return ((compile_options_ & e_collect_vars) == e_collect_vars);
|
|
}
|
|
|
|
inline bool collect_functions_enabled() const
|
|
{
|
|
return ((compile_options_ & e_collect_funcs) == e_collect_funcs);
|
|
}
|
|
|
|
inline bool collect_assignments_enabled() const
|
|
{
|
|
return ((compile_options_ & e_collect_assings) == e_collect_assings);
|
|
}
|
|
|
|
inline bool run_assemblies()
|
|
{
|
|
if (commutative_check_enabled())
|
|
{
|
|
helper_assembly_.run_inserters(lexer_);
|
|
}
|
|
|
|
if (joiner_enabled())
|
|
{
|
|
helper_assembly_.run_joiners(lexer_);
|
|
}
|
|
|
|
if (replacer_enabled())
|
|
{
|
|
helper_assembly_.run_modifiers(lexer_);
|
|
}
|
|
|
|
if (
|
|
numeric_check_enabled () ||
|
|
bracket_check_enabled () ||
|
|
sequence_check_enabled()
|
|
)
|
|
{
|
|
if (!helper_assembly_.run_scanners(lexer_))
|
|
{
|
|
if (helper_assembly_.error_token_scanner)
|
|
{
|
|
lexer::helper::bracket_checker* bracket_checker_ptr = 0;
|
|
lexer::helper::numeric_checker* numeric_checker_ptr = 0;
|
|
lexer::helper::sequence_validator* sequence_validator_ptr = 0;
|
|
|
|
if (0 != (bracket_checker_ptr = dynamic_cast<lexer::helper::bracket_checker*>(helper_assembly_.error_token_scanner)))
|
|
{
|
|
set_error(
|
|
make_error(parser_error::e_token,
|
|
bracket_checker_ptr->error_token(),
|
|
"ERR04 - Mismatched brackets: '" + bracket_checker_ptr->error_token().value + "'"));
|
|
}
|
|
else if (0 != (numeric_checker_ptr = dynamic_cast<lexer::helper::numeric_checker*>(helper_assembly_.error_token_scanner)))
|
|
{
|
|
for (std::size_t i = 0; i < numeric_checker_ptr->error_count(); ++i)
|
|
{
|
|
lexer::token error_token = lexer_[numeric_checker_ptr->error_index(i)];
|
|
|
|
set_error(
|
|
make_error(parser_error::e_token,
|
|
error_token,
|
|
"ERR05 - Invalid numeric token: '" + error_token.value + "'"));
|
|
}
|
|
|
|
if (numeric_checker_ptr->error_count())
|
|
{
|
|
numeric_checker_ptr->clear_errors();
|
|
}
|
|
}
|
|
else if (0 != (sequence_validator_ptr = dynamic_cast<lexer::helper::sequence_validator*>(helper_assembly_.error_token_scanner)))
|
|
{
|
|
for (std::size_t i = 0; i < sequence_validator_ptr->error_count(); ++i)
|
|
{
|
|
std::pair<lexer::token,lexer::token> error_token = sequence_validator_ptr->error(i);
|
|
|
|
set_error(
|
|
make_error(parser_error::e_token,
|
|
error_token.first,
|
|
"ERR06 - Invalid token sequence: '" +
|
|
error_token.first.value + "' and '" +
|
|
error_token.second.value + "'"));
|
|
}
|
|
|
|
if (sequence_validator_ptr->error_count())
|
|
{
|
|
sequence_validator_ptr->clear_errors();
|
|
}
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
inline parser_error::type get_error(const std::size_t& index)
|
|
{
|
|
if (index < error_list_.size())
|
|
return error_list_[index];
|
|
else
|
|
throw std::invalid_argument("parser::get_error() - Invalid error index specificed");
|
|
}
|
|
|
|
inline std::string error() const
|
|
{
|
|
if (!error_list_.empty())
|
|
{
|
|
return error_list_[0].diagnostic;
|
|
}
|
|
else
|
|
return std::string("No Error");
|
|
}
|
|
|
|
inline std::size_t error_count() const
|
|
{
|
|
return error_list_.size();
|
|
}
|
|
|
|
inline dependent_entity_collector& dec()
|
|
{
|
|
return dec_;
|
|
}
|
|
|
|
inline bool replace_symbol(const std::string& old_symbol, const std::string& new_symbol)
|
|
{
|
|
if (!replacer_enabled())
|
|
return false;
|
|
else if (details::is_reserved_word(old_symbol))
|
|
return false;
|
|
else
|
|
return symbol_replacer_.add_replace(old_symbol,new_symbol,lexer::token::e_symbol);
|
|
}
|
|
|
|
inline bool remove_replace_symbol(const std::string& symbol)
|
|
{
|
|
if (!replacer_enabled())
|
|
return false;
|
|
else if (details::is_reserved_word(symbol))
|
|
return false;
|
|
else
|
|
return symbol_replacer_.remove(symbol);
|
|
}
|
|
|
|
inline void enable_unknown_symbol_resolver(unknown_symbol_resolver* usr = reinterpret_cast<unknown_symbol_resolver*>(0))
|
|
{
|
|
resolve_unknown_symbol_ = true;
|
|
|
|
if (usr)
|
|
unknown_symbol_resolver_ = usr;
|
|
else
|
|
unknown_symbol_resolver_ = &default_usr_;
|
|
}
|
|
|
|
inline void disable_unknown_symbol_resolver()
|
|
{
|
|
resolve_unknown_symbol_ = false;
|
|
unknown_symbol_resolver_ = &default_usr_;
|
|
}
|
|
|
|
private:
|
|
|
|
inline bool valid_base_operation(const std::string& symbol)
|
|
{
|
|
const std::size_t length = symbol.size();
|
|
if (
|
|
(length < 3) || // Shortest base op symbol length
|
|
(length > 9) // Longest base op symbol length
|
|
)
|
|
return false;
|
|
else
|
|
return (base_ops_map_.end() != base_ops_map_.find(symbol));
|
|
}
|
|
|
|
inline bool valid_vararg_operation(const std::string& symbol)
|
|
{
|
|
static const std::string s_sum = "sum" ;
|
|
static const std::string s_mul = "mul" ;
|
|
static const std::string s_avg = "avg" ;
|
|
static const std::string s_min = "min" ;
|
|
static const std::string s_max = "max" ;
|
|
static const std::string s_mand = "mand";
|
|
static const std::string s_mor = "mor" ;
|
|
static const std::string s_multi = "~" ;
|
|
static const std::string s_mswitch = "[*]" ;
|
|
return
|
|
(
|
|
details::imatch(symbol,s_sum ) ||
|
|
details::imatch(symbol,s_mul ) ||
|
|
details::imatch(symbol,s_avg ) ||
|
|
details::imatch(symbol,s_min ) ||
|
|
details::imatch(symbol,s_max ) ||
|
|
details::imatch(symbol,s_mand ) ||
|
|
details::imatch(symbol,s_mor ) ||
|
|
details::imatch(symbol,s_multi ) ||
|
|
details::imatch(symbol,s_mswitch)
|
|
);
|
|
}
|
|
|
|
inline void store_token()
|
|
{
|
|
lexer_.store();
|
|
store_current_token_ = current_token_;
|
|
}
|
|
|
|
inline void restore_token()
|
|
{
|
|
lexer_.restore();
|
|
current_token_ = store_current_token_;
|
|
}
|
|
|
|
#ifndef exprtk_enable_debugging
|
|
inline void next_token()
|
|
{
|
|
current_token_ = lexer_.next_token();
|
|
}
|
|
#else
|
|
inline void next_token()
|
|
{
|
|
std::string ct_str = current_token_.value;
|
|
current_token_ = lexer_.next_token();
|
|
std::string depth(2 * scope_depth_,' ');
|
|
exprtk_debug(("%s"
|
|
"prev[%s] --> curr[%s]\n",
|
|
depth.c_str(),
|
|
ct_str.c_str(),
|
|
current_token_.value.c_str()));
|
|
}
|
|
#endif
|
|
|
|
inline const lexer::token& current_token() const
|
|
{
|
|
return current_token_;
|
|
}
|
|
|
|
inline expression_node_ptr parse_corpus()
|
|
{
|
|
std::vector<expression_node_ptr> arg_list;
|
|
expression_node_ptr result = error_node();
|
|
|
|
scoped_vec_delete<expression_node_t> sdd(*this,arg_list);
|
|
|
|
for (;;)
|
|
{
|
|
expression_node_ptr arg = parse_expression();
|
|
|
|
if (0 == arg)
|
|
{
|
|
if (error_list_.empty())
|
|
{
|
|
set_error(
|
|
make_error(parser_error::e_syntax,
|
|
current_token_,
|
|
"ERR07 - Invalid expression encountered"));
|
|
}
|
|
|
|
return error_node();
|
|
}
|
|
else
|
|
arg_list.push_back(arg);
|
|
|
|
if (lexer_.finished())
|
|
break;
|
|
else if (token_is(token_t::e_eof,false))
|
|
{
|
|
if (lexer_.finished())
|
|
break;
|
|
else
|
|
next_token();
|
|
}
|
|
}
|
|
|
|
result = simplify(arg_list);
|
|
|
|
sdd.delete_ptr = (0 == result);
|
|
return result;
|
|
}
|
|
|
|
static const precedence_level default_precedence = e_level00;
|
|
|
|
struct state_t
|
|
{
|
|
inline void set(const precedence_level& l,
|
|
const precedence_level& r,
|
|
const details::operator_type& o)
|
|
{
|
|
left = l;
|
|
right = r;
|
|
operation = o;
|
|
}
|
|
|
|
inline void reset()
|
|
{
|
|
left = e_level00;
|
|
right = e_level00;
|
|
}
|
|
|
|
precedence_level left;
|
|
precedence_level right;
|
|
details::operator_type operation;
|
|
};
|
|
|
|
inline expression_node_ptr parse_expression(precedence_level precedence = e_level00)
|
|
{
|
|
expression_node_ptr expression = parse_branch(precedence);
|
|
|
|
if (0 == expression)
|
|
{
|
|
return error_node();
|
|
}
|
|
|
|
bool break_loop = false;
|
|
|
|
state_t current_state;
|
|
|
|
for ( ; ; )
|
|
{
|
|
current_state.reset();
|
|
|
|
switch (current_token_.type)
|
|
{
|
|
case token_t::e_assign : current_state.set(e_level00,e_level00,details::e_assign); break;
|
|
case token_t::e_addass : current_state.set(e_level00,e_level00,details::e_addass); break;
|
|
case token_t::e_subass : current_state.set(e_level00,e_level00,details::e_subass); break;
|
|
case token_t::e_mulass : current_state.set(e_level00,e_level00,details::e_mulass); break;
|
|
case token_t::e_divass : current_state.set(e_level00,e_level00,details::e_divass); break;
|
|
case token_t::e_modass : current_state.set(e_level00,e_level00,details::e_modass); break;
|
|
case token_t::e_swap : current_state.set(e_level00,e_level00,details::e_swap ); break;
|
|
case token_t::e_lt : current_state.set(e_level05,e_level06,details:: e_lt); break;
|
|
case token_t::e_lte : current_state.set(e_level05,e_level06,details:: e_lte); break;
|
|
case token_t::e_eq : current_state.set(e_level05,e_level06,details:: e_eq); break;
|
|
case token_t::e_ne : current_state.set(e_level05,e_level06,details:: e_ne); break;
|
|
case token_t::e_gte : current_state.set(e_level05,e_level06,details:: e_gte); break;
|
|
case token_t::e_gt : current_state.set(e_level05,e_level06,details:: e_gt); break;
|
|
case token_t::e_add : current_state.set(e_level07,e_level08,details:: e_add); break;
|
|
case token_t::e_sub : current_state.set(e_level07,e_level08,details:: e_sub); break;
|
|
case token_t::e_div : current_state.set(e_level10,e_level11,details:: e_div); break;
|
|
case token_t::e_mul : current_state.set(e_level10,e_level11,details:: e_mul); break;
|
|
case token_t::e_mod : current_state.set(e_level10,e_level11,details:: e_mod); break;
|
|
case token_t::e_pow : current_state.set(e_level12,e_level12,details:: e_pow); break;
|
|
default : if (token_t::e_symbol == current_token_.type)
|
|
{
|
|
static const std::string s_and = "and";
|
|
static const std::string s_nand = "nand";
|
|
static const std::string s_or = "or";
|
|
static const std::string s_nor = "nor";
|
|
static const std::string s_xor = "xor";
|
|
static const std::string s_xnor = "xnor";
|
|
static const std::string s_in = "in";
|
|
static const std::string s_like = "like";
|
|
static const std::string s_ilike = "ilike";
|
|
static const std::string s_and1 = "&";
|
|
static const std::string s_or1 = "|";
|
|
|
|
if (details::imatch(current_token_.value,s_and))
|
|
{
|
|
current_state.set(e_level01,e_level02,details::e_and);
|
|
break;
|
|
}
|
|
else if (details::imatch(current_token_.value,s_and1))
|
|
{
|
|
#ifndef exprtk_disable_sc_andor
|
|
current_state.set(e_level01,e_level02,details::e_scand);
|
|
#else
|
|
current_state.set(e_level01,e_level02,details::e_and);
|
|
#endif
|
|
break;
|
|
}
|
|
else if (details::imatch(current_token_.value,s_nand))
|
|
{
|
|
current_state.set(e_level01,e_level02,details::e_nand);
|
|
break;
|
|
}
|
|
else if (details::imatch(current_token_.value,s_or))
|
|
{
|
|
current_state.set(e_level03,e_level04,details::e_or);
|
|
break;
|
|
}
|
|
else if (details::imatch(current_token_.value,s_or1))
|
|
{
|
|
#ifndef exprtk_disable_sc_andor
|
|
current_state.set(e_level03,e_level04,details::e_scor);
|
|
#else
|
|
current_state.set(e_level03,e_level04,details::e_or);
|
|
#endif
|
|
break;
|
|
}
|
|
else if (details::imatch(current_token_.value,s_nor))
|
|
{
|
|
current_state.set(e_level03,e_level04,details::e_nor);
|
|
break;
|
|
}
|
|
else if (details::imatch(current_token_.value,s_xor))
|
|
{
|
|
current_state.set(e_level03,e_level04,details::e_xor);
|
|
break;
|
|
}
|
|
else if (details::imatch(current_token_.value,s_xnor))
|
|
{
|
|
current_state.set(e_level03,e_level04,details::e_xnor);
|
|
break;
|
|
}
|
|
else if (details::imatch(current_token_.value,s_in))
|
|
{
|
|
current_state.set(e_level03,e_level04,details::e_in);
|
|
break;
|
|
}
|
|
else if (details::imatch(current_token_.value,s_like))
|
|
{
|
|
current_state.set(e_level03,e_level04,details::e_like);
|
|
break;
|
|
}
|
|
else if (details::imatch(current_token_.value,s_ilike))
|
|
{
|
|
current_state.set(e_level03,e_level04,details::e_ilike);
|
|
break;
|
|
}
|
|
}
|
|
|
|
break_loop = true;
|
|
}
|
|
|
|
if (break_loop)
|
|
{
|
|
parse_pending_string_rangesize(expression);
|
|
break;
|
|
}
|
|
else if (current_state.left < precedence)
|
|
break;
|
|
|
|
lexer::token prev_token = current_token_;
|
|
|
|
next_token();
|
|
|
|
expression_node_ptr right_branch = error_node();
|
|
expression_node_ptr new_expression = error_node();
|
|
|
|
if ((right_branch = parse_expression(current_state.right)))
|
|
{
|
|
new_expression = expression_generator_
|
|
(
|
|
current_state.operation,
|
|
expression,
|
|
right_branch
|
|
);
|
|
}
|
|
|
|
if (0 == new_expression)
|
|
{
|
|
if (error_list_.empty())
|
|
{
|
|
set_error(
|
|
make_error(parser_error::e_syntax,
|
|
prev_token,
|
|
!synthesis_error_.empty() ?
|
|
synthesis_error_ :
|
|
"ERR08 - General parsing error at token: '" + prev_token.value + "'"));
|
|
}
|
|
|
|
free_node(node_allocator_,expression);
|
|
|
|
return error_node();
|
|
}
|
|
else
|
|
{
|
|
expression = new_expression;
|
|
|
|
if (token_is(token_t::e_ternary,false) && (precedence == e_level00))
|
|
{
|
|
expression = parse_ternary_conditional_statement(expression);
|
|
}
|
|
|
|
parse_pending_string_rangesize(expression);
|
|
}
|
|
}
|
|
|
|
return expression;
|
|
}
|
|
|
|
bool simplify_unary_negation_branch(expression_node_ptr& node)
|
|
{
|
|
{
|
|
typedef details::unary_branch_node<T,details::neg_op<T> > ubn_t;
|
|
ubn_t* n = dynamic_cast<ubn_t*>(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<T,details::neg_op<T> > ubn_t;
|
|
|
|
ubn_t* n = dynamic_cast<ubn_t*>(node);
|
|
|
|
if (n)
|
|
{
|
|
const T& v = n->v();
|
|
expression_node_ptr return_node = error_node();
|
|
|
|
if (
|
|
(return_node = symbol_table_.get_variable(v)) ||
|
|
(return_node = sem_ .get_variable(v))
|
|
)
|
|
{
|
|
free_node(node_allocator_,node);
|
|
node = return_node;
|
|
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
set_error(
|
|
make_error(parser_error::e_syntax,
|
|
current_token_,
|
|
"ERR09 - Failed to find variable node in symbol table"));
|
|
free_node(node_allocator_,node);
|
|
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
static inline expression_node_ptr error_node()
|
|
{
|
|
return reinterpret_cast<expression_node_ptr>(0);
|
|
}
|
|
|
|
template <typename Type, std::size_t N>
|
|
struct scoped_delete
|
|
{
|
|
typedef Type* ptr_t;
|
|
|
|
scoped_delete(parser<T>& pr, ptr_t& p)
|
|
: delete_ptr(true),
|
|
parser_(pr),
|
|
p_(&p)
|
|
{}
|
|
|
|
scoped_delete(parser<T>& 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<T>& parser_;
|
|
ptr_t* p_;
|
|
|
|
private:
|
|
|
|
scoped_delete<Type,N>& operator=(const scoped_delete<Type,N>&);
|
|
};
|
|
|
|
template <typename Type>
|
|
struct scoped_deq_delete
|
|
{
|
|
typedef Type* ptr_t;
|
|
|
|
scoped_deq_delete(parser<T>& pr, std::deque<ptr_t>& 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<T>& parser_;
|
|
std::deque<ptr_t>& deq_;
|
|
|
|
private:
|
|
|
|
scoped_deq_delete<Type>& operator=(const scoped_deq_delete<Type>&);
|
|
};
|
|
|
|
template <typename Type>
|
|
struct scoped_vec_delete
|
|
{
|
|
typedef Type* ptr_t;
|
|
|
|
scoped_vec_delete(parser<T>& pr, std::vector<ptr_t>& 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<T>& parser_;
|
|
std::vector<ptr_t>& vec_;
|
|
|
|
private:
|
|
|
|
scoped_vec_delete<Type>& operator=(const scoped_vec_delete<Type>&);
|
|
};
|
|
|
|
inline expression_node_ptr parse_function_invocation(ifunction<T>* function, const std::string& function_name)
|
|
{
|
|
expression_node_ptr func_node = reinterpret_cast<expression_node_ptr>(0);
|
|
|
|
switch (function->param_count)
|
|
{
|
|
case 0 : func_node = parse_function_call_0 (function,function_name); break;
|
|
case 1 : func_node = parse_function_call< 1>(function,function_name); break;
|
|
case 2 : func_node = parse_function_call< 2>(function,function_name); break;
|
|
case 3 : func_node = parse_function_call< 3>(function,function_name); break;
|
|
case 4 : func_node = parse_function_call< 4>(function,function_name); break;
|
|
case 5 : func_node = parse_function_call< 5>(function,function_name); break;
|
|
case 6 : func_node = parse_function_call< 6>(function,function_name); break;
|
|
case 7 : func_node = parse_function_call< 7>(function,function_name); break;
|
|
case 8 : func_node = parse_function_call< 8>(function,function_name); break;
|
|
case 9 : func_node = parse_function_call< 9>(function,function_name); break;
|
|
case 10 : func_node = parse_function_call<10>(function,function_name); break;
|
|
case 11 : func_node = parse_function_call<11>(function,function_name); break;
|
|
case 12 : func_node = parse_function_call<12>(function,function_name); break;
|
|
case 13 : func_node = parse_function_call<13>(function,function_name); break;
|
|
case 14 : func_node = parse_function_call<14>(function,function_name); break;
|
|
case 15 : func_node = parse_function_call<15>(function,function_name); break;
|
|
case 16 : func_node = parse_function_call<16>(function,function_name); break;
|
|
case 17 : func_node = parse_function_call<17>(function,function_name); break;
|
|
case 18 : func_node = parse_function_call<18>(function,function_name); break;
|
|
case 19 : func_node = parse_function_call<19>(function,function_name); break;
|
|
case 20 : func_node = parse_function_call<20>(function,function_name); break;
|
|
default : {
|
|
set_error(
|
|
make_error(parser_error::e_syntax,
|
|
current_token_,
|
|
"ERR10 - Invalid number of parameters for function: '" + function_name + "'"));
|
|
|
|
return error_node();
|
|
}
|
|
}
|
|
|
|
if (func_node)
|
|
return func_node;
|
|
else
|
|
{
|
|
set_error(
|
|
make_error(parser_error::e_syntax,
|
|
current_token_,
|
|
"ERR11 - Failed to generate call to function: '" + function_name + "'"));
|
|
|
|
return error_node();
|
|
}
|
|
}
|
|
|
|
template <std::size_t NumberofParameters>
|
|
inline expression_node_ptr parse_function_call(ifunction<T>* function, const std::string& function_name)
|
|
{
|
|
if (0 == NumberofParameters)
|
|
{
|
|
set_error(
|
|
make_error(parser_error::e_syntax,
|
|
current_token_,
|
|
"ERR12 - Expecting ifunction '" + function_name + "' to have non-zero parameter count"));
|
|
|
|
return error_node();
|
|
}
|
|
|
|
expression_node_ptr branch[NumberofParameters];
|
|
expression_node_ptr result = error_node();
|
|
|
|
std::fill_n(branch,NumberofParameters,reinterpret_cast<expression_node_ptr>(0));
|
|
scoped_delete<expression_node_t,NumberofParameters> sd(*this,branch);
|
|
|
|
next_token();
|
|
|
|
if (!token_is(token_t::e_lbracket))
|
|
{
|
|
set_error(
|
|
make_error(parser_error::e_syntax,
|
|
current_token_,
|
|
"ERR13 - Expecting argument list for function: '" + function_name + "'"));
|
|
|
|
return error_node();
|
|
}
|
|
|
|
for (int i = 0; i < static_cast<int>(NumberofParameters); ++i)
|
|
{
|
|
branch[i] = parse_expression();
|
|
|
|
if (0 == branch[i])
|
|
{
|
|
set_error(
|
|
make_error(parser_error::e_syntax,
|
|
current_token_,
|
|
"ERR14 - Failed to parse argument " + details::to_str(i) + " for function: '" + function_name + "'"));
|
|
|
|
return error_node();
|
|
}
|
|
else if (i < static_cast<int>(NumberofParameters - 1))
|
|
{
|
|
if (!token_is(token_t::e_comma))
|
|
{
|
|
set_error(
|
|
make_error(parser_error::e_syntax,
|
|
current_token_,
|
|
"ERR15 - Invalid number of arguments for function: '" + function_name + "'"));
|
|
|
|
return error_node();
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!token_is(token_t::e_rbracket))
|
|
{
|
|
set_error(
|
|
make_error(parser_error::e_syntax,
|
|
current_token_,
|
|
"ERR16 - Invalid number of arguments for function: '" + function_name + "'"));
|
|
|
|
return error_node();
|
|
}
|
|
else
|
|
result = expression_generator_.function(function,branch);
|
|
|
|
sd.delete_ptr = false;
|
|
|
|
return result;
|
|
}
|
|
|
|
inline expression_node_ptr parse_function_call_0(ifunction<T>* function, const std::string& function_name)
|
|
{
|
|
expression_node_ptr result = expression_generator_.function(function);
|
|
next_token();
|
|
if (
|
|
token_is(token_t::e_lbracket) &&
|
|
!token_is(token_t::e_rbracket)
|
|
)
|
|
{
|
|
set_error(
|
|
make_error(parser_error::e_syntax,
|
|
current_token_,
|
|
"ERR17 - Expecting '()' to proceed call to function: '" + function_name + "'"));
|
|
|
|
free_node(node_allocator_,result);
|
|
|
|
return error_node();
|
|
}
|
|
else
|
|
return result;
|
|
}
|
|
|
|
template <std::size_t MaxNumberofParameters>
|
|
inline int parse_base_function_call(expression_node_ptr (¶m_list)[MaxNumberofParameters])
|
|
{
|
|
std::fill_n(param_list,MaxNumberofParameters,reinterpret_cast<expression_node_ptr>(0));
|
|
|
|
scoped_delete<expression_node_t,MaxNumberofParameters> sd(*this,param_list);
|
|
|
|
next_token();
|
|
|
|
if (!token_is(token_t::e_lbracket))
|
|
{
|
|
set_error(
|
|
make_error(parser_error::e_syntax,
|
|
current_token_,
|
|
"ERR18 - Expected a '(' at start of function call, instead got: '" + current_token_.value + "'"));
|
|
|
|
return 0;
|
|
}
|
|
|
|
int param_index = 0;
|
|
|
|
for (; param_index < static_cast<int>(MaxNumberofParameters); ++param_index)
|
|
{
|
|
param_list[param_index] = parse_expression();
|
|
|
|
if (0 == param_list[param_index])
|
|
{
|
|
return 0;
|
|
}
|
|
else if (token_is(token_t::e_rbracket))
|
|
break;
|
|
else if (token_is(token_t::e_comma))
|
|
continue;
|
|
else
|
|
{
|
|
set_error(
|
|
make_error(parser_error::e_syntax,
|
|
current_token_,
|
|
"ERR19 - Expected a ',' between function input parameters, instead got: '" + current_token_.value + "'"));
|
|
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
sd.delete_ptr = false;
|
|
|
|
return (param_index + 1);
|
|
}
|
|
|
|
inline expression_node_ptr parse_base_operation()
|
|
{
|
|
typedef std::pair<base_ops_map_t::iterator,base_ops_map_t::iterator> map_range_t;
|
|
|
|
const std::string operation_name = current_token_.value;
|
|
map_range_t itr_range = base_ops_map_.equal_range(operation_name);
|
|
|
|
if (0 == std::distance(itr_range.first,itr_range.second))
|
|
{
|
|
set_error(
|
|
make_error(parser_error::e_syntax,
|
|
current_token_,
|
|
"ERR20 - No entry found for base operation: " + operation_name));
|
|
|
|
return error_node();
|
|
}
|
|
|
|
const std::size_t MaxNumberofParameters = 6;
|
|
expression_node_ptr param_list[MaxNumberofParameters] = {0};
|
|
|
|
std::size_t parameter_count = parse_base_function_call(param_list);
|
|
|
|
if (0 == parameter_count)
|
|
{
|
|
return error_node();
|
|
}
|
|
else if (parameter_count <= 6)
|
|
{
|
|
for (base_ops_map_t::iterator itr = itr_range.first; itr != itr_range.second; ++itr)
|
|
{
|
|
details::base_operation_t& operation = itr->second;
|
|
|
|
if (operation.num_params == parameter_count)
|
|
{
|
|
switch (parameter_count)
|
|
{
|
|
#define base_opr_case(N) \
|
|
case N : { \
|
|
expression_node_ptr pl##N[N] = {0}; \
|
|
std::copy(param_list,param_list + N,pl##N); \
|
|
lodge_symbol(operation_name,e_st_function); \
|
|
return expression_generator_(operation.type,pl##N);\
|
|
} \
|
|
|
|
base_opr_case(1)
|
|
base_opr_case(2)
|
|
base_opr_case(3)
|
|
base_opr_case(4)
|
|
base_opr_case(5)
|
|
base_opr_case(6)
|
|
#undef base_opr_case
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
for (std::size_t i = 0; i < MaxNumberofParameters; ++i)
|
|
{
|
|
free_node(node_allocator_,param_list[i]);
|
|
}
|
|
|
|
set_error(
|
|
make_error(parser_error::e_syntax,
|
|
current_token_,
|
|
"ERR21 - Invalid number of parameters for call to function: '" + operation_name + "'"));
|
|
|
|
return error_node();
|
|
}
|
|
|
|
inline expression_node_ptr parse_conditional_statement_01(expression_node_ptr condition)
|
|
{
|
|
// Parse: [if][(][condition][,][consequent][,][alternative][)]
|
|
|
|
expression_node_ptr consequent = error_node();
|
|
expression_node_ptr alternative = error_node();
|
|
|
|
bool result = true;
|
|
|
|
if (!token_is(token_t::e_comma))
|
|
{
|
|
set_error(
|
|
make_error(parser_error::e_syntax,
|
|
current_token_,
|
|
"ERR22 - Expected ',' between if-statement condition and consequent"));
|
|
result = false;
|
|
}
|
|
else if (0 == (consequent = parse_expression()))
|
|
{
|
|
set_error(
|
|
make_error(parser_error::e_syntax,
|
|
current_token_,
|
|
"ERR23 - Failed to parse consequent for if-statement"));
|
|
result = false;
|
|
}
|
|
else if (!token_is(token_t::e_comma))
|
|
{
|
|
set_error(
|
|
make_error(parser_error::e_syntax,
|
|
current_token_,
|
|
"ERR24 - Expected ',' between if-statement consequent and alternative"));
|
|
result = false;
|
|
}
|
|
else if (0 == (alternative = parse_expression()))
|
|
{
|
|
set_error(
|
|
make_error(parser_error::e_syntax,
|
|
current_token_,
|
|
"ERR25 - Failed to parse alternative for if-statement"));
|
|
result = false;
|
|
}
|
|
else if (!token_is(token_t::e_rbracket))
|
|
{
|
|
set_error(
|
|
make_error(parser_error::e_syntax,
|
|
current_token_,
|
|
"ERR26 - Expected ')' at the end of if-statement"));
|
|
result = false;
|
|
}
|
|
|
|
if (!result)
|
|
{
|
|
free_node(node_allocator_, condition);
|
|
free_node(node_allocator_, consequent);
|
|
free_node(node_allocator_,alternative);
|
|
|
|
return error_node();
|
|
}
|
|
else
|
|
return expression_generator_.conditional(condition,consequent,alternative);
|
|
}
|
|
|
|
inline expression_node_ptr parse_conditional_statement_02(expression_node_ptr condition)
|
|
{
|
|
expression_node_ptr consequent = error_node();
|
|
expression_node_ptr alternative = error_node();
|
|
|
|
bool result = true;
|
|
|
|
if (token_is(token_t::e_lcrlbracket,false))
|
|
{
|
|
if (0 == (consequent = parse_multi_sequence("if-statement-01")))
|
|
{
|
|
set_error(
|
|
make_error(parser_error::e_syntax,
|
|
current_token_,
|
|
"ERR27 - Failed to parse body of consequent for if-statement"));
|
|
result = false;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (
|
|
commutative_check_enabled() &&
|
|
token_is(token_t::e_mul,false)
|
|
)
|
|
{
|
|
next_token();
|
|
}
|
|
|
|
if (0 != (consequent = parse_expression()))
|
|
{
|
|
if (!token_is(token_t::e_eof))
|
|
{
|
|
set_error(
|
|
make_error(parser_error::e_syntax,
|
|
current_token_,
|
|
"ERR28 - Expected ';' at the end of the consequent for if-statement"));
|
|
result = false;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
set_error(
|
|
make_error(parser_error::e_syntax,
|
|
current_token_,
|
|
"ERR29 - Failed to parse body of consequent for if-statement"));
|
|
result = false;
|
|
}
|
|
}
|
|
|
|
if (result)
|
|
{
|
|
if (details::imatch(current_token_.value,"else"))
|
|
{
|
|
next_token();
|
|
|
|
if (token_is(token_t::e_lcrlbracket,false))
|
|
{
|
|
if (0 == (alternative = parse_multi_sequence("else-statement-01")))
|
|
{
|
|
set_error(
|
|
make_error(parser_error::e_syntax,
|
|
current_token_,
|
|
"ERR30 - Failed to parse body of the 'else' for if-statement"));
|
|
result = false;
|
|
}
|
|
}
|
|
else if (details::imatch(current_token_.value,"if"))
|
|
{
|
|
if (0 == (alternative = parse_conditional_statement()))
|
|
{
|
|
set_error(
|
|
make_error(parser_error::e_syntax,
|
|
current_token_,
|
|
"ERR31 - Failed to parse body of if-else statement"));
|
|
result = false;
|
|
}
|
|
}
|
|
else if (0 != (alternative = parse_expression()))
|
|
{
|
|
if (!token_is(token_t::e_eof))
|
|
{
|
|
set_error(
|
|
make_error(parser_error::e_syntax,
|
|
current_token_,
|
|
"ERR32 - Expected ';' at the end of the 'else-if' for the if-statement"));
|
|
result = false;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
set_error(
|
|
make_error(parser_error::e_syntax,
|
|
current_token_,
|
|
"ERR33 - Failed to parse body of the 'else' for if-statement"));
|
|
result = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!result)
|
|
{
|
|
free_node(node_allocator_, condition);
|
|
free_node(node_allocator_, consequent);
|
|
free_node(node_allocator_,alternative);
|
|
|
|
return error_node();
|
|
}
|
|
else
|
|
return expression_generator_.conditional(condition,consequent,alternative);
|
|
}
|
|
|
|
inline expression_node_ptr parse_conditional_statement()
|
|
{
|
|
expression_node_ptr condition = error_node();
|
|
|
|
next_token();
|
|
|
|
if (!token_is(token_t::e_lbracket))
|
|
{
|
|
set_error(
|
|
make_error(parser_error::e_syntax,
|
|
current_token_,
|
|
"ERR34 - Expected '(' at start of if-statement, instead got: '" + current_token_.value + "'"));
|
|
|
|
return error_node();
|
|
}
|
|
else if (0 == (condition = parse_expression()))
|
|
{
|
|
set_error(
|
|
make_error(parser_error::e_syntax,
|
|
current_token_,
|
|
"ERR35 - Failed to parse condition for if-statement"));
|
|
|
|
return error_node();
|
|
}
|
|
else if (token_is(token_t::e_comma,false))
|
|
{
|
|
// if (x,y,z)
|
|
return parse_conditional_statement_01(condition);
|
|
}
|
|
else if (token_is(token_t::e_rbracket))
|
|
{
|
|
// 00. if (x) y;
|
|
// 01. if (x) y; else z;
|
|
// 02. if (x) y; else {z0; ... zn;}
|
|
// 03. if (x) y; else if (z) w;
|
|
// 04. if (x) y; else if (z) w; else u;
|
|
// 05. if (x) y; else if (z) w; else {u0; ... un;}
|
|
// 06. if (x) y; else if (z) {w0; ... wn;}
|
|
// 07. if (x) {y0; ... yn;}
|
|
// 08. if (x) {y0; ... yn;} else z;
|
|
// 09. if (x) {y0; ... yn;} else {z0; ... zn;};
|
|
// 10. if (x) {y0; ... yn;} else if (z) w;
|
|
// 11. if (x) {y0; ... yn;} else if (z) w; else u;
|
|
// 12. if (x) {y0; ... nex;} else if (z) w; else {u0 ... un;}
|
|
// 13. if (x) {y0; ... yn;} else if (z) {w0; ... wn;}
|
|
return parse_conditional_statement_02(condition);
|
|
}
|
|
|
|
set_error(
|
|
make_error(parser_error::e_syntax,
|
|
current_token_,
|
|
"ERR36 - Invalid if-statement"));
|
|
|
|
free_node(node_allocator_,condition);
|
|
|
|
return error_node();
|
|
}
|
|
|
|
inline expression_node_ptr parse_ternary_conditional_statement(expression_node_ptr condition)
|
|
{
|
|
// Parse: [condition][?][consequent][:][alternative]
|
|
expression_node_ptr consequent = error_node();
|
|
expression_node_ptr alternative = error_node();
|
|
|
|
bool result = true;
|
|
|
|
if (0 == condition)
|
|
{
|
|
set_error(
|
|
make_error(parser_error::e_syntax,
|
|
current_token_,
|
|
"ERR37 - Encountered invalid condition branch for ternary if-statement"));
|
|
|
|
return error_node();
|
|
}
|
|
else if (!token_is(token_t::e_ternary))
|
|
{
|
|
set_error(
|
|
make_error(parser_error::e_syntax,
|
|
current_token_,
|
|
"ERR38 - Expected '?' after condition of ternary if-statement"));
|
|
|
|
result = false;
|
|
}
|
|
else if (0 == (consequent = parse_expression()))
|
|
{
|
|
set_error(
|
|
make_error(parser_error::e_syntax,
|
|
current_token_,
|
|
"ERR39 - Failed to parse consequent for if-statement"));
|
|
|
|
result = false;
|
|
}
|
|
else if (!token_is(token_t::e_colon))
|
|
{
|
|
set_error(
|
|
make_error(parser_error::e_syntax,
|
|
current_token_,
|
|
"ERR40 - Expected ':' between ternary if-statement consequent and alternative"));
|
|
|
|
result = false;
|
|
}
|
|
else if (0 == (alternative = parse_expression()))
|
|
{
|
|
set_error(
|
|
make_error(parser_error::e_syntax,
|
|
current_token_,
|
|
"ERR41 - Failed to parse alternative for if-statement"));
|
|
|
|
result = false;
|
|
}
|
|
|
|
if (!result)
|
|
{
|
|
free_node(node_allocator_, condition);
|
|
free_node(node_allocator_, consequent);
|
|
free_node(node_allocator_,alternative);
|
|
|
|
return error_node();
|
|
}
|
|
else
|
|
return expression_generator_.conditional(condition,consequent,alternative);
|
|
}
|
|
|
|
inline expression_node_ptr parse_while_loop()
|
|
{
|
|
// Parse: [while][(][test expr][)][{][expression][}]
|
|
expression_node_ptr condition = error_node();
|
|
expression_node_ptr branch = error_node();
|
|
expression_node_ptr result_node = error_node();
|
|
|
|
bool result = true;
|
|
|
|
next_token();
|
|
|
|
if (!token_is(token_t::e_lbracket))
|
|
{
|
|
set_error(
|
|
make_error(parser_error::e_syntax,
|
|
current_token_,
|
|
"ERR42 - Expected '(' at start of while-loop condition statement"));
|
|
|
|
return error_node();
|
|
}
|
|
else if (0 == (condition = parse_expression()))
|
|
{
|
|
set_error(
|
|
make_error(parser_error::e_syntax,
|
|
current_token_,
|
|
"ERR43 - Failed to parse condition for while-loop"));
|
|
|
|
return error_node();
|
|
}
|
|
else if (!token_is(token_t::e_rbracket))
|
|
{
|
|
set_error(
|
|
make_error(parser_error::e_syntax,
|
|
current_token_,
|
|
"ERR44 - Expected ')' at end of while-loop condition statement"));
|
|
result = false;
|
|
}
|
|
|
|
brkcnt_list_.push_front(false);
|
|
|
|
if (result)
|
|
{
|
|
if (0 == (branch = parse_multi_sequence("while-loop")))
|
|
{
|
|
set_error(
|
|
make_error(parser_error::e_syntax,
|
|
current_token_,
|
|
"ERR45 - Failed to parse body of while-loop"));
|
|
result = false;
|
|
}
|
|
else if (0 == (result_node = expression_generator_.while_loop(condition,
|
|
branch,
|
|
brkcnt_list_.front())))
|
|
{
|
|
set_error(
|
|
make_error(parser_error::e_syntax,
|
|
current_token_,
|
|
"ERR46 - Failed to synthesize while-loop"));
|
|
result = false;
|
|
}
|
|
}
|
|
|
|
if (!result)
|
|
{
|
|
free_node(node_allocator_, branch);
|
|
free_node(node_allocator_, condition);
|
|
free_node(node_allocator_,result_node);
|
|
|
|
brkcnt_list_.pop_front();
|
|
|
|
return error_node();
|
|
}
|
|
else
|
|
return result_node;
|
|
}
|
|
|
|
inline expression_node_ptr parse_repeat_until_loop()
|
|
{
|
|
// Parse: [repeat][{][expression][}][until][(][test expr][)]
|
|
expression_node_ptr condition = error_node();
|
|
expression_node_ptr branch = error_node();
|
|
next_token();
|
|
|
|
std::vector<expression_node_ptr> arg_list;
|
|
scoped_vec_delete<expression_node_t> sdd(*this,arg_list);
|
|
|
|
brkcnt_list_.push_front(false);
|
|
|
|
if (details::imatch(current_token_.value,"until"))
|
|
{
|
|
next_token();
|
|
branch = node_allocator_.allocate<details::null_node<T> >();
|
|
}
|
|
else
|
|
{
|
|
token_t::token_type seperator = token_t::e_eof;
|
|
|
|
scope_handler sh(*this);
|
|
|
|
for (;;)
|
|
{
|
|
expression_node_ptr arg = parse_expression();
|
|
|
|
if (0 == arg)
|
|
return error_node();
|
|
else
|
|
arg_list.push_back(arg);
|
|
|
|
if (details::imatch(current_token_.value,"until"))
|
|
{
|
|
next_token();
|
|
break;
|
|
}
|
|
|
|
bool is_next_until = peek_token_is(token_t::e_symbol) &&
|
|
peek_token_is("until");
|
|
|
|
if (!token_is(seperator) && is_next_until)
|
|
{
|
|
set_error(
|
|
make_error(parser_error::e_syntax,
|
|
current_token_,
|
|
"ERR47 - Expected '" + token_t::to_str(seperator) + "' for body of repeat until loop"));
|
|
|
|
return error_node();
|
|
}
|
|
|
|
if (details::imatch(current_token_.value,"until"))
|
|
{
|
|
next_token();
|
|
break;
|
|
}
|
|
}
|
|
|
|
branch = simplify(arg_list);
|
|
|
|
if ((sdd.delete_ptr = (0 == branch)))
|
|
{
|
|
brkcnt_list_.pop_front();
|
|
|
|
set_error(
|
|
make_error(parser_error::e_syntax,
|
|
current_token_,
|
|
"ERR48 - Failed to parse body of repeat until loop"));
|
|
|
|
return error_node();
|
|
}
|
|
}
|
|
|
|
if (!token_is(token_t::e_lbracket))
|
|
{
|
|
brkcnt_list_.pop_front();
|
|
|
|
set_error(
|
|
make_error(parser_error::e_syntax,
|
|
current_token_,
|
|
"ERR49 - Expected '(' before condition statement of repeat until loop"));
|
|
|
|
free_node(node_allocator_,branch);
|
|
|
|
return error_node();
|
|
}
|
|
else if (0 == (condition = parse_expression()))
|
|
{
|
|
brkcnt_list_.pop_front();
|
|
|
|
set_error(
|
|
make_error(parser_error::e_syntax,
|
|
current_token_,
|
|
"ERR50 - Failed to parse condition for repeat until loop"));
|
|
|
|
free_node(node_allocator_,branch);
|
|
|
|
return error_node();
|
|
}
|
|
else if (!token_is(token_t::e_rbracket))
|
|
{
|
|
set_error(
|
|
make_error(parser_error::e_syntax,
|
|
current_token_,
|
|
"ERR51 - Expected ')' after condition of repeat until loop"));
|
|
|
|
free_node(node_allocator_, branch);
|
|
free_node(node_allocator_, condition);
|
|
|
|
brkcnt_list_.pop_front();
|
|
|
|
return error_node();
|
|
}
|
|
|
|
expression_node_ptr result;
|
|
|
|
result = expression_generator_
|
|
.repeat_until_loop(condition,branch,brkcnt_list_.front());
|
|
|
|
if (0 == result)
|
|
{
|
|
set_error(
|
|
make_error(parser_error::e_syntax,
|
|
current_token_,
|
|
"ERR52 - Failed to synthesize repeat until loop"));
|
|
|
|
free_node(node_allocator_, condition);
|
|
brkcnt_list_.pop_front();
|
|
|
|
return error_node();
|
|
}
|
|
else
|
|
{
|
|
brkcnt_list_.pop_front();
|
|
return result;
|
|
}
|
|
}
|
|
|
|
inline expression_node_ptr parse_for_loop()
|
|
{
|
|
expression_node_ptr initialiser = error_node();
|
|
expression_node_ptr condition = error_node();
|
|
expression_node_ptr incrementor = error_node();
|
|
expression_node_ptr loop_body = error_node();
|
|
|
|
scope_element* se = 0;
|
|
bool result = true;
|
|
std::string loop_counter_symbol;
|
|
|
|
next_token();
|
|
|
|
scope_handler sh(*this);
|
|
|
|
if (!token_is(token_t::e_lbracket))
|
|
{
|
|
set_error(
|
|
make_error(parser_error::e_syntax,
|
|
current_token_,
|
|
"ERR53 - Expected '(' at start of for-loop"));
|
|
|
|
return error_node();
|
|
}
|
|
|
|
if (!token_is(token_t::e_eof))
|
|
{
|
|
if (
|
|
!token_is(token_t::e_symbol,false) &&
|
|
details::imatch(current_token_.value,"var")
|
|
)
|
|
{
|
|
next_token();
|
|
|
|
if (!token_is(token_t::e_symbol,false))
|
|
{
|
|
set_error(
|
|
make_error(parser_error::e_syntax,
|
|
current_token_,
|
|
"ERR54 - Expected a variable at the start of initialiser section of for-loop"));
|
|
|
|
return error_node();
|
|
}
|
|
else if (!peek_token_is(token_t::e_assign))
|
|
{
|
|
set_error(
|
|
make_error(parser_error::e_syntax,
|
|
current_token_,
|
|
"ERR55 - Expected variable assignment of initialiser section of for-loop"));
|
|
|
|
return error_node();
|
|
}
|
|
|
|
loop_counter_symbol = current_token_.value;
|
|
|
|
se = &sem_.get_element(loop_counter_symbol);
|
|
|
|
if ((se->name == loop_counter_symbol) && se->active)
|
|
{
|
|
set_error(
|
|
make_error(parser_error::e_syntax,
|
|
current_token_,
|
|
"ERR56 - For-loop variable '" + loop_counter_symbol+ "' is being shadowed by a previous declaration"));
|
|
|
|
return error_node();
|
|
}
|
|
else if (!symbol_table_.is_variable(loop_counter_symbol))
|
|
{
|
|
if (
|
|
!se->active &&
|
|
(se->name == loop_counter_symbol) &&
|
|
(se->type == scope_element::e_variable)
|
|
)
|
|
{
|
|
se->active = true;
|
|
se->ref_count++;
|
|
}
|
|
else
|
|
{
|
|
scope_element nse;
|
|
nse.name = loop_counter_symbol;
|
|
nse.type = scope_element::e_variable;
|
|
nse.depth = scope_depth_;
|
|
nse.data = new T(T(0));
|
|
nse.var_node = new variable_node_t(*(T*)(nse.data));
|
|
|
|
if (!sem_.add_element(nse))
|
|
{
|
|
set_error(
|
|
make_error(parser_error::e_syntax,
|
|
current_token_,
|
|
"ERR57 - Failed to add new local variable '" + loop_counter_symbol + "' to SEM"));
|
|
|
|
result = false;
|
|
|
|
}
|
|
else
|
|
exprtk_debug(("parse_for_loop() - INFO - Added new local variable: %s\n",nse.name.c_str()));
|
|
}
|
|
}
|
|
}
|
|
|
|
if (0 == (initialiser = parse_expression()))
|
|
{
|
|
set_error(
|
|
make_error(parser_error::e_syntax,
|
|
current_token_,
|
|
"ERR58 - Failed to parse initialiser of for-loop"));
|
|
result = false;
|
|
}
|
|
|
|
if (!token_is(token_t::e_eof))
|
|
{
|
|
set_error(
|
|
make_error(parser_error::e_syntax,
|
|
current_token_,
|
|
"ERR59 - Expected ';' after initialiser of for-loop"));
|
|
result = false;
|
|
}
|
|
}
|
|
|
|
if (!token_is(token_t::e_eof))
|
|
{
|
|
if (0 == (condition = parse_expression()))
|
|
{
|
|
set_error(
|
|
make_error(parser_error::e_syntax,
|
|
current_token_,
|
|
"ERR60 - Failed to parse condition of for-loop"));
|
|
result = false;
|
|
}
|
|
else if (!token_is(token_t::e_eof))
|
|
{
|
|
set_error(
|
|
make_error(parser_error::e_syntax,
|
|
current_token_,
|
|
"ERR61 - Expected ';' after condition section of for-loop"));
|
|
result = false;
|
|
}
|
|
}
|
|
|
|
if (!token_is(token_t::e_rbracket))
|
|
{
|
|
if (0 == (incrementor = parse_expression()))
|
|
{
|
|
set_error(
|
|
make_error(parser_error::e_syntax,
|
|
current_token_,
|
|
"ERR62 - Failed to parse incrementor of for-loop"));
|
|
result = false;
|
|
}
|
|
else if (!token_is(token_t::e_rbracket))
|
|
{
|
|
set_error(
|
|
make_error(parser_error::e_syntax,
|
|
current_token_,
|
|
"ERR63 - Expected ')' after incrementor section of for-loop"));
|
|
result = false;
|
|
}
|
|
}
|
|
|
|
if (result)
|
|
{
|
|
brkcnt_list_.push_front(false);
|
|
if (0 == (loop_body = parse_multi_sequence("for-loop")))
|
|
{
|
|
set_error(
|
|
make_error(parser_error::e_syntax,
|
|
current_token_,
|
|
"ERR64 - Failed to parse body of for-loop"));
|
|
result = false;
|
|
}
|
|
}
|
|
|
|
if (!result)
|
|
{
|
|
if (se)
|
|
{
|
|
se->ref_count--;
|
|
}
|
|
|
|
sem_.cleanup();
|
|
|
|
free_node(node_allocator_,initialiser);
|
|
free_node(node_allocator_, condition);
|
|
free_node(node_allocator_,incrementor);
|
|
free_node(node_allocator_, loop_body);
|
|
|
|
if (!brkcnt_list_.empty())
|
|
{
|
|
brkcnt_list_.pop_front();
|
|
}
|
|
|
|
return error_node();
|
|
}
|
|
else
|
|
{
|
|
expression_node_ptr result_node =
|
|
expression_generator_.for_loop(initialiser,
|
|
condition,
|
|
incrementor,
|
|
loop_body,
|
|
brkcnt_list_.front());
|
|
brkcnt_list_.pop_front();
|
|
|
|
return result_node;
|
|
}
|
|
}
|
|
|
|
inline expression_node_ptr parse_switch_statement()
|
|
{
|
|
std::vector<expression_node_ptr> arg_list;
|
|
expression_node_ptr result = error_node();
|
|
|
|
if (!details::imatch(current_token_.value,"switch"))
|
|
{
|
|
set_error(
|
|
make_error(parser_error::e_syntax,
|
|
current_token_,
|
|
"ERR65 - Expected keyword 'switch'"));
|
|
|
|
return error_node();
|
|
}
|
|
|
|
scoped_vec_delete<expression_node_t> svd(*this,arg_list);
|
|
|
|
next_token();
|
|
|
|
if (!token_is(token_t::e_lcrlbracket))
|
|
{
|
|
set_error(
|
|
make_error(parser_error::e_syntax,
|
|
current_token_,
|
|
"ERR66 - Expected '{' for call to switch statement"));
|
|
|
|
return error_node();
|
|
}
|
|
|
|
for ( ; ; )
|
|
{
|
|
if (!details::imatch("case",current_token_.value))
|
|
{
|
|
set_error(
|
|
make_error(parser_error::e_syntax,
|
|
current_token_,
|
|
"ERR67 - Expected either a 'case' or 'default' statement"));
|
|
|
|
return error_node();
|
|
}
|
|
|
|
next_token();
|
|
|
|
expression_node_ptr condition = parse_expression();
|
|
|
|
if (0 == condition)
|
|
return error_node();
|
|
else if (!token_is(token_t::e_colon))
|
|
{
|
|
set_error(
|
|
make_error(parser_error::e_syntax,
|
|
current_token_,
|
|
"ERR68 - Expected ':' for case of switch statement"));
|
|
|
|
return error_node();
|
|
}
|
|
|
|
expression_node_ptr consequent = parse_expression();
|
|
|
|
if (0 == consequent)
|
|
return error_node();
|
|
else if (!token_is(token_t::e_eof))
|
|
{
|
|
set_error(
|
|
make_error(parser_error::e_syntax,
|
|
current_token_,
|
|
"ERR69 - Expected ';' at end of case for switch statement"));
|
|
|
|
return error_node();
|
|
}
|
|
|
|
// Can we optimize away the case statement?
|
|
if (is_constant_node(condition) && is_false(condition))
|
|
{
|
|
free_node(node_allocator_, condition);
|
|
free_node(node_allocator_,consequent);
|
|
|
|
condition = 0;
|
|
consequent = 0;
|
|
}
|
|
else
|
|
{
|
|
arg_list.push_back(condition);
|
|
arg_list.push_back(consequent);
|
|
}
|
|
|
|
if (details::imatch("default",current_token_.value))
|
|
{
|
|
next_token();
|
|
if (!token_is(token_t::e_colon))
|
|
{
|
|
set_error(
|
|
make_error(parser_error::e_syntax,
|
|
current_token_,
|
|
"ERR70 - Expected ':' for default of switch statement"));
|
|
|
|
return error_node();
|
|
}
|
|
|
|
expression_node_ptr default_statement = parse_expression();
|
|
|
|
if (0 == default_statement)
|
|
return error_node();
|
|
else if (!token_is(token_t::e_eof))
|
|
{
|
|
set_error(
|
|
make_error(parser_error::e_syntax,
|
|
current_token_,
|
|
"ERR71 - Expected ';' at end of default for switch statement"));
|
|
|
|
return error_node();
|
|
}
|
|
|
|
arg_list.push_back(default_statement);
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!token_is(token_t::e_rcrlbracket))
|
|
{
|
|
set_error(
|
|
make_error(parser_error::e_syntax,
|
|
current_token_,
|
|
"ERR72 - Expected '}' at end of switch statement"));
|
|
|
|
return error_node();
|
|
}
|
|
|
|
result = expression_generator_.switch_statement(arg_list);
|
|
|
|
svd.delete_ptr = (0 == result);
|
|
|
|
return result;
|
|
}
|
|
|
|
inline expression_node_ptr parse_multi_switch_statement()
|
|
{
|
|
std::vector<expression_node_ptr> arg_list;
|
|
expression_node_ptr result = error_node();
|
|
|
|
if (!details::imatch(current_token_.value,"[*]"))
|
|
{
|
|
set_error(
|
|
make_error(parser_error::e_syntax,
|
|
current_token_,
|
|
"ERR73 - Expected token '[*]'"));
|
|
|
|
return error_node();
|
|
}
|
|
|
|
scoped_vec_delete<expression_node_t> svd(*this,arg_list);
|
|
|
|
next_token();
|
|
|
|
if (!token_is(token_t::e_lcrlbracket))
|
|
{
|
|
set_error(
|
|
make_error(parser_error::e_syntax,
|
|
current_token_,
|
|
"ERR74 - Expected '{' for call to [*] statement"));
|
|
|
|
return error_node();
|
|
}
|
|
|
|
for ( ; ; )
|
|
{
|
|
if (!details::imatch("case",current_token_.value))
|
|
{
|
|
set_error(
|
|
make_error(parser_error::e_syntax,
|
|
current_token_,
|
|
"ERR75 - Expected a 'case' statement for multi-switch"));
|
|
|
|
return error_node();
|
|
}
|
|
|
|
next_token();
|
|
|
|
expression_node_ptr condition = parse_expression();
|
|
|
|
if (0 == condition)
|
|
return error_node();
|
|
|
|
if (!token_is(token_t::e_colon))
|
|
{
|
|
set_error(
|
|
make_error(parser_error::e_syntax,
|
|
current_token_,
|
|
"ERR76 - Expected ':' for case of [*] statement"));
|
|
|
|
return error_node();
|
|
}
|
|
|
|
expression_node_ptr consequent = parse_expression();
|
|
|
|
if (0 == consequent)
|
|
return error_node();
|
|
|
|
if (!token_is(token_t::e_eof))
|
|
{
|
|
set_error(
|
|
make_error(parser_error::e_syntax,
|
|
current_token_,
|
|
"ERR77 - Expected ';' at end of case for [*] statement"));
|
|
|
|
return error_node();
|
|
}
|
|
|
|
// Can we optimize away the case statement?
|
|
if (is_constant_node(condition) && is_false(condition))
|
|
{
|
|
free_node(node_allocator_, condition);
|
|
free_node(node_allocator_,consequent);
|
|
|
|
condition = 0;
|
|
consequent = 0;
|
|
}
|
|
else
|
|
{
|
|
arg_list.push_back(condition);
|
|
arg_list.push_back(consequent);
|
|
}
|
|
|
|
if (token_is(token_t::e_rcrlbracket,false))
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!token_is(token_t::e_rcrlbracket))
|
|
{
|
|
set_error(
|
|
make_error(parser_error::e_syntax,
|
|
current_token_,
|
|
"ERR78 - Expected '}' at end of [*] statement"));
|
|
|
|
return error_node();
|
|
}
|
|
|
|
result = expression_generator_.multi_switch_statement(arg_list);
|
|
|
|
svd.delete_ptr = (0 == result);
|
|
|
|
return result;
|
|
}
|
|
|
|
inline expression_node_ptr parse_vararg_function()
|
|
{
|
|
std::vector<expression_node_ptr> arg_list;
|
|
expression_node_ptr result = error_node();
|
|
|
|
details::operator_type opt_type = details::e_default;
|
|
const std::string symbol = current_token_.value;
|
|
|
|
if (details::imatch(symbol,"~"))
|
|
{
|
|
next_token();
|
|
return parse_multi_sequence();
|
|
}
|
|
else if (details::imatch(symbol,"[*]"))
|
|
{
|
|
return parse_multi_switch_statement();
|
|
}
|
|
else if (details::imatch(symbol,"avg" )) opt_type = details::e_avg;
|
|
else if (details::imatch(symbol,"mand")) opt_type = details::e_mand;
|
|
else if (details::imatch(symbol,"max" )) opt_type = details::e_max;
|
|
else if (details::imatch(symbol,"min" )) opt_type = details::e_min;
|
|
else if (details::imatch(symbol,"mor" )) opt_type = details::e_mor;
|
|
else if (details::imatch(symbol,"mul" )) opt_type = details::e_prod;
|
|
else if (details::imatch(symbol,"sum" )) opt_type = details::e_sum;
|
|
else
|
|
{
|
|
set_error(
|
|
make_error(parser_error::e_syntax,
|
|
current_token_,
|
|
"ERR79 - Unsupported vararg function: " + symbol));
|
|
|
|
return error_node();
|
|
}
|
|
|
|
scoped_vec_delete<expression_node_t> sdd(*this,arg_list);
|
|
|
|
next_token();
|
|
if (!token_is(token_t::e_lbracket))
|
|
{
|
|
set_error(
|
|
make_error(parser_error::e_syntax,
|
|
current_token_,
|
|
"ERR80 - Expected '(' for call to vararg function: " + symbol));
|
|
|
|
return error_node();
|
|
}
|
|
|
|
for ( ; ; )
|
|
{
|
|
expression_node_ptr arg = parse_expression();
|
|
|
|
if (0 == arg)
|
|
return error_node();
|
|
else
|
|
arg_list.push_back(arg);
|
|
|
|
if (token_is(token_t::e_rbracket))
|
|
break;
|
|
else if (!token_is(token_t::e_comma))
|
|
{
|
|
set_error(
|
|
make_error(parser_error::e_syntax,
|
|
current_token_,
|
|
"ERR81 - Expected ',' for call to vararg function: " + symbol));
|
|
|
|
return error_node();
|
|
}
|
|
}
|
|
|
|
result = expression_generator_.vararg_function(opt_type,arg_list);
|
|
|
|
sdd.delete_ptr = (0 == result);
|
|
return result;
|
|
}
|
|
|
|
inline expression_node_ptr parse_string_range_statement(expression_node_ptr& expression)
|
|
{
|
|
if (!token_is(token_t::e_lsqrbracket))
|
|
{
|
|
set_error(
|
|
make_error(parser_error::e_syntax,
|
|
current_token_,
|
|
"ERR82 - Expected '[' as start of string range definition"));
|
|
|
|
free_node(node_allocator_,expression);
|
|
|
|
return error_node();
|
|
}
|
|
else if (token_is(token_t::e_rsqrbracket))
|
|
{
|
|
return node_allocator_.allocate<details::string_size_node<T> >(expression);
|
|
}
|
|
|
|
range_t rp;
|
|
|
|
if (!parse_range(rp,true))
|
|
{
|
|
free_node(node_allocator_,expression);
|
|
|
|
return error_node();
|
|
}
|
|
|
|
expression_node_ptr result = expression_generator_(expression,rp);
|
|
|
|
if (0 == result)
|
|
{
|
|
set_error(
|
|
make_error(parser_error::e_syntax,
|
|
current_token_,
|
|
"ERR83 - Failed to generate string range node"));
|
|
|
|
free_node(node_allocator_,expression);
|
|
}
|
|
|
|
rp.clear();
|
|
|
|
return result;
|
|
}
|
|
|
|
inline void parse_pending_string_rangesize(expression_node_ptr& expression)
|
|
{
|
|
const std::size_t max_rangesize_parses = 100;
|
|
std::size_t i = 0;
|
|
|
|
while
|
|
(
|
|
(0 != expression) &&
|
|
(i++ < max_rangesize_parses) &&
|
|
error_list_.empty() &&
|
|
token_is(token_t::e_lsqrbracket,false) &&
|
|
is_generally_string_node(expression)
|
|
)
|
|
{
|
|
expression = parse_string_range_statement(expression);
|
|
}
|
|
}
|
|
|
|
template <typename Allocator,
|
|
template <typename,typename> class Sequence>
|
|
inline expression_node_ptr simplify(Sequence<expression_node_ptr,Allocator>& expression_list)
|
|
{
|
|
if (expression_list.empty())
|
|
return error_node();
|
|
else if (1 == expression_list.size())
|
|
return expression_list[0];
|
|
|
|
Sequence<expression_node_ptr,Allocator> tmp_expression_list;
|
|
|
|
for (std::size_t i = 0; i < (expression_list.size() - 1); ++i)
|
|
{
|
|
if (is_variable_node(expression_list[i]))
|
|
continue;
|
|
else if (
|
|
is_constant_node(expression_list[i]) ||
|
|
is_null_node (expression_list[i])
|
|
)
|
|
{
|
|
free_node(node_allocator_,expression_list[i]);
|
|
continue;
|
|
}
|
|
else
|
|
tmp_expression_list.push_back(expression_list[i]);
|
|
}
|
|
|
|
tmp_expression_list.push_back(expression_list.back());
|
|
expression_list.swap(tmp_expression_list);
|
|
|
|
if (1 == expression_list.size())
|
|
return expression_list[0];
|
|
else
|
|
return expression_generator_.vararg_function(details::e_multi,expression_list);
|
|
}
|
|
|
|
inline expression_node_ptr parse_multi_sequence(const std::string& source = "")
|
|
{
|
|
token_t::token_type close_bracket = token_t::e_rcrlbracket;
|
|
token_t::token_type seperator = token_t::e_eof;
|
|
|
|
if (!token_is(token_t::e_lcrlbracket))
|
|
{
|
|
if (token_is(token_t::e_lbracket))
|
|
{
|
|
close_bracket = token_t::e_rbracket;
|
|
seperator = token_t::e_comma;
|
|
}
|
|
else
|
|
{
|
|
set_error(
|
|
make_error(parser_error::e_syntax,
|
|
current_token_,
|
|
"ERR84 - Expected '" + token_t::to_str(close_bracket) + "' for call to multi-sequence" +
|
|
((!source.empty()) ? std::string(" section of " + source): "")));
|
|
|
|
return error_node();
|
|
}
|
|
}
|
|
else if (token_is(token_t::e_rcrlbracket))
|
|
{
|
|
return node_allocator_.allocate<details::null_node<T> >();
|
|
}
|
|
|
|
std::vector<expression_node_ptr> arg_list;
|
|
expression_node_ptr result = error_node();
|
|
|
|
scoped_vec_delete<expression_node_t> sdd(*this,arg_list);
|
|
|
|
scope_handler sh(*this);
|
|
|
|
for (;;)
|
|
{
|
|
expression_node_ptr arg = parse_expression();
|
|
|
|
if (0 == arg)
|
|
return error_node();
|
|
else
|
|
arg_list.push_back(arg);
|
|
|
|
if (token_is(close_bracket))
|
|
break;
|
|
|
|
bool is_next_close = peek_token_is(close_bracket);
|
|
|
|
if (!token_is(seperator) && is_next_close)
|
|
{
|
|
set_error(
|
|
make_error(parser_error::e_syntax,
|
|
current_token_,
|
|
"ERR85 - Expected '" + details::to_str(seperator) + "' for call to multi-sequence section of " + source));
|
|
|
|
return error_node();
|
|
}
|
|
|
|
if (token_is(close_bracket))
|
|
break;
|
|
}
|
|
|
|
result = simplify(arg_list);
|
|
|
|
sdd.delete_ptr = (0 == result);
|
|
return result;
|
|
}
|
|
|
|
inline bool parse_range(range_t& rp, const bool skip_lsqr = false)
|
|
{
|
|
// Examples of valid ranges:
|
|
// 1. [1:5] -> 1..5
|
|
// 2. [ :5] -> 0..5
|
|
// 3. [1: ] -> 1..end
|
|
// 4. [x:y] -> x..y where x <= y
|
|
// 5. [x+1:y/2] -> x+1..y/2 where x+1 <= y/2
|
|
// 6. [ :y] -> 0..y where 0 <= y
|
|
// 7. [x: ] -> x..end where x <= end
|
|
|
|
rp.clear();
|
|
|
|
if (!skip_lsqr && !token_is(token_t::e_lsqrbracket))
|
|
{
|
|
set_error(
|
|
make_error(parser_error::e_syntax,
|
|
current_token_,
|
|
"ERR86 - Expected '[' for start of range"));
|
|
|
|
return false;
|
|
}
|
|
|
|
if (token_is(token_t::e_colon))
|
|
{
|
|
rp.n0_c.first = true;
|
|
rp.n0_c.second = 0;
|
|
rp.cache.first = 0;
|
|
}
|
|
else
|
|
{
|
|
expression_node_ptr r0 = parse_expression();
|
|
|
|
if (0 == r0)
|
|
{
|
|
set_error(
|
|
make_error(parser_error::e_syntax,
|
|
current_token_,
|
|
"ERR87 - Failed parse begin section of range"));
|
|
|
|
return false;
|
|
|
|
}
|
|
else if (is_constant_node(r0))
|
|
{
|
|
T r0_value = r0->value();
|
|
|
|
if (r0_value >= T(0))
|
|
{
|
|
rp.n0_c.first = true;
|
|
rp.n0_c.second = static_cast<std::size_t>(details::numeric::to_int64(r0_value));
|
|
rp.cache.first = rp.n0_c.second;
|
|
}
|
|
|
|
free_node(node_allocator_,r0);
|
|
|
|
if (r0_value < T(0))
|
|
{
|
|
set_error(
|
|
make_error(parser_error::e_syntax,
|
|
current_token_,
|
|
"ERR88 - Range lower bound less than zero! Constraint: r0 >= 0"));
|
|
|
|
return false;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
rp.n0_e.first = true;
|
|
rp.n0_e.second = r0;
|
|
}
|
|
|
|
if (!token_is(token_t::e_colon))
|
|
{
|
|
set_error(
|
|
make_error(parser_error::e_syntax,
|
|
current_token_,
|
|
"ERR89 - Expected ':' for break in range"));
|
|
|
|
rp.free();
|
|
return false;
|
|
}
|
|
}
|
|
|
|
if (token_is(token_t::e_rsqrbracket))
|
|
{
|
|
rp.n1_c.first = true;
|
|
rp.n1_c.second = std::numeric_limits<std::size_t>::max();
|
|
}
|
|
else
|
|
{
|
|
expression_node_ptr r1 = parse_expression();
|
|
|
|
if (0 == r1)
|
|
{
|
|
set_error(
|
|
make_error(parser_error::e_syntax,
|
|
current_token_,
|
|
"ERR90 - Failed parse end section of range"));
|
|
|
|
rp.free();
|
|
return false;
|
|
|
|
}
|
|
else if (is_constant_node(r1))
|
|
{
|
|
T r1_value = r1->value();
|
|
|
|
if (r1_value >= T(0))
|
|
{
|
|
rp.n1_c.first = true;
|
|
rp.n1_c.second = static_cast<std::size_t>(details::numeric::to_int64(r1_value));
|
|
rp.cache.second = rp.n1_c.second;
|
|
}
|
|
|
|
free_node(node_allocator_,r1);
|
|
|
|
if (r1_value < T(0))
|
|
{
|
|
set_error(
|
|
make_error(parser_error::e_syntax,
|
|
current_token_,
|
|
"ERR91 - Range upper bound less than zero! Constraint: r1 >= 0"));
|
|
|
|
return false;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
rp.n1_e.first = true;
|
|
rp.n1_e.second = r1;
|
|
}
|
|
|
|
if (!token_is(token_t::e_rsqrbracket))
|
|
{
|
|
set_error(
|
|
make_error(parser_error::e_syntax,
|
|
current_token_,
|
|
"ERR92 - Expected ']' for start of range"));
|
|
|
|
rp.free();
|
|
return false;
|
|
}
|
|
}
|
|
|
|
if (rp.const_range())
|
|
{
|
|
std::size_t r0 = 0;
|
|
std::size_t r1 = 0;
|
|
|
|
bool rp_result = rp(r0,r1);
|
|
|
|
if (!rp_result || (r0 > r1))
|
|
{
|
|
set_error(
|
|
make_error(parser_error::e_syntax,
|
|
current_token_,
|
|
"ERR93 - Invalid range, Constraint: r0 <= r1"));
|
|
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
inline void lodge_symbol(const std::string& symbol,
|
|
const symbol_type st)
|
|
{
|
|
dec_.add_symbol(symbol,st);
|
|
}
|
|
|
|
inline expression_node_ptr parse_string()
|
|
{
|
|
const std::string symbol = current_token_.value;
|
|
|
|
if (!symbol_table_.is_conststr_stringvar(symbol))
|
|
{
|
|
set_error(
|
|
make_error(parser_error::e_syntax,
|
|
current_token_,
|
|
"ERR94 - Unknown string symbol"));
|
|
|
|
return error_node();
|
|
}
|
|
|
|
expression_node_ptr result = symbol_table_.get_stringvar(symbol);
|
|
|
|
typedef details::stringvar_node<T>* strvar_node_t;
|
|
strvar_node_t const_str_node = static_cast<strvar_node_t>(0);
|
|
|
|
const bool is_const_string = symbol_table_.is_constant_string(symbol);
|
|
|
|
if (is_const_string)
|
|
{
|
|
const_str_node = static_cast<strvar_node_t>(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<details::stringvar_size_node<T> >
|
|
(static_cast<details::stringvar_node<T>*>(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<details::stringvar_node<T>*>(result)->ref(),rp);
|
|
|
|
if (result)
|
|
rp.clear();
|
|
}
|
|
else
|
|
next_token();
|
|
|
|
return result;
|
|
}
|
|
|
|
inline expression_node_ptr parse_const_string()
|
|
{
|
|
const std::string const_str = current_token_.value;
|
|
expression_node_ptr result = expression_generator_(const_str);
|
|
|
|
if (peek_token_is(token_t::e_lsqrbracket))
|
|
{
|
|
next_token();
|
|
|
|
if (peek_token_is(token_t::e_rsqrbracket))
|
|
{
|
|
next_token();
|
|
next_token();
|
|
|
|
free_node(node_allocator_,result);
|
|
|
|
return expression_generator_(T(const_str.size()));
|
|
}
|
|
|
|
range_t rp;
|
|
|
|
if (!parse_range(rp))
|
|
{
|
|
free_node(node_allocator_,result);
|
|
|
|
return error_node();
|
|
}
|
|
|
|
free_node(node_allocator_,result);
|
|
|
|
if (rp.n1_c.first && (rp.n1_c.second == std::numeric_limits<std::size_t>::max()))
|
|
{
|
|
rp.n1_c.second = const_str.size() - 1;
|
|
rp.cache.second = rp.n1_c.second;
|
|
}
|
|
|
|
if (
|
|
(rp.n0_c.first && (rp.n0_c.second >= const_str.size())) ||
|
|
(rp.n1_c.first && (rp.n1_c.second >= const_str.size()))
|
|
)
|
|
{
|
|
set_error(
|
|
make_error(parser_error::e_syntax,
|
|
current_token_,
|
|
"ERR95 - Overflow in range for string: '" + const_str + "'[" +
|
|
(rp.n0_c.first ? details::to_str(rp.n0_c.second) : "?") + ":" +
|
|
(rp.n1_c.first ? details::to_str(rp.n1_c.second) : "?") + "]"));
|
|
|
|
return error_node();
|
|
}
|
|
|
|
result = expression_generator_(const_str,rp);
|
|
|
|
if (result)
|
|
rp.clear();
|
|
}
|
|
else
|
|
next_token();
|
|
|
|
return result;
|
|
}
|
|
|
|
inline expression_node_ptr parse_vector()
|
|
{
|
|
const std::string symbol = current_token_.value;
|
|
|
|
vector_holder_ptr vec = vector_holder_ptr(0);
|
|
|
|
const scope_element& se = sem_.get_element(symbol);
|
|
|
|
if (
|
|
(se.name != symbol) ||
|
|
(se.depth > scope_depth_) ||
|
|
(scope_element::e_vector != se.type)
|
|
)
|
|
{
|
|
if (0 == (vec = symbol_table_.get_vector(symbol)))
|
|
{
|
|
set_error(
|
|
make_error(parser_error::e_syntax,
|
|
current_token_,
|
|
"ERR96 - Symbol '" + symbol+ " not a vector"));
|
|
|
|
return error_node();
|
|
}
|
|
}
|
|
else
|
|
vec = se.vec_node;
|
|
|
|
expression_node_ptr index_expr = error_node();
|
|
|
|
next_token();
|
|
|
|
if (!token_is(token_t::e_lsqrbracket))
|
|
{
|
|
return node_allocator_.allocate<vector_node_t>(vec);
|
|
}
|
|
else if (token_is(token_t::e_rsqrbracket))
|
|
{
|
|
return expression_generator_(T(vec->size()));
|
|
}
|
|
else if (0 == (index_expr = parse_expression()))
|
|
{
|
|
set_error(
|
|
make_error(parser_error::e_syntax,
|
|
current_token_,
|
|
"ERR97 - Failed to parse index for vector: '" + symbol + "'"));
|
|
|
|
return error_node();
|
|
}
|
|
else if (!token_is(token_t::e_rsqrbracket))
|
|
{
|
|
set_error(
|
|
make_error(parser_error::e_syntax,
|
|
current_token_,
|
|
"ERR98 - Expected ']' for index of vector: '" + symbol + "'"));
|
|
|
|
free_node(node_allocator_,index_expr);
|
|
|
|
return error_node();
|
|
}
|
|
|
|
return expression_generator_.vector_element(symbol,vec,index_expr);
|
|
}
|
|
|
|
inline expression_node_ptr parse_vararg_function_call(ivararg_function<T>* vararg_function, const std::string& vararg_function_name)
|
|
{
|
|
std::vector<expression_node_ptr> arg_list;
|
|
expression_node_ptr result = error_node();
|
|
|
|
scoped_vec_delete<expression_node_t> sdd(*this,arg_list);
|
|
|
|
next_token();
|
|
|
|
if (token_is(token_t::e_lbracket))
|
|
{
|
|
if (!token_is(token_t::e_rbracket))
|
|
{
|
|
for ( ; ; )
|
|
{
|
|
expression_node_ptr arg = parse_expression();
|
|
|
|
if (0 == arg)
|
|
return error_node();
|
|
else
|
|
arg_list.push_back(arg);
|
|
|
|
if (token_is(token_t::e_rbracket))
|
|
break;
|
|
else if (!token_is(token_t::e_comma))
|
|
{
|
|
set_error(
|
|
make_error(parser_error::e_syntax,
|
|
current_token_,
|
|
"ERR99 - Expected ',' for call to vararg function: " + vararg_function_name));
|
|
|
|
return error_node();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
result = expression_generator_.vararg_function_call(vararg_function,arg_list);
|
|
|
|
sdd.delete_ptr = (0 == result);
|
|
|
|
return result;
|
|
}
|
|
|
|
class type_checker
|
|
{
|
|
public:
|
|
|
|
typedef parser<T> parser_t;
|
|
typedef std::vector<std::string> 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<std::pair<std::size_t,char> > error_list;
|
|
|
|
for (std::size_t i = 0; i < param_seq_list_.size(); ++i)
|
|
{
|
|
std::size_t diff_index = 0;
|
|
char diff_value = 0;
|
|
|
|
bool result = details::sequence_match(param_seq_list_[i],
|
|
param_seq,
|
|
diff_index,diff_value);
|
|
|
|
if (result)
|
|
{
|
|
pseq_index = i;
|
|
return true;
|
|
}
|
|
else
|
|
error_list.push_back(std::make_pair(diff_index,diff_value));
|
|
}
|
|
|
|
if (1 == error_list.size())
|
|
{
|
|
parser_.
|
|
set_error(
|
|
make_error(parser_error::e_syntax,
|
|
parser_.current_token(),
|
|
"ERR100 - Failed parameter type check for function '" + function_name_ + "', "
|
|
"Expected '" + param_seq_list_[0] + "' call set: '" + param_seq +"'"));
|
|
}
|
|
else
|
|
{
|
|
// find first with largest diff_index;
|
|
std::size_t max_diff_index = 0;
|
|
|
|
for (std::size_t i = 1; i < error_list.size(); ++i)
|
|
{
|
|
if (error_list[i].first > error_list[max_diff_index].first)
|
|
{
|
|
max_diff_index = i;
|
|
}
|
|
}
|
|
|
|
parser_.
|
|
set_error(
|
|
make_error(parser_error::e_syntax,
|
|
parser_.current_token(),
|
|
"ERR101 - Failed parameter type check for function '" + function_name_ + "', "
|
|
"Best match: '" + param_seq_list_[max_diff_index] + "' call set: '" + param_seq +"'"));
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
std::size_t paramseq_count() const
|
|
{
|
|
return param_seq_list_.size();
|
|
}
|
|
|
|
std::string paramseq(const std::size_t& index) const
|
|
{
|
|
return param_seq_list_[index];
|
|
}
|
|
|
|
bool invalid() const
|
|
{
|
|
return !invalid_state_;
|
|
}
|
|
|
|
private:
|
|
|
|
void split(const std::string& s)
|
|
{
|
|
if (s.empty())
|
|
return;
|
|
|
|
std::size_t start = 0;
|
|
std::size_t end = 0;
|
|
|
|
param_seq_list_t param_seq_list;
|
|
|
|
struct token_validator
|
|
{
|
|
static inline bool process(const std::string& str,
|
|
std::size_t s, std::size_t e,
|
|
param_seq_list_t& psl)
|
|
{
|
|
if (
|
|
(e - s) &&
|
|
(std::string::npos == str.find("?*")) &&
|
|
(std::string::npos == str.find("**"))
|
|
)
|
|
{
|
|
const std::string curr_str = str.substr(s,e - s);
|
|
|
|
if (std::string::npos == curr_str.find_first_not_of("STV*?|"))
|
|
{
|
|
psl.push_back(curr_str);
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
};
|
|
|
|
while (std::string::npos != (end = s.find('|',start)))
|
|
{
|
|
if (!token_validator::process(s,start,end,param_seq_list))
|
|
{
|
|
invalid_state_ = false;
|
|
|
|
const std::string err_param_seq = s.substr(start,end - start);
|
|
|
|
parser_.
|
|
set_error(
|
|
make_error(parser_error::e_syntax,
|
|
parser_.current_token(),
|
|
"ERR102 - Invalid parameter sequence of '" + err_param_seq +
|
|
"' for function: " + function_name_));
|
|
|
|
return;
|
|
}
|
|
else
|
|
start = end + 1;
|
|
}
|
|
|
|
if (start < s.size())
|
|
{
|
|
if (token_validator::process(s,start,s.size(),param_seq_list))
|
|
param_seq_list_ = param_seq_list;
|
|
else
|
|
{
|
|
const std::string err_param_seq = s.substr(start,s.size() - start);
|
|
|
|
parser_.
|
|
set_error(
|
|
make_error(parser_error::e_syntax,
|
|
parser_.current_token(),
|
|
"ERR103 - Invalid parameter sequence of '" + err_param_seq +
|
|
"' for function: " + function_name_));
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
type_checker(const type_checker&);
|
|
type_checker& operator=(const type_checker&);
|
|
|
|
bool invalid_state_;
|
|
parser_t& parser_;
|
|
std::string function_name_;
|
|
param_seq_list_t param_seq_list_;
|
|
};
|
|
|
|
inline expression_node_ptr parse_generic_function_call(igeneric_function<T>* function, const std::string& function_name)
|
|
{
|
|
std::vector<expression_node_ptr> arg_list;
|
|
|
|
scoped_vec_delete<expression_node_t> sdd(*this,arg_list);
|
|
|
|
next_token();
|
|
|
|
std::string param_type_list;
|
|
|
|
type_checker tc(*this,function_name,function->parameter_sequence);
|
|
|
|
if (tc.invalid())
|
|
{
|
|
set_error(
|
|
make_error(parser_error::e_syntax,
|
|
current_token_,
|
|
"ERR104 - Type checker instantiation failure for generic function: " + function_name));
|
|
|
|
return error_node();
|
|
}
|
|
|
|
if (token_is(token_t::e_lbracket))
|
|
{
|
|
if (!token_is(token_t::e_rbracket))
|
|
{
|
|
for ( ; ; )
|
|
{
|
|
expression_node_ptr arg = parse_expression();
|
|
|
|
if (0 == arg)
|
|
return error_node();
|
|
|
|
if (is_ivector_node(arg))
|
|
param_type_list += 'V';
|
|
else if (is_generally_string_node(arg))
|
|
param_type_list += 'S';
|
|
else // Everything else is assumed to be scalar returning expression
|
|
param_type_list += 'T';
|
|
|
|
arg_list.push_back(arg);
|
|
|
|
if (token_is(token_t::e_rbracket))
|
|
break;
|
|
else if (!token_is(token_t::e_comma))
|
|
{
|
|
set_error(
|
|
make_error(parser_error::e_syntax,
|
|
current_token_,
|
|
"ERR105 - Expected ',' for call to generic function: " + function_name));
|
|
|
|
return error_node();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
std::size_t param_seq_index = 0;
|
|
|
|
if (!tc.verify(param_type_list, param_seq_index))
|
|
{
|
|
set_error(
|
|
make_error(parser_error::e_syntax,
|
|
current_token_,
|
|
"ERR106 - Expected ',' for call to generic function: " + function_name));
|
|
|
|
return error_node();
|
|
}
|
|
|
|
expression_node_ptr result = error_node();
|
|
|
|
if (tc.paramseq_count() <= 1)
|
|
result = expression_generator_
|
|
.generic_function_call(function,arg_list);
|
|
else
|
|
result = expression_generator_
|
|
.generic_function_call(function,arg_list,param_seq_index);
|
|
|
|
sdd.delete_ptr = (0 == result);
|
|
|
|
return result;
|
|
}
|
|
|
|
inline expression_node_ptr parse_string_function_call(igeneric_function<T>* function, const std::string& function_name)
|
|
{
|
|
std::vector<expression_node_ptr> arg_list;
|
|
|
|
scoped_vec_delete<expression_node_t> sdd(*this,arg_list);
|
|
|
|
next_token();
|
|
|
|
std::string param_type_list;
|
|
|
|
type_checker tc(*this,function_name,function->parameter_sequence);
|
|
|
|
if (
|
|
(!function->parameter_sequence.empty()) &&
|
|
(0 == tc.paramseq_count())
|
|
)
|
|
{
|
|
return error_node();
|
|
}
|
|
|
|
if (token_is(token_t::e_lbracket))
|
|
{
|
|
if (!token_is(token_t::e_rbracket))
|
|
{
|
|
for ( ; ; )
|
|
{
|
|
expression_node_ptr arg = parse_expression();
|
|
|
|
if (0 == arg)
|
|
return error_node();
|
|
|
|
if (is_ivector_node(arg))
|
|
param_type_list += 'V';
|
|
else if (is_generally_string_node(arg))
|
|
param_type_list += 'S';
|
|
else // Everything else is a scalar returning expression
|
|
param_type_list += 'T';
|
|
|
|
arg_list.push_back(arg);
|
|
|
|
if (token_is(token_t::e_rbracket))
|
|
break;
|
|
else if (!token_is(token_t::e_comma))
|
|
{
|
|
set_error(
|
|
make_error(parser_error::e_syntax,
|
|
current_token_,
|
|
"ERR107 - Expected ',' for call to string function: " + function_name));
|
|
|
|
return error_node();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
std::size_t param_seq_index = 0;
|
|
|
|
if (!tc.verify(param_type_list, param_seq_index))
|
|
{
|
|
set_error(
|
|
make_error(parser_error::e_syntax,
|
|
current_token_,
|
|
"ERR108 - Expected ',' for call to string function: " + function_name));
|
|
|
|
return error_node();
|
|
}
|
|
|
|
expression_node_ptr result = error_node();
|
|
|
|
if (tc.paramseq_count() <= 1)
|
|
result = expression_generator_
|
|
.string_function_call(function,arg_list);
|
|
else
|
|
result = expression_generator_
|
|
.string_function_call(function,arg_list,param_seq_index);
|
|
|
|
sdd.delete_ptr = (0 == result);
|
|
|
|
return result;
|
|
}
|
|
|
|
template <typename Type, std::size_t NumberOfParameters>
|
|
struct parse_special_function_impl
|
|
{
|
|
static inline expression_node_ptr process(parser<Type>& 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<expression_node_ptr>(0));
|
|
scoped_delete<expression_node_t,NumberOfParameters> sd(p,branch);
|
|
|
|
p.next_token();
|
|
|
|
if (!p.token_is(token_t::e_lbracket))
|
|
{
|
|
p.set_error(
|
|
make_error(parser_error::e_syntax,
|
|
p.current_token(),
|
|
"ERR109 - Expected '(' for special function"));
|
|
|
|
return error_node();
|
|
}
|
|
|
|
for (std::size_t i = 0; i < NumberOfParameters; ++i)
|
|
{
|
|
branch[i] = p.parse_expression();
|
|
|
|
if (0 == branch[i])
|
|
{
|
|
return p.error_node();
|
|
}
|
|
else if (i < (NumberOfParameters - 1))
|
|
{
|
|
if (!p.token_is(token_t::e_comma))
|
|
{
|
|
p.set_error(
|
|
make_error(parser_error::e_syntax,
|
|
p.current_token(),
|
|
"ERR110 - Expected ',' before next parameter of special function"));
|
|
|
|
return p.error_node();
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!p.token_is(token_t::e_rbracket))
|
|
return p.error_node();
|
|
else
|
|
result = p.expression_generator_.special_function(opt_type,branch);
|
|
|
|
sd.delete_ptr = (0 == result);
|
|
|
|
return result;
|
|
}
|
|
};
|
|
|
|
inline expression_node_ptr parse_special_function()
|
|
{
|
|
// Expect: $fDD(expr0,expr1,expr2) or $fDD(expr0,expr1,expr2,expr3)
|
|
if (
|
|
!details::is_digit(current_token_.value[2]) ||
|
|
!details::is_digit(current_token_.value[3])
|
|
)
|
|
{
|
|
set_error(
|
|
make_error(parser_error::e_token,
|
|
current_token_,
|
|
"ERR111 - Invalid special function[1]: " + current_token_.value));
|
|
|
|
return error_node();
|
|
}
|
|
|
|
const unsigned int id = (current_token_.value[2] - '0') * 10 + (current_token_.value[3] - '0');
|
|
|
|
if (id >= details::e_sffinal)
|
|
{
|
|
set_error(
|
|
make_error(parser_error::e_token,
|
|
current_token_,
|
|
"ERR112 - Invalid special function[2]: " + current_token_.value));
|
|
|
|
return error_node();
|
|
}
|
|
|
|
const std::size_t sf_3_to_4 = details::e_sf48;
|
|
const details::operator_type opt_type = details::operator_type(id + 1000);
|
|
const std::size_t NumberOfParameters = (id < (sf_3_to_4 - 1000)) ? 3 : 4;
|
|
|
|
switch (NumberOfParameters)
|
|
{
|
|
case 3 : return parse_special_function_impl<T,3>::process(*this,opt_type);
|
|
case 4 : return parse_special_function_impl<T,4>::process(*this,opt_type);
|
|
default : return error_node();
|
|
}
|
|
}
|
|
|
|
inline expression_node_ptr parse_null_statement()
|
|
{
|
|
next_token();
|
|
return node_allocator_.allocate<details::null_node<T> >();
|
|
}
|
|
|
|
#ifndef exprtk_disable_break_continue
|
|
inline expression_node_ptr parse_break_statement()
|
|
{
|
|
if (!brkcnt_list_.empty())
|
|
{
|
|
next_token();
|
|
|
|
brkcnt_list_.front() = true;
|
|
|
|
expression_node_ptr return_expr = error_node();
|
|
|
|
if (token_is(token_t::e_lsqrbracket))
|
|
{
|
|
if (0 == (return_expr = parse_expression()))
|
|
{
|
|
set_error(
|
|
make_error(parser_error::e_syntax,
|
|
current_token_,
|
|
"ERR113 - Failed to parse return expression for 'break' statement"));
|
|
|
|
return error_node();
|
|
}
|
|
else if (!token_is(token_t::e_rsqrbracket))
|
|
{
|
|
set_error(
|
|
make_error(parser_error::e_syntax,
|
|
current_token_,
|
|
"ERR114 - Expected ']' at the completion of break's return expression"));
|
|
|
|
free_node(node_allocator_,return_expr);
|
|
|
|
return error_node();
|
|
}
|
|
}
|
|
|
|
return node_allocator_.allocate<details::break_node<T> >(return_expr);
|
|
}
|
|
else
|
|
{
|
|
set_error(
|
|
make_error(parser_error::e_syntax,
|
|
current_token_,
|
|
"ERR115 - Invalid use of 'break', allowed only in the scope of a loop"));
|
|
}
|
|
|
|
return error_node();
|
|
}
|
|
|
|
inline expression_node_ptr parse_continue_statement()
|
|
{
|
|
if (!brkcnt_list_.empty())
|
|
{
|
|
next_token();
|
|
brkcnt_list_.front() = true;
|
|
return node_allocator_.allocate<details::continue_node<T> >();
|
|
}
|
|
else
|
|
{
|
|
set_error(
|
|
make_error(parser_error::e_syntax,
|
|
current_token_,
|
|
"ERR116 - Invalid use of 'continue', allowed only in the scope of a loop"));
|
|
|
|
return error_node();
|
|
}
|
|
}
|
|
#endif
|
|
|
|
inline expression_node_ptr parse_define_vector_statement(const std::string& vec_name)
|
|
{
|
|
expression_node_ptr size_expr = error_node();
|
|
|
|
if (!token_is(token_t::e_lsqrbracket))
|
|
{
|
|
set_error(
|
|
make_error(parser_error::e_syntax,
|
|
current_token_,
|
|
"ERR117 - Expected '[' as part of vector size definition"));
|
|
|
|
return error_node();
|
|
}
|
|
else if (0 == (size_expr = parse_expression()))
|
|
{
|
|
set_error(
|
|
make_error(parser_error::e_syntax,
|
|
current_token_,
|
|
"ERR118 - Failed to determine size of vector '" + vec_name + "'"));
|
|
|
|
return error_node();
|
|
}
|
|
else if (!is_constant_node(size_expr))
|
|
{
|
|
free_node(node_allocator_,size_expr);
|
|
|
|
set_error(
|
|
make_error(parser_error::e_syntax,
|
|
current_token_,
|
|
"ERR119 - Expected a literal number as size of vector '" + vec_name + "'"));
|
|
|
|
return error_node();
|
|
}
|
|
|
|
T vector_size = size_expr->value();
|
|
|
|
free_node(node_allocator_,size_expr);
|
|
|
|
if (
|
|
(vector_size <= T(0)) ||
|
|
std::not_equal_to<T>()
|
|
(T(0),vector_size - details::numeric::trunc(vector_size))
|
|
)
|
|
{
|
|
set_error(
|
|
make_error(parser_error::e_syntax,
|
|
current_token_,
|
|
"ERR120 - Invalid vector size. Must be an integer greater than zero, size: " +
|
|
details::to_str(details::numeric::to_int32(vector_size))));
|
|
|
|
return error_node();
|
|
}
|
|
|
|
std::vector<expression_node_ptr> vec_initilizer_list;
|
|
|
|
scoped_vec_delete<expression_node_t> svd(*this,vec_initilizer_list);
|
|
|
|
bool single_value_initialiser = false;
|
|
|
|
if (!token_is(token_t::e_rsqrbracket))
|
|
{
|
|
set_error(
|
|
make_error(parser_error::e_syntax,
|
|
current_token_,
|
|
"ERR121 - Expected ']' as part of vector size definition"));
|
|
|
|
return error_node();
|
|
}
|
|
else if (!token_is(token_t::e_eof))
|
|
{
|
|
if (!token_is(token_t::e_assign))
|
|
{
|
|
set_error(
|
|
make_error(parser_error::e_syntax,
|
|
current_token_,
|
|
"ERR122 - Expected ':=' as part of vector definition"));
|
|
|
|
return error_node();
|
|
}
|
|
else if (token_is(token_t::e_lsqrbracket))
|
|
{
|
|
expression_node_ptr initialiser = parse_expression();
|
|
|
|
if (0 == initialiser)
|
|
{
|
|
set_error(
|
|
make_error(parser_error::e_syntax,
|
|
current_token_,
|
|
"ERR123 - Failed to parse single vector initialiser"));
|
|
|
|
return error_node();
|
|
}
|
|
|
|
vec_initilizer_list.push_back(initialiser);
|
|
|
|
if (!token_is(token_t::e_rsqrbracket))
|
|
{
|
|
set_error(
|
|
make_error(parser_error::e_syntax,
|
|
current_token_,
|
|
"ERR124 - Expected ']' to close single value vector initialiser"));
|
|
|
|
return error_node();
|
|
}
|
|
|
|
single_value_initialiser = true;
|
|
}
|
|
else if (!token_is(token_t::e_lcrlbracket))
|
|
{
|
|
set_error(
|
|
make_error(parser_error::e_syntax,
|
|
current_token_,
|
|
"ERR125 - Expected '{' as part of vector initialiser list"));
|
|
|
|
return error_node();
|
|
}
|
|
else if (!token_is(token_t::e_rcrlbracket))
|
|
{
|
|
for (;;)
|
|
{
|
|
expression_node_ptr initialiser = parse_expression();
|
|
|
|
if (0 == initialiser)
|
|
{
|
|
set_error(
|
|
make_error(parser_error::e_syntax,
|
|
current_token_,
|
|
"ERR126 - Expected '{' as part of vector initialiser list"));
|
|
|
|
return error_node();
|
|
}
|
|
else
|
|
vec_initilizer_list.push_back(initialiser);
|
|
|
|
if (token_is(token_t::e_rcrlbracket))
|
|
break;
|
|
|
|
bool is_next_close = peek_token_is(token_t::e_rcrlbracket);
|
|
|
|
if (!token_is(token_t::e_comma) && is_next_close)
|
|
{
|
|
set_error(
|
|
make_error(parser_error::e_syntax,
|
|
current_token_,
|
|
"ERR127 - Expected ',' between vector initialisers"));
|
|
|
|
return error_node();
|
|
}
|
|
|
|
if (token_is(token_t::e_rcrlbracket))
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (
|
|
!token_is(token_t::e_rbracket ,false) &&
|
|
!token_is(token_t::e_rcrlbracket,false) &&
|
|
!token_is(token_t::e_rsqrbracket,false)
|
|
)
|
|
{
|
|
if (!token_is(token_t::e_eof))
|
|
{
|
|
set_error(
|
|
make_error(parser_error::e_syntax,
|
|
current_token_,
|
|
"ERR128 - Expected ';' at end of vector definition"));
|
|
|
|
return error_node();
|
|
}
|
|
}
|
|
|
|
if (vec_initilizer_list.size() > vector_size)
|
|
{
|
|
set_error(
|
|
make_error(parser_error::e_syntax,
|
|
current_token_,
|
|
"ERR129 - Initialiser list larger than the number of elements in the vector: '" + vec_name + "'"));
|
|
|
|
return error_node();
|
|
}
|
|
}
|
|
|
|
typename symbol_table_t::vector_holder_ptr vec_holder = typename symbol_table_t::vector_holder_ptr(0);
|
|
|
|
std::size_t vec_size = static_cast<std::size_t>(details::numeric::to_int32(vector_size));
|
|
|
|
scope_element& se = sem_.get_element(vec_name);
|
|
|
|
if (se.name == vec_name)
|
|
{
|
|
if (se.active)
|
|
{
|
|
set_error(
|
|
make_error(parser_error::e_syntax,
|
|
current_token_,
|
|
"ERR130 - Illegal redefinition of local vector: '" + vec_name + "'"));
|
|
|
|
return error_node();
|
|
}
|
|
else if (
|
|
(se.size == vec_size) &&
|
|
(scope_element::e_vector == se.type)
|
|
)
|
|
{
|
|
vec_holder = se.vec_node;
|
|
se.active = true;
|
|
se.ref_count++;
|
|
}
|
|
}
|
|
|
|
if (0 == vec_holder)
|
|
{
|
|
scope_element nse;
|
|
nse.name = vec_name;
|
|
nse.type = scope_element::e_vector;
|
|
nse.depth = scope_depth_;
|
|
nse.size = vec_size;
|
|
nse.data = new T[vec_size];
|
|
nse.vec_node = new typename scope_element::vector_holder_t((T*)(nse.data),nse.size);
|
|
|
|
if (!sem_.add_element(nse))
|
|
{
|
|
set_error(
|
|
make_error(parser_error::e_syntax,
|
|
current_token_,
|
|
"ERR131 - Failed to add new local vector '" + vec_name + "' to SEM"));
|
|
|
|
return error_node();
|
|
}
|
|
|
|
vec_holder = nse.vec_node;
|
|
|
|
exprtk_debug(("parse_define_vector_statement() - INFO - Added new local vector: %s[%d]\n",
|
|
nse.name.c_str(),
|
|
static_cast<int>(nse.size)));
|
|
}
|
|
|
|
lodge_symbol(vec_name,e_st_local_vector);
|
|
|
|
expression_node_ptr result =
|
|
node_allocator_
|
|
.allocate<details::vector_assignment_node<T> >(
|
|
(*vec_holder)[0],
|
|
vec_size,
|
|
vec_initilizer_list,
|
|
single_value_initialiser);
|
|
|
|
svd.delete_ptr = (0 == result);
|
|
|
|
return result;
|
|
}
|
|
|
|
inline bool local_variable_is_shadowed(const std::string& symbol)
|
|
{
|
|
const scope_element& se = sem_.get_element(symbol);
|
|
return (se.name == symbol) && se.active;
|
|
}
|
|
|
|
inline expression_node_ptr parse_define_var_statement()
|
|
{
|
|
if (vardef_disabled_)
|
|
{
|
|
set_error(
|
|
make_error(parser_error::e_syntax,
|
|
current_token_,
|
|
"ERR132 - Illegal variable definition"));
|
|
|
|
return error_node();
|
|
}
|
|
else if (!details::imatch(current_token_.value,"var"))
|
|
{
|
|
return error_node();
|
|
}
|
|
else
|
|
next_token();
|
|
|
|
const std::string var_name = current_token_.value;
|
|
|
|
expression_node_ptr initialisation_expression = error_node();
|
|
|
|
if (!token_is(token_t::e_symbol))
|
|
{
|
|
set_error(
|
|
make_error(parser_error::e_syntax,
|
|
current_token_,
|
|
"ERR133 - Expected a symbol for variable definition"));
|
|
|
|
return error_node();
|
|
}
|
|
else if (details::is_reserved_symbol(var_name))
|
|
{
|
|
set_error(
|
|
make_error(parser_error::e_syntax,
|
|
current_token_,
|
|
"ERR134 - Illegal redefinition of reserved keyword: '" + var_name + "'"));
|
|
|
|
return error_node();
|
|
}
|
|
else if (symbol_table_.symbol_exists(var_name))
|
|
{
|
|
set_error(
|
|
make_error(parser_error::e_syntax,
|
|
current_token_,
|
|
"ERR135 - Illegal redefinition of variable '" + var_name + "'"));
|
|
|
|
return error_node();
|
|
}
|
|
else if (local_variable_is_shadowed(var_name))
|
|
{
|
|
set_error(
|
|
make_error(parser_error::e_syntax,
|
|
current_token_,
|
|
"ERR136 - Illegal redefinition of local variable: '" + var_name + "'"));
|
|
|
|
return error_node();
|
|
}
|
|
else if (token_is(token_t::e_lsqrbracket,false))
|
|
{
|
|
return parse_define_vector_statement(var_name);
|
|
}
|
|
else if (token_is(token_t::e_lcrlbracket,false))
|
|
{
|
|
return parse_uninitialised_var_statement(var_name);
|
|
}
|
|
else if (token_is(token_t::e_assign))
|
|
{
|
|
if (0 == (initialisation_expression = parse_expression()))
|
|
{
|
|
set_error(
|
|
make_error(parser_error::e_syntax,
|
|
current_token_,
|
|
"ERR137 - Failed to parse initialisation expression"));
|
|
|
|
return error_node();
|
|
}
|
|
}
|
|
|
|
if (
|
|
!token_is(token_t::e_rbracket ,false) &&
|
|
!token_is(token_t::e_rcrlbracket,false) &&
|
|
!token_is(token_t::e_rsqrbracket,false)
|
|
)
|
|
{
|
|
if (!token_is(token_t::e_eof,false))
|
|
{
|
|
set_error(
|
|
make_error(parser_error::e_syntax,
|
|
current_token_,
|
|
"ERR138 - Expected ';' after variable definition"));
|
|
|
|
free_node(node_allocator_,initialisation_expression);
|
|
|
|
return error_node();
|
|
}
|
|
}
|
|
|
|
variable_node_t* var_node = reinterpret_cast<variable_node_t*>(0);
|
|
|
|
scope_element& se = sem_.get_element(var_name);
|
|
|
|
if (se.name == var_name)
|
|
{
|
|
if (se.active)
|
|
{
|
|
set_error(
|
|
make_error(parser_error::e_syntax,
|
|
current_token_,
|
|
"ERR139 - Illegal redefinition of local variable: '" + var_name + "'"));
|
|
|
|
free_node(node_allocator_,initialisation_expression);
|
|
|
|
return error_node();
|
|
}
|
|
else if (scope_element::e_variable == se.type)
|
|
{
|
|
var_node = se.var_node;
|
|
se.active = true;
|
|
se.ref_count++;
|
|
}
|
|
}
|
|
|
|
if (0 == var_node)
|
|
{
|
|
scope_element nse;
|
|
nse.name = var_name;
|
|
nse.active = true;
|
|
nse.ref_count = 1;
|
|
nse.type = scope_element::e_variable;
|
|
nse.depth = scope_depth_;
|
|
nse.data = new T(T(0));
|
|
nse.var_node = new variable_node_t(*(T*)(nse.data));
|
|
|
|
if (!sem_.add_element(nse))
|
|
{
|
|
set_error(
|
|
make_error(parser_error::e_syntax,
|
|
current_token_,
|
|
"ERR140 - Failed to add new local variable '" + var_name + "' to SEM"));
|
|
|
|
free_node(node_allocator_,initialisation_expression);
|
|
|
|
return error_node();
|
|
}
|
|
|
|
var_node = nse.var_node;
|
|
|
|
exprtk_debug(("parse_define_var_statement() - INFO - Added new local variable: %s\n",nse.name.c_str()));
|
|
}
|
|
|
|
lodge_symbol(var_name,e_st_local_variable);
|
|
|
|
expression_node_ptr branch[2] = {0};
|
|
|
|
branch[0] = var_node;
|
|
branch[1] = initialisation_expression ? initialisation_expression : expression_generator_(T(0));
|
|
|
|
return expression_generator_(details::e_assign,branch);
|
|
}
|
|
|
|
inline expression_node_ptr parse_uninitialised_var_statement(const std::string& var_name)
|
|
{
|
|
if (
|
|
!token_is(token_t::e_lcrlbracket) ||
|
|
!token_is(token_t::e_rcrlbracket)
|
|
)
|
|
{
|
|
set_error(
|
|
make_error(parser_error::e_syntax,
|
|
current_token_,
|
|
"ERR141 - Expected a '{}' for uninitialised var definition"));
|
|
|
|
return error_node();
|
|
}
|
|
else if (!token_is(token_t::e_eof,false))
|
|
{
|
|
set_error(
|
|
make_error(parser_error::e_syntax,
|
|
current_token_,
|
|
"ERR142 - Expected ';' after uninitialised variable definition"));
|
|
|
|
return error_node();
|
|
}
|
|
|
|
variable_node_t* var_node = reinterpret_cast<variable_node_t*>(0);
|
|
|
|
scope_element& se = sem_.get_element(var_name);
|
|
|
|
if (se.name == var_name)
|
|
{
|
|
if (se.active)
|
|
{
|
|
set_error(
|
|
make_error(parser_error::e_syntax,
|
|
current_token_,
|
|
"ERR143 - Illegal redefinition of local variable: '" + var_name + "'"));
|
|
|
|
return error_node();
|
|
}
|
|
else if (scope_element::e_variable == se.type)
|
|
{
|
|
var_node = se.var_node;
|
|
se.active = true;
|
|
se.ref_count++;
|
|
}
|
|
}
|
|
|
|
if (0 == var_node)
|
|
{
|
|
scope_element nse;
|
|
nse.name = var_name;
|
|
nse.active = true;
|
|
nse.ref_count = 1;
|
|
nse.type = scope_element::e_variable;
|
|
nse.depth = scope_depth_;
|
|
nse.ip_index = sem_.next_ip_index();
|
|
nse.data = new T(T(0));
|
|
nse.var_node = new variable_node_t(*(T*)(nse.data));
|
|
|
|
if (!sem_.add_element(nse))
|
|
{
|
|
set_error(
|
|
make_error(parser_error::e_syntax,
|
|
current_token_,
|
|
"ERR144 - Failed to add new local variable '" + var_name + "' to SEM"));
|
|
|
|
return error_node();
|
|
}
|
|
|
|
exprtk_debug(("parse_uninitialised_var_statement() - INFO - Added new local variable: %s\n",nse.name.c_str()));
|
|
}
|
|
|
|
lodge_symbol(var_name,e_st_local_variable);
|
|
|
|
return expression_generator_(T(0));
|
|
}
|
|
|
|
inline expression_node_ptr parse_swap_statement()
|
|
{
|
|
if (!details::imatch(current_token_.value,"swap"))
|
|
{
|
|
return error_node();
|
|
}
|
|
else
|
|
next_token();
|
|
|
|
if (!token_is(token_t::e_lbracket))
|
|
{
|
|
set_error(
|
|
make_error(parser_error::e_syntax,
|
|
current_token_,
|
|
"ERR145 - Expected '(' at start of swap statement"));
|
|
|
|
return error_node();
|
|
}
|
|
|
|
expression_node_ptr variable0 = error_node();
|
|
expression_node_ptr variable1 = error_node();
|
|
|
|
bool variable0_generated = false;
|
|
bool variable1_generated = false;
|
|
|
|
const std::string var0_name = current_token_.value;
|
|
|
|
if (!token_is(token_t::e_symbol,false))
|
|
{
|
|
set_error(
|
|
make_error(parser_error::e_syntax,
|
|
current_token_,
|
|
"ERR146 - Expected a symbol for variable or vector element definition"));
|
|
|
|
return error_node();
|
|
}
|
|
else if (peek_token_is(token_t::e_lsqrbracket))
|
|
{
|
|
if (0 == (variable0 = parse_vector()))
|
|
{
|
|
set_error(
|
|
make_error(parser_error::e_syntax,
|
|
current_token_,
|
|
"ERR147 - First parameter to swap is an invalid vector element: '" + var0_name + "'"));
|
|
|
|
return error_node();
|
|
}
|
|
|
|
variable0_generated = true;
|
|
}
|
|
else
|
|
{
|
|
if (symbol_table_.is_variable(var0_name))
|
|
{
|
|
variable0 = symbol_table_.get_variable(var0_name);
|
|
}
|
|
|
|
scope_element& se = sem_.get_element(var0_name);
|
|
|
|
if (
|
|
(se.active) &&
|
|
(se.name == var0_name) &&
|
|
(scope_element::e_variable == se.type)
|
|
)
|
|
{
|
|
variable0 = se.var_node;
|
|
}
|
|
|
|
lodge_symbol(var0_name,e_st_variable);
|
|
|
|
if (0 == variable0)
|
|
{
|
|
set_error(
|
|
make_error(parser_error::e_syntax,
|
|
current_token_,
|
|
"ERR148 - First parameter to swap is an invalid variable: '" + var0_name + "'"));
|
|
|
|
return error_node();
|
|
}
|
|
else
|
|
next_token();
|
|
}
|
|
|
|
if (!token_is(token_t::e_comma))
|
|
{
|
|
set_error(
|
|
make_error(parser_error::e_syntax,
|
|
current_token(),
|
|
"ERR149 - Expected ',' between parameters to swap"));
|
|
|
|
if (variable0_generated)
|
|
{
|
|
free_node(node_allocator_,variable0);
|
|
}
|
|
|
|
return error_node();
|
|
}
|
|
|
|
const std::string var1_name = current_token_.value;
|
|
|
|
if (!token_is(token_t::e_symbol,false))
|
|
{
|
|
set_error(
|
|
make_error(parser_error::e_syntax,
|
|
current_token_,
|
|
"ERR150 - Expected a symbol for variable or vector element definition"));
|
|
|
|
if (variable0_generated)
|
|
{
|
|
free_node(node_allocator_,variable0);
|
|
}
|
|
|
|
return error_node();
|
|
}
|
|
else if (peek_token_is(token_t::e_lsqrbracket))
|
|
{
|
|
if (0 == (variable1 = parse_vector()))
|
|
{
|
|
set_error(
|
|
make_error(parser_error::e_syntax,
|
|
current_token_,
|
|
"ERR151 - Second parameter to swap is an invalid vector element: '" + var1_name + "'"));
|
|
|
|
if (variable0_generated)
|
|
{
|
|
free_node(node_allocator_,variable0);
|
|
}
|
|
|
|
return error_node();
|
|
}
|
|
|
|
variable1_generated = true;
|
|
}
|
|
else
|
|
{
|
|
if (symbol_table_.is_variable(var1_name))
|
|
{
|
|
variable1 = symbol_table_.get_variable(var1_name);
|
|
}
|
|
|
|
scope_element& se = sem_.get_element(var1_name);
|
|
|
|
if (
|
|
(se.active) &&
|
|
(se.name == var1_name) &&
|
|
(scope_element::e_variable == se.type)
|
|
)
|
|
{
|
|
variable1 = se.var_node;
|
|
}
|
|
|
|
lodge_symbol(var1_name,e_st_variable);
|
|
|
|
if (0 == variable1)
|
|
{
|
|
set_error(
|
|
make_error(parser_error::e_syntax,
|
|
current_token_,
|
|
"ERR152 - Second parameter to swap is an invalid variable: '" + var1_name + "'"));
|
|
|
|
if (variable0_generated)
|
|
{
|
|
free_node(node_allocator_,variable0);
|
|
}
|
|
|
|
return error_node();
|
|
}
|
|
else
|
|
next_token();
|
|
}
|
|
|
|
if (!token_is(token_t::e_rbracket))
|
|
{
|
|
set_error(
|
|
make_error(parser_error::e_syntax,
|
|
current_token_,
|
|
"ERR153 - Expected ')' at end of swap statement"));
|
|
|
|
if (variable0_generated)
|
|
{
|
|
free_node(node_allocator_,variable0);
|
|
}
|
|
|
|
if (variable1_generated)
|
|
{
|
|
free_node(node_allocator_,variable1);
|
|
}
|
|
|
|
return error_node();
|
|
}
|
|
|
|
typedef details::variable_node<T>* variable_node_ptr;
|
|
variable_node_ptr v0 = variable_node_ptr(0);
|
|
variable_node_ptr v1 = variable_node_ptr(0);
|
|
|
|
if (
|
|
(0 != (v0 = dynamic_cast<variable_node_ptr>(variable0))) &&
|
|
(0 != (v1 = dynamic_cast<variable_node_ptr>(variable1)))
|
|
)
|
|
{
|
|
expression_node_ptr result = node_allocator_.allocate<details::swap_node<T> >(v0,v1);
|
|
|
|
if (variable0_generated)
|
|
{
|
|
free_node(node_allocator_,variable0);
|
|
}
|
|
|
|
if (variable1_generated)
|
|
{
|
|
free_node(node_allocator_,variable1);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
else
|
|
return node_allocator_.allocate<details::swap_generic_node<T> >(variable0,variable1);
|
|
}
|
|
|
|
inline bool post_variable_process(const std::string& symbol)
|
|
{
|
|
if (
|
|
peek_token_is(token_t::e_lbracket ) ||
|
|
peek_token_is(token_t::e_lcrlbracket) ||
|
|
peek_token_is(token_t::e_lsqrbracket)
|
|
)
|
|
{
|
|
if (!commutative_check_enabled())
|
|
{
|
|
set_error(
|
|
make_error(parser_error::e_syntax,
|
|
current_token_,
|
|
"ERR154 - Invalid sequence of variable '"+ symbol + "' and bracket"));
|
|
|
|
return false;
|
|
}
|
|
|
|
lexer_.insert_front(token_t::e_mul);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
inline bool post_bracket_process(const typename token_t::token_type& token, expression_node_ptr& branch)
|
|
{
|
|
bool implied_mul = false;
|
|
|
|
if (is_generally_string_node(branch))
|
|
return true;
|
|
|
|
switch (token)
|
|
{
|
|
case token_t::e_lcrlbracket : implied_mul = token_is(token_t::e_lbracket ,false) ||
|
|
token_is(token_t::e_lcrlbracket,false) ||
|
|
token_is(token_t::e_lsqrbracket,false) ;
|
|
break;
|
|
|
|
case token_t::e_lbracket : implied_mul = token_is(token_t::e_lbracket ,false) ||
|
|
token_is(token_t::e_lcrlbracket,false) ||
|
|
token_is(token_t::e_lsqrbracket,false) ;
|
|
break;
|
|
|
|
case token_t::e_lsqrbracket : implied_mul = token_is(token_t::e_lbracket ,false) ||
|
|
token_is(token_t::e_lcrlbracket,false) ||
|
|
token_is(token_t::e_lsqrbracket,false) ;
|
|
break;
|
|
|
|
default : return true;
|
|
}
|
|
|
|
if (implied_mul)
|
|
{
|
|
if (!commutative_check_enabled())
|
|
{
|
|
set_error(
|
|
make_error(parser_error::e_syntax,
|
|
current_token_,
|
|
"ERR155 - Invalid sequence of brackets"));
|
|
|
|
return false;
|
|
}
|
|
else if (token_t::e_eof != current_token_.type)
|
|
{
|
|
lexer_.insert_front(current_token_.type);
|
|
lexer_.insert_front(token_t::e_mul);
|
|
next_token();
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
inline expression_node_ptr parse_symtab_symbol()
|
|
{
|
|
const std::string symbol = current_token_.value;
|
|
|
|
// Are we dealing with a variable or a special constant?
|
|
expression_node_ptr variable = symbol_table_.get_variable(symbol);
|
|
|
|
if (variable)
|
|
{
|
|
if (symbol_table_.is_constant_node(symbol))
|
|
{
|
|
variable = expression_generator_(variable->value());
|
|
}
|
|
|
|
if (!post_variable_process(symbol))
|
|
return error_node();
|
|
|
|
lodge_symbol(symbol,e_st_variable);
|
|
next_token();
|
|
|
|
return variable;
|
|
}
|
|
|
|
// Are we dealing with a locally defined variable or vector?
|
|
if (!sem_.empty())
|
|
{
|
|
scope_element& se = sem_.get_element(symbol);
|
|
|
|
if (se.name == symbol)
|
|
{
|
|
if (scope_element::e_variable == se.type)
|
|
{
|
|
se.active = true;
|
|
lodge_symbol(symbol,e_st_local_variable);
|
|
|
|
if (!post_variable_process(symbol))
|
|
return error_node();
|
|
|
|
next_token();
|
|
|
|
return se.var_node;
|
|
}
|
|
else if (scope_element::e_vector == se.type)
|
|
{
|
|
return parse_vector();
|
|
}
|
|
}
|
|
}
|
|
|
|
#ifndef exprtk_disable_string_capabilities
|
|
// Are we dealing with a string variable?
|
|
if (symbol_table_.is_stringvar(symbol))
|
|
{
|
|
return parse_string();
|
|
}
|
|
#endif
|
|
|
|
{
|
|
// Are we dealing with a function?
|
|
ifunction<T>* function = symbol_table_.get_function(symbol);
|
|
|
|
if (function)
|
|
{
|
|
lodge_symbol(symbol,e_st_function);
|
|
|
|
expression_node_ptr func_node =
|
|
parse_function_invocation(function,symbol);
|
|
|
|
if (func_node)
|
|
return func_node;
|
|
else
|
|
{
|
|
set_error(
|
|
make_error(parser_error::e_syntax,
|
|
current_token_,
|
|
"ERR156 - Failed to generate node for function: '" + symbol + "'"));
|
|
|
|
return error_node();
|
|
}
|
|
}
|
|
}
|
|
|
|
{
|
|
// Are we dealing with a vararg function?
|
|
ivararg_function<T>* vararg_function = symbol_table_.get_vararg_function(symbol);
|
|
|
|
if (vararg_function)
|
|
{
|
|
lodge_symbol(symbol,e_st_function);
|
|
|
|
expression_node_ptr vararg_func_node =
|
|
parse_vararg_function_call(vararg_function,symbol);
|
|
|
|
if (vararg_func_node)
|
|
return vararg_func_node;
|
|
else
|
|
{
|
|
set_error(
|
|
make_error(parser_error::e_syntax,
|
|
current_token_,
|
|
"ERR157 - Failed to generate node for vararg function: '" + symbol + "'"));
|
|
|
|
return error_node();
|
|
}
|
|
}
|
|
}
|
|
|
|
{
|
|
// Are we dealing with a vararg generic function?
|
|
igeneric_function<T>* generic_function = symbol_table_.get_generic_function(symbol);
|
|
|
|
if (generic_function)
|
|
{
|
|
lodge_symbol(symbol,e_st_function);
|
|
|
|
expression_node_ptr genericfunc_node =
|
|
parse_generic_function_call(generic_function,symbol);
|
|
|
|
if (genericfunc_node)
|
|
return genericfunc_node;
|
|
else
|
|
{
|
|
set_error(
|
|
make_error(parser_error::e_syntax,
|
|
current_token_,
|
|
"ERR158 - Failed to generate node for generic function: '" + symbol + "'"));
|
|
|
|
return error_node();
|
|
}
|
|
}
|
|
}
|
|
|
|
{
|
|
// Are we dealing with a vararg string returing function?
|
|
igeneric_function<T>* string_function = symbol_table_.get_string_function(symbol);
|
|
|
|
if (string_function)
|
|
{
|
|
lodge_symbol(symbol,e_st_function);
|
|
|
|
expression_node_ptr stringfunc_node =
|
|
parse_string_function_call(string_function,symbol);
|
|
|
|
if (stringfunc_node)
|
|
return stringfunc_node;
|
|
else
|
|
{
|
|
set_error(
|
|
make_error(parser_error::e_syntax,
|
|
current_token_,
|
|
"ERR159 - Failed to generate node for string function: '" + symbol + "'"));
|
|
|
|
return error_node();
|
|
}
|
|
}
|
|
}
|
|
|
|
// Are we dealing with a vector element?
|
|
if (symbol_table_.is_vector(symbol))
|
|
{
|
|
lodge_symbol(symbol,e_st_vector);
|
|
return parse_vector();
|
|
}
|
|
|
|
if (details::is_reserved_symbol(symbol))
|
|
{
|
|
set_error(
|
|
make_error(parser_error::e_syntax,
|
|
current_token_,
|
|
"ERR160 - Invalid use of reserved symbol '" + symbol + "'"));
|
|
|
|
return error_node();
|
|
}
|
|
|
|
// Should we handle unknown symbols?
|
|
if (resolve_unknown_symbol_ && unknown_symbol_resolver_)
|
|
{
|
|
T default_value = T(0);
|
|
std::string error_message;
|
|
typename unknown_symbol_resolver::usr_symbol_type usr_symbol_type;
|
|
|
|
if (unknown_symbol_resolver_->process(symbol,usr_symbol_type,default_value,error_message))
|
|
{
|
|
bool create_result = false;
|
|
|
|
switch (usr_symbol_type)
|
|
{
|
|
case unknown_symbol_resolver::e_usr_variable_type : create_result = symbol_table_.create_variable(symbol,default_value);
|
|
break;
|
|
|
|
case unknown_symbol_resolver::e_usr_constant_type : create_result = symbol_table_.add_constant(symbol,default_value);
|
|
break;
|
|
|
|
default : create_result = false;
|
|
}
|
|
|
|
if (create_result)
|
|
{
|
|
expression_node_ptr var = symbol_table_.get_variable(symbol);
|
|
|
|
if (var)
|
|
{
|
|
if (symbol_table_.is_constant_node(symbol))
|
|
{
|
|
var = expression_generator_(var->value());
|
|
}
|
|
|
|
lodge_symbol(symbol,e_st_variable);
|
|
|
|
if (!post_variable_process(symbol))
|
|
return error_node();
|
|
|
|
next_token();
|
|
|
|
return var;
|
|
}
|
|
}
|
|
|
|
set_error(
|
|
make_error(parser_error::e_symtab,
|
|
current_token_,
|
|
"ERR161 - Failed to create variable: '" + symbol + "'"));
|
|
|
|
return error_node();
|
|
}
|
|
}
|
|
|
|
set_error(
|
|
make_error(parser_error::e_syntax,
|
|
current_token_,
|
|
"ERR162 - Undefined symbol: '" + symbol + "'"));
|
|
|
|
return error_node();
|
|
}
|
|
|
|
inline expression_node_ptr parse_symbol()
|
|
{
|
|
static const std::string symbol_if = "if" ;
|
|
static const std::string symbol_while = "while" ;
|
|
static const std::string symbol_repeat = "repeat" ;
|
|
static const std::string symbol_for = "for" ;
|
|
static const std::string symbol_switch = "switch" ;
|
|
static const std::string symbol_null = "null" ;
|
|
static const std::string symbol_break = "break" ;
|
|
static const std::string symbol_continue = "continue";
|
|
static const std::string symbol_var = "var" ;
|
|
static const std::string symbol_swap = "swap" ;
|
|
|
|
if (valid_vararg_operation(current_token_.value))
|
|
{
|
|
return parse_vararg_function();
|
|
}
|
|
else if (valid_base_operation(current_token_.value))
|
|
{
|
|
return parse_base_operation();
|
|
}
|
|
else if (details::imatch(current_token_.value,symbol_if))
|
|
{
|
|
return parse_conditional_statement();
|
|
}
|
|
else if (details::imatch(current_token_.value,symbol_while))
|
|
{
|
|
return parse_while_loop();
|
|
}
|
|
else if (details::imatch(current_token_.value,symbol_repeat))
|
|
{
|
|
return parse_repeat_until_loop();
|
|
}
|
|
else if (details::imatch(current_token_.value,symbol_for))
|
|
{
|
|
return parse_for_loop();
|
|
}
|
|
else if (details::imatch(current_token_.value,symbol_switch))
|
|
{
|
|
return parse_switch_statement();
|
|
}
|
|
else if (details::is_valid_sf_symbol(current_token_.value))
|
|
{
|
|
return parse_special_function();
|
|
}
|
|
else if (details::imatch(current_token_.value,symbol_null))
|
|
{
|
|
return parse_null_statement();
|
|
}
|
|
#ifndef exprtk_disable_break_continue
|
|
else if (details::imatch(current_token_.value,symbol_break))
|
|
{
|
|
return parse_break_statement();
|
|
}
|
|
else if (details::imatch(current_token_.value,symbol_continue))
|
|
{
|
|
return parse_continue_statement();
|
|
}
|
|
#endif
|
|
else if (details::imatch(current_token_.value,symbol_var))
|
|
{
|
|
return parse_define_var_statement();
|
|
}
|
|
else if (details::imatch(current_token_.value,symbol_swap))
|
|
{
|
|
return parse_swap_statement();
|
|
}
|
|
else if (symbol_table_.valid() || !sem_.empty())
|
|
{
|
|
return parse_symtab_symbol();
|
|
}
|
|
else
|
|
{
|
|
set_error(
|
|
make_error(parser_error::e_symtab,
|
|
current_token_,
|
|
"ERR163 - Variable or function detected, yet symbol-table is invalid, Symbol: " + current_token_.value));
|
|
|
|
return error_node();
|
|
}
|
|
}
|
|
|
|
inline expression_node_ptr parse_branch(precedence_level precedence = e_level00)
|
|
{
|
|
expression_node_ptr branch = error_node();
|
|
|
|
if (token_t::e_number == current_token_.type)
|
|
{
|
|
T numeric_value = T(0);
|
|
|
|
if (details::string_to_real(current_token_.value,numeric_value))
|
|
{
|
|
expression_node_ptr literal_exp = expression_generator_(numeric_value);
|
|
next_token();
|
|
branch = literal_exp;
|
|
}
|
|
else
|
|
{
|
|
set_error(
|
|
make_error(parser_error::e_numeric,
|
|
current_token_,
|
|
"ERR164 - Failed to convert '" + current_token_.value + "' to a number"));
|
|
|
|
return error_node();
|
|
}
|
|
}
|
|
else if (token_t::e_symbol == current_token_.type)
|
|
{
|
|
branch = parse_symbol();
|
|
}
|
|
#ifndef exprtk_disable_string_capabilities
|
|
else if (token_t::e_string == current_token_.type)
|
|
{
|
|
branch = parse_const_string();
|
|
}
|
|
#endif
|
|
else if (token_t::e_lbracket == current_token_.type)
|
|
{
|
|
next_token();
|
|
|
|
if (0 == (branch = parse_expression()))
|
|
return error_node();
|
|
else if (!token_is(token_t::e_rbracket))
|
|
{
|
|
set_error(
|
|
make_error(parser_error::e_syntax,
|
|
current_token_,
|
|
"ERR165 - Expected ')' instead of: '" + current_token_.value + "'"));
|
|
|
|
free_node(node_allocator_,branch);
|
|
|
|
return error_node();
|
|
}
|
|
else if (!post_bracket_process(token_t::e_lbracket,branch))
|
|
{
|
|
free_node(node_allocator_,branch);
|
|
|
|
return error_node();
|
|
}
|
|
}
|
|
else if (token_t::e_lsqrbracket == current_token_.type)
|
|
{
|
|
next_token();
|
|
|
|
if (0 == (branch = parse_expression()))
|
|
return error_node();
|
|
else if (!token_is(token_t::e_rsqrbracket))
|
|
{
|
|
set_error(
|
|
make_error(parser_error::e_syntax,
|
|
current_token_,
|
|
"ERR166 - Expected ']' instead of: '" + current_token_.value + "'"));
|
|
|
|
free_node(node_allocator_,branch);
|
|
|
|
return error_node();
|
|
}
|
|
else if (!post_bracket_process(token_t::e_lsqrbracket,branch))
|
|
{
|
|
free_node(node_allocator_,branch);
|
|
|
|
return error_node();
|
|
}
|
|
}
|
|
else if (token_t::e_lcrlbracket == current_token_.type)
|
|
{
|
|
next_token();
|
|
|
|
if (0 == (branch = parse_expression()))
|
|
return error_node();
|
|
else if (!token_is(token_t::e_rcrlbracket))
|
|
{
|
|
set_error(
|
|
make_error(parser_error::e_syntax,
|
|
current_token_,
|
|
"ERR167 - Expected '}' instead of: '" + current_token_.value + "'"));
|
|
|
|
free_node(node_allocator_,branch);
|
|
|
|
return error_node();
|
|
}
|
|
else if (!post_bracket_process(token_t::e_lcrlbracket,branch))
|
|
{
|
|
free_node(node_allocator_,branch);
|
|
|
|
return error_node();
|
|
}
|
|
}
|
|
else if (token_t::e_sub == current_token_.type)
|
|
{
|
|
next_token();
|
|
branch = parse_expression(e_level11);
|
|
|
|
if (
|
|
branch &&
|
|
!(
|
|
details::is_neg_unary_node (branch) &&
|
|
simplify_unary_negation_branch(branch)
|
|
)
|
|
)
|
|
{
|
|
branch = expression_generator_(details::e_neg,branch);
|
|
}
|
|
}
|
|
else if (token_t::e_add == current_token_.type)
|
|
{
|
|
next_token();
|
|
branch = parse_expression(e_level13);
|
|
}
|
|
else if (token_t::e_eof == current_token_.type)
|
|
{
|
|
set_error(
|
|
make_error(parser_error::e_syntax,
|
|
current_token_,
|
|
"ERR168 - Premature end of expression[1]"));
|
|
|
|
return error_node();
|
|
}
|
|
else
|
|
{
|
|
set_error(
|
|
make_error(parser_error::e_syntax,
|
|
current_token_,
|
|
"ERR169 - Premature end of expression[2]"));
|
|
|
|
return error_node();
|
|
}
|
|
|
|
if (
|
|
branch &&
|
|
(e_level00 == precedence) &&
|
|
token_is(token_t::e_ternary,false)
|
|
)
|
|
{
|
|
branch = parse_ternary_conditional_statement(branch);
|
|
}
|
|
|
|
parse_pending_string_rangesize(branch);
|
|
|
|
return branch;
|
|
}
|
|
|
|
inline bool token_is(const typename token_t::token_type& ttype, const bool advance_token = true)
|
|
{
|
|
if (current_token_.type != ttype)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (advance_token)
|
|
{
|
|
next_token();
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
inline bool peek_token_is(const typename token_t::token_type& ttype)
|
|
{
|
|
return (lexer_.peek_next_token().type == ttype);
|
|
}
|
|
|
|
inline bool peek_token_is(const std::string& s)
|
|
{
|
|
return (details::imatch(lexer_.peek_next_token().value,s));
|
|
}
|
|
|
|
template <typename Type>
|
|
class expression_generator
|
|
{
|
|
public:
|
|
|
|
typedef details::expression_node<Type>* expression_node_ptr;
|
|
typedef expression_node_ptr (*synthesize_functor_t)(expression_generator<T>&, const details::operator_type& operation, expression_node_ptr (&branch)[2]);
|
|
typedef std::map<std::string,synthesize_functor_t> synthesize_map_t;
|
|
typedef typename exprtk::parser<Type> 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<literal_node_t>(v);
|
|
}
|
|
|
|
inline expression_node_ptr operator()(const std::string& s) const
|
|
{
|
|
return node_allocator_->allocate<string_literal_node_t>(s);
|
|
}
|
|
|
|
inline expression_node_ptr operator()(std::string& s, range_t& rp) const
|
|
{
|
|
return node_allocator_->allocate_rr<string_range_node_t>(s,rp);
|
|
}
|
|
|
|
inline expression_node_ptr operator()(const std::string& s, range_t& rp) const
|
|
{
|
|
return node_allocator_->allocate_tt<const_string_range_node_t>(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<generic_string_range_node_t>(branch,rp);
|
|
else
|
|
return error_node();
|
|
}
|
|
|
|
inline bool unary_optimizable(const details::operator_type& operation) const
|
|
{
|
|
return (details::e_abs == operation) || (details::e_acos == operation) ||
|
|
(details::e_acosh == operation) || (details::e_asin == operation) ||
|
|
(details::e_asinh == operation) || (details::e_atan == operation) ||
|
|
(details::e_atanh == operation) || (details::e_ceil == operation) ||
|
|
(details::e_cos == operation) || (details::e_cosh == operation) ||
|
|
(details::e_exp == operation) || (details::e_expm1 == operation) ||
|
|
(details::e_floor == operation) || (details::e_log == operation) ||
|
|
(details::e_log10 == operation) || (details::e_log2 == operation) ||
|
|
(details::e_log1p == operation) || (details::e_neg == operation) ||
|
|
(details::e_pos == operation) || (details::e_round == operation) ||
|
|
(details::e_sin == operation) || (details::e_sinc == operation) ||
|
|
(details::e_sinh == operation) || (details::e_sqrt == operation) ||
|
|
(details::e_tan == operation) || (details::e_tanh == operation) ||
|
|
(details::e_cot == operation) || (details::e_sec == operation) ||
|
|
(details::e_csc == operation) || (details::e_r2d == operation) ||
|
|
(details::e_d2r == operation) || (details::e_d2g == operation) ||
|
|
(details::e_g2d == operation) || (details::e_notl == operation) ||
|
|
(details::e_sgn == operation) || (details::e_erf == operation) ||
|
|
(details::e_erfc == operation) || (details::e_ncdf == operation) ||
|
|
(details::e_frac == operation) || (details::e_trunc == operation);
|
|
}
|
|
|
|
inline bool sf3_optimizable(const std::string& sf3id, trinary_functor_t& tfunc)
|
|
{
|
|
typename sf3_map_t::iterator itr = sf3_map_->find(sf3id);
|
|
|
|
if (sf3_map_->end() == itr)
|
|
return false;
|
|
else
|
|
tfunc = itr->second.first;
|
|
|
|
return true;
|
|
}
|
|
|
|
inline bool sf4_optimizable(const std::string& sf4id, quaternary_functor_t& qfunc)
|
|
{
|
|
typename sf4_map_t::iterator itr = sf4_map_->find(sf4id);
|
|
|
|
if (sf4_map_->end() == itr)
|
|
return false;
|
|
else
|
|
qfunc = itr->second.first;
|
|
|
|
return true;
|
|
}
|
|
|
|
inline bool sf3_optimizable(const std::string& sf3id, details::operator_type& operation)
|
|
{
|
|
typename sf3_map_t::iterator itr = sf3_map_->find(sf3id);
|
|
|
|
if (sf3_map_->end() == itr)
|
|
return false;
|
|
else
|
|
operation = itr->second.second;
|
|
|
|
return true;
|
|
}
|
|
|
|
inline bool sf4_optimizable(const std::string& sf4id, details::operator_type& operation)
|
|
{
|
|
typename sf4_map_t::iterator itr = sf4_map_->find(sf4id);
|
|
|
|
if (sf4_map_->end() == itr)
|
|
return false;
|
|
else
|
|
operation = itr->second.second;
|
|
|
|
return true;
|
|
}
|
|
|
|
inline expression_node_ptr operator()(const details::operator_type& operation, expression_node_ptr (&branch)[1])
|
|
{
|
|
if (0 == branch[0])
|
|
return error_node();
|
|
else if (details::is_null_node(branch[0]))
|
|
return branch[0];
|
|
else if (details::is_break_node(branch[0]))
|
|
return error_node();
|
|
else if (details::is_continue_node(branch[0]))
|
|
return error_node();
|
|
else if (details::is_constant_node(branch[0]))
|
|
return synthesize_expression<unary_node_t,1>(operation,branch);
|
|
else if (unary_optimizable(operation) && details::is_variable_node(branch[0]))
|
|
return synthesize_uv_expression(operation,branch);
|
|
else if (unary_optimizable(operation) && details::is_ivector_node(branch[0]))
|
|
return synthesize_uvec_expression(operation,branch);
|
|
else
|
|
return synthesize_unary_expression(operation,branch);
|
|
}
|
|
|
|
inline bool is_assignment_operation(const details::operator_type& operation) const
|
|
{
|
|
return (details::e_addass == operation) ||
|
|
(details::e_subass == operation) ||
|
|
(details::e_mulass == operation) ||
|
|
(details::e_divass == operation) ||
|
|
(details::e_modass == operation) ;
|
|
}
|
|
|
|
#ifndef exprtk_disable_string_capabilities
|
|
inline bool valid_string_operation(const details::operator_type& operation) const
|
|
{
|
|
return (details::e_add == operation) ||
|
|
(details::e_lt == operation) ||
|
|
(details::e_lte == operation) ||
|
|
(details::e_gt == operation) ||
|
|
(details::e_gte == operation) ||
|
|
(details::e_eq == operation) ||
|
|
(details::e_ne == operation) ||
|
|
(details::e_in == operation) ||
|
|
(details::e_like == operation) ||
|
|
(details::e_ilike == operation) ||
|
|
(details::e_assign == operation) ||
|
|
(details::e_addass == operation) ||
|
|
(details::e_swap == operation) ;
|
|
}
|
|
#else
|
|
inline bool valid_string_operation(const details::operator_type&) const
|
|
{
|
|
return false;
|
|
}
|
|
#endif
|
|
|
|
inline std::string to_str(const details::operator_type& operation) const
|
|
{
|
|
switch (operation)
|
|
{
|
|
case details::e_add : return "+";
|
|
case details::e_sub : return "-";
|
|
case details::e_mul : return "*";
|
|
case details::e_div : return "/";
|
|
case details::e_mod : return "%";
|
|
case details::e_pow : return "^";
|
|
case details::e_lt : return "<";
|
|
case details::e_lte : return "<=";
|
|
case details::e_gt : return ">";
|
|
case details::e_gte : return ">=";
|
|
case details::e_eq : return "==";
|
|
case details::e_ne : return "!=";
|
|
case details::e_and : return "and";
|
|
case details::e_nand : return "nand";
|
|
case details::e_or : return "or";
|
|
case details::e_nor : return "nor";
|
|
case details::e_xor : return "xor";
|
|
case details::e_xnor : return "xnor";
|
|
default : return "UNKNOWN";
|
|
}
|
|
}
|
|
|
|
inline bool operation_optimizable(const details::operator_type& operation) const
|
|
{
|
|
return (details::e_add == operation) ||
|
|
(details::e_sub == operation) ||
|
|
(details::e_mul == operation) ||
|
|
(details::e_div == operation) ||
|
|
(details::e_mod == operation) ||
|
|
(details::e_pow == operation) ||
|
|
(details::e_lt == operation) ||
|
|
(details::e_lte == operation) ||
|
|
(details::e_gt == operation) ||
|
|
(details::e_gte == operation) ||
|
|
(details::e_eq == operation) ||
|
|
(details::e_ne == operation) ||
|
|
(details::e_and == operation) ||
|
|
(details::e_nand == operation) ||
|
|
(details::e_or == operation) ||
|
|
(details::e_nor == operation) ||
|
|
(details::e_xor == operation) ||
|
|
(details::e_xnor == operation) ;
|
|
}
|
|
|
|
inline std::string branch_to_id(expression_node_ptr branch)
|
|
{
|
|
static const std::string null_str ("(null)" );
|
|
static const std::string const_str ("(c)" );
|
|
static const std::string var_str ("(v)" );
|
|
static const std::string vov_str ("(vov)" );
|
|
static const std::string cov_str ("(cov)" );
|
|
static const std::string voc_str ("(voc)" );
|
|
static const std::string str_str ("(s)" );
|
|
static const std::string strrng_str ("(rngs)" );
|
|
static const std::string cs_str ("(cs)" );
|
|
static const std::string cstrrng_str("(crngs)");
|
|
|
|
if (details::is_null_node(branch))
|
|
return null_str;
|
|
else if (details::is_constant_node(branch))
|
|
return const_str;
|
|
else if (details::is_variable_node(branch))
|
|
return var_str;
|
|
else if (details::is_vov_node(branch))
|
|
return vov_str;
|
|
else if (details::is_cov_node(branch))
|
|
return cov_str;
|
|
else if (details::is_voc_node(branch))
|
|
return voc_str;
|
|
else if (details::is_string_node(branch))
|
|
return str_str;
|
|
else if (details::is_const_string_node(branch))
|
|
return cs_str;
|
|
else if (details::is_string_range_node(branch))
|
|
return strrng_str;
|
|
else if (details::is_const_string_range_node(branch))
|
|
return cstrrng_str;
|
|
else if (details::is_t0ot1ot2_node(branch))
|
|
return "(" + dynamic_cast<details::T0oT1oT2_base_node<T>*>(branch)->type_id() + ")";
|
|
else if (details::is_t0ot1ot2ot3_node(branch))
|
|
return "(" + dynamic_cast<details::T0oT1oT2oT3_base_node<T>*>(branch)->type_id() + ")";
|
|
else
|
|
return "ERROR";
|
|
}
|
|
|
|
inline std::string branch_to_id(expression_node_ptr (&branch)[2])
|
|
{
|
|
return branch_to_id(branch[0]) + std::string("o") + branch_to_id(branch[1]);
|
|
}
|
|
|
|
inline bool cov_optimizable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const
|
|
{
|
|
if (!operation_optimizable(operation))
|
|
return false;
|
|
else
|
|
return (details::is_constant_node(branch[0]) && details::is_variable_node(branch[1]));
|
|
}
|
|
|
|
inline bool voc_optimizable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const
|
|
{
|
|
if (!operation_optimizable(operation))
|
|
return false;
|
|
else
|
|
return (details::is_variable_node(branch[0]) && details::is_constant_node(branch[1]));
|
|
}
|
|
|
|
inline bool vov_optimizable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const
|
|
{
|
|
if (!operation_optimizable(operation))
|
|
return false;
|
|
else
|
|
return (details::is_variable_node(branch[0]) && details::is_variable_node(branch[1]));
|
|
}
|
|
|
|
inline bool cob_optimizable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const
|
|
{
|
|
if (!operation_optimizable(operation))
|
|
return false;
|
|
else
|
|
return (details::is_constant_node(branch[0]) && !details::is_constant_node(branch[1]));
|
|
}
|
|
|
|
inline bool boc_optimizable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const
|
|
{
|
|
if (!operation_optimizable(operation))
|
|
return false;
|
|
else
|
|
return (!details::is_constant_node(branch[0]) && details::is_constant_node(branch[1]));
|
|
}
|
|
|
|
inline bool cocob_optimizable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const
|
|
{
|
|
if (
|
|
(details::e_add == operation) ||
|
|
(details::e_sub == operation) ||
|
|
(details::e_mul == operation) ||
|
|
(details::e_div == operation)
|
|
)
|
|
{
|
|
return (details::is_constant_node(branch[0]) && details::is_cob_node(branch[1])) ||
|
|
(details::is_constant_node(branch[1]) && details::is_cob_node(branch[0]));
|
|
}
|
|
else
|
|
return false;
|
|
}
|
|
|
|
inline bool coboc_optimizable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const
|
|
{
|
|
if (
|
|
(details::e_add == operation) ||
|
|
(details::e_sub == operation) ||
|
|
(details::e_mul == operation) ||
|
|
(details::e_div == operation)
|
|
)
|
|
{
|
|
return (details::is_constant_node(branch[0]) && details::is_boc_node(branch[1])) ||
|
|
(details::is_constant_node(branch[1]) && details::is_boc_node(branch[0]));
|
|
}
|
|
else
|
|
return false;
|
|
}
|
|
|
|
inline bool uvouv_optimizable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const
|
|
{
|
|
if (!operation_optimizable(operation))
|
|
return false;
|
|
else
|
|
return (details::is_uv_node(branch[0]) && details::is_uv_node(branch[1]));
|
|
}
|
|
|
|
inline bool vob_optimizable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const
|
|
{
|
|
if (!operation_optimizable(operation))
|
|
return false;
|
|
else
|
|
return (details::is_variable_node(branch[0]) && !details::is_variable_node(branch[1]));
|
|
}
|
|
|
|
inline bool bov_optimizable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const
|
|
{
|
|
if (!operation_optimizable(operation))
|
|
return false;
|
|
else
|
|
return (!details::is_variable_node(branch[0]) && details::is_variable_node(branch[1]));
|
|
}
|
|
|
|
inline bool binext_optimizable(const details::operator_type& operation, expression_node_ptr (&branch)[2]) const
|
|
{
|
|
if (!operation_optimizable(operation))
|
|
return false;
|
|
else
|
|
return (!details::is_constant_node(branch[0]) || !details::is_constant_node(branch[1]));
|
|
}
|
|
|
|
inline bool is_invalid_assignment_op(const details::operator_type& operation, expression_node_ptr (&branch)[2])
|
|
{
|
|
if (is_assignment_operation(operation))
|
|
{
|
|
const bool b1_is_genstring = details::is_generally_string_node(branch[1]);
|
|
|
|
if (details::is_string_node(branch[0]))
|
|
return !b1_is_genstring;
|
|
else
|
|
return (
|
|
!details::is_variable_node (branch[0]) &&
|
|
!details::is_vector_elem_node(branch[0]) &&
|
|
!details::is_vector_node (branch[0])
|
|
)
|
|
|| b1_is_genstring;
|
|
}
|
|
else
|
|
return false;
|
|
}
|
|
|
|
inline bool is_invalid_break_continue_op(expression_node_ptr (&branch)[2])
|
|
{
|
|
return (
|
|
details::is_break_node (branch[0]) ||
|
|
details::is_break_node (branch[1]) ||
|
|
details::is_continue_node(branch[0]) ||
|
|
details::is_continue_node(branch[1])
|
|
);
|
|
}
|
|
|
|
inline bool is_invalid_string_op(const details::operator_type& operation, expression_node_ptr (&branch)[2])
|
|
{
|
|
const bool b0_string = is_generally_string_node(branch[0]);
|
|
const bool b1_string = is_generally_string_node(branch[1]);
|
|
|
|
bool result = false;
|
|
|
|
if (b0_string ^ b1_string)
|
|
result = true;
|
|
else if (!valid_string_operation(operation) && b0_string && b1_string)
|
|
result = true;
|
|
|
|
if (result)
|
|
{
|
|
parser_->set_synthesis_error("Invalid string operation");
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
inline bool is_invalid_string_op(const details::operator_type& operation, expression_node_ptr (&branch)[3])
|
|
{
|
|
const bool b0_string = is_generally_string_node(branch[0]);
|
|
const bool b1_string = is_generally_string_node(branch[1]);
|
|
const bool b2_string = is_generally_string_node(branch[2]);
|
|
|
|
bool result = false;
|
|
|
|
if ((b0_string ^ b1_string) || (b1_string ^ b2_string))
|
|
result = true;
|
|
else if ((details::e_inrange != operation) && b0_string && b1_string && b2_string)
|
|
result = true;
|
|
|
|
if (result)
|
|
{
|
|
parser_->set_synthesis_error("Invalid string operation");
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
inline bool is_string_operation(const details::operator_type& operation, expression_node_ptr (&branch)[2])
|
|
{
|
|
const bool b0_string = is_generally_string_node(branch[0]);
|
|
const bool b1_string = is_generally_string_node(branch[1]);
|
|
|
|
return (b0_string && b1_string && valid_string_operation(operation));
|
|
}
|
|
|
|
inline bool is_string_operation(const details::operator_type& operation, expression_node_ptr (&branch)[3])
|
|
{
|
|
const bool b0_string = is_generally_string_node(branch[0]);
|
|
const bool b1_string = is_generally_string_node(branch[1]);
|
|
const bool b2_string = is_generally_string_node(branch[2]);
|
|
|
|
return (b0_string && b1_string && b2_string && (details::e_inrange == operation));
|
|
}
|
|
|
|
#ifndef exprtk_disable_sc_andor
|
|
inline bool is_shortcircuit_expression(const details::operator_type& operation)
|
|
{
|
|
return (
|
|
(details::e_scand == operation) ||
|
|
(details::e_scor == operation)
|
|
);
|
|
}
|
|
#else
|
|
inline bool is_shortcircuit_expression(const details::operator_type&)
|
|
{
|
|
return false;
|
|
}
|
|
#endif
|
|
|
|
inline bool is_null_present(expression_node_ptr (&branch)[2])
|
|
{
|
|
return (
|
|
details::is_null_node(branch[0]) ||
|
|
details::is_null_node(branch[1])
|
|
);
|
|
}
|
|
|
|
inline bool is_vector_eqineq_operation(const details::operator_type& operation, expression_node_ptr (&branch)[2])
|
|
{
|
|
if (!is_ivector_node(branch[0]) && !is_ivector_node(branch[1]))
|
|
return false;
|
|
else
|
|
return (
|
|
(details::e_lt == operation) ||
|
|
(details::e_lte == operation) ||
|
|
(details::e_gt == operation) ||
|
|
(details::e_gte == operation) ||
|
|
(details::e_eq == operation) ||
|
|
(details::e_ne == operation)
|
|
);
|
|
}
|
|
|
|
inline bool is_vector_arithmetic_operation(const details::operator_type& operation, expression_node_ptr (&branch)[2])
|
|
{
|
|
if (!is_ivector_node(branch[0]) && !is_ivector_node(branch[1]))
|
|
return false;
|
|
else
|
|
return (
|
|
(details::e_add == operation) ||
|
|
(details::e_sub == operation) ||
|
|
(details::e_mul == operation) ||
|
|
(details::e_div == operation) ||
|
|
(details::e_pow == operation)
|
|
);
|
|
}
|
|
|
|
inline expression_node_ptr operator()(const details::operator_type& operation, expression_node_ptr (&branch)[2])
|
|
{
|
|
if ((0 == branch[0]) || (0 == branch[1]))
|
|
return error_node();
|
|
else if (is_invalid_string_op(operation,branch))
|
|
return error_node();
|
|
else if (is_invalid_assignment_op(operation,branch))
|
|
return error_node();
|
|
else if (is_invalid_break_continue_op(branch))
|
|
return error_node();
|
|
else if (details::e_assign == operation)
|
|
return synthesize_assignment_expression(operation,branch);
|
|
else if (details::e_swap == operation)
|
|
return synthesize_swap_expression(branch);
|
|
else if (is_assignment_operation(operation))
|
|
return synthesize_assignment_operation_expression(operation,branch);
|
|
else if (is_vector_eqineq_operation(operation,branch))
|
|
return synthesize_veceqineq_operation_expression(operation,branch);
|
|
else if (is_vector_arithmetic_operation(operation,branch))
|
|
return synthesize_vecarithmetic_operation_expression(operation,branch);
|
|
else if (is_shortcircuit_expression(operation))
|
|
return synthesize_shortcircuit_expression(operation,branch);
|
|
else if (is_string_operation(operation,branch))
|
|
return synthesize_string_expression(operation,branch);
|
|
else if (is_null_present(branch))
|
|
return synthesize_null_expression(operation,branch);
|
|
|
|
expression_node_ptr result = error_node();
|
|
|
|
#ifndef exprtk_disable_enhanced_features
|
|
if (synthesize_expression(operation,branch,result))
|
|
return result;
|
|
else
|
|
#endif
|
|
|
|
{
|
|
/*
|
|
Possible reductions:
|
|
1. c o cob -> cob
|
|
2. cob o c -> cob
|
|
3. c o boc -> boc
|
|
4. boc o c -> boc
|
|
*/
|
|
result = error_node();
|
|
|
|
if (cocob_optimizable(operation,branch))
|
|
result = synthesize_cocob_expression::process(*this,operation,branch);
|
|
else if (coboc_optimizable(operation,branch) && (0 == result))
|
|
result = synthesize_coboc_expression::process(*this,operation,branch);
|
|
|
|
if (result)
|
|
return result;
|
|
}
|
|
|
|
if (uvouv_optimizable(operation,branch))
|
|
return synthesize_uvouv_expression(operation,branch);
|
|
else if (vob_optimizable(operation,branch))
|
|
return synthesize_vob_expression::process(*this,operation,branch);
|
|
else if (bov_optimizable(operation,branch))
|
|
return synthesize_bov_expression::process(*this,operation,branch);
|
|
else if (cob_optimizable(operation,branch))
|
|
return synthesize_cob_expression::process(*this,operation,branch);
|
|
else if (boc_optimizable(operation,branch))
|
|
return synthesize_boc_expression::process(*this,operation,branch);
|
|
#ifndef exprtk_disable_enhanced_features
|
|
else if (cov_optimizable(operation,branch))
|
|
return synthesize_cov_expression::process(*this,operation,branch);
|
|
#endif
|
|
else if (binext_optimizable(operation,branch))
|
|
return synthesize_binary_ext_expression::process(*this,operation,branch);
|
|
else
|
|
return synthesize_expression<binary_node_t,2>(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<trinary_node_t,3>(operation,branch);
|
|
}
|
|
|
|
inline expression_node_ptr operator()(const details::operator_type& operation, expression_node_ptr (&branch)[4])
|
|
{
|
|
return synthesize_expression<quaternary_node_t,4>(operation,branch);
|
|
}
|
|
|
|
inline expression_node_ptr operator()(const details::operator_type& operation, expression_node_ptr (&branch)[5])
|
|
{
|
|
return synthesize_expression<quinary_node_t,5>(operation,branch);
|
|
}
|
|
|
|
inline expression_node_ptr operator()(const details::operator_type& operation, expression_node_ptr (&branch)[6])
|
|
{
|
|
return synthesize_expression<senary_node_t,6>(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<Type>::operator()(operation,branch);
|
|
}
|
|
}
|
|
|
|
inline expression_node_ptr conditional(expression_node_ptr condition,
|
|
expression_node_ptr consequent,
|
|
expression_node_ptr alternative) const
|
|
{
|
|
if ((0 == condition) || (0 == consequent))
|
|
{
|
|
free_node(*node_allocator_,condition );
|
|
free_node(*node_allocator_,consequent );
|
|
free_node(*node_allocator_,alternative);
|
|
|
|
return error_node();
|
|
}
|
|
// Can the condition be immediately evaluated? if so optimize.
|
|
else if (details::is_constant_node(condition))
|
|
{
|
|
// True branch
|
|
if (details::is_true(condition))
|
|
{
|
|
free_node(*node_allocator_,condition );
|
|
free_node(*node_allocator_,alternative);
|
|
|
|
return consequent;
|
|
}
|
|
// False branch
|
|
else
|
|
{
|
|
free_node(*node_allocator_,condition);
|
|
free_node(*node_allocator_,consequent);
|
|
|
|
if (alternative)
|
|
return alternative;
|
|
else
|
|
return node_allocator_->allocate<details::null_node<T> >();
|
|
}
|
|
}
|
|
else if ((0 != consequent) && (0 != alternative))
|
|
{
|
|
return node_allocator_->allocate<conditional_node_t>(condition,consequent,alternative);
|
|
}
|
|
else
|
|
return node_allocator_->allocate<cons_conditional_node_t>(condition,consequent);
|
|
}
|
|
|
|
inline expression_node_ptr while_loop(expression_node_ptr& condition,
|
|
expression_node_ptr& branch,
|
|
const bool brkcont = false) const
|
|
{
|
|
if (!brkcont && details::is_constant_node(condition))
|
|
{
|
|
expression_node_ptr result = error_node();
|
|
if (details::is_true(condition))
|
|
// Infinite loops are not allowed.
|
|
result = error_node();
|
|
else
|
|
result = node_allocator_->allocate<details::null_node<Type> >();
|
|
|
|
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<while_loop_node_t>(condition,branch);
|
|
#ifndef exprtk_disable_break_continue
|
|
else
|
|
return node_allocator_->allocate<while_loop_bc_node_t>(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<repeat_until_loop_node_t>(condition,branch);
|
|
#ifndef exprtk_disable_break_continue
|
|
else
|
|
return node_allocator_->allocate<repeat_until_loop_bc_node_t>(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<details::null_node<Type> >();
|
|
|
|
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<for_loop_node_t>(initialiser,
|
|
condition,
|
|
incrementor,
|
|
loop_body);
|
|
#ifndef exprtk_disable_break_continue
|
|
else
|
|
return node_allocator_->allocate<for_loop_bc_node_t>(initialiser,
|
|
condition,
|
|
incrementor,
|
|
loop_body);
|
|
#else
|
|
return error_node();
|
|
#endif
|
|
}
|
|
|
|
template <typename Allocator,
|
|
template <typename,typename> class Sequence>
|
|
inline expression_node_ptr const_optimize_switch(Sequence<expression_node_ptr,Allocator>& 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 <typename Allocator,
|
|
template <typename,typename> class Sequence>
|
|
inline expression_node_ptr const_optimize_mswitch(Sequence<expression_node_ptr,Allocator>& 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<literal_node_t>(zero);
|
|
}
|
|
|
|
for (std::size_t i = 0; i < arg_list.size(); ++i)
|
|
{
|
|
expression_node_ptr& current_expr = arg_list[i];
|
|
|
|
if (current_expr && (current_expr != result))
|
|
{
|
|
free_node(*node_allocator_,current_expr);
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
template <typename Allocator,
|
|
template <typename,typename> class Sequence>
|
|
inline expression_node_ptr switch_statement(Sequence<expression_node_ptr,Allocator>& arg_list)
|
|
{
|
|
if (!all_nodes_valid(arg_list))
|
|
{
|
|
details::free_all_nodes(*node_allocator_,arg_list);
|
|
|
|
return error_node();
|
|
}
|
|
else if (is_constant_foldable(arg_list))
|
|
return const_optimize_switch(arg_list);
|
|
else
|
|
return node_allocator_->allocate<details::switch_node<Type> >(arg_list);
|
|
}
|
|
|
|
template <typename Allocator,
|
|
template <typename,typename> class Sequence>
|
|
inline expression_node_ptr multi_switch_statement(Sequence<expression_node_ptr,Allocator>& arg_list)
|
|
{
|
|
if (!all_nodes_valid(arg_list))
|
|
{
|
|
details::free_all_nodes(*node_allocator_,arg_list);
|
|
|
|
return error_node();
|
|
}
|
|
else if (is_constant_foldable(arg_list))
|
|
return const_optimize_mswitch(arg_list);
|
|
else
|
|
return node_allocator_->allocate<details::multi_switch_node<Type> >(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<details::variable_node<T>*>(branch[0])->ref();
|
|
|
|
switch (operation)
|
|
{
|
|
#define case_stmt(op0,op1) \
|
|
case op0 : return node_allocator_-> \
|
|
allocate<typename details::unary_variable_node<Type,op1<Type> > >(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<typename details::unary_vector_node<Type,op1<Type> > > \
|
|
(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<typename details::unary_branch_node<Type,op1<Type> > >(branch[0]); \
|
|
|
|
unary_opr_switch_statements
|
|
#undef case_stmt
|
|
default : return error_node();
|
|
}
|
|
}
|
|
|
|
inline expression_node_ptr const_optimize_sf3(const details::operator_type& operation,
|
|
expression_node_ptr (&branch)[3])
|
|
{
|
|
expression_node_ptr temp_node = error_node();
|
|
|
|
switch (operation)
|
|
{
|
|
#define case_stmt(op0,op1) \
|
|
case op0 : temp_node = node_allocator_-> \
|
|
allocate<details::sf3_node<Type,op1<Type> > > \
|
|
(operation,branch); \
|
|
break; \
|
|
|
|
case_stmt(details::e_sf00,details::sf00_op) case_stmt(details::e_sf01,details::sf01_op)
|
|
case_stmt(details::e_sf02,details::sf02_op) case_stmt(details::e_sf03,details::sf03_op)
|
|
case_stmt(details::e_sf04,details::sf04_op) case_stmt(details::e_sf05,details::sf05_op)
|
|
case_stmt(details::e_sf06,details::sf06_op) case_stmt(details::e_sf07,details::sf07_op)
|
|
case_stmt(details::e_sf08,details::sf08_op) case_stmt(details::e_sf09,details::sf09_op)
|
|
case_stmt(details::e_sf10,details::sf10_op) case_stmt(details::e_sf11,details::sf11_op)
|
|
case_stmt(details::e_sf12,details::sf12_op) case_stmt(details::e_sf13,details::sf13_op)
|
|
case_stmt(details::e_sf14,details::sf14_op) case_stmt(details::e_sf15,details::sf15_op)
|
|
case_stmt(details::e_sf16,details::sf16_op) case_stmt(details::e_sf17,details::sf17_op)
|
|
case_stmt(details::e_sf18,details::sf18_op) case_stmt(details::e_sf19,details::sf19_op)
|
|
case_stmt(details::e_sf20,details::sf20_op) case_stmt(details::e_sf21,details::sf21_op)
|
|
case_stmt(details::e_sf22,details::sf22_op) case_stmt(details::e_sf23,details::sf23_op)
|
|
case_stmt(details::e_sf24,details::sf24_op) case_stmt(details::e_sf25,details::sf25_op)
|
|
case_stmt(details::e_sf26,details::sf26_op) case_stmt(details::e_sf27,details::sf27_op)
|
|
case_stmt(details::e_sf28,details::sf28_op) case_stmt(details::e_sf29,details::sf29_op)
|
|
case_stmt(details::e_sf30,details::sf30_op) case_stmt(details::e_sf31,details::sf31_op)
|
|
case_stmt(details::e_sf32,details::sf32_op) case_stmt(details::e_sf33,details::sf33_op)
|
|
case_stmt(details::e_sf34,details::sf34_op) case_stmt(details::e_sf35,details::sf35_op)
|
|
case_stmt(details::e_sf36,details::sf36_op) case_stmt(details::e_sf37,details::sf37_op)
|
|
case_stmt(details::e_sf38,details::sf38_op) case_stmt(details::e_sf39,details::sf39_op)
|
|
case_stmt(details::e_sf40,details::sf40_op) case_stmt(details::e_sf41,details::sf41_op)
|
|
case_stmt(details::e_sf42,details::sf42_op) case_stmt(details::e_sf43,details::sf43_op)
|
|
case_stmt(details::e_sf44,details::sf44_op) case_stmt(details::e_sf45,details::sf45_op)
|
|
case_stmt(details::e_sf46,details::sf46_op) case_stmt(details::e_sf47,details::sf47_op)
|
|
#undef case_stmt
|
|
default : return error_node();
|
|
}
|
|
|
|
T v = temp_node->value();
|
|
node_allocator_->free(temp_node);
|
|
details::free_node(*node_allocator_,temp_node);
|
|
|
|
return node_allocator_->allocate<literal_node_t>(v);
|
|
}
|
|
|
|
inline expression_node_ptr varnode_optimize_sf3(const details::operator_type& operation, expression_node_ptr (&branch)[3])
|
|
{
|
|
typedef details::variable_node<Type>* variable_ptr;
|
|
|
|
const Type& v0 = static_cast<variable_ptr>(branch[0])->ref();
|
|
const Type& v1 = static_cast<variable_ptr>(branch[1])->ref();
|
|
const Type& v2 = static_cast<variable_ptr>(branch[2])->ref();
|
|
|
|
switch (operation)
|
|
{
|
|
#define case_stmt(op0,op1) \
|
|
case op0 : return node_allocator_-> \
|
|
allocate_rrr<details::sf3_var_node<Type,op1<Type> > > \
|
|
(v0,v1,v2); \
|
|
|
|
case_stmt(details::e_sf00,details::sf00_op) case_stmt(details::e_sf01,details::sf01_op)
|
|
case_stmt(details::e_sf02,details::sf02_op) case_stmt(details::e_sf03,details::sf03_op)
|
|
case_stmt(details::e_sf04,details::sf04_op) case_stmt(details::e_sf05,details::sf05_op)
|
|
case_stmt(details::e_sf06,details::sf06_op) case_stmt(details::e_sf07,details::sf07_op)
|
|
case_stmt(details::e_sf08,details::sf08_op) case_stmt(details::e_sf09,details::sf09_op)
|
|
case_stmt(details::e_sf10,details::sf10_op) case_stmt(details::e_sf11,details::sf11_op)
|
|
case_stmt(details::e_sf12,details::sf12_op) case_stmt(details::e_sf13,details::sf13_op)
|
|
case_stmt(details::e_sf14,details::sf14_op) case_stmt(details::e_sf15,details::sf15_op)
|
|
case_stmt(details::e_sf16,details::sf16_op) case_stmt(details::e_sf17,details::sf17_op)
|
|
case_stmt(details::e_sf18,details::sf18_op) case_stmt(details::e_sf19,details::sf19_op)
|
|
case_stmt(details::e_sf20,details::sf20_op) case_stmt(details::e_sf21,details::sf21_op)
|
|
case_stmt(details::e_sf22,details::sf22_op) case_stmt(details::e_sf23,details::sf23_op)
|
|
case_stmt(details::e_sf24,details::sf24_op) case_stmt(details::e_sf25,details::sf25_op)
|
|
case_stmt(details::e_sf26,details::sf26_op) case_stmt(details::e_sf27,details::sf27_op)
|
|
case_stmt(details::e_sf28,details::sf28_op) case_stmt(details::e_sf29,details::sf29_op)
|
|
case_stmt(details::e_sf30,details::sf30_op) case_stmt(details::e_sf31,details::sf31_op)
|
|
case_stmt(details::e_sf32,details::sf32_op) case_stmt(details::e_sf33,details::sf33_op)
|
|
case_stmt(details::e_sf34,details::sf34_op) case_stmt(details::e_sf35,details::sf35_op)
|
|
case_stmt(details::e_sf36,details::sf36_op) case_stmt(details::e_sf37,details::sf37_op)
|
|
case_stmt(details::e_sf38,details::sf38_op) case_stmt(details::e_sf39,details::sf39_op)
|
|
case_stmt(details::e_sf40,details::sf40_op) case_stmt(details::e_sf41,details::sf41_op)
|
|
case_stmt(details::e_sf42,details::sf42_op) case_stmt(details::e_sf43,details::sf43_op)
|
|
case_stmt(details::e_sf44,details::sf44_op) case_stmt(details::e_sf45,details::sf45_op)
|
|
case_stmt(details::e_sf46,details::sf46_op) case_stmt(details::e_sf47,details::sf47_op)
|
|
#undef case_stmt
|
|
default : return error_node();
|
|
}
|
|
}
|
|
|
|
inline expression_node_ptr special_function(const details::operator_type& operation, expression_node_ptr (&branch)[3])
|
|
{
|
|
if (!all_nodes_valid(branch))
|
|
return error_node();
|
|
else if (is_constant_foldable(branch))
|
|
return const_optimize_sf3(operation,branch);
|
|
else if (all_nodes_variables(branch))
|
|
return varnode_optimize_sf3(operation,branch);
|
|
else
|
|
{
|
|
switch (operation)
|
|
{
|
|
#define case_stmt(op0,op1) \
|
|
case op0 : return node_allocator_-> \
|
|
allocate<details::sf3_node<Type,op1<Type> > >(operation,branch); \
|
|
|
|
case_stmt(details::e_sf00,details::sf00_op) case_stmt(details::e_sf01,details::sf01_op)
|
|
case_stmt(details::e_sf02,details::sf02_op) case_stmt(details::e_sf03,details::sf03_op)
|
|
case_stmt(details::e_sf04,details::sf04_op) case_stmt(details::e_sf05,details::sf05_op)
|
|
case_stmt(details::e_sf06,details::sf06_op) case_stmt(details::e_sf07,details::sf07_op)
|
|
case_stmt(details::e_sf08,details::sf08_op) case_stmt(details::e_sf09,details::sf09_op)
|
|
case_stmt(details::e_sf10,details::sf10_op) case_stmt(details::e_sf11,details::sf11_op)
|
|
case_stmt(details::e_sf12,details::sf12_op) case_stmt(details::e_sf13,details::sf13_op)
|
|
case_stmt(details::e_sf14,details::sf14_op) case_stmt(details::e_sf15,details::sf15_op)
|
|
case_stmt(details::e_sf16,details::sf16_op) case_stmt(details::e_sf17,details::sf17_op)
|
|
case_stmt(details::e_sf18,details::sf18_op) case_stmt(details::e_sf19,details::sf19_op)
|
|
case_stmt(details::e_sf20,details::sf20_op) case_stmt(details::e_sf21,details::sf21_op)
|
|
case_stmt(details::e_sf22,details::sf22_op) case_stmt(details::e_sf23,details::sf23_op)
|
|
case_stmt(details::e_sf24,details::sf24_op) case_stmt(details::e_sf25,details::sf25_op)
|
|
case_stmt(details::e_sf26,details::sf26_op) case_stmt(details::e_sf27,details::sf27_op)
|
|
case_stmt(details::e_sf28,details::sf28_op) case_stmt(details::e_sf29,details::sf29_op)
|
|
case_stmt(details::e_sf30,details::sf30_op) case_stmt(details::e_sf31,details::sf31_op)
|
|
case_stmt(details::e_sf32,details::sf32_op) case_stmt(details::e_sf33,details::sf33_op)
|
|
case_stmt(details::e_sf34,details::sf34_op) case_stmt(details::e_sf35,details::sf35_op)
|
|
case_stmt(details::e_sf36,details::sf36_op) case_stmt(details::e_sf37,details::sf37_op)
|
|
case_stmt(details::e_sf38,details::sf38_op) case_stmt(details::e_sf39,details::sf39_op)
|
|
case_stmt(details::e_sf40,details::sf40_op) case_stmt(details::e_sf41,details::sf41_op)
|
|
case_stmt(details::e_sf42,details::sf42_op) case_stmt(details::e_sf43,details::sf43_op)
|
|
case_stmt(details::e_sf44,details::sf44_op) case_stmt(details::e_sf45,details::sf45_op)
|
|
case_stmt(details::e_sf46,details::sf46_op) case_stmt(details::e_sf47,details::sf47_op)
|
|
#undef case_stmt
|
|
default : return error_node();
|
|
}
|
|
}
|
|
}
|
|
|
|
inline expression_node_ptr const_optimize_sf4(const details::operator_type& operation, expression_node_ptr (&branch)[4])
|
|
{
|
|
expression_node_ptr temp_node = error_node();
|
|
|
|
switch (operation)
|
|
{
|
|
#define case_stmt(op0,op1) \
|
|
case op0 : temp_node = node_allocator_-> \
|
|
allocate<details::sf4_node<Type,op1<Type> > >(operation,branch); \
|
|
break; \
|
|
|
|
case_stmt(details::e_sf48,details::sf48_op) case_stmt(details::e_sf49,details::sf49_op)
|
|
case_stmt(details::e_sf50,details::sf50_op) case_stmt(details::e_sf51,details::sf51_op)
|
|
case_stmt(details::e_sf52,details::sf52_op) case_stmt(details::e_sf53,details::sf53_op)
|
|
case_stmt(details::e_sf54,details::sf54_op) case_stmt(details::e_sf55,details::sf55_op)
|
|
case_stmt(details::e_sf56,details::sf56_op) case_stmt(details::e_sf57,details::sf57_op)
|
|
case_stmt(details::e_sf58,details::sf58_op) case_stmt(details::e_sf59,details::sf59_op)
|
|
case_stmt(details::e_sf60,details::sf60_op) case_stmt(details::e_sf61,details::sf61_op)
|
|
case_stmt(details::e_sf62,details::sf62_op) case_stmt(details::e_sf63,details::sf63_op)
|
|
case_stmt(details::e_sf64,details::sf64_op) case_stmt(details::e_sf65,details::sf65_op)
|
|
case_stmt(details::e_sf66,details::sf66_op) case_stmt(details::e_sf67,details::sf67_op)
|
|
case_stmt(details::e_sf68,details::sf68_op) case_stmt(details::e_sf69,details::sf69_op)
|
|
case_stmt(details::e_sf70,details::sf70_op) case_stmt(details::e_sf71,details::sf71_op)
|
|
case_stmt(details::e_sf72,details::sf72_op) case_stmt(details::e_sf73,details::sf73_op)
|
|
case_stmt(details::e_sf74,details::sf74_op) case_stmt(details::e_sf75,details::sf75_op)
|
|
case_stmt(details::e_sf76,details::sf76_op) case_stmt(details::e_sf77,details::sf77_op)
|
|
case_stmt(details::e_sf78,details::sf78_op) case_stmt(details::e_sf79,details::sf79_op)
|
|
case_stmt(details::e_sf80,details::sf80_op) case_stmt(details::e_sf81,details::sf81_op)
|
|
case_stmt(details::e_sf82,details::sf82_op) case_stmt(details::e_sf83,details::sf83_op)
|
|
case_stmt(details::e_sf84,details::sf84_op) case_stmt(details::e_sf85,details::sf85_op)
|
|
case_stmt(details::e_sf86,details::sf86_op) case_stmt(details::e_sf87,details::sf87_op)
|
|
case_stmt(details::e_sf88,details::sf88_op) case_stmt(details::e_sf89,details::sf89_op)
|
|
case_stmt(details::e_sf90,details::sf90_op) case_stmt(details::e_sf91,details::sf91_op)
|
|
case_stmt(details::e_sf92,details::sf92_op) case_stmt(details::e_sf93,details::sf93_op)
|
|
case_stmt(details::e_sf94,details::sf94_op) case_stmt(details::e_sf95,details::sf95_op)
|
|
case_stmt(details::e_sf96,details::sf96_op) case_stmt(details::e_sf97,details::sf97_op)
|
|
case_stmt(details::e_sf98,details::sf98_op) case_stmt(details::e_sf99,details::sf99_op)
|
|
#undef case_stmt
|
|
default : return error_node();
|
|
}
|
|
|
|
T v = temp_node->value();
|
|
details::free_node(*node_allocator_,temp_node);
|
|
|
|
return node_allocator_->allocate<literal_node_t>(v);
|
|
}
|
|
|
|
inline expression_node_ptr varnode_optimize_sf4(const details::operator_type& operation, expression_node_ptr (&branch)[4])
|
|
{
|
|
typedef details::variable_node<Type>* variable_ptr;
|
|
|
|
const Type& v0 = static_cast<variable_ptr>(branch[0])->ref();
|
|
const Type& v1 = static_cast<variable_ptr>(branch[1])->ref();
|
|
const Type& v2 = static_cast<variable_ptr>(branch[2])->ref();
|
|
const Type& v3 = static_cast<variable_ptr>(branch[3])->ref();
|
|
|
|
switch (operation)
|
|
{
|
|
#define case_stmt(op0,op1) \
|
|
case op0 : return node_allocator_-> \
|
|
allocate_rrrr<details::sf4_var_node<Type,op1<Type> > >(v0,v1,v2,v3); \
|
|
|
|
case_stmt(details::e_sf48,details::sf48_op) case_stmt(details::e_sf49,details::sf49_op)
|
|
case_stmt(details::e_sf50,details::sf50_op) case_stmt(details::e_sf51,details::sf51_op)
|
|
case_stmt(details::e_sf52,details::sf52_op) case_stmt(details::e_sf53,details::sf53_op)
|
|
case_stmt(details::e_sf54,details::sf54_op) case_stmt(details::e_sf55,details::sf55_op)
|
|
case_stmt(details::e_sf56,details::sf56_op) case_stmt(details::e_sf57,details::sf57_op)
|
|
case_stmt(details::e_sf58,details::sf58_op) case_stmt(details::e_sf59,details::sf59_op)
|
|
case_stmt(details::e_sf60,details::sf60_op) case_stmt(details::e_sf61,details::sf61_op)
|
|
case_stmt(details::e_sf62,details::sf62_op) case_stmt(details::e_sf63,details::sf63_op)
|
|
case_stmt(details::e_sf64,details::sf64_op) case_stmt(details::e_sf65,details::sf65_op)
|
|
case_stmt(details::e_sf66,details::sf66_op) case_stmt(details::e_sf67,details::sf67_op)
|
|
case_stmt(details::e_sf68,details::sf68_op) case_stmt(details::e_sf69,details::sf69_op)
|
|
case_stmt(details::e_sf70,details::sf70_op) case_stmt(details::e_sf71,details::sf71_op)
|
|
case_stmt(details::e_sf72,details::sf72_op) case_stmt(details::e_sf73,details::sf73_op)
|
|
case_stmt(details::e_sf74,details::sf74_op) case_stmt(details::e_sf75,details::sf75_op)
|
|
case_stmt(details::e_sf76,details::sf76_op) case_stmt(details::e_sf77,details::sf77_op)
|
|
case_stmt(details::e_sf78,details::sf78_op) case_stmt(details::e_sf79,details::sf79_op)
|
|
case_stmt(details::e_sf80,details::sf80_op) case_stmt(details::e_sf81,details::sf81_op)
|
|
case_stmt(details::e_sf82,details::sf82_op) case_stmt(details::e_sf83,details::sf83_op)
|
|
case_stmt(details::e_sf84,details::sf84_op) case_stmt(details::e_sf85,details::sf85_op)
|
|
case_stmt(details::e_sf86,details::sf86_op) case_stmt(details::e_sf87,details::sf87_op)
|
|
case_stmt(details::e_sf88,details::sf88_op) case_stmt(details::e_sf89,details::sf89_op)
|
|
case_stmt(details::e_sf90,details::sf90_op) case_stmt(details::e_sf91,details::sf91_op)
|
|
case_stmt(details::e_sf92,details::sf92_op) case_stmt(details::e_sf93,details::sf93_op)
|
|
case_stmt(details::e_sf94,details::sf94_op) case_stmt(details::e_sf95,details::sf95_op)
|
|
case_stmt(details::e_sf96,details::sf96_op) case_stmt(details::e_sf97,details::sf97_op)
|
|
case_stmt(details::e_sf98,details::sf98_op) case_stmt(details::e_sf99,details::sf99_op)
|
|
#undef case_stmt
|
|
default : return error_node();
|
|
}
|
|
}
|
|
|
|
inline expression_node_ptr special_function(const details::operator_type& operation, expression_node_ptr (&branch)[4])
|
|
{
|
|
if (!all_nodes_valid(branch))
|
|
return error_node();
|
|
else if (is_constant_foldable(branch))
|
|
return const_optimize_sf4(operation,branch);
|
|
else if (all_nodes_variables(branch))
|
|
return varnode_optimize_sf4(operation,branch);
|
|
switch (operation)
|
|
{
|
|
#define case_stmt(op0,op1) \
|
|
case op0 : return node_allocator_-> \
|
|
allocate<details::sf4_node<Type,op1<Type> > >(operation,branch); \
|
|
|
|
case_stmt(details::e_sf48,details::sf48_op) case_stmt(details::e_sf49,details::sf49_op)
|
|
case_stmt(details::e_sf50,details::sf50_op) case_stmt(details::e_sf51,details::sf51_op)
|
|
case_stmt(details::e_sf52,details::sf52_op) case_stmt(details::e_sf53,details::sf53_op)
|
|
case_stmt(details::e_sf54,details::sf54_op) case_stmt(details::e_sf55,details::sf55_op)
|
|
case_stmt(details::e_sf56,details::sf56_op) case_stmt(details::e_sf57,details::sf57_op)
|
|
case_stmt(details::e_sf58,details::sf58_op) case_stmt(details::e_sf59,details::sf59_op)
|
|
case_stmt(details::e_sf60,details::sf60_op) case_stmt(details::e_sf61,details::sf61_op)
|
|
case_stmt(details::e_sf62,details::sf62_op) case_stmt(details::e_sf63,details::sf63_op)
|
|
case_stmt(details::e_sf64,details::sf64_op) case_stmt(details::e_sf65,details::sf65_op)
|
|
case_stmt(details::e_sf66,details::sf66_op) case_stmt(details::e_sf67,details::sf67_op)
|
|
case_stmt(details::e_sf68,details::sf68_op) case_stmt(details::e_sf69,details::sf69_op)
|
|
case_stmt(details::e_sf70,details::sf70_op) case_stmt(details::e_sf71,details::sf71_op)
|
|
case_stmt(details::e_sf72,details::sf72_op) case_stmt(details::e_sf73,details::sf73_op)
|
|
case_stmt(details::e_sf74,details::sf74_op) case_stmt(details::e_sf75,details::sf75_op)
|
|
case_stmt(details::e_sf76,details::sf76_op) case_stmt(details::e_sf77,details::sf77_op)
|
|
case_stmt(details::e_sf78,details::sf78_op) case_stmt(details::e_sf79,details::sf79_op)
|
|
case_stmt(details::e_sf80,details::sf80_op) case_stmt(details::e_sf81,details::sf81_op)
|
|
case_stmt(details::e_sf82,details::sf82_op) case_stmt(details::e_sf83,details::sf83_op)
|
|
case_stmt(details::e_sf84,details::sf84_op) case_stmt(details::e_sf85,details::sf85_op)
|
|
case_stmt(details::e_sf86,details::sf86_op) case_stmt(details::e_sf87,details::sf87_op)
|
|
case_stmt(details::e_sf88,details::sf88_op) case_stmt(details::e_sf89,details::sf89_op)
|
|
case_stmt(details::e_sf90,details::sf90_op) case_stmt(details::e_sf91,details::sf91_op)
|
|
case_stmt(details::e_sf92,details::sf92_op) case_stmt(details::e_sf93,details::sf93_op)
|
|
case_stmt(details::e_sf94,details::sf94_op) case_stmt(details::e_sf95,details::sf95_op)
|
|
case_stmt(details::e_sf96,details::sf96_op) case_stmt(details::e_sf97,details::sf97_op)
|
|
case_stmt(details::e_sf98,details::sf98_op) case_stmt(details::e_sf99,details::sf99_op)
|
|
#undef case_stmt
|
|
default : return error_node();
|
|
}
|
|
}
|
|
|
|
template <typename Allocator,
|
|
template <typename,typename> class Sequence>
|
|
inline expression_node_ptr const_optimize_varargfunc(const details::operator_type& operation, Sequence<expression_node_ptr,Allocator>& arg_list)
|
|
{
|
|
expression_node_ptr temp_node = error_node();
|
|
|
|
switch (operation)
|
|
{
|
|
#define case_stmt(op0,op1) \
|
|
case op0 : temp_node = node_allocator_-> \
|
|
allocate<details::vararg_node<Type,op1<Type> > > \
|
|
(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<literal_node_t>(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 <typename Allocator,
|
|
template <typename,typename> class Sequence>
|
|
inline expression_node_ptr varnode_optimize_varargfunc(const details::operator_type& operation, Sequence<expression_node_ptr,Allocator>& arg_list)
|
|
{
|
|
switch (operation)
|
|
{
|
|
#define case_stmt(op0,op1) \
|
|
case op0 : return node_allocator_-> \
|
|
allocate<details::vararg_varnode<Type,op1<Type> > >(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 <typename Allocator,
|
|
template <typename,typename> class Sequence>
|
|
inline expression_node_ptr vectorize_func(const details::operator_type& operation, Sequence<expression_node_ptr,Allocator>& arg_list)
|
|
{
|
|
if (1 == arg_list.size())
|
|
{
|
|
switch (operation)
|
|
{
|
|
#define case_stmt(op0,op1) \
|
|
case op0 : return node_allocator_-> \
|
|
allocate<details::vectorize_node<Type,op1<Type> > >(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 <typename Allocator,
|
|
template <typename,typename> class Sequence>
|
|
inline expression_node_ptr vararg_function(const details::operator_type& operation, Sequence<expression_node_ptr,Allocator>& arg_list)
|
|
{
|
|
if (!all_nodes_valid(arg_list))
|
|
{
|
|
details::free_all_nodes(*node_allocator_,arg_list);
|
|
|
|
return error_node();
|
|
}
|
|
else if (is_constant_foldable(arg_list))
|
|
return const_optimize_varargfunc(operation,arg_list);
|
|
else if ((arg_list.size() == 1) && details::is_ivector_node(arg_list[0]))
|
|
return vectorize_func(operation,arg_list);
|
|
else if ((arg_list.size() == 1) && special_one_parameter_vararg(operation))
|
|
return arg_list[0];
|
|
else if (all_nodes_variables(arg_list))
|
|
return varnode_optimize_varargfunc(operation,arg_list);
|
|
|
|
switch (operation)
|
|
{
|
|
#define case_stmt(op0,op1) \
|
|
case op0 : return node_allocator_-> \
|
|
allocate<details::vararg_node<Type,op1<Type> > >(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 <std::size_t N>
|
|
inline expression_node_ptr function(ifunction_t* f, expression_node_ptr (&b)[N])
|
|
{
|
|
typedef typename details::function_N_node<T,ifunction_t,N> function_N_node_t;
|
|
expression_node_ptr result = synthesize_expression<function_N_node_t,N>(f,b);
|
|
|
|
if (0 == result)
|
|
return error_node();
|
|
else
|
|
{
|
|
// Can the function call be completely optimized?
|
|
if (details::is_constant_node(result))
|
|
return result;
|
|
else if (!all_nodes_valid(b))
|
|
return error_node();
|
|
else if (N != f->param_count)
|
|
{
|
|
details::free_all_nodes(*node_allocator_,b);
|
|
|
|
return error_node();
|
|
}
|
|
|
|
function_N_node_t* func_node_ptr = static_cast<function_N_node_t*>(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<Type,ifunction_t,0> function_N_node_t;
|
|
return node_allocator_->allocate<function_N_node_t>(f);
|
|
}
|
|
|
|
inline expression_node_ptr vararg_function_call(ivararg_function_t* vaf,
|
|
std::vector<expression_node_ptr>& arg_list)
|
|
{
|
|
if (!all_nodes_valid(arg_list))
|
|
{
|
|
details::free_all_nodes(*node_allocator_,arg_list);
|
|
|
|
return error_node();
|
|
}
|
|
|
|
typedef details::vararg_function_node<Type,ivararg_function_t> alloc_type;
|
|
|
|
expression_node_ptr result = node_allocator_->allocate<alloc_type>(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<literal_node_t>(v);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
inline expression_node_ptr generic_function_call(igeneric_function_t* gf,
|
|
std::vector<expression_node_ptr>& arg_list,
|
|
const std::size_t& param_seq_index = std::numeric_limits<std::size_t>::max())
|
|
{
|
|
if (!all_nodes_valid(arg_list))
|
|
{
|
|
details::free_all_nodes(*node_allocator_,arg_list);
|
|
return error_node();
|
|
}
|
|
|
|
typedef details::generic_function_node <Type,igeneric_function_t> alloc_type1;
|
|
typedef details::multimode_genfunction_node<Type,igeneric_function_t> alloc_type2;
|
|
|
|
const std::size_t no_psi = std::numeric_limits<std::size_t>::max();
|
|
|
|
expression_node_ptr result = error_node();
|
|
|
|
if (no_psi == param_seq_index)
|
|
result = node_allocator_->allocate<alloc_type1>(gf,arg_list);
|
|
else
|
|
result = node_allocator_->allocate<alloc_type2>(gf,param_seq_index,arg_list);
|
|
|
|
alloc_type1* genfunc_node_ptr = static_cast<alloc_type1*>(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<literal_node_t>(v);
|
|
}
|
|
else if (genfunc_node_ptr->init_branches())
|
|
return result;
|
|
else
|
|
{
|
|
details::free_node(*node_allocator_,result);
|
|
details::free_all_nodes(*node_allocator_,arg_list);
|
|
return error_node();
|
|
}
|
|
}
|
|
|
|
inline expression_node_ptr string_function_call(igeneric_function_t* gf,
|
|
std::vector<expression_node_ptr>& arg_list,
|
|
const std::size_t& param_seq_index = std::numeric_limits<std::size_t>::max())
|
|
{
|
|
if (!all_nodes_valid(arg_list))
|
|
{
|
|
details::free_all_nodes(*node_allocator_,arg_list);
|
|
return error_node();
|
|
}
|
|
|
|
typedef details::string_function_node <Type,igeneric_function_t> alloc_type1;
|
|
typedef details::multimode_strfunction_node<Type,igeneric_function_t> alloc_type2;
|
|
|
|
const std::size_t no_psi = std::numeric_limits<std::size_t>::max();
|
|
|
|
expression_node_ptr result = error_node();
|
|
|
|
if (no_psi == param_seq_index)
|
|
result = node_allocator_->allocate<alloc_type1>(gf,arg_list);
|
|
else
|
|
result = node_allocator_->allocate<alloc_type2>(gf,param_seq_index,arg_list);
|
|
|
|
alloc_type1* strfunc_node_ptr = static_cast<alloc_type1*>(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<literal_node_t>(v);
|
|
}
|
|
else if (strfunc_node_ptr->init_branches())
|
|
return result;
|
|
else
|
|
{
|
|
details::free_node(*node_allocator_,result);
|
|
details::free_all_nodes(*node_allocator_,arg_list);
|
|
return error_node();
|
|
}
|
|
}
|
|
|
|
inline expression_node_ptr vector_element(const std::string& symbol,
|
|
vector_holder_ptr vector_base,
|
|
expression_node_ptr index)
|
|
{
|
|
expression_node_ptr result = error_node();
|
|
|
|
if (details::is_constant_node(index))
|
|
{
|
|
std::size_t i = static_cast<std::size_t>(details::numeric::to_int64(index->value()));
|
|
details::free_node(*node_allocator_,index);
|
|
Type* v = (*vector_base)[i];
|
|
|
|
scope_element& se = parser_->sem_.get_element(symbol,i);
|
|
|
|
if (se.index == i)
|
|
{
|
|
result = se.var_node;
|
|
}
|
|
else
|
|
{
|
|
scope_element nse;
|
|
nse.name = symbol;
|
|
nse.type = scope_element::e_vecelem;
|
|
nse.index = i;
|
|
nse.depth = parser_->scope_depth_;
|
|
nse.data = 0;
|
|
nse.var_node = new variable_node_t((*v));
|
|
|
|
if (!parser_->sem_.add_element(nse))
|
|
{
|
|
parser_->set_synthesis_error("Failed to add new local vector element to SEM [1]");
|
|
result = error_node();
|
|
}
|
|
else
|
|
exprtk_debug(("vector_element() - INFO - Added new local vector element: %s\n",nse.name.c_str()));
|
|
|
|
result = nse.var_node;
|
|
}
|
|
}
|
|
else
|
|
result = node_allocator_->allocate<details::vector_elem_node<Type> >(index,(*vector_base)[0]);
|
|
|
|
return result;
|
|
}
|
|
|
|
private:
|
|
|
|
template <std::size_t N, typename NodePtr>
|
|
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 <typename NodePtr,
|
|
typename Allocator,
|
|
template <typename,typename> class Sequence>
|
|
inline bool is_constant_foldable(const Sequence<NodePtr,Allocator>& b) const
|
|
{
|
|
for (std::size_t i = 0; i < b.size(); ++i)
|
|
{
|
|
if (0 == b[i])
|
|
return false;
|
|
else if (!details::is_constant_node(b[i]))
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void lodge_assignment(symbol_type cst, expression_node_ptr node)
|
|
{
|
|
if (!parser_->dec_.collect_assignments())
|
|
return;
|
|
|
|
std::string symbol_name;
|
|
|
|
switch (cst)
|
|
{
|
|
case e_st_variable : symbol_name = parser_->symbol_table_
|
|
.get_variable_name(node);
|
|
break;
|
|
|
|
case e_st_string : symbol_name = parser_->symbol_table_
|
|
.get_stringvar_name(node);
|
|
break;
|
|
|
|
case e_st_vector : {
|
|
typedef details::vector_holder<T> vector_holder_t;
|
|
|
|
vector_holder_t& vh = static_cast<vector_node_t*>(node)->ref();
|
|
|
|
symbol_name = parser_->symbol_table_.get_vector_name(&vh);
|
|
}
|
|
break;
|
|
|
|
default : return;
|
|
}
|
|
|
|
parser_->dec_.add_assignment(symbol_name,cst);
|
|
}
|
|
|
|
inline expression_node_ptr synthesize_assignment_expression(const details::operator_type& operation, expression_node_ptr (&branch)[2])
|
|
{
|
|
if (details::is_variable_node(branch[0]))
|
|
{
|
|
lodge_assignment(e_st_variable,branch[0]);
|
|
|
|
return synthesize_expression<assignment_node_t,2>(operation,branch);
|
|
}
|
|
else if (details::is_vector_elem_node(branch[0]))
|
|
return synthesize_expression<assignment_vec_elem_node_t,2>(operation,branch);
|
|
else if (details::is_string_node(branch[0]))
|
|
{
|
|
lodge_assignment(e_st_string,branch[0]);
|
|
|
|
return synthesize_expression<assignment_string_node_t,2>(operation,branch);
|
|
}
|
|
else if (details::is_string_range_node(branch[0]))
|
|
{
|
|
lodge_assignment(e_st_string,branch[0]);
|
|
|
|
return synthesize_expression<assignment_string_range_node_t,2>(operation,branch);
|
|
}
|
|
else if (details::is_vector_node(branch[0]))
|
|
{
|
|
lodge_assignment(e_st_vector,branch[0]);
|
|
|
|
if (details::is_ivector_node(branch[1]))
|
|
return synthesize_expression<assignment_vecvec_node_t,2>(operation,branch);
|
|
else
|
|
return synthesize_expression<assignment_vec_node_t,2>(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<typename details::assignment_op_node<Type,op1<Type> > > \
|
|
(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<typename details::assignment_vec_elem_op_node<Type,op1<Type> > > \
|
|
(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<typename details::assignment_vecvec_op_node<Type,op1<Type> > > \
|
|
(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<typename details::assignment_vec_op_node<Type,op1<Type> > > \
|
|
(operation,branch[0],branch[1]); \
|
|
|
|
case_stmt(details::e_addass,details::add_op)
|
|
case_stmt(details::e_subass,details::sub_op)
|
|
case_stmt(details::e_mulass,details::mul_op)
|
|
case_stmt(details::e_divass,details::div_op)
|
|
case_stmt(details::e_modass,details::mod_op)
|
|
#undef case_stmt
|
|
default : return error_node();
|
|
}
|
|
}
|
|
}
|
|
else if (
|
|
(details::e_addass == operation) &&
|
|
details::is_string_node(branch[0])
|
|
)
|
|
{
|
|
typedef details::assignment_string_node<T,details::asn_addassignment> addass_t;
|
|
|
|
lodge_assignment(e_st_string,branch[0]);
|
|
|
|
return synthesize_expression<addass_t,2>(operation,branch);
|
|
}
|
|
else
|
|
{
|
|
parser_->set_synthesis_error("Invalid assignment operation[2]");
|
|
|
|
return error_node();
|
|
}
|
|
}
|
|
|
|
inline expression_node_ptr synthesize_veceqineq_operation_expression(const details::operator_type& operation,
|
|
expression_node_ptr (&branch)[2])
|
|
{
|
|
const bool is_b0_ivec = details::is_ivector_node(branch[0]);
|
|
const bool is_b1_ivec = details::is_ivector_node(branch[1]);
|
|
|
|
if (is_b0_ivec && is_b1_ivec)
|
|
{
|
|
switch (operation)
|
|
{
|
|
#define case_stmt(op0,op1) \
|
|
case op0 : return node_allocator_-> \
|
|
template allocate_rrr<typename details::eqineq_vecvec_node<Type,op1<Type> > > \
|
|
(operation,branch[0],branch[1]); \
|
|
|
|
case_stmt(details:: e_lt,details:: lt_op)
|
|
case_stmt(details:: e_lte,details:: lte_op)
|
|
case_stmt(details:: e_gt,details:: gt_op)
|
|
case_stmt(details:: e_gte,details:: gte_op)
|
|
case_stmt(details:: e_eq,details:: eq_op)
|
|
case_stmt(details:: e_ne,details:: ne_op)
|
|
#undef case_stmt
|
|
default : return error_node();
|
|
}
|
|
}
|
|
else if (is_b0_ivec && !is_b1_ivec)
|
|
{
|
|
switch (operation)
|
|
{
|
|
#define case_stmt(op0,op1) \
|
|
case op0 : return node_allocator_-> \
|
|
template allocate_rrr<typename details::eqineq_vecval_node<Type,op1<Type> > > \
|
|
(operation,branch[0],branch[1]); \
|
|
|
|
case_stmt(details:: e_lt,details:: lt_op)
|
|
case_stmt(details:: e_lte,details:: lte_op)
|
|
case_stmt(details:: e_gt,details:: gt_op)
|
|
case_stmt(details:: e_gte,details:: gte_op)
|
|
case_stmt(details:: e_eq,details:: eq_op)
|
|
case_stmt(details:: e_ne,details:: ne_op)
|
|
#undef case_stmt
|
|
default : return error_node();
|
|
}
|
|
}
|
|
else if (!is_b0_ivec && is_b1_ivec)
|
|
{
|
|
switch (operation)
|
|
{
|
|
#define case_stmt(op0,op1) \
|
|
case op0 : return node_allocator_-> \
|
|
template allocate_rrr<typename details::eqineq_valvec_node<Type,op1<Type> > > \
|
|
(operation,branch[0],branch[1]); \
|
|
|
|
case_stmt(details:: e_lt,details:: lt_op)
|
|
case_stmt(details:: e_lte,details:: lte_op)
|
|
case_stmt(details:: e_gt,details:: gt_op)
|
|
case_stmt(details:: e_gte,details:: gte_op)
|
|
case_stmt(details:: e_eq,details:: eq_op)
|
|
case_stmt(details:: e_ne,details:: ne_op)
|
|
#undef case_stmt
|
|
default : return error_node();
|
|
}
|
|
}
|
|
else
|
|
return error_node();
|
|
}
|
|
|
|
inline expression_node_ptr synthesize_vecarithmetic_operation_expression(const details::operator_type& operation,
|
|
expression_node_ptr (&branch)[2])
|
|
{
|
|
const bool is_b0_ivec = details::is_ivector_node(branch[0]);
|
|
const bool is_b1_ivec = details::is_ivector_node(branch[1]);
|
|
|
|
#define vector_ops \
|
|
case_stmt(details::e_add,details::add_op) \
|
|
case_stmt(details::e_sub,details::sub_op) \
|
|
case_stmt(details::e_mul,details::mul_op) \
|
|
case_stmt(details::e_div,details::div_op) \
|
|
case_stmt(details::e_mod,details::mod_op) \
|
|
|
|
if (is_b0_ivec && is_b1_ivec)
|
|
{
|
|
switch (operation)
|
|
{
|
|
#define case_stmt(op0,op1) \
|
|
case op0 : return node_allocator_-> \
|
|
template allocate_rrr<typename details::vecarith_vecvec_node<Type,op1<Type> > > \
|
|
(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<typename details::vecarith_vecval_node<Type,op1<Type> > > \
|
|
(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<typename details::vecarith_valvec_node<Type,op1<Type> > > \
|
|
(operation,branch[0],branch[1]); \
|
|
|
|
vector_ops
|
|
#undef case_stmt
|
|
default : return error_node();
|
|
}
|
|
}
|
|
else
|
|
return error_node();
|
|
|
|
#undef vector_ops
|
|
}
|
|
|
|
inline expression_node_ptr synthesize_swap_expression(expression_node_ptr (&branch)[2])
|
|
{
|
|
const bool v0_is_ivar = details::is_ivariable_node(branch[0]);
|
|
const bool v1_is_ivar = details::is_ivariable_node(branch[1]);
|
|
|
|
const bool v0_is_ivec = details::is_ivector_node(branch[0]);
|
|
const bool v1_is_ivec = details::is_ivector_node(branch[1]);
|
|
|
|
const bool v0_is_str = details::is_generally_string_node(branch[0]);
|
|
const bool v1_is_str = details::is_generally_string_node(branch[1]);
|
|
|
|
if (v0_is_ivar && v1_is_ivar)
|
|
{
|
|
typedef details::variable_node<T>* variable_node_ptr;
|
|
|
|
variable_node_ptr v0 = variable_node_ptr(0);
|
|
variable_node_ptr v1 = variable_node_ptr(0);
|
|
|
|
if (
|
|
(0 != (v0 = dynamic_cast<variable_node_ptr>(branch[0]))) &&
|
|
(0 != (v1 = dynamic_cast<variable_node_ptr>(branch[1])))
|
|
)
|
|
{
|
|
return node_allocator_->allocate<details::swap_node<T> >(v0,v1);
|
|
}
|
|
else
|
|
return node_allocator_->allocate<details::swap_generic_node<T> >(branch[0],branch[1]);
|
|
}
|
|
else if (v0_is_ivec && v1_is_ivec)
|
|
{
|
|
return node_allocator_->allocate<details::swap_vecvec_node<T> >(branch[0],branch[1]);
|
|
}
|
|
else if (v0_is_str && v1_is_str)
|
|
{
|
|
return node_allocator_->allocate<details::swap_string_node<T> >(branch[0],branch[1]);
|
|
}
|
|
else
|
|
{
|
|
parser_->set_synthesis_error("Only variables, strings, vectors or vector elements can be swapped");
|
|
|
|
return error_node();
|
|
}
|
|
}
|
|
|
|
#ifndef exprtk_disable_sc_andor
|
|
inline expression_node_ptr synthesize_shortcircuit_expression(const details::operator_type& operation, expression_node_ptr (&branch)[2])
|
|
{
|
|
expression_node_ptr result = error_node();
|
|
|
|
if (details::is_constant_node(branch[0]))
|
|
{
|
|
if (
|
|
(details::e_scand == operation) &&
|
|
std::equal_to<T>()(T(0),branch[0]->value())
|
|
)
|
|
result = node_allocator_->allocate_c<literal_node_t>(T(0));
|
|
else if (
|
|
(details::e_scor == operation) &&
|
|
std::not_equal_to<T>()(T(0),branch[0]->value())
|
|
)
|
|
result = node_allocator_->allocate_c<literal_node_t>(T(1));
|
|
}
|
|
|
|
if (details::is_constant_node(branch[1]) && (0 == result))
|
|
{
|
|
if (
|
|
(details::e_scand == operation) &&
|
|
std::equal_to<T>()(T(0),branch[1]->value())
|
|
)
|
|
result = node_allocator_->allocate_c<literal_node_t>(T(0));
|
|
else if (
|
|
(details::e_scor == operation) &&
|
|
std::not_equal_to<T>()(T(0),branch[1]->value())
|
|
)
|
|
result = node_allocator_->allocate_c<literal_node_t>(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<scand_node_t,2>(operation,branch);
|
|
else if (details::e_scor == operation)
|
|
return synthesize_expression<scor_node_t,2>(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 <template <typename,typename> class IPowNode>
|
|
inline expression_node_ptr cardinal_pow_optimization_impl(const T& v, const unsigned int& p)
|
|
{
|
|
switch (p)
|
|
{
|
|
#define case_stmt(cp) \
|
|
case cp : return node_allocator_-> \
|
|
allocate<IPowNode<T,details::numeric::fast_exp<T,cp> > >(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_optimization(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<literal_node_t>(T(1));
|
|
else if (std::equal_to<T>()(T(2),c))
|
|
{
|
|
return node_allocator_->
|
|
template allocate_rr<typename details::vov_node<Type,details::mul_op<Type> > >(v,v);
|
|
}
|
|
else
|
|
{
|
|
if (not_recipricol)
|
|
return cardinal_pow_optimization_impl<details::ipow_node>(v,p);
|
|
else
|
|
return cardinal_pow_optimization_impl<details::ipowinv_node>(v,p);
|
|
}
|
|
}
|
|
|
|
inline bool cardinal_pow_optimizable(const details::operator_type& operation, const T& c)
|
|
{
|
|
return (details::e_pow == operation) && (details::numeric::abs(c) <= T(60)) && details::numeric::is_integer(c);
|
|
}
|
|
#else
|
|
inline expression_node_ptr cardinal_pow_optimization(T&, const T&)
|
|
{
|
|
return error_node();
|
|
}
|
|
|
|
inline bool cardinal_pow_optimizable(const details::operator_type&, const T&)
|
|
{
|
|
return false;
|
|
}
|
|
#endif
|
|
|
|
struct synthesize_binary_ext_expression
|
|
{
|
|
static inline expression_node_ptr process(expression_generator<Type>& 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<typename details::binary_ext_node<Type,details::add_op<Type> > >
|
|
(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<typename details::binary_ext_node<Type,details::sub_op<Type> > >
|
|
(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<typename details::binary_ext_node<Type,details::sub_op<Type> > >
|
|
(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<typename details::binary_ext_node<Type,details::add_op<Type> > >
|
|
(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<typename details::binary_ext_node<Type,details::mul_op<Type> > >
|
|
(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<typename details::binary_ext_node<Type,details::div_op<Type> > >
|
|
(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<typename details::binary_ext_node<Type,details::sub_op<Type> > >
|
|
(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<typename details::binary_ext_node<Type,details::add_op<Type> > >
|
|
(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<typename details::binary_ext_node<Type,details::mul_op<Type> > >
|
|
(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<typename details::binary_ext_node<Type,details::div_op<Type> > >
|
|
(branch[0],branch[1]));
|
|
|
|
default : return error_node();
|
|
}
|
|
}
|
|
}
|
|
|
|
switch (operation)
|
|
{
|
|
#define case_stmt(op0,op1) \
|
|
case op0 : return expr_gen.node_allocator_-> \
|
|
template allocate<typename details::binary_ext_node<Type,op1<Type> > > \
|
|
(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<Type>& expr_gen,
|
|
const details::operator_type& operation,
|
|
expression_node_ptr (&branch)[2])
|
|
{
|
|
const Type& v = static_cast<details::variable_node<Type>*>(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<vtype>(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]))
|
|
{
|
|
details::operator_type o = static_cast<details::uv_base_node<Type>*>(branch[1])->operation();
|
|
|
|
if (details::e_neg == o)
|
|
{
|
|
const Type& v1 = static_cast<details::uv_base_node<Type>*>(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<typename details::
|
|
vov_node<Type,details::mul_op<Type> > >(v,v1));
|
|
|
|
case details::e_div : return expr_gen(details::e_neg,
|
|
expr_gen.node_allocator_->
|
|
template allocate_rr<typename details::
|
|
vov_node<Type,details::div_op<Type> > >(v,v1));
|
|
|
|
default : break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
switch (operation)
|
|
{
|
|
#define case_stmt(op0,op1) \
|
|
case op0 : return expr_gen.node_allocator_-> \
|
|
template allocate_rc<typename details::vob_node<Type,op1<Type> > > \
|
|
(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<Type>& expr_gen,
|
|
const details::operator_type& operation,
|
|
expression_node_ptr (&branch)[2])
|
|
{
|
|
const Type& v = static_cast<details::variable_node<Type>*>(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<vtype>(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]))
|
|
{
|
|
details::operator_type o = static_cast<details::uv_base_node<Type>*>(branch[0])->operation();
|
|
|
|
if (details::e_neg == o)
|
|
{
|
|
const Type& v0 = static_cast<details::uv_base_node<Type>*>(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<typename details::
|
|
vov_node<Type,details::sub_op<Type> > >(v,v0);
|
|
|
|
case details::e_sub : return expr_gen(details::e_neg,
|
|
expr_gen.node_allocator_->
|
|
template allocate_rr<typename details::
|
|
vov_node<Type,details::add_op<Type> > >(v0,v));
|
|
|
|
case details::e_mul : return expr_gen(details::e_neg,
|
|
expr_gen.node_allocator_->
|
|
template allocate_rr<typename details::
|
|
vov_node<Type,details::mul_op<Type> > >(v0,v));
|
|
|
|
case details::e_div : return expr_gen(details::e_neg,
|
|
expr_gen.node_allocator_->
|
|
template allocate_rr<typename details::
|
|
vov_node<Type,details::div_op<Type> > >(v0,v));
|
|
default : break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
switch (operation)
|
|
{
|
|
#define case_stmt(op0,op1) \
|
|
case op0 : return expr_gen.node_allocator_-> \
|
|
template allocate_cr<typename details::bov_node<Type,op1<Type> > > \
|
|
(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<Type>& expr_gen,
|
|
const details::operator_type& operation,
|
|
expression_node_ptr (&branch)[2])
|
|
{
|
|
const Type c = static_cast<details::literal_node<Type>*>(branch[0])->value();
|
|
free_node(*expr_gen.node_allocator_,branch[0]);
|
|
|
|
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<Type>* cobnode = static_cast<details::cob_base_node<Type>*>(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<Type>* cobnode = static_cast<details::cob_base_node<Type>*>(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<Type>* cobnode = static_cast<details::cob_base_node<Type>*>(branch[1]);
|
|
details::operator_type cob_opr = cobnode->operation();
|
|
|
|
if (
|
|
(details::e_div == cob_opr) ||
|
|
(details::e_mul == cob_opr)
|
|
)
|
|
{
|
|
details::expression_node<Type>* new_cobnode = error_node();
|
|
|
|
switch (cob_opr)
|
|
{
|
|
case details::e_div : new_cobnode = expr_gen.node_allocator_->
|
|
template allocate_tt<typename details::cob_node<Type,details::mul_op<Type> > >
|
|
(c / cobnode->c(),cobnode->move_branch(0));
|
|
break;
|
|
|
|
case details::e_mul : new_cobnode = expr_gen.node_allocator_->
|
|
template allocate_tt<typename details::cob_node<Type,details::div_op<Type> > >
|
|
(c / cobnode->c(),cobnode->move_branch(0));
|
|
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<ctype>(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<typename details::cob_node<Type,op1<Type> > > \
|
|
(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<Type>& expr_gen,
|
|
const details::operator_type& operation,
|
|
expression_node_ptr (&branch)[2])
|
|
{
|
|
const Type c = static_cast<details::literal_node<Type>*>(branch[1])->value();
|
|
details::free_node(*(expr_gen.node_allocator_),branch[1]);
|
|
|
|
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<Type>* bocnode = static_cast<details::boc_base_node<Type>*>(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<Type>* bocnode = static_cast<details::boc_base_node<Type>*>(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;
|
|
}
|
|
}
|
|
}
|
|
|
|
#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<ctype>(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<typename details::boc_node<Type,op1<Type> > > \
|
|
(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<Type>& 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<Type>* cobnode = static_cast<details::cob_base_node<Type>*>(branch[0]);
|
|
const Type c = static_cast<details::literal_node<Type>*>(branch[1])->value();
|
|
|
|
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<typename details::cob_node<Type,details::div_op<Type> > >
|
|
(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<Type>* cobnode = static_cast<details::cob_base_node<Type>*>(branch[1]);
|
|
const Type c = static_cast<details::literal_node<Type>*>(branch[0])->value();
|
|
|
|
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<typename details::cob_node<Type,details::sub_op<Type> > >
|
|
(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<typename details::cob_node<Type,details::add_op<Type> > >
|
|
(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<typename details::cob_node<Type,details::div_op<Type> > >
|
|
(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<typename details::cob_node<Type,details::mul_op<Type> > >
|
|
(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<Type>& 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<Type>* bocnode = static_cast<details::boc_base_node<Type>*>(branch[0]);
|
|
const Type c = static_cast<details::literal_node<Type>*>(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<typename details::boc_node<Type,details::add_op<Type> > >
|
|
(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<Type>* bocnode = static_cast<details::boc_base_node<Type>*>(branch[1]);
|
|
const Type c = static_cast<details::literal_node<Type>*>(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<typename details::cob_node<Type,details::sub_op<Type> > >
|
|
(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<typename details::boc_node<Type,details::add_op<Type> > >
|
|
(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<typename details::cob_node<Type,details::sub_op<Type> > >
|
|
(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<typename details::cob_node<Type,details::div_op<Type> > >
|
|
(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<typename details::cob_node<Type,details::div_op<Type> > >
|
|
(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_optimizable(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<Type>& expr_gen,
|
|
const details::operator_type& operation,
|
|
expression_node_ptr (&branch)[2])
|
|
{
|
|
const Type& v1 = static_cast<details::variable_node<Type>*>(branch[0])->ref();
|
|
const Type& v2 = static_cast<details::variable_node<Type>*>(branch[1])->ref();
|
|
|
|
switch (operation)
|
|
{
|
|
#define case_stmt(op0,op1) \
|
|
case op0 : return expr_gen.node_allocator_-> \
|
|
template allocate_rr<typename details::vov_node<Type,op1<Type> > > \
|
|
(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<Type>& expr_gen,
|
|
const details::operator_type& operation,
|
|
expression_node_ptr (&branch)[2])
|
|
{
|
|
const Type c = static_cast<details::literal_node<Type>*> (branch[0])->value();
|
|
const Type& v = static_cast<details::variable_node<Type>*>(branch[1])->ref();
|
|
|
|
details::free_node(*(expr_gen.node_allocator_),branch[0]);
|
|
|
|
switch (operation)
|
|
{
|
|
#define case_stmt(op0,op1) \
|
|
case op0 : return expr_gen.node_allocator_-> \
|
|
template allocate_cr<typename details::cov_node<Type,op1<Type> > > \
|
|
(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<Type>& expr_gen,
|
|
const details::operator_type& operation,
|
|
expression_node_ptr (&branch)[2])
|
|
{
|
|
const Type& v = static_cast<details::variable_node<Type>*>(branch[0])->ref();
|
|
const Type c = static_cast<details::literal_node<Type>*> (branch[1])->value();
|
|
|
|
details::free_node(*(expr_gen.node_allocator_),branch[1]);
|
|
|
|
if (expr_gen.cardinal_pow_optimizable(operation,c))
|
|
{
|
|
if (std::equal_to<T>()(T(1),c))
|
|
return branch[0];
|
|
else
|
|
return expr_gen.cardinal_pow_optimization(v,c);
|
|
}
|
|
|
|
switch (operation)
|
|
{
|
|
#define case_stmt(op0,op1) \
|
|
case op0 : return expr_gen.node_allocator_-> \
|
|
template allocate_rc<typename details::voc_node<Type,op1<Type> > > \
|
|
(v,c); \
|
|
|
|
basic_opr_switch_statements
|
|
extended_opr_switch_statements
|
|
#undef case_stmt
|
|
default : return error_node();
|
|
}
|
|
}
|
|
};
|
|
|
|
struct synthesize_sf3ext_expression
|
|
{
|
|
template <typename T0, typename T1, typename T2>
|
|
static inline expression_node_ptr process(expression_generator<Type>& expr_gen,
|
|
const details::operator_type& sf3opr,
|
|
T0 t0, T1 t1, T2 t2)
|
|
{
|
|
switch (sf3opr)
|
|
{
|
|
#define case_stmt(op0,op1) \
|
|
case op0 : return details::T0oT1oT2_sf3ext<T,T0,T1,T2,op1<Type> >:: \
|
|
allocate(*(expr_gen.node_allocator_),t0,t1,t2); \
|
|
|
|
case_stmt(details::e_sf00,details::sf00_op) case_stmt(details::e_sf01,details::sf01_op)
|
|
case_stmt(details::e_sf02,details::sf02_op) case_stmt(details::e_sf03,details::sf03_op)
|
|
case_stmt(details::e_sf04,details::sf04_op) case_stmt(details::e_sf05,details::sf05_op)
|
|
case_stmt(details::e_sf06,details::sf06_op) case_stmt(details::e_sf07,details::sf07_op)
|
|
case_stmt(details::e_sf08,details::sf08_op) case_stmt(details::e_sf09,details::sf09_op)
|
|
case_stmt(details::e_sf10,details::sf10_op) case_stmt(details::e_sf11,details::sf11_op)
|
|
case_stmt(details::e_sf12,details::sf12_op) case_stmt(details::e_sf13,details::sf13_op)
|
|
case_stmt(details::e_sf14,details::sf14_op) case_stmt(details::e_sf15,details::sf15_op)
|
|
case_stmt(details::e_sf16,details::sf16_op) case_stmt(details::e_sf17,details::sf17_op)
|
|
case_stmt(details::e_sf18,details::sf18_op) case_stmt(details::e_sf19,details::sf19_op)
|
|
case_stmt(details::e_sf20,details::sf20_op) case_stmt(details::e_sf21,details::sf21_op)
|
|
case_stmt(details::e_sf22,details::sf22_op) case_stmt(details::e_sf23,details::sf23_op)
|
|
case_stmt(details::e_sf24,details::sf24_op) case_stmt(details::e_sf25,details::sf25_op)
|
|
case_stmt(details::e_sf26,details::sf26_op) case_stmt(details::e_sf27,details::sf27_op)
|
|
case_stmt(details::e_sf28,details::sf28_op) case_stmt(details::e_sf29,details::sf29_op)
|
|
case_stmt(details::e_sf30,details::sf30_op)
|
|
#undef case_stmt
|
|
default : return error_node();
|
|
}
|
|
}
|
|
|
|
template <typename T0, typename T1, typename T2>
|
|
static inline bool compile(expression_generator<Type>& expr_gen, const std::string& id,
|
|
T0 t0, T1 t1, T2 t2,
|
|
expression_node_ptr& result)
|
|
{
|
|
details::operator_type sf3opr;
|
|
|
|
if (!expr_gen.sf3_optimizable(id,sf3opr))
|
|
return false;
|
|
else
|
|
result = synthesize_sf3ext_expression::template process<T0,T1,T2>(expr_gen,sf3opr,t0,t1,t2);
|
|
|
|
return true;
|
|
}
|
|
};
|
|
|
|
struct synthesize_sf4ext_expression
|
|
{
|
|
template <typename T0, typename T1, typename T2, typename T3>
|
|
static inline expression_node_ptr process(expression_generator<Type>& expr_gen,
|
|
const details::operator_type& sf4opr,
|
|
T0 t0, T1 t1, T2 t2, T3 t3)
|
|
{
|
|
switch (sf4opr)
|
|
{
|
|
#define case_stmt(op0,op1) \
|
|
case op0 : return details::T0oT1oT2oT3_sf4ext<Type,T0,T1,T2,T3,op1<Type> >:: \
|
|
allocate(*(expr_gen.node_allocator_),t0,t1,t2,t3); \
|
|
|
|
case_stmt(details::e_sf48,details::sf48_op) case_stmt(details::e_sf49,details::sf49_op)
|
|
case_stmt(details::e_sf50,details::sf50_op) case_stmt(details::e_sf51,details::sf51_op)
|
|
case_stmt(details::e_sf52,details::sf52_op) case_stmt(details::e_sf53,details::sf53_op)
|
|
case_stmt(details::e_sf54,details::sf54_op) case_stmt(details::e_sf55,details::sf55_op)
|
|
case_stmt(details::e_sf56,details::sf56_op) case_stmt(details::e_sf57,details::sf57_op)
|
|
case_stmt(details::e_sf58,details::sf58_op) case_stmt(details::e_sf59,details::sf59_op)
|
|
case_stmt(details::e_sf60,details::sf60_op) case_stmt(details::e_sf61,details::sf61_op)
|
|
case_stmt(details::e_sf62,details::sf62_op) case_stmt(details::e_sf63,details::sf63_op)
|
|
case_stmt(details::e_sf64,details::sf64_op) case_stmt(details::e_sf65,details::sf65_op)
|
|
case_stmt(details::e_sf66,details::sf66_op) case_stmt(details::e_sf67,details::sf67_op)
|
|
case_stmt(details::e_sf68,details::sf68_op) case_stmt(details::e_sf69,details::sf69_op)
|
|
case_stmt(details::e_sf70,details::sf70_op) case_stmt(details::e_sf71,details::sf71_op)
|
|
case_stmt(details::e_sf72,details::sf72_op) case_stmt(details::e_sf73,details::sf73_op)
|
|
case_stmt(details::e_sf74,details::sf74_op) case_stmt(details::e_sf75,details::sf75_op)
|
|
case_stmt(details::e_sf76,details::sf76_op) case_stmt(details::e_sf77,details::sf77_op)
|
|
case_stmt(details::e_sf78,details::sf78_op) case_stmt(details::e_sf79,details::sf79_op)
|
|
case_stmt(details::e_sf80,details::sf80_op) case_stmt(details::e_sf81,details::sf81_op)
|
|
case_stmt(details::e_sf82,details::sf82_op) case_stmt(details::e_sf83,details::sf83_op)
|
|
case_stmt(details::e_sf4ext00,details::sfext00_op) case_stmt(details::e_sf4ext01,details::sfext01_op)
|
|
case_stmt(details::e_sf4ext02,details::sfext02_op) case_stmt(details::e_sf4ext03,details::sfext03_op)
|
|
case_stmt(details::e_sf4ext04,details::sfext04_op) case_stmt(details::e_sf4ext05,details::sfext05_op)
|
|
case_stmt(details::e_sf4ext06,details::sfext06_op) case_stmt(details::e_sf4ext07,details::sfext07_op)
|
|
case_stmt(details::e_sf4ext08,details::sfext08_op) case_stmt(details::e_sf4ext09,details::sfext09_op)
|
|
case_stmt(details::e_sf4ext10,details::sfext10_op) case_stmt(details::e_sf4ext11,details::sfext11_op)
|
|
case_stmt(details::e_sf4ext12,details::sfext12_op) case_stmt(details::e_sf4ext13,details::sfext13_op)
|
|
case_stmt(details::e_sf4ext14,details::sfext14_op) case_stmt(details::e_sf4ext15,details::sfext15_op)
|
|
case_stmt(details::e_sf4ext16,details::sfext16_op) case_stmt(details::e_sf4ext17,details::sfext17_op)
|
|
case_stmt(details::e_sf4ext18,details::sfext18_op) case_stmt(details::e_sf4ext19,details::sfext19_op)
|
|
case_stmt(details::e_sf4ext20,details::sfext20_op) case_stmt(details::e_sf4ext21,details::sfext21_op)
|
|
case_stmt(details::e_sf4ext22,details::sfext22_op) case_stmt(details::e_sf4ext23,details::sfext23_op)
|
|
case_stmt(details::e_sf4ext24,details::sfext24_op) case_stmt(details::e_sf4ext25,details::sfext25_op)
|
|
case_stmt(details::e_sf4ext26,details::sfext26_op) case_stmt(details::e_sf4ext27,details::sfext27_op)
|
|
case_stmt(details::e_sf4ext28,details::sfext28_op) case_stmt(details::e_sf4ext29,details::sfext29_op)
|
|
case_stmt(details::e_sf4ext30,details::sfext30_op) case_stmt(details::e_sf4ext31,details::sfext31_op)
|
|
case_stmt(details::e_sf4ext32,details::sfext32_op) case_stmt(details::e_sf4ext33,details::sfext33_op)
|
|
case_stmt(details::e_sf4ext34,details::sfext34_op) case_stmt(details::e_sf4ext35,details::sfext35_op)
|
|
case_stmt(details::e_sf4ext36,details::sfext36_op) case_stmt(details::e_sf4ext37,details::sfext37_op)
|
|
case_stmt(details::e_sf4ext38,details::sfext38_op) case_stmt(details::e_sf4ext39,details::sfext39_op)
|
|
case_stmt(details::e_sf4ext40,details::sfext40_op) case_stmt(details::e_sf4ext41,details::sfext41_op)
|
|
case_stmt(details::e_sf4ext42,details::sfext42_op) case_stmt(details::e_sf4ext43,details::sfext43_op)
|
|
case_stmt(details::e_sf4ext44,details::sfext44_op) case_stmt(details::e_sf4ext45,details::sfext45_op)
|
|
case_stmt(details::e_sf4ext46,details::sfext46_op) case_stmt(details::e_sf4ext47,details::sfext47_op)
|
|
case_stmt(details::e_sf4ext48,details::sfext48_op) case_stmt(details::e_sf4ext49,details::sfext49_op)
|
|
case_stmt(details::e_sf4ext50,details::sfext50_op) case_stmt(details::e_sf4ext51,details::sfext51_op)
|
|
case_stmt(details::e_sf4ext52,details::sfext52_op) case_stmt(details::e_sf4ext53,details::sfext53_op)
|
|
case_stmt(details::e_sf4ext54,details::sfext54_op) case_stmt(details::e_sf4ext55,details::sfext55_op)
|
|
case_stmt(details::e_sf4ext56,details::sfext56_op) case_stmt(details::e_sf4ext57,details::sfext57_op)
|
|
case_stmt(details::e_sf4ext58,details::sfext58_op) case_stmt(details::e_sf4ext59,details::sfext59_op)
|
|
|
|
#undef case_stmt
|
|
default : return error_node();
|
|
}
|
|
}
|
|
|
|
template <typename T0, typename T1, typename T2, typename T3>
|
|
static inline bool compile(expression_generator<Type>& 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_optimizable(id,sf4opr))
|
|
return false;
|
|
else
|
|
result = synthesize_sf4ext_expression::template process<T0,T1,T2,T3>(expr_gen,sf4opr,t0,t1,t2,t3);
|
|
|
|
return true;
|
|
}
|
|
|
|
// T o (sf3ext)
|
|
template <typename ExternalType>
|
|
static inline bool compile_right(expression_generator<Type>& 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<Type>* sf3ext_base_ptr;
|
|
|
|
sf3ext_base_ptr n = static_cast<sf3ext_base_ptr>(sf3node);
|
|
std::string id = "t" + expr_gen.to_str(operation) + "(" + n->type_id() + ")";
|
|
|
|
switch (n->type())
|
|
{
|
|
case details::expression_node<Type>::e_covoc : return compile_right_impl
|
|
<typename covoc_t::sf3_type_node,ExternalType,ctype,vtype,ctype>
|
|
(expr_gen,id,t,sf3node,result);
|
|
|
|
case details::expression_node<Type>::e_covov : return compile_right_impl
|
|
<typename covov_t::sf3_type_node,ExternalType,ctype,vtype,vtype>
|
|
(expr_gen,id,t,sf3node,result);
|
|
|
|
case details::expression_node<Type>::e_vocov : return compile_right_impl
|
|
<typename vocov_t::sf3_type_node,ExternalType,vtype,ctype,vtype>
|
|
(expr_gen,id,t,sf3node,result);
|
|
|
|
case details::expression_node<Type>::e_vovoc : return compile_right_impl
|
|
<typename vovoc_t::sf3_type_node,ExternalType,vtype,vtype,ctype>
|
|
(expr_gen,id,t,sf3node,result);
|
|
|
|
case details::expression_node<Type>::e_vovov : return compile_right_impl
|
|
<typename vovov_t::sf3_type_node,ExternalType,vtype,vtype,vtype>
|
|
(expr_gen,id,t,sf3node,result);
|
|
|
|
default : return false;
|
|
}
|
|
}
|
|
|
|
// (sf3ext) o T
|
|
template <typename ExternalType>
|
|
static inline bool compile_left(expression_generator<Type>& 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<Type>* sf3ext_base_ptr;
|
|
|
|
sf3ext_base_ptr n = static_cast<sf3ext_base_ptr>(sf3node);
|
|
std::string id = "(" + n->type_id() + ")" + expr_gen.to_str(operation) + "t";
|
|
|
|
switch (n->type())
|
|
{
|
|
case details::expression_node<Type>::e_covoc : return compile_left_impl
|
|
<typename covoc_t::sf3_type_node,ExternalType,ctype,vtype,ctype>
|
|
(expr_gen,id,t,sf3node,result);
|
|
|
|
case details::expression_node<Type>::e_covov : return compile_left_impl
|
|
<typename covov_t::sf3_type_node,ExternalType,ctype,vtype,vtype>
|
|
(expr_gen,id,t,sf3node,result);
|
|
|
|
case details::expression_node<Type>::e_vocov : return compile_left_impl
|
|
<typename vocov_t::sf3_type_node,ExternalType,vtype,ctype,vtype>
|
|
(expr_gen,id,t,sf3node,result);
|
|
|
|
case details::expression_node<Type>::e_vovoc : return compile_left_impl
|
|
<typename vovoc_t::sf3_type_node,ExternalType,vtype,vtype,ctype>
|
|
(expr_gen,id,t,sf3node,result);
|
|
|
|
case details::expression_node<Type>::e_vovov : return compile_left_impl
|
|
<typename vovov_t::sf3_type_node,ExternalType,vtype,vtype,vtype>
|
|
(expr_gen,id,t,sf3node,result);
|
|
|
|
default : return false;
|
|
}
|
|
}
|
|
|
|
template <typename SF3TypeNode, typename ExternalType, typename T0, typename T1, typename T2>
|
|
static inline bool compile_right_impl(expression_generator<Type>& expr_gen,
|
|
const std::string& id,
|
|
ExternalType t,
|
|
expression_node_ptr& node,
|
|
expression_node_ptr& result)
|
|
{
|
|
SF3TypeNode* n = dynamic_cast<SF3TypeNode*>(node);
|
|
|
|
if (n)
|
|
{
|
|
T0 t0 = n->t0();
|
|
T1 t1 = n->t1();
|
|
T2 t2 = n->t2();
|
|
|
|
return synthesize_sf4ext_expression::
|
|
template compile<ExternalType,T0,T1,T2>(expr_gen,id,t,t0,t1,t2,result);
|
|
}
|
|
else
|
|
return false;
|
|
}
|
|
|
|
template <typename SF3TypeNode, typename ExternalType, typename T0, typename T1, typename T2>
|
|
static inline bool compile_left_impl(expression_generator<Type>& expr_gen,
|
|
const std::string& id,
|
|
ExternalType t,
|
|
expression_node_ptr& node,
|
|
expression_node_ptr& result)
|
|
{
|
|
SF3TypeNode* n = dynamic_cast<SF3TypeNode*>(node);
|
|
|
|
if (n)
|
|
{
|
|
T0 t0 = n->t0();
|
|
T1 t1 = n->t1();
|
|
T2 t2 = n->t2();
|
|
|
|
return synthesize_sf4ext_expression::
|
|
template compile<T0,T1,T2,ExternalType>(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<Type>& expr_gen,
|
|
const details::operator_type& operation,
|
|
expression_node_ptr (&branch)[2])
|
|
{
|
|
// (v0 o0 v1) o1 (v2)
|
|
const details::vov_base_node<Type>* vov = static_cast<details::vov_base_node<Type>*>(branch[0]);
|
|
const Type& v0 = vov->v0();
|
|
const Type& v1 = vov->v1();
|
|
const Type& v2 = static_cast<details::variable_node<Type>*>(branch[1])->ref();
|
|
const details::operator_type o0 = vov->operation();
|
|
const details::operator_type o1 = operation;
|
|
|
|
binary_functor_t f0 = reinterpret_cast<binary_functor_t>(0);
|
|
binary_functor_t f1 = reinterpret_cast<binary_functor_t>(0);
|
|
|
|
details::free_node(*(expr_gen.node_allocator_),branch[0]);
|
|
|
|
expression_node_ptr result = error_node();
|
|
|
|
if (expr_gen.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<vtype,vtype,vtype>(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<vtype,vtype,vtype>(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<Type>& 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<Type>& expr_gen,
|
|
const details::operator_type& operation,
|
|
expression_node_ptr (&branch)[2])
|
|
{
|
|
// (v0) o0 (v1 o1 v2)
|
|
const details::vov_base_node<Type>* vov = static_cast<details::vov_base_node<Type>*>(branch[1]);
|
|
const Type& v0 = static_cast<details::variable_node<Type>*>(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<binary_functor_t>(0);
|
|
binary_functor_t f1 = reinterpret_cast<binary_functor_t>(0);
|
|
|
|
details::free_node(*(expr_gen.node_allocator_),branch[1]);
|
|
|
|
expression_node_ptr result = error_node();
|
|
|
|
if (expr_gen.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<vtype,vtype,vtype>(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<vtype,vtype,vtype>(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<Type>& 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<Type>& expr_gen,
|
|
const details::operator_type& operation,
|
|
expression_node_ptr (&branch)[2])
|
|
{
|
|
// (v0 o0 v1) o1 (c)
|
|
const details::vov_base_node<Type>* vov = static_cast<details::vov_base_node<Type>*>(branch[0]);
|
|
const Type& v0 = vov->v0();
|
|
const Type& v1 = vov->v1();
|
|
const Type c = static_cast<details::literal_node<Type>*>(branch[1])->value();
|
|
const details::operator_type o0 = vov->operation();
|
|
const details::operator_type o1 = operation;
|
|
|
|
binary_functor_t f0 = reinterpret_cast<binary_functor_t>(0);
|
|
binary_functor_t f1 = reinterpret_cast<binary_functor_t>(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.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<vtype,vtype,ctype>(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<vtype,vtype,ctype>(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<Type>& 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<Type>& expr_gen,
|
|
const details::operator_type& operation,
|
|
expression_node_ptr (&branch)[2])
|
|
{
|
|
// (v0) o0 (v1 o1 c)
|
|
const details::voc_base_node<Type>* voc = static_cast<const details::voc_base_node<Type>*>(branch[1]);
|
|
const Type& v0 = static_cast<details::variable_node<Type>*>(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<binary_functor_t>(0);
|
|
binary_functor_t f1 = reinterpret_cast<binary_functor_t>(0);
|
|
|
|
details::free_node(*(expr_gen.node_allocator_),branch[1]);
|
|
|
|
expression_node_ptr result = error_node();
|
|
|
|
if (expr_gen.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<vtype,ctype,vtype>(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<vtype,vtype,ctype>(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<Type>& 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<Type>& expr_gen,
|
|
const details::operator_type& operation,
|
|
expression_node_ptr (&branch)[2])
|
|
{
|
|
// (v0 o0 c) o1 (v1)
|
|
const details::voc_base_node<Type>* voc = static_cast<details::voc_base_node<Type>*>(branch[0]);
|
|
const Type& v0 = voc->v();
|
|
const Type c = voc->c();
|
|
const Type& v1 = static_cast<details::variable_node<Type>*>(branch[1])->ref();
|
|
const details::operator_type o0 = voc->operation();
|
|
const details::operator_type o1 = operation;
|
|
|
|
binary_functor_t f0 = reinterpret_cast<binary_functor_t>(0);
|
|
binary_functor_t f1 = reinterpret_cast<binary_functor_t>(0);
|
|
|
|
details::free_node(*(expr_gen.node_allocator_),branch[0]);
|
|
|
|
expression_node_ptr result = error_node();
|
|
|
|
if (expr_gen.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<vtype,vtype,ctype>(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<vtype,ctype,vtype>(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<Type>& 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<Type>& expr_gen,
|
|
const details::operator_type& operation,
|
|
expression_node_ptr (&branch)[2])
|
|
{
|
|
// (v0) o0 (c o1 v1)
|
|
const details::cov_base_node<Type>* cov = static_cast<details::cov_base_node<Type>*>(branch[1]);
|
|
const Type& v0 = static_cast<details::variable_node<Type>*>(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<binary_functor_t>(0);
|
|
binary_functor_t f1 = reinterpret_cast<binary_functor_t>(0);
|
|
|
|
details::free_node(*(expr_gen.node_allocator_),branch[1]);
|
|
|
|
expression_node_ptr result = error_node();
|
|
|
|
if (expr_gen.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<vtype,vtype,ctype>(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<vtype,ctype,vtype>(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<Type>& 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<Type>& expr_gen,
|
|
const details::operator_type& operation,
|
|
expression_node_ptr (&branch)[2])
|
|
{
|
|
// (c o0 v0) o1 (v1)
|
|
const details::cov_base_node<Type>* cov = static_cast<details::cov_base_node<Type>*>(branch[0]);
|
|
const Type c = cov->c();
|
|
const Type& v0 = cov->v();
|
|
const Type& v1 = static_cast<details::variable_node<Type>*>(branch[1])->ref();
|
|
const details::operator_type o0 = cov->operation();
|
|
const details::operator_type o1 = operation;
|
|
|
|
binary_functor_t f0 = reinterpret_cast<binary_functor_t>(0);
|
|
binary_functor_t f1 = reinterpret_cast<binary_functor_t>(0);
|
|
|
|
details::free_node(*(expr_gen.node_allocator_),branch[0]);
|
|
|
|
expression_node_ptr result = error_node();
|
|
|
|
if (expr_gen.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<ctype,vtype,vtype>(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<ctype,vtype,vtype>(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<Type>& 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<Type>& expr_gen,
|
|
const details::operator_type& operation,
|
|
expression_node_ptr (&branch)[2])
|
|
{
|
|
// (c) o0 (v0 o1 v1)
|
|
const details::vov_base_node<Type>* vov = static_cast<details::vov_base_node<Type>*>(branch[1]);
|
|
const Type c = static_cast<details::literal_node<Type>*>(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<binary_functor_t>(0);
|
|
binary_functor_t f1 = reinterpret_cast<binary_functor_t>(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.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<ctype,vtype,vtype>(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<ctype,vtype,vtype>(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<Type>& 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<Type>& expr_gen,
|
|
const details::operator_type& operation,
|
|
expression_node_ptr (&branch)[2])
|
|
{
|
|
// (c0 o0 v) o1 (c1)
|
|
const details::cov_base_node<Type>* cov = static_cast<details::cov_base_node<Type>*>(branch[0]);
|
|
const Type c0 = cov->c();
|
|
const Type& v = cov->v();
|
|
const Type c1 = static_cast<details::literal_node<Type>*>(branch[1])->value();
|
|
const details::operator_type o0 = cov->operation();
|
|
const details::operator_type o1 = operation;
|
|
|
|
binary_functor_t f0 = reinterpret_cast<binary_functor_t>(0);
|
|
binary_functor_t f1 = reinterpret_cast<binary_functor_t>(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.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<typename details::cov_node<Type,details::add_op<Type> > >(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<typename details::cov_node<Type,details::add_op<Type> > >(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<typename details::cov_node<Type,details::sub_op<Type> > >(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<typename details::cov_node<Type,details::sub_op<Type> > >(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<typename details::cov_node<Type,details::mul_op<Type> > >(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<typename details::cov_node<Type,details::mul_op<Type> > >(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<typename details::cov_node<Type,details::div_op<Type> > >(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<typename details::cov_node<Type,details::div_op<Type> > >(c0 / c1,v);
|
|
}
|
|
}
|
|
|
|
if (synthesize_sf3ext_expression::template compile<ctype,vtype,ctype>(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<Type>& 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<Type>& expr_gen,
|
|
const details::operator_type& operation,
|
|
expression_node_ptr (&branch)[2])
|
|
{
|
|
// (c0) o0 (v o1 c1)
|
|
const details::voc_base_node<Type>* voc = static_cast<details::voc_base_node<Type>*>(branch[1]);
|
|
const Type c0 = static_cast<details::literal_node<Type>*>(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<binary_functor_t>(0);
|
|
binary_functor_t f1 = reinterpret_cast<binary_functor_t>(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.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<typename details::cov_node<Type,details::add_op<Type> > >(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<typename details::cov_node<Type,details::add_op<Type> > >(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<typename details::cov_node<Type,details::sub_op<Type> > >(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<typename details::cov_node<Type,details::sub_op<Type> > >(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<typename details::cov_node<Type,details::mul_op<Type> > >(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<typename details::cov_node<Type,details::mul_op<Type> > >(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<typename details::cov_node<Type,details::div_op<Type> > >(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<typename details::cov_node<Type,details::div_op<Type> > >(c0 * c1,v);
|
|
}
|
|
}
|
|
|
|
if (synthesize_sf3ext_expression::template compile<ctype,vtype,ctype>(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<Type>& 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<Type>&, 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<Type>& expr_gen,
|
|
const details::operator_type& operation,
|
|
expression_node_ptr (&branch)[2])
|
|
{
|
|
// (c0) o0 (c1 o1 v)
|
|
const details::cov_base_node<Type>* cov = static_cast<details::cov_base_node<Type>*>(branch[1]);
|
|
const Type c0 = static_cast<details::literal_node<Type>*>(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<binary_functor_t>(0);
|
|
binary_functor_t f1 = reinterpret_cast<binary_functor_t>(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.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<typename details::cov_node<Type,details::add_op<Type> > >(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<typename details::cov_node<Type,details::sub_op<Type> > >(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<typename details::cov_node<Type,details::sub_op<Type> > >(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<typename details::cov_node<Type,details::add_op<Type> > >(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<typename details::cov_node<Type,details::mul_op<Type> > >(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<typename details::cov_node<Type,details::div_op<Type> > >(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<typename details::cov_node<Type,details::div_op<Type> > >(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<typename details::cov_node<Type,details::mul_op<Type> > >(c0 / c1,v);
|
|
}
|
|
}
|
|
|
|
if (synthesize_sf3ext_expression::template compile<ctype,ctype,vtype>(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<Type>& 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<Type>& expr_gen,
|
|
const details::operator_type& operation,
|
|
expression_node_ptr (&branch)[2])
|
|
{
|
|
// (v o0 c0) o1 (c1)
|
|
const details::voc_base_node<Type>* voc = static_cast<details::voc_base_node<Type>*>(branch[0]);
|
|
const Type& v = voc->v();
|
|
const Type& c0 = voc->c();
|
|
const Type& c1 = static_cast<details::literal_node<Type>*>(branch[1])->value();
|
|
const details::operator_type o0 = voc->operation();
|
|
const details::operator_type o1 = operation;
|
|
|
|
binary_functor_t f0 = reinterpret_cast<binary_functor_t>(0);
|
|
binary_functor_t f1 = reinterpret_cast<binary_functor_t>(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.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<typename details::voc_node<Type,details::add_op<Type> > >(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<typename details::voc_node<Type,details::add_op<Type> > >(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<typename details::voc_node<Type,details::add_op<Type> > >(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<typename details::voc_node<Type,details::sub_op<Type> > >(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<typename details::voc_node<Type,details::mul_op<Type> > >(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<typename details::voc_node<Type,details::mul_op<Type> > >(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<typename details::voc_node<Type,details::mul_op<Type> > >(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<typename details::voc_node<Type,details::div_op<Type> > >(v,c0 * c1);
|
|
}
|
|
}
|
|
|
|
if (synthesize_sf3ext_expression::template compile<vtype,ctype,ctype>(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<Type>& 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<Type>&, 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<Type>& expr_gen,
|
|
const details::operator_type& operation,
|
|
expression_node_ptr (&branch)[2])
|
|
{
|
|
// (v0 o0 v1) o1 (v2 o2 v3)
|
|
const details::vov_base_node<Type>* vov0 = static_cast<details::vov_base_node<Type>*>(branch[0]);
|
|
const details::vov_base_node<Type>* vov1 = static_cast<details::vov_base_node<Type>*>(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<binary_functor_t>(0);
|
|
binary_functor_t f1 = reinterpret_cast<binary_functor_t>(0);
|
|
binary_functor_t f2 = reinterpret_cast<binary_functor_t>(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.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<vtype,vtype,vtype,vtype>(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<vtype,vtype,vtype,vtype>(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();
|
|
}
|
|
}
|
|
|
|
if (synthesize_sf4ext_expression::template compile<T0,T1,T2,T3>(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<Type>& 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<Type>& expr_gen,
|
|
const details::operator_type& operation,
|
|
expression_node_ptr (&branch)[2])
|
|
{
|
|
// (v0 o0 v1) o1 (v2 o2 c)
|
|
const details::vov_base_node<Type>* vov = static_cast<details::vov_base_node<Type>*>(branch[0]);
|
|
const details::voc_base_node<Type>* voc = static_cast<details::voc_base_node<Type>*>(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<binary_functor_t>(0);
|
|
binary_functor_t f1 = reinterpret_cast<binary_functor_t>(0);
|
|
binary_functor_t f2 = reinterpret_cast<binary_functor_t>(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.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<vtype,vtype,vtype,ctype>(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<vtype,ctype,vtype,vtype>(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<T0,T1,T2,T3>(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<Type>& 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<Type>& expr_gen,
|
|
const details::operator_type& operation,
|
|
expression_node_ptr (&branch)[2])
|
|
{
|
|
// (v0 o0 v1) o1 (c o2 v2)
|
|
const details::vov_base_node<Type>* vov = static_cast<details::vov_base_node<Type>*>(branch[0]);
|
|
const details::cov_base_node<Type>* cov = static_cast<details::cov_base_node<Type>*>(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<binary_functor_t>(0);
|
|
binary_functor_t f1 = reinterpret_cast<binary_functor_t>(0);
|
|
binary_functor_t f2 = reinterpret_cast<binary_functor_t>(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.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<vtype,ctype,vtype,vtype>(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<vtype,vtype,vtype,ctype>(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<T0,T1,T2,T3>(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<Type>& 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<Type>& expr_gen,
|
|
const details::operator_type& operation,
|
|
expression_node_ptr (&branch)[2])
|
|
{
|
|
// (v0 o0 c) o1 (v1 o2 v2)
|
|
const details::voc_base_node<Type>* voc = static_cast<details::voc_base_node<Type>*>(branch[0]);
|
|
const details::vov_base_node<Type>* vov = static_cast<details::vov_base_node<Type>*>(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<binary_functor_t>(0);
|
|
binary_functor_t f1 = reinterpret_cast<binary_functor_t>(0);
|
|
binary_functor_t f2 = reinterpret_cast<binary_functor_t>(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.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<vtype,vtype,ctype,vtype>(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<vtype,vtype,ctype,vtype>(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<T0,T1,T2,T3>(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<Type>& 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<Type>& expr_gen,
|
|
const details::operator_type& operation,
|
|
expression_node_ptr (&branch)[2])
|
|
{
|
|
// (c o0 v0) o1 (v1 o2 v2)
|
|
const details::cov_base_node<Type>* cov = static_cast<details::cov_base_node<Type>*>(branch[0]);
|
|
const details::vov_base_node<Type>* vov = static_cast<details::vov_base_node<Type>*>(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<binary_functor_t>(0);
|
|
binary_functor_t f1 = reinterpret_cast<binary_functor_t>(0);
|
|
binary_functor_t f2 = reinterpret_cast<binary_functor_t>(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.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<ctype,vtype,vtype,vtype>(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<ctype,vtype,vtype,vtype>(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<T0,T1,T2,T3>(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<Type>& 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<Type>& expr_gen,
|
|
const details::operator_type& operation,
|
|
expression_node_ptr (&branch)[2])
|
|
{
|
|
// (c0 o0 v0) o1 (c1 o2 v1)
|
|
const details::cov_base_node<Type>* cov0 = static_cast<details::cov_base_node<Type>*>(branch[0]);
|
|
const details::cov_base_node<Type>* cov1 = static_cast<details::cov_base_node<Type>*>(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<binary_functor_t>(0);
|
|
binary_functor_t f1 = reinterpret_cast<binary_functor_t>(0);
|
|
binary_functor_t f2 = reinterpret_cast<binary_functor_t>(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.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<ctype,vtype,vtype>(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<ctype,vtype,vtype>(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<ctype,vtype,vtype>(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<ctype,vtype,vtype>(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<ctype,vtype,vtype>(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<ctype,vtype,vtype>(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<ctype,vtype,vtype>(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<ctype,vtype,vtype>(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<ctype,vtype,vtype>(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<T>()(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<ctype,vtype,vtype>(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<T0,T1,T2,T3>(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<Type>& 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<Type>& expr_gen,
|
|
const details::operator_type& operation,
|
|
expression_node_ptr (&branch)[2])
|
|
{
|
|
// (v0 o0 c0) o1 (v1 o2 c1)
|
|
const details::voc_base_node<Type>* voc0 = static_cast<details::voc_base_node<Type>*>(branch[0]);
|
|
const details::voc_base_node<Type>* voc1 = static_cast<details::voc_base_node<Type>*>(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<binary_functor_t>(0);
|
|
binary_functor_t f1 = reinterpret_cast<binary_functor_t>(0);
|
|
binary_functor_t f2 = reinterpret_cast<binary_functor_t>(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.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<ctype,vtype,vtype>(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<ctype,vtype,vtype>(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<ctype,vtype,vtype>(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<ctype,vtype,vtype>(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<ctype,vtype,vtype>(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<ctype,vtype,vtype>(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<ctype,vtype,vtype>(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<ctype,vtype,vtype>(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<ctype,vtype,vtype>(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<vtype,ctype,vtype,ctype>(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<vtype,ctype,vtype,ctype>(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<T>()(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<ctype,vtype,vtype>(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<T>()(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<ctype,vtype,vtype>(expr_gen,specfunc,c0,v0,v1,result);
|
|
|
|
exprtk_debug(("(v0 / c) +/- (v1 / c) --> (vovoc) (v0 +/- v1) / c\n"));
|
|
|
|
return (synthesis_result) ? result : error_node();
|
|
}
|
|
}
|
|
|
|
if (synthesize_sf4ext_expression::template compile<T0,T1,T2,T3>(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<Type>& 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<Type>& expr_gen,
|
|
const details::operator_type& operation,
|
|
expression_node_ptr (&branch)[2])
|
|
{
|
|
// (c0 o0 v0) o1 (v1 o2 c1)
|
|
const details::cov_base_node<Type>* cov = static_cast<details::cov_base_node<Type>*>(branch[0]);
|
|
const details::voc_base_node<Type>* voc = static_cast<details::voc_base_node<Type>*>(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<binary_functor_t>(0);
|
|
binary_functor_t f1 = reinterpret_cast<binary_functor_t>(0);
|
|
binary_functor_t f2 = reinterpret_cast<binary_functor_t>(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.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<ctype,vtype,vtype>(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<ctype,vtype,vtype>(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<ctype,vtype,vtype>(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<ctype,vtype,vtype>(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<ctype,vtype,vtype>(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<ctype,vtype,vtype>(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<ctype,vtype,vtype>(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<ctype,vtype,vtype>(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<ctype,vtype,vtype>(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<T>()(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<ctype,vtype,vtype>(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<T0,T1,T2,T3>(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<Type>& 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<Type>& expr_gen,
|
|
const details::operator_type& operation,
|
|
expression_node_ptr (&branch)[2])
|
|
{
|
|
// (v0 o0 c0) o1 (c1 o2 v1)
|
|
const details::voc_base_node<Type>* voc = static_cast<details::voc_base_node<Type>*>(branch[0]);
|
|
const details::cov_base_node<Type>* cov = static_cast<details::cov_base_node<Type>*>(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<binary_functor_t>(0);
|
|
binary_functor_t f1 = reinterpret_cast<binary_functor_t>(0);
|
|
binary_functor_t f2 = reinterpret_cast<binary_functor_t>(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.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<ctype,vtype,vtype>(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<ctype,vtype,vtype>(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<vtype,vtype,ctype>(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<ctype,vtype,vtype>(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<ctype,vtype,vtype>(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<ctype,vtype,vtype>(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<ctype,vtype,vtype>(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<ctype,vtype,vtype>(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<vtype,vtype,ctype>(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<T>()(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<ctype,vtype,vtype>(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<T0,T1,T2,T3>(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<Type>& 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<Type>& 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 vovov_t;
|
|
|
|
const vovov_t* vovov = static_cast<const vovov_t*>(branch[1]);
|
|
const Type& v0 = static_cast<details::variable_node<Type>*>(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<binary_functor_t>(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<T0,T1,T2,T3>(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<Type>& 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<Type>& 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 vovoc_t;
|
|
|
|
const vovoc_t* vovoc = static_cast<const vovoc_t*>(branch[1]);
|
|
const Type& v0 = static_cast<details::variable_node<Type>*>(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<binary_functor_t>(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<T0,T1,T2,T3>(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<Type>& 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<Type>& 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 vocov_t;
|
|
|
|
const vocov_t* vocov = static_cast<const vocov_t*>(branch[1]);
|
|
const Type& v0 = static_cast<details::variable_node<Type>*>(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<binary_functor_t>(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<T0,T1,T2,T3>(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<Type>& 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<Type>& 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 covov_t;
|
|
|
|
const covov_t* covov = static_cast<const covov_t*>(branch[1]);
|
|
const Type& v0 = static_cast<details::variable_node<Type>*>(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<binary_functor_t>(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<T0,T1,T2,T3>(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<Type>& 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<Type>& 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 vovov_t;
|
|
|
|
const vovov_t* vovov = static_cast<const vovov_t*>(branch[1]);
|
|
const Type c = static_cast<details::literal_node<Type>*>(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<binary_functor_t>(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<T0,T1,T2,T3>(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<Type>& 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<Type>& 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 vocov_t;
|
|
|
|
const vocov_t* vocov = static_cast<const vocov_t*>(branch[1]);
|
|
const Type c0 = static_cast<details::literal_node<Type>*>(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<binary_functor_t>(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<T0,T1,T2,T3>(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<Type>& 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<Type>& 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 covoc_t;
|
|
|
|
const covoc_t* covoc = static_cast<const covoc_t*>(branch[1]);
|
|
const Type& v0 = static_cast<details::variable_node<Type>*>(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<binary_functor_t>(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<T0,T1,T2,T3>(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<Type>& 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<Type>& 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 vovoc_t;
|
|
|
|
const vovoc_t* vovoc = static_cast<const vovoc_t*>(branch[1]);
|
|
const Type c0 = static_cast<details::literal_node<Type>*>(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<binary_functor_t>(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<T0,T1,T2,T3>(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<Type>& 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<Type>& 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 cocov_t;
|
|
|
|
const cocov_t* cocov = static_cast<const cocov_t*>(branch[1]);
|
|
const Type& v0 = static_cast<details::variable_node<Type>*>(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<binary_functor_t>(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<T0,T1,T2,T3>(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<Type>& 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<Type>& 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 vovov_t;
|
|
|
|
const vovov_t* vovov = static_cast<const vovov_t*>(branch[1]);
|
|
const Type& v0 = static_cast<details::variable_node<Type>*>(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<binary_functor_t>(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<T0,T1,T2,T3>(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<Type>& 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<Type>& 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 vovoc_t;
|
|
|
|
const vovoc_t* vovoc = static_cast<const vovoc_t*>(branch[1]);
|
|
const Type& v0 = static_cast<details::variable_node<Type>*>(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<binary_functor_t>(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<T0,T1,T2,T3>(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<Type>& 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<Type>& 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 vocov_t;
|
|
|
|
const vocov_t* vocov = static_cast<const vocov_t*>(branch[1]);
|
|
const Type& v0 = static_cast<details::variable_node<Type>*>(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<binary_functor_t>(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<T0,T1,T2,T3>(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<Type>& 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<Type>& 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 covov_t;
|
|
|
|
const covov_t* covov = static_cast<const covov_t*>(branch[1]);
|
|
const Type& v0 = static_cast<details::variable_node<Type>*>(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<binary_functor_t>(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<T0,T1,T2,T3>(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<Type>& 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<Type>& 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 vovov_t;
|
|
|
|
const vovov_t* vovov = static_cast<const vovov_t*>(branch[1]);
|
|
const Type c = static_cast<details::literal_node<Type>*>(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<binary_functor_t>(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<T0,T1,T2,T3>(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<Type>& 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<Type>& 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 vocov_t;
|
|
|
|
const vocov_t* vocov = static_cast<const vocov_t*>(branch[1]);
|
|
const Type c0 = static_cast<details::literal_node<Type>*>(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<binary_functor_t>(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<T0,T1,T2,T3>(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<Type>& 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<Type>& 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 covoc_t;
|
|
|
|
const covoc_t* covoc = static_cast<const covoc_t*>(branch[1]);
|
|
const Type& v0 = static_cast<details::variable_node<Type>*>(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<binary_functor_t>(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<T0,T1,T2,T3>(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<Type>& 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<Type>& 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 vovoc_t;
|
|
|
|
const vovoc_t* vovoc = static_cast<const vovoc_t*>(branch[1]);
|
|
const Type c0 = static_cast<details::literal_node<Type>*>(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<binary_functor_t>(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<T0,T1,T2,T3>(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<Type>& 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<Type>&, 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<Type>&,
|
|
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<Type>& 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 vovov_t;
|
|
|
|
const vovov_t* vovov = static_cast<const vovov_t*>(branch[0]);
|
|
const Type& v0 = vovov->t0();
|
|
const Type& v1 = vovov->t1();
|
|
const Type& v2 = vovov->t2();
|
|
const Type& v3 = static_cast<details::variable_node<Type>*>(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<binary_functor_t>(0);
|
|
|
|
details::free_node(*(expr_gen.node_allocator_),branch[0]);
|
|
|
|
expression_node_ptr result = error_node();
|
|
|
|
if (synthesize_sf4ext_expression::template compile<T0,T1,T2,T3>(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<Type>& 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<Type>& 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 vovov_t;
|
|
|
|
const vovov_t* vovov = static_cast<const vovov_t*>(branch[0]);
|
|
const Type& v0 = vovov->t0();
|
|
const Type& v1 = vovov->t1();
|
|
const Type& v2 = vovov->t2();
|
|
const Type c = static_cast<details::literal_node<Type>*>(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<binary_functor_t>(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<T0,T1,T2,T3>(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<Type>& 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<Type>& 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 vovoc_t;
|
|
|
|
const vovoc_t* vovoc = static_cast<const vovoc_t*>(branch[0]);
|
|
const Type& v0 = vovoc->t0();
|
|
const Type& v1 = vovoc->t1();
|
|
const Type c = vovoc->t2();
|
|
const Type& v2 = static_cast<details::variable_node<Type>*>(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<binary_functor_t>(0);
|
|
|
|
details::free_node(*(expr_gen.node_allocator_),branch[0]);
|
|
|
|
expression_node_ptr result = error_node();
|
|
|
|
if (synthesize_sf4ext_expression::template compile<T0,T1,T2,T3>(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<Type>& 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<Type>& 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 vocov_t;
|
|
|
|
const vocov_t* vocov = static_cast<const vocov_t*>(branch[0]);
|
|
const Type& v0 = vocov->t0();
|
|
const Type c = vocov->t1();
|
|
const Type& v1 = vocov->t2();
|
|
const Type& v2 = static_cast<details::variable_node<Type>*>(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<binary_functor_t>(0);
|
|
|
|
details::free_node(*(expr_gen.node_allocator_),branch[0]);
|
|
|
|
expression_node_ptr result = error_node();
|
|
|
|
if (synthesize_sf4ext_expression::template compile<T0,T1,T2,T3>(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<Type>& 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<Type>& 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 covov_t;
|
|
|
|
const covov_t* covov = static_cast<const covov_t*>(branch[0]);
|
|
const Type c = covov->t0();
|
|
const Type& v0 = covov->t1();
|
|
const Type& v1 = covov->t2();
|
|
const Type& v2 = static_cast<details::variable_node<Type>*>(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<binary_functor_t>(0);
|
|
|
|
details::free_node(*(expr_gen.node_allocator_),branch[0]);
|
|
|
|
expression_node_ptr result = error_node();
|
|
|
|
if (synthesize_sf4ext_expression::template compile<T0,T1,T2,T3>(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<Type>& 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<Type>& 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 covoc_t;
|
|
|
|
const covoc_t* covoc = static_cast<const covoc_t*>(branch[0]);
|
|
const Type c0 = covoc->t0();
|
|
const Type& v0 = covoc->t1();
|
|
const Type c1 = covoc->t2();
|
|
const Type& v1 = static_cast<details::variable_node<Type>*>(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<binary_functor_t>(0);
|
|
|
|
details::free_node(*(expr_gen.node_allocator_),branch[0]);
|
|
|
|
expression_node_ptr result = error_node();
|
|
|
|
if (synthesize_sf4ext_expression::template compile<T0,T1,T2,T3>(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<Type>& 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<Type>& 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 vocov_t;
|
|
|
|
const vocov_t* vocov = static_cast<const vocov_t*>(branch[0]);
|
|
const Type& v0 = vocov->t0();
|
|
const Type c0 = vocov->t1();
|
|
const Type& v1 = vocov->t2();
|
|
const Type c1 = static_cast<details::literal_node<Type>*>(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<binary_functor_t>(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<T0,T1,T2,T3>(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<Type>& 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<Type>& 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 covov_t;
|
|
|
|
const covov_t* covov = static_cast<const covov_t*>(branch[0]);
|
|
const Type c0 = covov->t0();
|
|
const Type& v0 = covov->t1();
|
|
const Type& v1 = covov->t2();
|
|
const Type c1 = static_cast<details::literal_node<Type>*>(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<binary_functor_t>(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<T0,T1,T2,T3>(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<Type>& 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<Type>& 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 vococ_t;
|
|
|
|
const vococ_t* vococ = static_cast<const vococ_t*>(branch[0]);
|
|
const Type& v0 = vococ->t0();
|
|
const Type c0 = vococ->t1();
|
|
const Type c1 = vococ->t2();
|
|
const Type& v1 = static_cast<details::variable_node<Type>*>(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<binary_functor_t>(0);
|
|
|
|
details::free_node(*(expr_gen.node_allocator_),branch[0]);
|
|
|
|
expression_node_ptr result = error_node();
|
|
|
|
if (synthesize_sf4ext_expression::template compile<T0,T1,T2,T3>(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<Type>& 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<Type>& 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 vovov_t;
|
|
|
|
const vovov_t* vovov = static_cast<const vovov_t*>(branch[0]);
|
|
const Type& v0 = vovov->t0();
|
|
const Type& v1 = vovov->t1();
|
|
const Type& v2 = vovov->t2();
|
|
const Type& v3 = static_cast<details::variable_node<Type>*>(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<binary_functor_t>(0);
|
|
|
|
details::free_node(*(expr_gen.node_allocator_),branch[0]);
|
|
|
|
expression_node_ptr result = error_node();
|
|
|
|
if (synthesize_sf4ext_expression::template compile<T0,T1,T2,T3>(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<Type>& 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<Type>& 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 vovov_t;
|
|
|
|
const vovov_t* vovov = static_cast<const vovov_t*>(branch[0]);
|
|
const Type& v0 = vovov->t0();
|
|
const Type& v1 = vovov->t1();
|
|
const Type& v2 = vovov->t2();
|
|
const Type c = static_cast<details::literal_node<Type>*>(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<binary_functor_t>(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<T0,T1,T2,T3>(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<Type>& 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<Type>& 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 vovoc_t;
|
|
|
|
const vovoc_t* vovoc = static_cast<const vovoc_t*>(branch[0]);
|
|
const Type& v0 = vovoc->t0();
|
|
const Type& v1 = vovoc->t1();
|
|
const Type c = vovoc->t2();
|
|
const Type& v2 = static_cast<details::variable_node<Type>*>(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<binary_functor_t>(0);
|
|
|
|
details::free_node(*(expr_gen.node_allocator_),branch[0]);
|
|
|
|
expression_node_ptr result = error_node();
|
|
|
|
if (synthesize_sf4ext_expression::template compile<T0,T1,T2,T3>(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<Type>& 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<Type>& 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 vocov_t;
|
|
|
|
const vocov_t* vocov = static_cast<const vocov_t*>(branch[0]);
|
|
const Type& v0 = vocov->t0();
|
|
const Type c = vocov->t1();
|
|
const Type& v1 = vocov->t2();
|
|
const Type& v2 = static_cast<details::variable_node<Type>*>(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<binary_functor_t>(0);
|
|
|
|
details::free_node(*(expr_gen.node_allocator_),branch[0]);
|
|
expression_node_ptr result = error_node();
|
|
|
|
if (synthesize_sf4ext_expression::template compile<T0,T1,T2,T3>(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<Type>& 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<Type>& 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 covov_t;
|
|
|
|
const covov_t* covov = static_cast<const covov_t*>(branch[0]);
|
|
const Type c = covov->t0();
|
|
const Type& v0 = covov->t1();
|
|
const Type& v1 = covov->t2();
|
|
const Type& v2 = static_cast<details::variable_node<Type>*>(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<binary_functor_t>(0);
|
|
|
|
details::free_node(*(expr_gen.node_allocator_),branch[0]);
|
|
|
|
expression_node_ptr result = error_node();
|
|
|
|
if (synthesize_sf4ext_expression::template compile<T0,T1,T2,T3>(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<Type>& 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<Type>& 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 covoc_t;
|
|
|
|
const covoc_t* covoc = static_cast<const covoc_t*>(branch[0]);
|
|
const Type c0 = covoc->t0();
|
|
const Type& v0 = covoc->t1();
|
|
const Type c1 = covoc->t2();
|
|
const Type& v1 = static_cast<details::variable_node<Type>*>(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<binary_functor_t>(0);
|
|
|
|
details::free_node(*(expr_gen.node_allocator_),branch[0]);
|
|
|
|
expression_node_ptr result = error_node();
|
|
|
|
if (synthesize_sf4ext_expression::template compile<T0,T1,T2,T3>(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<Type>& 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<Type>& 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 vocov_t;
|
|
|
|
const vocov_t* vocov = static_cast<const vocov_t*>(branch[0]);
|
|
const Type& v0 = vocov->t0();
|
|
const Type c0 = vocov->t1();
|
|
const Type& v1 = vocov->t2();
|
|
const Type c1 = static_cast<details::literal_node<Type>*>(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<binary_functor_t>(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<T0,T1,T2,T3>(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<Type>& 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<Type>& 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 covov_t;
|
|
|
|
const covov_t* covov = static_cast<const covov_t*>(branch[0]);
|
|
const Type c0 = covov->t0();
|
|
const Type& v0 = covov->t1();
|
|
const Type& v1 = covov->t2();
|
|
const Type c1 = static_cast<details::literal_node<Type>*>(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<binary_functor_t>(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<T0,T1,T2,T3>(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<Type>& 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<Type>&, 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<Type>&,
|
|
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<details::uv_base_node<Type>*>(branch[0])->operation();
|
|
details::operator_type o1 = static_cast<details::uv_base_node<Type>*>(branch[1])->operation();
|
|
const Type& v0 = static_cast<details::uv_base_node<Type>*>(branch[0])->v();
|
|
const Type& v1 = static_cast<details::uv_base_node<Type>*>(branch[1])->v();
|
|
unary_functor_t u0 = reinterpret_cast<unary_functor_t> (0);
|
|
unary_functor_t u1 = reinterpret_cast<unary_functor_t> (0);
|
|
binary_functor_t f = reinterpret_cast<binary_functor_t>(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<typename details::
|
|
vov_node<Type,details::add_op<Type> > >(v0,v1));
|
|
exprtk_debug(("(-v0 + -v1) --> -(v0 + v1)\n"));
|
|
break;
|
|
|
|
// (-v0 - -v1) --> (v1 - v0)
|
|
case details::e_sub : result = node_allocator_->
|
|
allocate_rr<typename details::
|
|
vov_node<Type,details::sub_op<Type> > >(v1,v0);
|
|
exprtk_debug(("(-v0 - -v1) --> (v1 - v0)\n"));
|
|
break;
|
|
|
|
// (-v0 * -v1) --> (v0 * v1)
|
|
case details::e_mul : result = node_allocator_->
|
|
allocate_rr<typename details::
|
|
vov_node<Type,details::mul_op<Type> > >(v0,v1);
|
|
exprtk_debug(("(-v0 * -v1) --> (v0 * v1)\n"));
|
|
break;
|
|
|
|
// (-v0 / -v1) --> (v0 / v1)
|
|
case details::e_div : result = node_allocator_->
|
|
allocate_rr<typename details::
|
|
vov_node<Type,details::div_op<Type> > >(v0,v1);
|
|
exprtk_debug(("(-v0 / -v1) --> (v0 / v1)\n"));
|
|
break;
|
|
|
|
default : break;
|
|
}
|
|
}
|
|
|
|
if (0 == result)
|
|
{
|
|
result = node_allocator_->
|
|
allocate_rrrrr<typename details::uvouv_node<Type> >(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 <typename T0, typename T1>
|
|
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<typename details::str_xrox_node<Type,T0,T1,range_t,op1<Type> >,T0,T1> \
|
|
(s0,s1,rp0); \
|
|
|
|
string_opr_switch_statements
|
|
#undef case_stmt
|
|
default : return error_node();
|
|
}
|
|
}
|
|
|
|
template <typename T0, typename T1>
|
|
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<typename details::str_xoxr_node<Type,T0,T1,range_t,op1<Type> >,T0,T1> \
|
|
(s0,s1,rp1); \
|
|
|
|
string_opr_switch_statements
|
|
#undef case_stmt
|
|
default : return error_node();
|
|
}
|
|
}
|
|
|
|
template <typename T0, typename T1>
|
|
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<typename details::str_xroxr_node<Type,T0,T1,range_t,op1<Type> >,T0,T1> \
|
|
(s0,s1,rp0,rp1); \
|
|
|
|
string_opr_switch_statements
|
|
#undef case_stmt
|
|
default : return error_node();
|
|
}
|
|
}
|
|
|
|
template <typename T0, typename T1>
|
|
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<typename details::sos_node<Type,T0,T1,op1<Type> >,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<details::stringvar_node<Type>*>(branch[0])->ref();
|
|
std::string& s1 = static_cast<details::stringvar_node<Type>*>(branch[1])->ref();
|
|
|
|
return synthesize_sos_expression_impl<std::string&,std::string&>(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<details::string_range_node<Type>*>(branch[0])->ref ();
|
|
std::string& s1 = static_cast<details::stringvar_node<Type>*> (branch[1])->ref ();
|
|
range_t rp0 = static_cast<details::string_range_node<Type>*>(branch[0])->range();
|
|
|
|
static_cast<details::string_range_node<Type>*>(branch[0])->range_ref().clear();
|
|
|
|
free_node(*node_allocator_,branch[0]);
|
|
|
|
return synthesize_str_xrox_expression_impl<std::string&,std::string&>(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<details::stringvar_node<Type>*> (branch[0])->ref ();
|
|
std::string& s1 = static_cast<details::string_range_node<Type>*>(branch[1])->ref ();
|
|
range_t rp1 = static_cast<details::string_range_node<Type>*>(branch[1])->range();
|
|
|
|
static_cast<details::string_range_node<Type>*>(branch[1])->range_ref().clear();
|
|
|
|
free_node(*node_allocator_,branch[1]);
|
|
|
|
return synthesize_str_xoxr_expression_impl<std::string&,std::string&>(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<details::stringvar_node<Type>*> (branch[0])->ref ();
|
|
std::string s1 = static_cast<details::const_string_range_node<Type>*>(branch[1])->str ();
|
|
range_t rp1 = static_cast<details::const_string_range_node<Type>*>(branch[1])->range();
|
|
|
|
static_cast<details::const_string_range_node<Type>*>(branch[1])->range_ref().clear();
|
|
|
|
free_node(*node_allocator_,branch[1]);
|
|
|
|
return synthesize_str_xoxr_expression_impl<std::string&,const std::string>(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<details::string_range_node<Type>*>(branch[0])->ref ();
|
|
std::string& s1 = static_cast<details::string_range_node<Type>*>(branch[1])->ref ();
|
|
range_t rp0 = static_cast<details::string_range_node<Type>*>(branch[0])->range();
|
|
range_t rp1 = static_cast<details::string_range_node<Type>*>(branch[1])->range();
|
|
|
|
static_cast<details::string_range_node<Type>*>(branch[0])->range_ref().clear();
|
|
static_cast<details::string_range_node<Type>*>(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<std::string&,std::string&>(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<Type>*>(branch[0])->ref();
|
|
std::string s1 = static_cast<details::string_literal_node<Type>*>(branch[1])->str();
|
|
|
|
details::free_node(*node_allocator_,branch[1]);
|
|
|
|
return synthesize_sos_expression_impl<std::string&,const std::string>(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<details::string_literal_node<Type>*>(branch[0])->str();
|
|
std::string& s1 = static_cast< details::stringvar_node<Type>*>(branch[1])->ref();
|
|
|
|
details::free_node(*node_allocator_,branch[0]);
|
|
|
|
return synthesize_sos_expression_impl<const std::string,std::string&>(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<details::string_literal_node<Type>*>(branch[0])->str ();
|
|
std::string& s1 = static_cast<details::string_range_node<Type>*> (branch[1])->ref ();
|
|
range_t rp1 = static_cast<details::string_range_node<Type>*> (branch[1])->range();
|
|
|
|
static_cast<details::string_range_node<Type>*>(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<const std::string,std::string&>(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<details::string_range_node<Type>*> (branch[0])->ref ();
|
|
std::string s1 = static_cast<details::string_literal_node<Type>*>(branch[1])->str ();
|
|
range_t rp0 = static_cast<details::string_range_node<Type>*> (branch[0])->range();
|
|
|
|
static_cast<details::string_range_node<Type>*>(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<std::string&,const std::string>(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<details::string_range_node<Type>*> (branch[0])->ref ();
|
|
std::string s1 = static_cast<details::const_string_range_node<Type>*>(branch[1])->str ();
|
|
range_t rp0 = static_cast<details::string_range_node<Type>*> (branch[0])->range();
|
|
range_t rp1 = static_cast<details::const_string_range_node<Type>*>(branch[1])->range();
|
|
|
|
static_cast<details::string_range_node<Type>*> (branch[0])->range_ref().clear();
|
|
static_cast<details::const_string_range_node<Type>*>(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<std::string&,const std::string>(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<details::string_literal_node<Type>*>(branch[0])->str();
|
|
const std::string s1 = static_cast<details::string_literal_node<Type>*>(branch[1])->str();
|
|
|
|
expression_node_ptr result = error_node();
|
|
|
|
if (details::e_add == opr)
|
|
result = node_allocator_->allocate_c<details::string_literal_node<Type> >(s0 + s1);
|
|
else if (details::e_in == opr)
|
|
result = node_allocator_->allocate_c<details::literal_node<Type> >(details::in_op<Type>::process(s0,s1));
|
|
else if (details::e_like == opr)
|
|
result = node_allocator_->allocate_c<details::literal_node<Type> >(details::like_op<Type>::process(s0,s1));
|
|
else if (details::e_ilike == opr)
|
|
result = node_allocator_->allocate_c<details::literal_node<Type> >(details::ilike_op<Type>::process(s0,s1));
|
|
else
|
|
{
|
|
expression_node_ptr temp = synthesize_sos_expression_impl<const std::string,const std::string>(opr,s0,s1);
|
|
Type v = temp->value();
|
|
details::free_node(*node_allocator_,temp);
|
|
result = node_allocator_->allocate<literal_node_t>(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<details::string_literal_node<Type>*> (branch[0])->str ();
|
|
std::string s1 = static_cast<details::const_string_range_node<Type>*>(branch[1])->str ();
|
|
range_t rp1 = static_cast<details::const_string_range_node<Type>*>(branch[1])->range();
|
|
|
|
static_cast<details::const_string_range_node<Type>*>(branch[1])->range_ref().clear();
|
|
|
|
free_node(*node_allocator_,branch[0]);
|
|
free_node(*node_allocator_,branch[1]);
|
|
|
|
return synthesize_str_xoxr_expression_impl<const std::string,const std::string>(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<details::const_string_range_node<Type>*>(branch[0])->str ();
|
|
std::string& s1 = static_cast<details::stringvar_node<Type>*> (branch[1])->ref ();
|
|
range_t rp0 = static_cast<details::const_string_range_node<Type>*>(branch[0])->range();
|
|
|
|
static_cast<details::const_string_range_node<Type>*>(branch[0])->range_ref().clear();
|
|
|
|
free_node(*node_allocator_,branch[0]);
|
|
|
|
return synthesize_str_xrox_expression_impl<const std::string,std::string&>(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<details::const_string_range_node<Type>*>(branch[0])->str ();
|
|
std::string& s1 = static_cast<details::string_range_node<Type>*> (branch[1])->ref ();
|
|
range_t rp0 = static_cast<details::const_string_range_node<Type>*>(branch[0])->range();
|
|
range_t rp1 = static_cast<details::string_range_node<Type>*> (branch[1])->range();
|
|
|
|
static_cast<details::const_string_range_node<Type>*>(branch[0])->range_ref().clear();
|
|
static_cast<details::string_range_node<Type>*> (branch[1])->range_ref().clear();
|
|
|
|
free_node(*node_allocator_,branch[0]);
|
|
free_node(*node_allocator_,branch[1]);
|
|
|
|
return synthesize_str_xroxr_expression_impl<const std::string,std::string&>(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<details::const_string_range_node<Type>*>(branch[0])->str ();
|
|
const std::string s1 = static_cast<details::string_literal_node<Type>*> (branch[1])->str ();
|
|
range_t rp0 = static_cast<details::const_string_range_node<Type>*>(branch[0])->range();
|
|
|
|
static_cast<details::const_string_range_node<Type>*>(branch[0])->range_ref().clear();
|
|
|
|
details::free_all_nodes(*node_allocator_,branch);
|
|
|
|
return synthesize_str_xrox_expression_impl<const std::string,std::string>(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<details::const_string_range_node<Type>*>(branch[0])->str ();
|
|
std::string s1 = static_cast<details::const_string_range_node<Type>*>(branch[1])->str ();
|
|
range_t rp0 = static_cast<details::const_string_range_node<Type>*>(branch[0])->range();
|
|
range_t rp1 = static_cast<details::const_string_range_node<Type>*>(branch[1])->range();
|
|
|
|
static_cast<details::const_string_range_node<Type>*>(branch[0])->range_ref().clear();
|
|
static_cast<details::const_string_range_node<Type>*>(branch[1])->range_ref().clear();
|
|
|
|
details::free_all_nodes(*node_allocator_,branch);
|
|
|
|
return synthesize_str_xroxr_expression_impl<const std::string,const std::string>(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<typename details::str_sogens_node<Type,op1<Type> > > \
|
|
(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]) ;
|
|
|
|
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]) ;
|
|
|
|
if (details::e_add == opr)
|
|
{
|
|
if (!b0_is_cs || !b1_is_cs)
|
|
{
|
|
return synthesize_expression<string_concat_node_t,2>(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<details::string_literal_node<Type>*>(branch[0])->str();
|
|
const std::string s1 = static_cast<details::string_literal_node<Type>*>(branch[1])->str();
|
|
const std::string s2 = static_cast<details::string_literal_node<Type>*>(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<details::literal_node<Type> >(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<details::stringvar_node<Type>*>(branch[0])->ref();
|
|
std::string& s1 = static_cast<details::stringvar_node<Type>*>(branch[1])->ref();
|
|
std::string& s2 = static_cast<details::stringvar_node<Type>*>(branch[2])->ref();
|
|
|
|
typedef typename details::sosos_node<Type,std::string&,std::string&,std::string&,details::inrange_op<Type> > inrange_t;
|
|
|
|
return node_allocator_->allocate_type<inrange_t,std::string&,std::string&,std::string&>(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<details::string_literal_node<Type>*>(branch[0])->str();
|
|
std::string& s1 = static_cast< details::stringvar_node<Type>*>(branch[1])->ref();
|
|
std::string s2 = static_cast<details::string_literal_node<Type>*>(branch[2])->str();
|
|
|
|
typedef typename details::sosos_node<Type,std::string,std::string&,std::string,details::inrange_op<Type> > inrange_t;
|
|
|
|
details::free_node(*node_allocator_,branch[0]);
|
|
details::free_node(*node_allocator_,branch[2]);
|
|
|
|
return node_allocator_->allocate_type<inrange_t,std::string,std::string&,std::string>(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<Type>*>(branch[0])->ref();
|
|
std::string s1 = static_cast<details::string_literal_node<Type>*>(branch[1])->str();
|
|
std::string& s2 = static_cast< details::stringvar_node<Type>*>(branch[2])->ref();
|
|
|
|
typedef typename details::sosos_node<Type,std::string&,std::string,std::string&,details::inrange_op<Type> > inrange_t;
|
|
|
|
details::free_node(*node_allocator_,branch[1]);
|
|
|
|
return node_allocator_->allocate_type<inrange_t,std::string&,std::string,std::string&>(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<Type>*>(branch[0])->ref();
|
|
std::string& s1 = static_cast< details::stringvar_node<Type>*>(branch[1])->ref();
|
|
std::string s2 = static_cast<details::string_literal_node<Type>*>(branch[2])->str();
|
|
|
|
typedef typename details::sosos_node<Type,std::string&,std::string&,std::string,details::inrange_op<Type> > inrange_t;
|
|
|
|
details::free_node(*node_allocator_,branch[2]);
|
|
|
|
return node_allocator_->allocate_type<inrange_t,std::string&,std::string&,std::string>(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<details::string_literal_node<Type>*>(branch[0])->str();
|
|
std::string& s1 = static_cast< details::stringvar_node<Type>*>(branch[1])->ref();
|
|
std::string& s2 = static_cast< details::stringvar_node<Type>*>(branch[2])->ref();
|
|
|
|
typedef typename details::sosos_node<Type,std::string,std::string&,std::string&,details::inrange_op<Type> > inrange_t;
|
|
|
|
details::free_node(*node_allocator_,branch[0]);
|
|
|
|
return node_allocator_->allocate_type<inrange_t,std::string,std::string&,std::string&>(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<T> 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<literal_node_t>(T(1));
|
|
else if (details::e_ne == operation)
|
|
result = node_allocator_->allocate_c<literal_node_t>(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<nulleq_node_t>(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<nulleq_node_t>(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<literal_node_t>(T(0));
|
|
}
|
|
|
|
details::free_node(*node_allocator_,branch[0]);
|
|
|
|
return node_allocator_->allocate<details::null_node<Type> >();
|
|
}
|
|
|
|
template <typename NodeType, std::size_t N>
|
|
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<N>(branch))
|
|
{
|
|
free_all_nodes(*node_allocator_,branch);
|
|
|
|
return error_node();
|
|
}
|
|
else if ((details::e_default != operation))
|
|
{
|
|
// Attempt simple constant folding optimization.
|
|
expression_node_ptr expression_point = node_allocator_->allocate<NodeType>(operation,branch);
|
|
|
|
if (is_constant_foldable<N>(branch))
|
|
{
|
|
Type v = expression_point->value();
|
|
details::free_node(*node_allocator_,expression_point);
|
|
|
|
return node_allocator_->allocate<literal_node_t>(v);
|
|
}
|
|
else
|
|
return expression_point;
|
|
}
|
|
else
|
|
return error_node();
|
|
}
|
|
|
|
template <typename NodeType, std::size_t N>
|
|
inline expression_node_ptr synthesize_expression(F* f, expression_node_ptr (&branch)[N])
|
|
{
|
|
if (!details::all_nodes_valid<N>(branch))
|
|
{
|
|
free_all_nodes(*node_allocator_,branch);
|
|
|
|
return error_node();
|
|
}
|
|
|
|
typedef typename details::function_N_node<T,ifunction_t,N> function_N_node_t;
|
|
|
|
// Attempt simple constant folding optimization.
|
|
|
|
expression_node_ptr expression_point = node_allocator_->allocate<NodeType>(f);
|
|
function_N_node_t* func_node_ptr = dynamic_cast<function_N_node_t*>(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<N>(branch) && !f->has_side_effects)
|
|
{
|
|
Type v = expression_point->value();
|
|
details::free_node(*node_allocator_,expression_point);
|
|
|
|
return node_allocator_->allocate<literal_node_t>(v);
|
|
}
|
|
else
|
|
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<T>& 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);
|
|
}
|
|
}
|
|
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,true);
|
|
}
|
|
}
|
|
|
|
se.var_node = 0;
|
|
se.vec_node = 0;
|
|
se.data = 0;
|
|
se.ref_count = 0;
|
|
se.active = false;
|
|
}
|
|
}
|
|
|
|
inline void load_unary_operations_map(unary_op_map_t& m)
|
|
{
|
|
#define register_unary_op(Op,UnaryFunctor) \
|
|
m.insert(std::make_pair(Op,UnaryFunctor<T>::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<T>::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<T>::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<trinary_functor_t,details::operator_type> pair_t;
|
|
|
|
#define register_sf3(Op) \
|
|
sf3_map[details::sf##Op##_op<T>::id()] = pair_t(details::sf##Op##_op<T>::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<quaternary_functor_t,details::operator_type> pair_t;
|
|
|
|
#define register_sf4(Op) \
|
|
sf4_map[details::sf##Op##_op<T>::id()] = pair_t(details::sf##Op##_op<T>::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<T>::id()] = pair_t(details::sfext##Op##_op<T>::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)
|
|
#undef register_sf4ext
|
|
}
|
|
|
|
private:
|
|
|
|
parser(const parser<T>&);
|
|
parser<T>& operator=(const parser<T>&);
|
|
|
|
lexer::generator lexer_;
|
|
lexer::token current_token_;
|
|
lexer::token store_current_token_;
|
|
expression_generator<T> expression_generator_;
|
|
details::node_allocator node_allocator_;
|
|
symbol_table_t symbol_table_;
|
|
dependent_entity_collector dec_;
|
|
std::size_t compile_options_;
|
|
std::deque<parser_error::type> error_list_;
|
|
std::deque<bool> brkcnt_list_;
|
|
bool resolve_unknown_symbol_;
|
|
bool vardef_disabled_;
|
|
std::size_t scope_depth_;
|
|
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 <typename T>
|
|
inline T integrate(expression<T>& 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 <typename T>
|
|
inline T integrate(expression<T>& e,
|
|
const std::string& variable_name,
|
|
const T& r0, const T& r1,
|
|
const std::size_t number_of_intervals = 1000000)
|
|
{
|
|
symbol_table<T>& sym_table = e.get_symbol_table();
|
|
|
|
if (!sym_table.valid())
|
|
return std::numeric_limits<T>::quiet_NaN();
|
|
|
|
details::variable_node<T>* 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<T>::quiet_NaN();
|
|
}
|
|
|
|
template <typename T>
|
|
inline T derivative(expression<T>& 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 <typename T>
|
|
inline T second_derivative(expression<T>& 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 <typename T>
|
|
inline T third_derivative(expression<T>& 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 <typename T>
|
|
inline T derivative(expression<T>& e,
|
|
const std::string& variable_name,
|
|
const T& h = T(0.00000001))
|
|
{
|
|
symbol_table<T>& sym_table = e.get_symbol_table();
|
|
|
|
if (!sym_table.valid())
|
|
{
|
|
return std::numeric_limits<T>::quiet_NaN();
|
|
}
|
|
|
|
details::variable_node<T>* 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<T>::quiet_NaN();
|
|
}
|
|
|
|
template <typename T>
|
|
inline T second_derivative(expression<T>& e,
|
|
const std::string& variable_name,
|
|
const T& h = T(0.00001))
|
|
{
|
|
symbol_table<T>& sym_table = e.get_symbol_table();
|
|
|
|
if (!sym_table.valid())
|
|
{
|
|
return std::numeric_limits<T>::quiet_NaN();
|
|
}
|
|
|
|
details::variable_node<T>* 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<T>::quiet_NaN();
|
|
}
|
|
|
|
template <typename T>
|
|
inline T third_derivative(expression<T>& e,
|
|
const std::string& variable_name,
|
|
const T& h = T(0.0001))
|
|
{
|
|
symbol_table<T>& sym_table = e.get_symbol_table();
|
|
|
|
if (!sym_table.valid())
|
|
{
|
|
return std::numeric_limits<T>::quiet_NaN();
|
|
}
|
|
|
|
details::variable_node<T>* 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<T>::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 <typename T>
|
|
inline bool compute(const std::string& expression_string, T& result)
|
|
{
|
|
// No variables
|
|
symbol_table<T> symbol_table;
|
|
symbol_table.add_constants();
|
|
|
|
expression<T> expression;
|
|
parser<T> parser;
|
|
|
|
if (parser.compile(expression_string,expression))
|
|
{
|
|
result = expression.value();
|
|
|
|
return true;
|
|
}
|
|
else
|
|
return false;
|
|
}
|
|
|
|
template <typename T>
|
|
inline bool compute(const std::string& expression_string,
|
|
const T& x,
|
|
T& result)
|
|
{
|
|
// Only 'x'
|
|
static const std::string x_var("x");
|
|
|
|
symbol_table<T> symbol_table;
|
|
symbol_table.add_constants();
|
|
symbol_table.add_variable(x_var,x);
|
|
|
|
expression<T> expression;
|
|
parser<T> parser;
|
|
|
|
if (parser.compile(expression_string,expression))
|
|
{
|
|
result = expression.value();
|
|
|
|
return true;
|
|
}
|
|
else
|
|
return false;
|
|
}
|
|
|
|
template <typename T>
|
|
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<T> symbol_table;
|
|
symbol_table.add_constants();
|
|
symbol_table.add_variable(x_var,x);
|
|
symbol_table.add_variable(y_var,y);
|
|
|
|
expression<T> expression;
|
|
parser<T> parser;
|
|
|
|
if (parser.compile(expression_string,expression))
|
|
{
|
|
result = expression.value();
|
|
|
|
return true;
|
|
}
|
|
else
|
|
return false;
|
|
}
|
|
|
|
template <typename T>
|
|
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<T> 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<T> expression;
|
|
parser<T> parser;
|
|
|
|
if (parser.compile(expression_string,expression))
|
|
{
|
|
result = expression.value();
|
|
|
|
return true;
|
|
}
|
|
else
|
|
return false;
|
|
}
|
|
|
|
template <typename T, std::size_t N>
|
|
class polynomial : public ifunction<T>
|
|
{
|
|
private:
|
|
|
|
template <typename Type, std::size_t NumberOfCoefficients>
|
|
struct poly_impl { };
|
|
|
|
template <typename Type>
|
|
struct poly_impl <Type,12>
|
|
{
|
|
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 <typename Type>
|
|
struct poly_impl <Type,11>
|
|
{
|
|
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 <typename Type>
|
|
struct poly_impl <Type,10>
|
|
{
|
|
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 <typename Type>
|
|
struct poly_impl <Type,9>
|
|
{
|
|
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 <typename Type>
|
|
struct poly_impl <Type,8>
|
|
{
|
|
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 <typename Type>
|
|
struct poly_impl <Type,7>
|
|
{
|
|
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 <typename Type>
|
|
struct poly_impl <Type,6>
|
|
{
|
|
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 <typename Type>
|
|
struct poly_impl <Type,5>
|
|
{
|
|
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 <typename Type>
|
|
struct poly_impl <Type,4>
|
|
{
|
|
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 <typename Type>
|
|
struct poly_impl <Type,3>
|
|
{
|
|
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 <typename Type>
|
|
struct poly_impl <Type,2>
|
|
{
|
|
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 <typename Type>
|
|
struct poly_impl <Type,1>
|
|
{
|
|
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:
|
|
|
|
polynomial()
|
|
: exprtk::ifunction<T>((N+2 <= 20) ? (N + 2) : std::numeric_limits<std::size_t>::max(),false)
|
|
{}
|
|
|
|
inline virtual T operator()(const T& x, const T& c1, const T& c0)
|
|
{
|
|
return ((1 == N) ? poly_impl<T,1>::evaluate(x,c1,c0) : std::numeric_limits<T>::quiet_NaN());
|
|
}
|
|
|
|
inline virtual T operator()(const T& x, const T& c2, const T& c1, const T& c0)
|
|
{
|
|
return ((2 == N) ? poly_impl<T,2>::evaluate(x,c2,c1,c0) : std::numeric_limits<T>::quiet_NaN());
|
|
}
|
|
|
|
inline virtual T operator()(const T& x, const T& c3, const T& c2, const T& c1, const T& c0)
|
|
{
|
|
return ((3 == N) ? poly_impl<T,3>::evaluate(x,c3,c2,c1,c0) : std::numeric_limits<T>::quiet_NaN());
|
|
}
|
|
|
|
inline virtual T operator()(const T& x, const T& c4, const T& c3, const T& c2, const T& c1, const T& c0)
|
|
{
|
|
return ((4 == N) ? poly_impl<T,4>::evaluate(x,c4,c3,c2,c1,c0) : std::numeric_limits<T>::quiet_NaN());
|
|
}
|
|
|
|
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)
|
|
{
|
|
return ((5 == N) ? poly_impl<T,5>::evaluate(x,c5,c4,c3,c2,c1,c0) : std::numeric_limits<T>::quiet_NaN());
|
|
}
|
|
|
|
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)
|
|
{
|
|
return ((6 == N) ? poly_impl<T,6>::evaluate(x,c6,c5,c4,c3,c2,c1,c0) : std::numeric_limits<T>::quiet_NaN());
|
|
}
|
|
|
|
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)
|
|
{
|
|
return ((7 == N) ? poly_impl<T,7>::evaluate(x,c7,c6,c5,c4,c3,c2,c1,c0) : std::numeric_limits<T>::quiet_NaN());
|
|
}
|
|
|
|
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)
|
|
{
|
|
return ((8 == N) ? poly_impl<T,8>::evaluate(x,c8,c7,c6,c5,c4,c3,c2,c1,c0) : std::numeric_limits<T>::quiet_NaN());
|
|
}
|
|
|
|
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)
|
|
{
|
|
return ((9 == N) ? poly_impl<T,9>::evaluate(x,c9,c8,c7,c6,c5,c4,c3,c2,c1,c0) : std::numeric_limits<T>::quiet_NaN());
|
|
}
|
|
|
|
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)
|
|
{
|
|
return ((10 == N) ? poly_impl<T,10>::evaluate(x,c10,c9,c8,c7,c6,c5,c4,c3,c2,c1,c0) : std::numeric_limits<T>::quiet_NaN());
|
|
}
|
|
|
|
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)
|
|
{
|
|
return ((11 == N) ? poly_impl<T,11>::evaluate(x,c11,c10,c9,c8,c7,c6,c5,c4,c3,c2,c1,c0) : std::numeric_limits<T>::quiet_NaN());
|
|
}
|
|
|
|
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)
|
|
{
|
|
return ((12 == N) ? poly_impl<T,12>::evaluate(x,c12,c11,c10,c9,c8,c7,c6,c5,c4,c3,c2,c1,c0) : std::numeric_limits<T>::quiet_NaN());
|
|
}
|
|
|
|
inline virtual T operator()()
|
|
{
|
|
return std::numeric_limits<T>::quiet_NaN();
|
|
}
|
|
|
|
inline virtual T operator()(const T&)
|
|
{
|
|
return std::numeric_limits<T>::quiet_NaN();
|
|
}
|
|
|
|
inline virtual T operator()(const T&, const T&)
|
|
{
|
|
return std::numeric_limits<T>::quiet_NaN();
|
|
}
|
|
};
|
|
|
|
template <typename T>
|
|
class function_compositor
|
|
{
|
|
public:
|
|
|
|
typedef exprtk::expression<T> expression_t;
|
|
typedef exprtk::symbol_table<T> symbol_table_t;
|
|
typedef exprtk::parser<T> parser_t;
|
|
|
|
struct function
|
|
{
|
|
function()
|
|
{}
|
|
|
|
function(const std::string& n)
|
|
: name_(n)
|
|
{}
|
|
|
|
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<std::string> v_;
|
|
};
|
|
|
|
private:
|
|
|
|
struct base_func : public exprtk::ifunction<T>
|
|
{
|
|
typedef const T& type;
|
|
typedef exprtk::ifunction<T> function_t;
|
|
typedef std::vector<T*> varref_t;
|
|
typedef std::vector<T> var_t;
|
|
typedef std::pair<T*,std::size_t> lvarref_t;
|
|
typedef std::vector<lvarref_t> lvr_vec_t;
|
|
|
|
base_func(const std::size_t& pc = 0)
|
|
: exprtk::ifunction<T>(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::expression_holder::local_data_list_t ldl_t;
|
|
ldl_t ldl = expr.local_data_list();
|
|
|
|
std::vector<std::size_t> 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<T*>(ldl[index].pointer),
|
|
ldl[index].size));
|
|
|
|
local_var_stack_size += ldl[index].size;
|
|
}
|
|
else
|
|
v[input_param_count++] = reinterpret_cast<T*>(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;
|
|
}
|
|
}
|
|
|
|
expression_t expression;
|
|
varref_t v;
|
|
lvr_vec_t lv;
|
|
std::size_t local_var_stack_size;
|
|
std::size_t stack_depth;
|
|
std::deque<var_t> param_stack;
|
|
std::deque<var_t> local_stack;
|
|
};
|
|
|
|
typedef std::map<std::string,base_func*> funcparam_t;
|
|
|
|
struct func_0param : public base_func
|
|
{
|
|
func_0param() : base_func(0) {}
|
|
|
|
inline T operator()()
|
|
{
|
|
return base_func::expression.value();
|
|
}
|
|
};
|
|
|
|
typedef const T& type;
|
|
|
|
struct func_1param : public base_func
|
|
{
|
|
func_1param() : base_func(1) {}
|
|
|
|
inline T operator()(type v0)
|
|
{
|
|
base_func::pre();
|
|
base_func::update(v0);
|
|
T result = base_func::expression.value();
|
|
base_func::post();
|
|
return result;
|
|
}
|
|
};
|
|
|
|
struct func_2param : public base_func
|
|
{
|
|
func_2param() : base_func(2) {}
|
|
|
|
inline T operator()(type v0, type v1)
|
|
{
|
|
base_func::pre();
|
|
base_func::update(v0,v1);
|
|
T result = base_func::expression.value();
|
|
base_func::post();
|
|
return result;
|
|
}
|
|
};
|
|
|
|
struct func_3param : public base_func
|
|
{
|
|
func_3param() : base_func(3) {}
|
|
|
|
inline T operator()(type v0, type v1, type v2)
|
|
{
|
|
base_func::pre();
|
|
base_func::update(v0,v1,v2);
|
|
T result = base_func::expression.value();
|
|
base_func::post();
|
|
return result;
|
|
}
|
|
};
|
|
|
|
struct func_4param : public base_func
|
|
{
|
|
func_4param() : base_func(4) {}
|
|
|
|
inline T operator()(type v0, type v1, type v2, type v3)
|
|
{
|
|
base_func::pre();
|
|
base_func::update(v0,v1,v2,v3);
|
|
T result = base_func::expression.value();
|
|
base_func::post();
|
|
return result;
|
|
}
|
|
};
|
|
|
|
struct func_5param : public base_func
|
|
{
|
|
func_5param() : base_func(5) {}
|
|
|
|
inline T operator()(type v0, type v1, type v2, type v3, type v4)
|
|
{
|
|
base_func::pre();
|
|
base_func::update(v0,v1,v2,v3,v4);
|
|
T result = base_func::expression.value();
|
|
base_func::post();
|
|
return result;
|
|
}
|
|
};
|
|
|
|
struct func_6param : public base_func
|
|
{
|
|
func_6param() : base_func(6) {}
|
|
|
|
inline T operator()(type v0, type v1, type v2, type v3, type v4, type v5)
|
|
{
|
|
base_func::pre();
|
|
base_func::update(v0,v1,v2,v3,v4,v5);
|
|
T result = base_func::expression.value();
|
|
base_func::post();
|
|
return result;
|
|
}
|
|
};
|
|
|
|
template <typename Allocator,
|
|
template <typename,typename> class Sequence>
|
|
inline bool add(const std::string& name,
|
|
const std::string& expression,
|
|
const Sequence<std::string,Allocator>& var_list)
|
|
{
|
|
const std::size_t n = var_list.size();
|
|
|
|
if (expr_map_.end() != expr_map_.find(name))
|
|
return false;
|
|
else if (compile_expression(name,expression,var_list))
|
|
{
|
|
fp_map_[n][name]->setup(expr_map_[name]);
|
|
return true;
|
|
}
|
|
else
|
|
return false;
|
|
}
|
|
|
|
public:
|
|
|
|
function_compositor()
|
|
: fp_map_(7)
|
|
{}
|
|
|
|
function_compositor(const symbol_table_t& st)
|
|
: symbol_table_(st),
|
|
fp_map_(7)
|
|
{}
|
|
|
|
~function_compositor()
|
|
{
|
|
clear();
|
|
}
|
|
|
|
inline symbol_table_t& symbol_table()
|
|
{
|
|
return symbol_table_;
|
|
}
|
|
|
|
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)
|
|
{
|
|
return add(f.name_,f.expression_,f.v_);
|
|
}
|
|
|
|
inline bool add(const std::string& name,
|
|
const std::string& expression)
|
|
{
|
|
const std::size_t n = 0;
|
|
std::vector<std::string> v(n);
|
|
return add(name,expression,v);
|
|
}
|
|
|
|
inline bool add(const std::string& name,
|
|
const std::string& expression,
|
|
const std::string& v0)
|
|
{
|
|
const std::size_t n = 1;
|
|
std::vector<std::string> v(n);
|
|
v[0] = v0;
|
|
return add(name,expression,v);
|
|
}
|
|
|
|
inline bool add(const std::string& name,
|
|
const std::string& expression,
|
|
const std::string& v0, const std::string& v1)
|
|
{
|
|
const std::size_t n = 2;
|
|
std::vector<std::string> v(n);
|
|
v[0] = v0; v[1] = v1;
|
|
return add(name,expression,v);
|
|
}
|
|
|
|
inline bool add(const std::string& name,
|
|
const std::string& expression,
|
|
const std::string& v0, const std::string& v1, const std::string& v2)
|
|
{
|
|
const std::size_t n = 3;
|
|
std::vector<std::string> v(n);
|
|
v[0] = v0; v[1] = v1; v[2] = v2;
|
|
return add(name,expression,v);
|
|
}
|
|
|
|
inline bool add(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::size_t n = 4;
|
|
std::vector<std::string> v(n);
|
|
v[0] = v0; v[1] = v1;
|
|
v[2] = v2; v[3] = v3;
|
|
return add(name,expression,v);
|
|
}
|
|
|
|
inline bool add(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)
|
|
{
|
|
const std::size_t n = 5;
|
|
std::vector<std::string> v(n);
|
|
v[0] = v0; v[1] = v1;
|
|
v[2] = v2; v[3] = v3;
|
|
v[4] = v4;
|
|
return add(name,expression,v);
|
|
}
|
|
|
|
inline bool add(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, const std::string& v5)
|
|
{
|
|
const std::size_t n = 5;
|
|
std::vector<std::string> v(n);
|
|
v[0] = v0; v[1] = v1;
|
|
v[2] = v2; v[3] = v3;
|
|
v[4] = v4; v[5] = v5;
|
|
return add(name,expression,v);
|
|
}
|
|
|
|
private:
|
|
|
|
template <typename Allocator,
|
|
template <typename,typename> class Sequence>
|
|
bool compile_expression(const std::string& name,
|
|
const std::string& expression,
|
|
const Sequence<std::string,Allocator>& input_var_list)
|
|
{
|
|
expression_t compiled_expression;
|
|
symbol_table_t local_symbol_table;
|
|
|
|
local_symbol_table.load_from(symbol_table_);
|
|
local_symbol_table.add_constants();
|
|
|
|
if (!forward(name,input_var_list.size(),local_symbol_table))
|
|
return false;
|
|
|
|
compiled_expression.register_symbol_table(local_symbol_table);
|
|
|
|
std::string mod_expression;
|
|
|
|
for (std::size_t i = 0; i < input_var_list.size(); ++i)
|
|
{
|
|
mod_expression += " var " + input_var_list[i] + "{};\n";
|
|
}
|
|
|
|
mod_expression += "~{" + expression + "};";
|
|
|
|
if (!parser_.compile(mod_expression,compiled_expression))
|
|
{
|
|
exprtk_debug(("Error: %s\n",parser_.error().c_str()));
|
|
return false;
|
|
}
|
|
|
|
expr_map_[name] = compiled_expression;
|
|
|
|
exprtk::ifunction<T>& ifunc = (*(fp_map_[input_var_list.size()])[name]);
|
|
|
|
return symbol_table_.add_function(name,ifunc);
|
|
}
|
|
|
|
inline bool symbol_used(const std::string& symbol)
|
|
{
|
|
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 forward(const std::string& name, const std::size_t& arg_count, symbol_table_t& sym_table)
|
|
{
|
|
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;
|
|
|
|
switch (arg_count)
|
|
{
|
|
case 0 : (fp_map_[arg_count])[name] = new func_0param(); break;
|
|
case 1 : (fp_map_[arg_count])[name] = new func_1param(); break;
|
|
case 2 : (fp_map_[arg_count])[name] = new func_2param(); break;
|
|
case 3 : (fp_map_[arg_count])[name] = new func_3param(); break;
|
|
case 4 : (fp_map_[arg_count])[name] = new func_4param(); break;
|
|
case 5 : (fp_map_[arg_count])[name] = new func_5param(); break;
|
|
case 6 : (fp_map_[arg_count])[name] = new func_6param(); break;
|
|
}
|
|
|
|
exprtk::ifunction<T>& ifunc = (*(fp_map_[arg_count])[name]);
|
|
|
|
return sym_table.add_function(name,ifunc);
|
|
}
|
|
}
|
|
|
|
template <typename Allocator,
|
|
template <typename,typename> class Sequence>
|
|
inline void remove(const std::string& name, const Sequence<std::string,Allocator>& v)
|
|
{
|
|
symbol_table_.remove_function(name);
|
|
|
|
for (std::size_t i = 0; i < v.size(); ++i)
|
|
{
|
|
symbol_table_.remove_variable(v[i]);
|
|
}
|
|
|
|
remove(name,v.size());
|
|
}
|
|
|
|
inline void remove(const std::string& name, const std::size_t& arg_count)
|
|
{
|
|
if (arg_count > 6)
|
|
return;
|
|
|
|
typename std::map<std::string,expression_t>::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)
|
|
return;
|
|
else
|
|
delete fp_itr->second;
|
|
|
|
fp_map_[arg_count].erase(fp_itr);
|
|
}
|
|
|
|
private:
|
|
|
|
symbol_table_t symbol_table_;
|
|
parser_t parser_;
|
|
std::map<std::string,expression_t> expr_map_;
|
|
std::vector<funcparam_t> fp_map_;
|
|
};
|
|
|
|
template <typename T>
|
|
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<T> 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<exprtk::expression<T> > 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<T> parser;
|
|
|
|
for (std::size_t i = 0; i < expression_list_size; ++i)
|
|
{
|
|
exprtk::expression<T> 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<T>& 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<T, 1>::result(v),details::numeric::pow(v,T( 1))))) return false;
|
|
else if (details::is_true(details::numeric::nequal(details::numeric::fast_exp<T, 2>::result(v),details::numeric::pow(v,T( 2))))) return false;
|
|
else if (details::is_true(details::numeric::nequal(details::numeric::fast_exp<T, 3>::result(v),details::numeric::pow(v,T( 3))))) return false;
|
|
else if (details::is_true(details::numeric::nequal(details::numeric::fast_exp<T, 4>::result(v),details::numeric::pow(v,T( 4))))) return false;
|
|
else if (details::is_true(details::numeric::nequal(details::numeric::fast_exp<T, 5>::result(v),details::numeric::pow(v,T( 5))))) return false;
|
|
else if (details::is_true(details::numeric::nequal(details::numeric::fast_exp<T, 6>::result(v),details::numeric::pow(v,T( 6))))) return false;
|
|
else if (details::is_true(details::numeric::nequal(details::numeric::fast_exp<T, 7>::result(v),details::numeric::pow(v,T( 7))))) return false;
|
|
else if (details::is_true(details::numeric::nequal(details::numeric::fast_exp<T, 8>::result(v),details::numeric::pow(v,T( 8))))) return false;
|
|
else if (details::is_true(details::numeric::nequal(details::numeric::fast_exp<T, 9>::result(v),details::numeric::pow(v,T( 9))))) return false;
|
|
else if (details::is_true(details::numeric::nequal(details::numeric::fast_exp<T,10>::result(v),details::numeric::pow(v,T(10))))) return false;
|
|
else if (details::is_true(details::numeric::nequal(details::numeric::fast_exp<T,11>::result(v),details::numeric::pow(v,T(11))))) return false;
|
|
else if (details::is_true(details::numeric::nequal(details::numeric::fast_exp<T,12>::result(v),details::numeric::pow(v,T(12))))) return false;
|
|
else if (details::is_true(details::numeric::nequal(details::numeric::fast_exp<T,13>::result(v),details::numeric::pow(v,T(13))))) return false;
|
|
else if (details::is_true(details::numeric::nequal(details::numeric::fast_exp<T,14>::result(v),details::numeric::pow(v,T(14))))) return false;
|
|
else if (details::is_true(details::numeric::nequal(details::numeric::fast_exp<T,15>::result(v),details::numeric::pow(v,T(15))))) return false;
|
|
else if (details::is_true(details::numeric::nequal(details::numeric::fast_exp<T,16>::result(v),details::numeric::pow(v,T(16))))) return false;
|
|
else if (details::is_true(details::numeric::nequal(details::numeric::fast_exp<T,17>::result(v),details::numeric::pow(v,T(17))))) return false;
|
|
else if (details::is_true(details::numeric::nequal(details::numeric::fast_exp<T,18>::result(v),details::numeric::pow(v,T(18))))) return false;
|
|
else if (details::is_true(details::numeric::nequal(details::numeric::fast_exp<T,19>::result(v),details::numeric::pow(v,T(19))))) return false;
|
|
else if (details::is_true(details::numeric::nequal(details::numeric::fast_exp<T,20>::result(v),details::numeric::pow(v,T(20))))) return false;
|
|
else if (details::is_true(details::numeric::nequal(details::numeric::fast_exp<T,21>::result(v),details::numeric::pow(v,T(21))))) return false;
|
|
else if (details::is_true(details::numeric::nequal(details::numeric::fast_exp<T,22>::result(v),details::numeric::pow(v,T(22))))) return false;
|
|
else if (details::is_true(details::numeric::nequal(details::numeric::fast_exp<T,23>::result(v),details::numeric::pow(v,T(23))))) return false;
|
|
else if (details::is_true(details::numeric::nequal(details::numeric::fast_exp<T,24>::result(v),details::numeric::pow(v,T(24))))) return false;
|
|
else if (details::is_true(details::numeric::nequal(details::numeric::fast_exp<T,25>::result(v),details::numeric::pow(v,T(25))))) return false;
|
|
else if (details::is_true(details::numeric::nequal(details::numeric::fast_exp<T,26>::result(v),details::numeric::pow(v,T(26))))) return false;
|
|
else if (details::is_true(details::numeric::nequal(details::numeric::fast_exp<T,27>::result(v),details::numeric::pow(v,T(27))))) return false;
|
|
else if (details::is_true(details::numeric::nequal(details::numeric::fast_exp<T,28>::result(v),details::numeric::pow(v,T(28))))) return false;
|
|
else if (details::is_true(details::numeric::nequal(details::numeric::fast_exp<T,29>::result(v),details::numeric::pow(v,T(29))))) return false;
|
|
else if (details::is_true(details::numeric::nequal(details::numeric::fast_exp<T,30>::result(v),details::numeric::pow(v,T(30))))) return false;
|
|
else if (details::is_true(details::numeric::nequal(details::numeric::fast_exp<T,31>::result(v),details::numeric::pow(v,T(31))))) return false;
|
|
else if (details::is_true(details::numeric::nequal(details::numeric::fast_exp<T,32>::result(v),details::numeric::pow(v,T(32))))) return false;
|
|
else if (details::is_true(details::numeric::nequal(details::numeric::fast_exp<T,33>::result(v),details::numeric::pow(v,T(33))))) return false;
|
|
else if (details::is_true(details::numeric::nequal(details::numeric::fast_exp<T,34>::result(v),details::numeric::pow(v,T(34))))) return false;
|
|
else if (details::is_true(details::numeric::nequal(details::numeric::fast_exp<T,35>::result(v),details::numeric::pow(v,T(35))))) return false;
|
|
else if (details::is_true(details::numeric::nequal(details::numeric::fast_exp<T,36>::result(v),details::numeric::pow(v,T(36))))) return false;
|
|
else if (details::is_true(details::numeric::nequal(details::numeric::fast_exp<T,37>::result(v),details::numeric::pow(v,T(37))))) return false;
|
|
else if (details::is_true(details::numeric::nequal(details::numeric::fast_exp<T,38>::result(v),details::numeric::pow(v,T(38))))) return false;
|
|
else if (details::is_true(details::numeric::nequal(details::numeric::fast_exp<T,39>::result(v),details::numeric::pow(v,T(39))))) return false;
|
|
else if (details::is_true(details::numeric::nequal(details::numeric::fast_exp<T,40>::result(v),details::numeric::pow(v,T(40))))) return false;
|
|
else if (details::is_true(details::numeric::nequal(details::numeric::fast_exp<T,41>::result(v),details::numeric::pow(v,T(41))))) return false;
|
|
else if (details::is_true(details::numeric::nequal(details::numeric::fast_exp<T,42>::result(v),details::numeric::pow(v,T(42))))) return false;
|
|
else if (details::is_true(details::numeric::nequal(details::numeric::fast_exp<T,43>::result(v),details::numeric::pow(v,T(43))))) return false;
|
|
else if (details::is_true(details::numeric::nequal(details::numeric::fast_exp<T,44>::result(v),details::numeric::pow(v,T(44))))) return false;
|
|
else if (details::is_true(details::numeric::nequal(details::numeric::fast_exp<T,45>::result(v),details::numeric::pow(v,T(45))))) return false;
|
|
else if (details::is_true(details::numeric::nequal(details::numeric::fast_exp<T,46>::result(v),details::numeric::pow(v,T(46))))) return false;
|
|
else if (details::is_true(details::numeric::nequal(details::numeric::fast_exp<T,47>::result(v),details::numeric::pow(v,T(47))))) return false;
|
|
else if (details::is_true(details::numeric::nequal(details::numeric::fast_exp<T,48>::result(v),details::numeric::pow(v,T(48))))) return false;
|
|
else if (details::is_true(details::numeric::nequal(details::numeric::fast_exp<T,49>::result(v),details::numeric::pow(v,T(49))))) return false;
|
|
else if (details::is_true(details::numeric::nequal(details::numeric::fast_exp<T,50>::result(v),details::numeric::pow(v,T(50))))) return false;
|
|
else if (details::is_true(details::numeric::nequal(details::numeric::fast_exp<T,51>::result(v),details::numeric::pow(v,T(51))))) return false;
|
|
else if (details::is_true(details::numeric::nequal(details::numeric::fast_exp<T,52>::result(v),details::numeric::pow(v,T(52))))) return false;
|
|
else if (details::is_true(details::numeric::nequal(details::numeric::fast_exp<T,53>::result(v),details::numeric::pow(v,T(53))))) return false;
|
|
else if (details::is_true(details::numeric::nequal(details::numeric::fast_exp<T,54>::result(v),details::numeric::pow(v,T(54))))) return false;
|
|
else if (details::is_true(details::numeric::nequal(details::numeric::fast_exp<T,55>::result(v),details::numeric::pow(v,T(55))))) return false;
|
|
else if (details::is_true(details::numeric::nequal(details::numeric::fast_exp<T,56>::result(v),details::numeric::pow(v,T(56))))) return false;
|
|
else if (details::is_true(details::numeric::nequal(details::numeric::fast_exp<T,57>::result(v),details::numeric::pow(v,T(57))))) return false;
|
|
else if (details::is_true(details::numeric::nequal(details::numeric::fast_exp<T,58>::result(v),details::numeric::pow(v,T(58))))) return false;
|
|
else if (details::is_true(details::numeric::nequal(details::numeric::fast_exp<T,59>::result(v),details::numeric::pow(v,T(59))))) return false;
|
|
else if (details::is_true(details::numeric::nequal(details::numeric::fast_exp<T,60>::result(v),details::numeric::pow(v,T(60))))) return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
namespace helper
|
|
{
|
|
namespace details
|
|
{
|
|
template <typename T>
|
|
inline void print_type(const std::string& fmt, const T v, exprtk::details::numeric::details::real_type_tag)
|
|
{
|
|
printf(fmt.c_str(),v);
|
|
}
|
|
|
|
template <typename T>
|
|
struct print_impl
|
|
{
|
|
typedef typename igeneric_function<T>::generic_type generic_type;
|
|
typedef typename igeneric_function<T>::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;
|
|
|
|
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];
|
|
|
|
typename exprtk::details::numeric::details::number_type<T>::type num_type;
|
|
|
|
switch (gt.type)
|
|
{
|
|
case generic_type::e_scalar : print_type(scalar_format.c_str(),scalar_t(gt)(),num_type);
|
|
break;
|
|
|
|
case generic_type::e_vector : {
|
|
vector_t vector(gt);
|
|
|
|
for (std::size_t x = 0; x < vector.size(); ++x)
|
|
{
|
|
print_type(scalar_format.c_str(),vector[x],num_type);
|
|
|
|
if ((x + 1) < vector.size())
|
|
printf(" ");
|
|
}
|
|
}
|
|
break;
|
|
|
|
case generic_type::e_string : printf("%s",to_str(string_t(gt)).c_str());
|
|
break;
|
|
|
|
default : continue;
|
|
}
|
|
}
|
|
}
|
|
};
|
|
}
|
|
|
|
template <typename T>
|
|
struct print : public exprtk::igeneric_function<T>
|
|
{
|
|
typedef typename igeneric_function<T>::parameter_list_t parameter_list_t;
|
|
|
|
print(const std::string& scalar_format = "%10.5f")
|
|
: scalar_format_(scalar_format)
|
|
{}
|
|
|
|
inline T operator()(parameter_list_t parameters)
|
|
{
|
|
details::print_impl<T>::process(scalar_format_,parameters);
|
|
return T(0);
|
|
}
|
|
|
|
std::string scalar_format_;
|
|
};
|
|
|
|
template <typename T>
|
|
struct println : public exprtk::igeneric_function<T>
|
|
{
|
|
typedef typename igeneric_function<T>::parameter_list_t parameter_list_t;
|
|
|
|
println(const std::string& scalar_format = "%10.5f")
|
|
: scalar_format_(scalar_format)
|
|
{}
|
|
|
|
inline T operator()(parameter_list_t parameters)
|
|
{
|
|
details::print_impl<T>::process(scalar_format_,parameters);
|
|
printf("\n");
|
|
return T(0);
|
|
}
|
|
|
|
std::string scalar_format_;
|
|
};
|
|
}
|
|
}
|
|
|
|
#if defined(_WIN32) || defined(__WIN32__) || defined(WIN32)
|
|
# ifndef NOMINMAX
|
|
# define NOMINMAX
|
|
# endif
|
|
# ifndef WIN32_LEAN_AND_MEAN
|
|
# define WIN32_LEAN_AND_MEAN
|
|
# endif
|
|
# include <windows.h>
|
|
# include <ctime>
|
|
#else
|
|
# include <ctime>
|
|
# include <sys/time.h>
|
|
# include <sys/types.h>
|
|
#endif
|
|
|
|
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<unsigned long long int>::max();
|
|
}
|
|
else
|
|
return std::numeric_limits<unsigned long long int>::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 information
|
|
{
|
|
static const char* library = "Mathematical Expression Toolkit";
|
|
static const char* version = "2.7182818284590452353602874713526624977572470936999595";
|
|
static const char* date = "20150111";
|
|
|
|
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
|