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

This commit is contained in:
Arash Partow 2014-12-22 22:00:49 +11:00
parent 4d68702f25
commit 371d28c3a8
3 changed files with 197 additions and 49 deletions

View File

@ -449,8 +449,6 @@ namespace exprtk
{
if (str.empty() || pattern.empty())
return false;
else if (str.size() < pattern.size())
return false;
else if ('*' == pattern[0])
return false;
@ -504,8 +502,11 @@ namespace exprtk
}
return (
(p_end == p_itr) &&
(s_end == s_itr)
(s_end == s_itr) &&
(
(p_end == p_itr) ||
('*' == *p_itr)
)
);
}
@ -12610,14 +12611,23 @@ namespace exprtk
template <typename T>
inline bool is_generally_string_node(const expression_node<T>* node)
{
return is_string_node (node) ||
is_const_string_node (node) ||
is_string_range_node (node) ||
is_const_string_range_node(node) ||
is_genricstring_range_node(node) ||
is_string_assignment_node (node) ||
is_string_concat_node (node) ||
is_string_function_node (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
@ -15082,7 +15092,7 @@ namespace exprtk
T* data = (T*)(element_[i].data);
switch(element_[i].type)
switch (element_[i].type)
{
case scope_element::e_variable : delete data; break;
case scope_element::e_vector : delete [] data; break;
@ -17587,7 +17597,7 @@ namespace exprtk
set_error(
make_error(parser_error::e_syntax,
current_token_,
"ERR83 - Failed to generate string range node."));
"ERR83 - Failed to generate string range node"));
free_node(node_allocator_,expression);
}
@ -18168,7 +18178,7 @@ namespace exprtk
param_seq,
diff_index,diff_value);
if (result)
if (result)
{
pseq_index = i;
return true;
@ -18182,9 +18192,9 @@ namespace exprtk
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 +"'"));
parser_.current_token(),
"ERR100 - Failed parameter type check for function '" + function_name_ + "', "
"Expected '" + param_seq_list_[0] + "' call set: '" + param_seq +"'"));
}
else
{
@ -18202,9 +18212,9 @@ namespace exprtk
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 +"'"));
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;
@ -19358,7 +19368,7 @@ namespace exprtk
return node_allocator_.allocate<details::swap_generic_node<T> >(variable0,variable1);
}
inline bool post_variable_process()
inline bool post_variable_process(const std::string& symbol)
{
if (
peek_token_is(token_t::e_lbracket ) ||
@ -19367,7 +19377,14 @@ namespace exprtk
)
{
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);
}
@ -19375,6 +19392,55 @@ namespace exprtk
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;
@ -19389,7 +19455,7 @@ namespace exprtk
variable = expression_generator_(variable->value());
}
if (!post_variable_process())
if (!post_variable_process(symbol))
return error_node();
lodge_symbol(symbol,e_st_variable);
@ -19410,7 +19476,7 @@ namespace exprtk
se.active = true;
lodge_symbol(symbol,e_st_local_variable);
if (!post_variable_process())
if (!post_variable_process(symbol))
return error_node();
next_token();
@ -19450,7 +19516,7 @@ namespace exprtk
set_error(
make_error(parser_error::e_syntax,
current_token_,
"ERR154 - Failed to generate node for function: '" + symbol + "'"));
"ERR156 - Failed to generate node for function: '" + symbol + "'"));
return error_node();
}
@ -19475,7 +19541,7 @@ namespace exprtk
set_error(
make_error(parser_error::e_syntax,
current_token_,
"ERR155 - Failed to generate node for vararg function: '" + symbol + "'"));
"ERR157 - Failed to generate node for vararg function: '" + symbol + "'"));
return error_node();
}
@ -19500,7 +19566,7 @@ namespace exprtk
set_error(
make_error(parser_error::e_syntax,
current_token_,
"ERR156 - Failed to generate node for generic function: '" + symbol + "'"));
"ERR158 - Failed to generate node for generic function: '" + symbol + "'"));
return error_node();
}
@ -19525,7 +19591,7 @@ namespace exprtk
set_error(
make_error(parser_error::e_syntax,
current_token_,
"ERR157 - Failed to generate node for string function: '" + symbol + "'"));
"ERR159 - Failed to generate node for string function: '" + symbol + "'"));
return error_node();
}
@ -19544,7 +19610,7 @@ namespace exprtk
set_error(
make_error(parser_error::e_syntax,
current_token_,
"ERR158 - Invalid use of reserved symbol '" + symbol + "'"));
"ERR160 - Invalid use of reserved symbol '" + symbol + "'"));
return error_node();
}
@ -19584,7 +19650,7 @@ namespace exprtk
lodge_symbol(symbol,e_st_variable);
if (!post_variable_process())
if (!post_variable_process(symbol))
return error_node();
next_token();
@ -19596,7 +19662,7 @@ namespace exprtk
set_error(
make_error(parser_error::e_symtab,
current_token_,
"ERR159 - Failed to create variable: '" + symbol + "'"));
"ERR161 - Failed to create variable: '" + symbol + "'"));
return error_node();
}
@ -19605,7 +19671,7 @@ namespace exprtk
set_error(
make_error(parser_error::e_syntax,
current_token_,
"ERR160 - Undefined symbol: '" + symbol + "'"));
"ERR162 - Undefined symbol: '" + symbol + "'"));
return error_node();
}
@ -19686,7 +19752,7 @@ namespace exprtk
set_error(
make_error(parser_error::e_symtab,
current_token_,
"ERR161 - Variable or function detected, yet symbol-table is invalid, Symbol: " + current_token_.value));
"ERR163 - Variable or function detected, yet symbol-table is invalid, Symbol: " + current_token_.value));
return error_node();
}
@ -19711,7 +19777,7 @@ namespace exprtk
set_error(
make_error(parser_error::e_numeric,
current_token_,
"ERR162 - Failed to convert '" + current_token_.value + "' to a number"));
"ERR164 - Failed to convert '" + current_token_.value + "' to a number"));
return error_node();
}
@ -19737,10 +19803,16 @@ namespace exprtk
set_error(
make_error(parser_error::e_syntax,
current_token_,
"ERR163 - Expected ')' instead of: '" + current_token_.value + "'"));
"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();
}
}
@ -19755,10 +19827,16 @@ namespace exprtk
set_error(
make_error(parser_error::e_syntax,
current_token_,
"ERR164 - Expected ']' instead of: '" + current_token_.value + "'"));
"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();
}
}
@ -19773,10 +19851,16 @@ namespace exprtk
set_error(
make_error(parser_error::e_syntax,
current_token_,
"ERR165 - Expected '}' instead of: '" + current_token_.value + "'"));
"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();
}
}
@ -19806,7 +19890,7 @@ namespace exprtk
set_error(
make_error(parser_error::e_syntax,
current_token_,
"ERR166 - Premature end of expression[1]"));
"ERR168 - Premature end of expression[1]"));
return error_node();
}
@ -19815,7 +19899,7 @@ namespace exprtk
set_error(
make_error(parser_error::e_syntax,
current_token_,
"ERR167 - Premature end of expression[2]"));
"ERR169 - Premature end of expression[2]"));
return error_node();
}

View File

@ -1276,6 +1276,42 @@ inline bool run_test01()
test_xy<T>(" x (y) == (x*y)" ,T(2.0),T(3.0),T(1.0)),
test_xy<T>(" ((x) y) == (x*y)" ,T(2.0),T(3.0),T(1.0)),
test_xy<T>(" (x (y)) == (x*y)" ,T(2.0),T(3.0),T(1.0)),
test_xy<T>(" (x)3 == (x*3)" ,T(2.0),T(3.0),T(1.0)),
test_xy<T>(" x(3) == (x*3)" ,T(2.0),T(3.0),T(1.0)),
test_xy<T>(" (x) 3 == (x*3)" ,T(2.0),T(3.0),T(1.0)),
test_xy<T>(" x (3) == (x*3)" ,T(2.0),T(3.0),T(1.0)),
test_xy<T>(" ((x) 3) == (x*3)" ,T(2.0),T(3.0),T(1.0)),
test_xy<T>(" (x (3)) == (x*3)" ,T(2.0),T(3.0),T(1.0)),
test_xy<T>(" (2)y == (2*y)" ,T(2.0),T(3.0),T(1.0)),
test_xy<T>(" 2(y) == (2*y)" ,T(2.0),T(3.0),T(1.0)),
test_xy<T>(" (2) y == (2*y)" ,T(2.0),T(3.0),T(1.0)),
test_xy<T>(" 2 (y) == (2*y)" ,T(2.0),T(3.0),T(1.0)),
test_xy<T>(" ((2) y) == (2*y)" ,T(2.0),T(3.0),T(1.0)),
test_xy<T>(" (2 (y)) == (2*y)" ,T(2.0),T(3.0),T(1.0)),
test_xy<T>("var a := 2; (a)(3) == 6" ,T(2.0),T(3.0),T(1.0)),
test_xy<T>("var a := 2; (a){3} == 6" ,T(2.0),T(3.0),T(1.0)),
test_xy<T>("var a := 2; (a)[3] == 6" ,T(2.0),T(3.0),T(1.0)),
test_xy<T>("var a := 2; {a}(3) == 6" ,T(2.0),T(3.0),T(1.0)),
test_xy<T>("var a := 2; {a}{3} == 6" ,T(2.0),T(3.0),T(1.0)),
test_xy<T>("var a := 2; {a}[3] == 6" ,T(2.0),T(3.0),T(1.0)),
test_xy<T>("var a := 2; var b := 3; (a)(b) == 6" ,T(2.0),T(3.0),T(1.0)),
test_xy<T>("var a := 2; var b := 3; (a){b} == 6" ,T(2.0),T(3.0),T(1.0)),
test_xy<T>("var a := 2; var b := 3; (a)[b] == 6" ,T(2.0),T(3.0),T(1.0)),
test_xy<T>("var a := 2; var b := 3; {a}(b) == 6" ,T(2.0),T(3.0),T(1.0)),
test_xy<T>("var a := 2; var b := 3; {a}{b} == 6" ,T(2.0),T(3.0),T(1.0)),
test_xy<T>("var a := 2; var b := 3; {a}[b] == 6" ,T(2.0),T(3.0),T(1.0)),
test_xy<T>("var a := 2; (a)(a+1) == 6" ,T(2.0),T(3.0),T(1.0)),
test_xy<T>("var a := 2; (a){a+1} == 6" ,T(2.0),T(3.0),T(1.0)),
test_xy<T>("var a := 2; (a)[a+1] == 6" ,T(2.0),T(3.0),T(1.0)),
test_xy<T>("var a := 2; {a}(a+1) == 6" ,T(2.0),T(3.0),T(1.0)),
test_xy<T>("var a := 2; {a}{a+1} == 6" ,T(2.0),T(3.0),T(1.0)),
test_xy<T>("var a := 2; {a}[a+1] == 6" ,T(2.0),T(3.0),T(1.0)),
test_xy<T>("var a := 2; var b := 3; (b-1)(b) == 6" ,T(2.0),T(3.0),T(1.0)),
test_xy<T>("var a := 2; var b := 3; (b-1){b} == 6" ,T(2.0),T(3.0),T(1.0)),
test_xy<T>("var a := 2; var b := 3; (b-1)[b] == 6" ,T(2.0),T(3.0),T(1.0)),
test_xy<T>("var a := 2; var b := 3; {b-1}(b) == 6" ,T(2.0),T(3.0),T(1.0)),
test_xy<T>("var a := 2; var b := 3; {b-1}{b} == 6" ,T(2.0),T(3.0),T(1.0)),
test_xy<T>("var a := 2; var b := 3; {b-1}[b] == 6" ,T(2.0),T(3.0),T(1.0)),
test_xy<T>("equal(x^2.2^1.1,17.15193942371376191362)" ,T(3.3),T(0.0),T(1.0)),
test_xy<T>("equal(3.3^x^1.1,17.15193942371376191362)" ,T(2.2),T(0.0),T(1.0)),
test_xy<T>("equal(3.3^2.2^x,17.15193942371376191362)" ,T(1.1),T(0.0),T(1.0)),
@ -4725,6 +4761,7 @@ struct inc_func : public exprtk::igeneric_function<T>
case generic_type::e_vector : {
vector_t vector(gt);
for (std::size_t x = 0; x < vector.size(); ++x)
{
vector[x] += T(1);
@ -4734,6 +4771,7 @@ struct inc_func : public exprtk::igeneric_function<T>
case generic_type::e_string : {
string_t string(gt);
for (std::size_t x = 0; x < string.size(); ++x)
{
string[x] += static_cast<typename string_t::value_t>(1);
@ -5021,12 +5059,23 @@ inline bool run_test18()
"var z := 3; var w[3] := { 1/3, 1/5, 1/7 }; foo(v0,v1 + v2, v0[2], x, 2x + y, z, 2w / 3, 'abc123',s0[2:5]);",
"var z := 3; var w[3] := { 1/3, 1/5, 1/7 }; foo(v0,v1 + v2, v0[2], x, 2x + y, z, 2w / 3, 'abc123',s0[2:5]);",
"var z := 3; var w[3] := { 1/3, 1/5, 1/7 }; foo(x);",
"var z := 3; var w[3] := { 1/3, 1/5, 1/7 }; foo(x,x);",
"var z := 3; var w[3] := { 1/3, 1/5, 1/7 }; foo(x,x,x);",
"var z := 3; var w[3] := { 1/3, 1/5, 1/7 }; foo(x,x,x,x);",
"var z := 3; var w[3] := { 1/3, 1/5, 1/7 }; foo(s0);",
"var z := 3; var w[3] := { 1/3, 1/5, 1/7 }; foo(s0,s0);",
"var z := 3; var w[3] := { 1/3, 1/5, 1/7 }; foo(s0,s0,s0);",
"var z := 3; var w[3] := { 1/3, 1/5, 1/7 }; foo(s0,s0,s0,s0);",
"var z := 3; var w[3] := { 1/3, 1/5, 1/7 }; foo(v0);",
"var z := 3; var w[3] := { 1/3, 1/5, 1/7 }; foo(v0,v0);",
"var z := 3; var w[3] := { 1/3, 1/5, 1/7 }; foo(v0,v0,v0);",
"var z := 3; var w[3] := { 1/3, 1/5, 1/7 }; foo(v0,v0,v0,v0);",
"var z := 3; var w[3] := { 1/3, 1/5, 1/7 }; foo(v0,v1 + v2, v0[2], x, 2x + y, z, 2w / 3, 'abc123',s0[2:5]);",
"var z := 3; var w[3] := { 1/3, 1/5, 1/7 }; foo(v0,v1 + v2, v0[2], x, 2x + y, z, 2w / 3, 'abc123',s0[2:5]);",
"var z := 3; var w[3] := { 1/3, 1/5, 1/7 }; foo(v0,v1 + v2, v0[2], x, 2x + y, z, 2w / 3, 'abc123',s0[2:5]);",
"var z := 3; var w[3] := { 1/3, 1/5, 1/7 }; foo(v0,v1 + v2, v0[2], x, 2x + y, z, 2w / 3, 'abc123',s0[2:5]);"
};
static const std::size_t expression_list_size = sizeof(expression_list) / sizeof(std::string);
@ -5047,10 +5096,24 @@ inline bool run_test18()
"V*TTTTVSS",
"VVT*VSS" ,
"VVTTTTVS*",
"T*",
"T*",
"T*",
"T*",
"S*",
"S*",
"S*",
"S*",
"V*",
"V*",
"V*",
"V*",
"TTTTTTT|STSTSTS|V*T*VS*" ,
"TTTTTTT|STSTSTS|V*TTTTVSS",
"TTTTTTT|STSTSTS|VVT*VSS" ,
"TTTTTTT|STSTSTS|VVTTTTVS*"
"TTTTTTT|STSTSTS|VVTTTTVS*",
};
bool failure = false;
@ -5262,7 +5325,6 @@ inline bool run_test18()
std::size_t parameter_type_list_size = sizeof(parameter_type_list) / sizeof(std::string);
for (std::size_t i = 0; i < parameter_type_list_size; ++i)
{
expression_t expression;

View File

@ -1026,8 +1026,8 @@ with vectors:
(c) Assignment: :=, +=, -=, *=, /=, %=, <=>
(d) Inequalities: <, <=, >, >=, ==, =
(e) Unary operations:
abs, acos, acosh, asin, asinh, atan, atanh, ceil, cos, cosh,
cot, csc, deg2grad, deg2rad, erf, erfc, exp, expm1, floor,
abs, acos, acosh, asin, asinh, atan, atanh, ceil, cos, cosh,
cot, csc, deg2grad, deg2rad, erf, erfc, exp, expm1, floor,
frac, grad2deg, log, log10, log1p, log2, rad2deg, round, sec,
sgn, sin, sinc, sinh, sqrt, swap, tan, tanh, trunc
(f) Aggregate and Reduce operations:
@ -1403,10 +1403,12 @@ parameters in the following sequence:
A final piece of type checking functionality is available for the
scenarios where a single function name is intended to be used for
multiple distinct parameter sequences. Two specific overrides of the
function operator are provided one for standard generic functions and
one for string returning functions. The overrides are as follows:
scenarios where a single function name is intended to be used for
multiple distinct parameter sequences. The parameter sequences are
passed to the constructor as a single string delimited by the pipe '|'
character. Two specific overrides of the function operator are
provided one for standard generic functions and one for string
returning functions. The overrides are as follows:
// f(psi,i_0,i_1,....,i_N) --> Scalar
inline T operator()(const std::size_t& ps_index,