C++ Mathematical Expression Library (ExprTk) http://www.partow.net/programming/exprtk/index.html

This commit is contained in:
Arash Partow 2013-04-27 13:55:23 +10:00
parent 37324fc51b
commit f14ec583ae
4 changed files with 624 additions and 199 deletions

View File

@ -228,8 +228,8 @@ namespace exprtk
static const std::string reserved_words[] =
{
"and", "default", "case", "false", "for", "if", "ilike", "in", "like",
"nand", "nor", "not", "null", "or", "shl", "shr", "switch", "true",
"while", "xnor", "xor", "&", "|"
"nand", "nor", "not", "null", "or", "repeat", "shl", "shr", "switch",
"true", "until", "while", "xnor", "xor", "&", "|"
};
static const std::size_t reserved_words_size = sizeof(reserved_words) / sizeof(std::string);
@ -241,9 +241,9 @@ namespace exprtk
"equal", "erf", "erfc", "exp", "false", "floor", "for", "frac", "grad2deg",
"hypot", "if", "ilike", "in", "inrange", "like", "log", "log10", "log2",
"logn", "log1p", "mand", "max", "min", "mod", "mor", "mul", "nand", "nor",
"not", "not_equal", "null", "or", "pow", "rad2deg", "root", "round", "roundn",
"sec", "sgn", "shl", "shr", "sin", "sinh", "sqrt", "sum", "switch", "tan",
"tanh", "true", "trunc", "while", "xnor", "xor", "&", "|"
"not", "not_equal", "null", "or", "pow", "rad2deg", "repeat", "root", "round",
"roundn", "sec", "sgn", "shl", "shr", "sin", "sinh", "sqrt", "sum", "switch",
"tan", "tanh", "true", "trunc", "until", "while", "xnor", "xor", "&", "|"
};
static const std::size_t reserved_symbols_size = sizeof(reserved_symbols) / sizeof(std::string);
@ -1296,8 +1296,8 @@ namespace exprtk
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 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);
@ -1314,39 +1314,17 @@ namespace exprtk
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_shr = 11,
e_shl = 12,
e_lte = 13,
e_ne = 14,
e_gte = 15,
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_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_shr = 11,
e_shl = 12, e_lte = 13, e_ne = 14,
e_gte = 15, 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 = ':'
};
token()
@ -1423,7 +1401,7 @@ namespace exprtk
return *this;
}
inline std::string to_str(token_type t) const
static inline std::string to_str(token_type t)
{
switch (t)
{
@ -1561,6 +1539,16 @@ namespace exprtk
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())
@ -3002,29 +2990,29 @@ namespace exprtk
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_switch , e_variable , e_stringvar ,
e_stringconst , e_function , e_vafunction , 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_asin , e_atan , e_ceil ,
e_cos , e_cosh , e_exp , e_floor ,
e_log , e_log10 , e_log2 , e_log1p ,
e_neg , e_pos , e_round , e_sin ,
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_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_while , e_repeat , e_switch , e_variable ,
e_stringvar , e_stringconst , e_function , e_vafunction ,
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_asin , e_atan ,
e_ceil , e_cos , e_cosh , e_exp ,
e_floor , e_log , e_log10 , e_log2 ,
e_log1p , e_neg , e_pos , e_round ,
e_sin , 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_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
};
typedef T value_type;
@ -3586,9 +3574,9 @@ namespace exprtk
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();
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();
}
}
@ -3762,8 +3750,7 @@ namespace exprtk
typedef expression_node<T>* expression_ptr;
while_loop_node(expression_ptr test,
expression_ptr branch)
while_loop_node(expression_ptr test, expression_ptr branch)
: test_(test),
branch_(branch),
test_deletable_(!is_variable_node(test_)),
@ -3799,6 +3786,50 @@ namespace exprtk
bool branch_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 test, expression_ptr branch)
: test_(test),
branch_(branch),
test_deletable_(!is_variable_node(test_)),
branch_deletable_(!is_variable_node(branch_))
{}
~repeat_until_loop_node()
{
if (test_ && test_deletable_) delete test_;
if (branch_ && branch_deletable_) delete branch_;
}
inline T value() const
{
T result = T(0);
do
{
result = branch_->value();
}
while (is_false(test_));
return result;
}
inline typename expression_node<T>::node_type type() const
{
return expression_node<T>::e_repeat;
}
private:
expression_ptr test_;
expression_ptr branch_;
bool test_deletable_;
bool branch_deletable_;
};
template <typename T>
class switch_node : public expression_node<T>
{
@ -4369,12 +4400,13 @@ namespace exprtk
assignment_node(const operator_type& operation,
expression_ptr branch0,
expression_ptr branch1)
: binary_node<T>(operation,branch0,branch1)
: binary_node<T>(operation,branch0,branch1),
is_lefthand_variable_(is_variable_node(binary_node<T>::branch_[0].first))
{}
inline T value() const
{
if (is_variable_node(binary_node<T>::branch_[0].first))
if (is_lefthand_variable_)
{
variable_node<T>* var_node_ptr = dynamic_cast<variable_node<T>*>(binary_node<T>::branch_[0].first);
if (var_node_ptr)
@ -4386,6 +4418,10 @@ namespace exprtk
}
return std::numeric_limits<T>::quiet_NaN();
}
private:
bool is_lefthand_variable_;
};
template <typename T>
@ -9324,32 +9360,34 @@ namespace exprtk
struct state_t;
typedef const T& cref_t;
typedef const T const_t;
typedef ifunction <T> F;
typedef ivararg_function <T> VAF;
typedef ifunction <T> ifunction_t;
typedef ivararg_function <T> ivararg_function_t;
typedef details::expression_node <T> expression_node_t;
typedef details::literal_node <T> literal_node_t;
typedef details::string_literal_node<T> string_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::while_loop_node <T> while_loop_node_t;
typedef details::variable_node <T> variable_node_t;
typedef const T& cref_t;
typedef const T const_t;
typedef ifunction <T> F;
typedef ivararg_function <T> VAF;
typedef ifunction <T> ifunction_t;
typedef ivararg_function <T> ivararg_function_t;
typedef details::expression_node <T> expression_node_t;
typedef details::literal_node <T> literal_node_t;
typedef details::string_literal_node<T> string_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::while_loop_node <T> while_loop_node_t;
typedef details::repeat_until_loop_node<T> repeat_until_loop_node_t;
typedef details::switch_node<T> switch_node_t;
typedef details::variable_node <T> variable_node_t;
#ifndef exprtk_disable_string_capabilities
typedef details::stringvar_node <T> stringvar_node_t;
typedef details::stringvar_node <T> stringvar_node_t;
#endif
typedef details::assignment_node <T> assignment_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 details::assignment_node <T> assignment_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 typename details::functor_t<T> functor_t;
typedef typename functor_t::qfunc_t quaternary_functor_t;
@ -9387,6 +9425,8 @@ namespace exprtk
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 range_pack;
public:
enum precompilation_step
@ -9847,12 +9887,7 @@ namespace exprtk
}
while (!lexer_.finished());
if (arg_list.empty())
return error_node();
else if (arg_list.size() == 1)
result = arg_list[0];
else
result = expression_generator_.vararg_function(details::e_multi,arg_list);
result = simplify(arg_list);
sdd.delete_ptr = (0 == result);
return result;
@ -10382,6 +10417,88 @@ namespace exprtk
return result;
}
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::deque<expression_node_ptr> arg_list;
scoped_deq_delete<expression_node_t> sdd(*this,arg_list);
{
token_t::token_type seperator = token_t::e_eof;
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;
}
else if (!token_is(seperator))
{
set_error(
make_error(parser_error::e_syntax,
current_token_,
"ERR22 - 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);
sdd.delete_ptr = (0 == branch);
if (0 == branch)
{
set_error(
make_error(parser_error::e_syntax,
current_token_,
"ERR23 - Failed to parse body of repeat until loop."));
return error_node();
}
}
if (!token_is(token_t::e_lbracket))
return error_node();
else if (0 == (condition = parse_expression()))
{
set_error(
make_error(parser_error::e_syntax,
current_token_,
"ERR24 - Failed to parse condition for repeat until loop."));
return error_node();
}
else if (!token_is(token_t::e_rbracket))
return error_node();
expression_node_ptr result;
if (0 == (result = expression_generator_.repeat_until_loop(condition,branch)))
{
set_error(
make_error(parser_error::e_syntax,
current_token_,
"ERR25 - Failed to synthesize repeat until loop."));
return error_node();
}
else
return result;
}
inline expression_node_ptr parse_switch_statement()
{
std::vector<expression_node_ptr> arg_list;
@ -10397,11 +10514,11 @@ namespace exprtk
set_error(
make_error(parser_error::e_syntax,
current_token_,
"ERR22 - Expected '{' for call to switch statement."));
"ERR26 - Expected '{' for call to switch statement."));
return error_node();
}
for (;;)
for ( ; ; )
{
if (!details::imatch("case",current_token_.value))
return error_node();
@ -10417,7 +10534,7 @@ namespace exprtk
set_error(
make_error(parser_error::e_syntax,
current_token_,
"ERR23 - Expected ':' for case of switch statement."));
"ERR27 - Expected ':' for case of switch statement."));
return error_node();
}
@ -10430,7 +10547,7 @@ namespace exprtk
set_error(
make_error(parser_error::e_syntax,
current_token_,
"ERR24 - Expected ';' at end of case for switch statement."));
"ERR28 - Expected ';' at end of case for switch statement."));
return error_node();
}
@ -10445,7 +10562,7 @@ namespace exprtk
set_error(
make_error(parser_error::e_syntax,
current_token_,
"ERR25 - Expected ':' for default of switch statement."));
"ERR29 - Expected ':' for default of switch statement."));
return error_node();
}
@ -10456,7 +10573,7 @@ namespace exprtk
{
set_error(make_error(parser_error::e_syntax,
current_token_,
"ERR26 - Expected ';' at end of default for switch statement."));
"ERR30 - Expected ';' at end of default for switch statement."));
return error_node();
}
@ -10470,7 +10587,7 @@ namespace exprtk
set_error(
make_error(parser_error::e_syntax,
current_token_,
"ERR27 - Expected '}' at end of switch statement."));
"ERR31 - Expected '}' at end of switch statement."));
return error_node();
}
@ -10505,7 +10622,7 @@ namespace exprtk
set_error(
make_error(parser_error::e_syntax,
current_token_,
"ERR28 - Unsupported vararg function: " + symbol));
"ERR32 - Unsupported vararg function: " + symbol));
return error_node();
}
@ -10517,7 +10634,7 @@ namespace exprtk
set_error(
make_error(parser_error::e_syntax,
current_token_,
"ERR29 - Expected '(' for call to vararg function: " + symbol));
"ERR33 - Expected '(' for call to vararg function: " + symbol));
return error_node();
}
@ -10535,7 +10652,7 @@ namespace exprtk
set_error(
make_error(parser_error::e_syntax,
current_token_,
"ERR30 - Expected ',' for call to vararg function: " + symbol));
"ERR34 - Expected ',' for call to vararg function: " + symbol));
return error_node();
}
}
@ -10546,6 +10663,35 @@ namespace exprtk
return result;
}
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();
if (expression_list.size() == 1)
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]))
{
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);
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;
@ -10563,7 +10709,7 @@ namespace exprtk
set_error(
make_error(parser_error::e_syntax,
current_token_,
"ERR31 - Expected '"+ details::to_str(close_bracket) + "' for call to multi-sequence" +
"ERR35 - Expected '"+ details::to_str(close_bracket) + "' for call to multi-sequence" +
((!source.empty()) ? std::string(" section of " + source): "")));
return error_node();
}
@ -10583,24 +10729,199 @@ namespace exprtk
arg_list.push_back(arg);
if (token_is(close_bracket))
break;
else if (!token_is(seperator))
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_,
"ERR32 - Expected '"+ details::to_str(seperator) +"' for call to multi-sequence section of " + source));
"ERR36 - 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;
}
struct range_pack
{
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))
{}
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);
}
void free()
{
if (n0_e.first && n0_e.second)
{
n0_e.first = false;
delete n0_e.second;
}
if (n1_e.first && n1_e.second)
{
n1_e.first = false;
delete n1_e.second;
}
}
if (arg_list.empty())
return error_node();
else if (arg_list.size() == 1)
result = arg_list[0];
else
result = expression_generator_.vararg_function(details::e_multi,arg_list);
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;
};
sdd.delete_ptr = (0 == result);
inline bool parse_range(range_pack& rp)
{
//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 (!token_is(token_t::e_lsqrbracket))
{
set_error(
make_error(parser_error::e_syntax,
current_token_,
"ERR37 - Expected '[' for start of range."));
return false;
}
if (token_is(token_t::e_colon))
{
rp.n0_c.first = true;
rp.n0_c.second = 0;
}
else
{
expression_node_ptr r0 = parse_expression();
if (0 == r0)
{
set_error(
make_error(parser_error::e_syntax,
current_token_,
"ERR38 - Failed parse begin section of range."));
return false;
}
else if (is_constant_node(r0))
{
rp.n0_c.first = true;
rp.n0_c.second = static_cast<std::size_t>(r0->value());
free_node(node_allocator_,r0);
}
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_,
"ERR39 - 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_,
"ERR40 - Failed parse end section of range."));
rp.free();
return false;
}
else if (is_constant_node(r1))
{
rp.n1_c.first = true;
rp.n1_c.second = static_cast<std::size_t>(r1->value());
free_node(node_allocator_,r1);
}
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_,
"ERR41 - Expected ']' for start of range."));
rp.free();
return false;
}
}
return true;
}
inline expression_node_ptr parse_string()
{
const std::string symbol = current_token_.value;
expression_node_ptr result = symbol_table_.get_stringvar(symbol);
if (symbol_name_caching_)
{
symbol_name_cache_.push_back(symbol);
}
if (symbol_table_.is_constant_node(symbol))
{
result = expression_generator_(dynamic_cast<details::string_literal_node<T>*>(result)->str());
}
if (peek_token_is(token_t::e_lsqrbracket))
{
next_token();
range_pack rp;
if (!parse_range(rp))
{
free_node(node_allocator_,result);
return error_node();
}
}
else
next_token();
return result;
}
@ -10619,7 +10940,7 @@ namespace exprtk
set_error(
make_error(parser_error::e_syntax,
current_token_,
"ERR33 - Expected '(' for call to vararg function: " + vararg_function_name));
"ERR42 - Expected '(' for call to vararg function: " + vararg_function_name));
return error_node();
}
@ -10637,7 +10958,7 @@ namespace exprtk
set_error(
make_error(parser_error::e_syntax,
current_token_,
"ERR34 - Expected ',' for call to vararg function: " + vararg_function_name));
"ERR43 - Expected ',' for call to vararg function: " + vararg_function_name));
return error_node();
}
}
@ -10698,7 +11019,7 @@ namespace exprtk
set_error(
make_error(parser_error::e_token,
current_token_,
"ERR35 - Invalid special function[1]: " + current_token_.value));
"ERR44 - Invalid special function[1]: " + current_token_.value));
return error_node();
}
@ -10709,7 +11030,7 @@ namespace exprtk
set_error(
make_error(parser_error::e_token,
current_token_,
"ERR36 - Invalid special function[2]: " + current_token_.value));
"ERR45 - Invalid special function[2]: " + current_token_.value));
return error_node();
}
@ -10752,19 +11073,9 @@ namespace exprtk
#ifndef exprtk_disable_string_capabilities
// Are we dealing with a string variable?
variable = symbol_table_.get_stringvar(symbol);
if (variable)
if (symbol_table_.is_stringvar(symbol))
{
if (symbol_name_caching_)
{
symbol_name_cache_.push_back(symbol);
}
if (symbol_table_.is_constant_node(symbol))
{
variable = expression_generator_(dynamic_cast<details::string_literal_node<T>*>(variable)->str());
}
next_token();
return variable;
return parse_string();
}
#endif
@ -10801,7 +11112,7 @@ namespace exprtk
set_error(
make_error(parser_error::e_syntax,
current_token_,
"ERR37 - Invalid number of parameters for function: " + symbol));
"ERR46 - Invalid number of parameters for function: " + symbol));
return error_node();
}
}
@ -10813,7 +11124,7 @@ namespace exprtk
set_error(
make_error(parser_error::e_syntax,
current_token_,
"ERR38 - Failed to generate node for function: '" + symbol + "'"));
"ERR47 - Failed to generate node for function: '" + symbol + "'"));
return error_node();
}
}
@ -10833,7 +11144,7 @@ namespace exprtk
set_error(
make_error(parser_error::e_syntax,
current_token_,
"ERR39 - Failed to generate node for vararg function: '" + symbol + "'"));
"ERR48 - Failed to generate node for vararg function: '" + symbol + "'"));
return error_node();
}
}
@ -10880,7 +11191,7 @@ namespace exprtk
set_error(
make_error(parser_error::e_symtab,
current_token_,
"ERR40 - Failed to create variable: '" + symbol + "'"));
"ERR49 - Failed to create variable: '" + symbol + "'"));
return error_node();
}
@ -10889,7 +11200,7 @@ namespace exprtk
set_error(
make_error(parser_error::e_syntax,
current_token_,
"ERR41 - Undefined variable or function: '" + symbol + "'"));
"ERR50 - Undefined variable or function: '" + symbol + "'"));
return error_node();
}
@ -10897,6 +11208,7 @@ namespace exprtk
{
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_switch = "switch";
static const std::string symbol_null = "null";
@ -10916,6 +11228,10 @@ namespace exprtk
{
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_switch))
{
return parse_switch_statement();
@ -10937,7 +11253,7 @@ namespace exprtk
set_error(
make_error(parser_error::e_symtab,
current_token_,
"ERR41 - Variable or function detected, yet symbol-table is invalid, Symbol: " + current_token_.value));
"ERR51 - Variable or function detected, yet symbol-table is invalid, Symbol: " + current_token_.value));
return error_node();
}
}
@ -11012,7 +11328,7 @@ namespace exprtk
set_error(
make_error(parser_error::e_syntax,
current_token_,
"ERR42 - Premature end of expression.[1]"));
"ERR52 - Premature end of expression.[1]"));
return error_node();
}
else
@ -11020,7 +11336,7 @@ namespace exprtk
set_error(
make_error(parser_error::e_syntax,
current_token_,
"ERR43 - Premature end of expression.[2]"));
"ERR53 - Premature end of expression.[2]"));
return error_node();
}
}
@ -11035,6 +11351,11 @@ namespace exprtk
return true;
}
inline bool peek_token_is(const typename token_t::token_type& ttype)
{
return (lexer_.peek_next_token().type == ttype);
}
template <typename Type>
class expression_generator
{
@ -11641,6 +11962,30 @@ namespace exprtk
return node_allocator_->allocate<while_loop_node_t>(condition,branch);
}
inline expression_node_ptr repeat_until_loop(expression_node_ptr condition,
expression_node_ptr branch) const
{
if (details::is_constant_node(condition))
{
if (details::is_true(condition) && details::is_constant_node(branch))
{
free_node(*node_allocator_,condition);
return branch;
}
expression_node_ptr result = error_node();
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
return node_allocator_->allocate<repeat_until_loop_node_t>(condition,branch);
}
template <typename Allocator,
template <typename,typename> class Sequence>
inline expression_node_ptr const_optimize_switch(Sequence<expression_node_ptr,Allocator>& arglist)

View File

@ -50,11 +50,10 @@ void newton_sqrt()
" ~{ "
" z := 100; "
" y := x / 2; "
" while ((z := (z - 1)) > 0) "
" { "
" repeat "
" if (equal(y * y,x), z := 0, 0);"
" y := (1 / 2) * (y + (x / y)) "
" } "
" y := (1 / 2) * (y + (x / y)); "
" until ((z := (z - 1)) <= 0) "
" }; "
"} ",
"x","y","z");

View File

@ -968,7 +968,15 @@ static const test_t test_list[] =
test_t("switch { case {1 <= 2} : switch { case {1 <= 2} : 1; default: 1.12345; }; default: 1.12345; }",1.0),
test_t("switch { case [(1 <= 2)] : {1}; default: 1.12345; }",1.0),
test_t("switch { case ([1 > 2]) : [0]; case ([1 <= 2]) : 1; default: 1.12345; }",1.0),
test_t("switch { case {(1 <= 2)} : switch { case ({1 <= 2}) : 1; default: 1.12345; }; default: 1.12345; }",1.0)
test_t("switch { case {(1 <= 2)} : switch { case ({1 <= 2}) : 1; default: 1.12345; }; default: 1.12345; }",1.0),
test_t("repeat 1.1 + 2.2 until (1 < 2)",3.3),
test_t("repeat (1.1 + 2.2) until (1 < 2)",3.3),
test_t("repeat 1.1 + 2.2; until (1 < 2)",3.3),
test_t("repeat (1.1 + 2.2); until (1 < 2)",3.3),
test_t("repeat 1.1234; 1 < 2; 1.1 + 2.2 until (1 < 2)",3.3),
test_t("repeat 1.1234; 1 < 2; (1.1 + 2.2) until (1 < 2)",3.3),
test_t("repeat 1.1234; 1 < 2; 1.1 + 2.2; until (1 < 2)",3.3),
test_t("repeat 1.1234; 1 < 2; (1.1 + 2.2); until (1 < 2)",3.3)
};
static const std::size_t test_list_size = sizeof(test_list) / sizeof(test_t);
@ -3737,6 +3745,27 @@ inline bool run_test19()
"fibonacci_impl3(x,0,1,0)",
"x");
compositor
.add("fibonacci_impl4",
"switch "
"{ "
" case x == 0 : 0; "
" case x == 1 : 1; "
" default : repeat "
" w := z; "
" z := z + y; "
" y := w; "
" x := x - 1; "
" z "
" until (x <= 1);"
"} ",
"x","y","z","w");
compositor
.add("fibonacci4",
"fibonacci_impl4(x,0,1,0)",
"x");
exprtk::symbol_table<T>& symbol_table = compositor.symbol_table();
symbol_table.add_constants();
@ -3745,13 +3774,16 @@ inline bool run_test19()
std::string expression_str1 = "fibonacci1(x)";
std::string expression_str2 = "fibonacci2(x)";
std::string expression_str3 = "fibonacci3(x)";
std::string expression_str4 = "fibonacci4(x)";
expression_t expression1;
expression_t expression2;
expression_t expression3;
expression_t expression4;
expression1.register_symbol_table(symbol_table);
expression2.register_symbol_table(symbol_table);
expression3.register_symbol_table(symbol_table);
expression4.register_symbol_table(symbol_table);
exprtk::parser<T> parser;
@ -3779,18 +3811,26 @@ inline bool run_test19()
return false;
}
if (!parser.compile(expression_str4,expression4))
{
printf("run_test19() - Error: %s Expression4: %s\n",
parser.error().c_str(),
expression_str4.c_str());
return false;
}
bool failure = false;
const std::size_t fibonacci_list[] =
{
0, 1, 1, 2,
3, 5, 8, 13,
21, 34, 55, 89,
144, 233, 377, 610,
987, 1597, 2584, 4181,
6765, 10946, 17711, 28657,
46368, 75025, 121393, 196418,
317811, 514229, 832040, 1346269
0, 1, 1, 2,
3, 5, 8, 13,
21, 34, 55, 89,
144, 233, 377, 610,
987, 1597, 2584, 4181,
6765, 10946, 17711, 28657,
46368, 75025, 121393, 196418,
317811, 514229, 832040, 1346269
};
const std::size_t fibonacci_list_size = sizeof(fibonacci_list) / sizeof(std::size_t);
@ -3800,28 +3840,43 @@ inline bool run_test19()
T result1 = expression1.value();
T result2 = expression2.value();
T result3 = expression3.value();
T result4 = expression4.value();
if ((result1 != result2) || (result1 != result3))
if (
(result1 != result2) ||
(result1 != result3) ||
(result1 != result4)
)
{
printf("run_test19() - Error in evaluation! (3) Results don't match! fibonacci(%d) = %d "
"Expression1: %s Expression2: %s Expression3: %s\n",
"Expression1: %s = %d Expression2: %s = %d Expression3: %s = %d Expression4: %s = %d\n",
static_cast<unsigned int>(i),
static_cast<unsigned int>(fibonacci_list[i]),
expression_str1.c_str(),
static_cast<unsigned int>(result1),
expression_str2.c_str(),
expression_str3.c_str());
static_cast<unsigned int>(result2),
expression_str3.c_str(),
static_cast<unsigned int>(result3),
expression_str4.c_str(),
static_cast<unsigned int>(result4));
failure = true;
}
if (fibonacci_list[i] != expression1.value())
{
printf("run_test19() - Error in evaluation! (4) fibonacci(%d) = %d "
"Expression1: %s Expression2: %s Expression3: %s\n",
"Expression1: %s = %d Expression2: %s = %d Expression3: %s = %d Expression4: %s = %d\n",
static_cast<unsigned int>(i),
static_cast<unsigned int>(fibonacci_list[i]),
expression_str1.c_str(),
static_cast<unsigned int>(result1),
expression_str2.c_str(),
expression_str3.c_str());
static_cast<unsigned int>(result2),
expression_str3.c_str(),
static_cast<unsigned int>(result3),
expression_str4.c_str(),
static_cast<unsigned int>(result4));
failure = true;
}
}
@ -3923,7 +3978,7 @@ struct my_usr : public exprtk::parser<T>::unknown_symbol_resolver
error_message = "";
return true;
}
else if (unknown_symbol[0] == 'w')
else if (unknown_symbol[0] == 'c')
{
st = usr_t::e_constant_type;
default_value = next_value();
@ -3966,13 +4021,13 @@ inline bool run_test20()
musr.next_value(true);
parser.enable_unknown_symbol_resolver(&musr);
std::string expr_str = "v01+w02+v03+w04+v05+w06+v07+w08+v09+w10+"
"v11+w12+v13+w14+v15+w16+v17+w18+v19+w20+"
"v21+w22+v23+w24+v25+w26+v27+w28+v29+w30";
std::string expr_str = "v01+c02+v03+c04+v05+c06+v07+c08+v09+c10+"
"v11+c12+v13+c14+v15+c16+v17+c18+v19+c20+"
"v21+c22+v23+c24+v25+c26+v27+c28+v29+c30 ";
if (!parser.compile(expr_str,expression))
{
printf("run_test18() - Error: %s Expression: %s\n",
printf("run_test20() - Error: %s Expression: %s\n",
parser.error().c_str(),
expr_str.c_str());
return false;

View File

@ -10,7 +10,7 @@ very easily extendible.
[01 - CAPABILITIES]
The ExprTk evaluator supports the following fundamental mathematical
The ExprTk evaluator supports the following fundamental arithmetic
operations, functions and processes:
(0) Basic operators: +, -, *, /, %, ^
@ -114,7 +114,7 @@ include path (e.g: /usr/include/).
[08 - BUILT-IN OPERATIONS & FUNCTIONS]
(0) Basic Operators
(0) Arithmetic Operators
+-----------+--------------------------------------------------------+
| OPERATOR | DEFINITION |
+-----------+--------------------------------------------------------+
@ -158,14 +158,14 @@ include path (e.g: /usr/include/).
| true | True state or any value other than zero (typically 1). |
+-----------+--------------------------------------------------------+
| false | False state, value of zero. |
+-----------|--------------------------------------------------------+
+-----------+--------------------------------------------------------+
| and | Logical AND, True only if x and y are both true. |
| | (eg: x and y) |
+-----------+--------------------------------------------------------+
| mand | Multi-input logical AND, True only if all inputs are |
| | true. Left to right short-circuiting of expressions. |
| | (eg: mand(x > y,z < w,u or v,w and x)) |
+-----------|--------------------------------------------------------+
+-----------+--------------------------------------------------------+
| mor | Multi-input logical OR, True if at least one of the |
| | inputs are true. Left to right short-circuiting of |
| | expressions. (eg: mand(x > y,z < w,u or v,w and x)) |
@ -187,25 +187,9 @@ include path (e.g: /usr/include/).
| xnor | Logical XNOR, True iff the biconditional of x and y is |
| | satisfied. (eg: x xnor y) |
+-----------+--------------------------------------------------------+
| if | If x is true then return y else return z. |
| | (eg: if(x, y, z) or if((x + 1) > 2y, z + 1, w / v)) |
+-----------+--------------------------------------------------------+
| switch | The first true case condition that is encountered will |
| | determine the result of the switch. If none of the case|
| | conditions hold true, the default action is assumed as |
| | the final return value. This is sometimes also known as|
| | a multi-way branch mechanism. |
| | eg: |
| | switch |
| | { |
| | case x > (y+z) : 2*x/abs(y-z); |
| | case x < 3 : sin(x + y) |
| | default : 1 + x; |
| | } |
+-----------|--------------------------------------------------------+
| & | Similar to AND but with left to right expression short |
| | circuiting optimisation. (eg: (x & y) == (y and x)) |
+-----------|--------------------------------------------------------+
+-----------+--------------------------------------------------------+
| | | Similar to OR but with left to right expression short |
| | circuiting optimisation. (eg: (x | y) == (y or x)) |
+-----------+--------------------------------------------------------+
@ -217,7 +201,7 @@ include path (e.g: /usr/include/).
| abs | Absolute value of x. |
+-----------+--------------------------------------------------------+
| avg | Average of all the inputs. |
| | (eg: avg(x,y,z,w,u,v) == (x+y+z+w+u+v)/6) |
| | (eg: avg(x,y,z,w,u,v) == (x + y + z + w + u + v) / 6) |
+-----------+--------------------------------------------------------+
| ceil | Smallest integer that is greater than or equal to x. |
+-----------+--------------------------------------------------------+
@ -255,7 +239,7 @@ include path (e.g: /usr/include/).
| min | Smallest value of all the inputs. (eg: min(x,y,z,w,u)) |
+-----------+--------------------------------------------------------+
| mul | Product of all the inputs. |
| | (eg: mul(x,y,z,w,u,v,t) == (x*y*z*w*u*v*t)) |
| | (eg: mul(x,y,z,w,u,v,t) == (x * y * z * w * u * v * t))|
+-----------+--------------------------------------------------------+
| nequal | Not-equal test between x and y using normalized epsilon|
+-----------+--------------------------------------------------------+
@ -272,17 +256,10 @@ include path (e.g: /usr/include/).
| sqrt | Square root of x, where x > 0 |
+-----------+--------------------------------------------------------+
| sum | Sum of all the inputs. |
| | (eg: sum(x,y,z,w,u,v,t) == (x+y+z+w+u+v+t)) |
| | (eg: sum(x,y,z,w,u,v,t) == (x + y + z + w + u + v + t))|
+-----------+--------------------------------------------------------+
| trunc | Integer portion of x |
+-----------+--------------------------------------------------------+
| ~ | Evaluate each sub-expression, then return as the result|
| | the value of the last sub-expression. This is sometimes|
| | known as multiple sequence point evaluation. |
| | eg: |
| | ~(i:=x+1, j:=y/z, k:=sin(w/u)) == (sin(w/u))) |
| | ~{i:=x+1; j:=y/z; k:=sin(w/u)} == (sin(w/u))) |
+-----------+--------------------------------------------------------+
(4) Trigonometry Functions
+-----------+--------------------------------------------------------+
@ -342,6 +319,55 @@ include path (e.g: /usr/include/).
| | (eg: x ilike y or 'a1B2c3D4e5F6g7H' like 'a?d*h') |
+-----------+--------------------------------------------------------+
(6) Control Structures
+-----------+--------------------------------------------------------+
| STRUCTURE | DEFINITION |
+-----------+--------------------------------------------------------+
| if | If x is true then return y else return z. |
| | (eg: if(x, y, z) or if((x + 1) > 2y, z + 1, w / v)) |
+-----------+--------------------------------------------------------+
| switch | The first true case condition that is encountered will |
| | determine the result of the switch. If none of the case|
| | conditions hold true, the default action is assumed as |
| | the final return value. This is sometimes also known as|
| | a multi-way branch mechanism. |
| | eg: |
| | switch |
| | { |
| | case x > (y + z) : 2 * x / abs(y - z); |
| | case x < 3 : sin(x + y) |
| | default : 1 + x; |
| | } |
+-----------+--------------------------------------------------------+
| while | The structure will repeatedly evaluate the internal |
| | statement(s) 'while' the condition is true. The final |
| | statement in the final iteration will be used as the |
| | return value of the loop. |
| | eg: |
| | while ((x := (x - 1)) > 0) |
| | { |
| | y := x + z; |
| | w := z + y; |
| | } |
+-----------+--------------------------------------------------------+
| repeat/ | The structure will repeatedly evaluate the internal |
| until | statement(s) 'until' the condition is true. The final |
| | statement in the final iteration will be used as the |
| | return value of the loop. |
| | eg: |
| | repeat |
| | y := x + z; |
| | w := z + y; |
| | until ((x := (x - 1)) <= 0) |
+-----------+--------------------------------------------------------+
| ~ | Evaluate each sub-expression, then return as the result|
| | the value of the last sub-expression. This is sometimes|
| | known as multiple sequence point evaluation. |
| | eg: |
| | ~(i := x + 1, j := y / z, k := sin(w/u)) == (sin(w/u)))|
| | ~{i := x + 1; j := y / z; k := sin(w/u)} == (sin(w/u)))|
+-----------+--------------------------------------------------------+
[09 - SPECIAL FUNCTIONS]