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

This commit is contained in:
Arash Partow 2015-08-12 06:28:07 +10:00
parent 3f228b3f86
commit 16a0e6b5ee
3 changed files with 2086 additions and 835 deletions

1522
exprtk.hpp

File diff suppressed because it is too large Load Diff

View File

@ -32,7 +32,7 @@
typedef double numeric_type; typedef double numeric_type;
typedef std::pair<std::string,numeric_type> test_t; typedef std::pair<std::string,numeric_type> test_t;
static const test_t test_list[] = static const test_t global_test_list[] =
{ {
// Note: Each of following tests must compile down // Note: Each of following tests must compile down
// to a single literal node. // to a single literal node.
@ -1061,7 +1061,7 @@ static const test_t test_list[] =
test_t("if (1 > 2) { 1+2; 3;} else if (1 > 2) {1+2; 4;} == null",1.0) test_t("if (1 > 2) { 1+2; 3;} else if (1 > 2) {1+2; 4;} == null",1.0)
}; };
static const std::size_t test_list_size = sizeof(test_list) / sizeof(test_t); static const std::size_t global_test_list_size = sizeof(global_test_list) / sizeof(test_t);
template <typename T> template <typename T>
inline bool not_equal_impl(const T& t1, inline bool not_equal_impl(const T& t1,
@ -1165,9 +1165,9 @@ inline bool run_test00()
for (std::size_t r = 0; r < rounds; ++r) for (std::size_t r = 0; r < rounds; ++r)
{ {
bool result = true; bool result = true;
for (std::size_t i = 0; i < test_list_size; ++i) for (std::size_t i = 0; i < global_test_list_size; ++i)
{ {
if (!test_expression<T>(test_list[i].first,T(test_list[i].second))) if (!test_expression<T>(global_test_list[i].first,T(global_test_list[i].second)))
{ {
result = false; result = false;
} }
@ -1576,7 +1576,14 @@ inline bool run_test01()
test_xy<T>("for(var i := 0; (i < 10) and (i != y); i+=2) { x += i; }; x;" ,T(1),T(20),T(21)), test_xy<T>("for(var i := 0; (i < 10) and (i != y); i+=2) { x += i; }; x;" ,T(1),T(20),T(21)),
test_xy<T>("for(var i := 0; (i < 10) and (i != y);) { x += i; i+=2; }; x;",T(1),T(20),T(21)), test_xy<T>("for(var i := 0; (i < 10) and (i != y);) { x += i; i+=2; }; x;",T(1),T(20),T(21)),
test_xy<T>("for(var i := 0; (i < y); i += 1) { if (i <= (y / 2)) x += i; else break; }; x;" ,T(0),T(10),T(15)), test_xy<T>("for(var i := 0; (i < y); i += 1) { if (i <= (y / 2)) x += i; else break; }; x;" ,T(0),T(10),T(15)),
test_xy<T>("for(var i := 0; (i < y); i += 1) { if (i <= (y / 2)) continue; else x += i; }; x;" ,T(0),T(10),T(30)) test_xy<T>("for(var i := 0; (i < y); i += 1) { if (i <= (y / 2)) continue; else x += i; }; x;" ,T(0),T(10),T(30)),
test_xy<T>("var a := 2; (0 * a) == 0",T(0),T(0),T(1)),
test_xy<T>("var a := 2; (0 / a) == 0",T(0),T(0),T(1)),
test_xy<T>("var a := 2; (a * 0) == 0",T(0),T(0),T(1)),
test_xy<T>("var a := 2; (a / 1) == a",T(0),T(0),T(1)),
test_xy<T>("var a := 2; (0 + a) == a",T(0),T(0),T(1)),
test_xy<T>("var a := 2; (a + 0) == a",T(0),T(0),T(1)),
test_xy<T>("var a := 2; (1 * a) == a",T(0),T(0),T(1))
}; };
static const std::size_t test_list_size = sizeof(test_list) / sizeof(test_xy<T>); static const std::size_t test_list_size = sizeof(test_list) / sizeof(test_xy<T>);
@ -2270,12 +2277,42 @@ inline bool run_test02()
test_ab<T>("'a\\'\\\\b' == a" ,"a'\\b","",T(1.0)), test_ab<T>("'a\\'\\\\b' == a" ,"a'\\b","",T(1.0)),
test_ab<T>("'a\\\\\\'b' == a" ,"a\\'b","",T(1.0)), test_ab<T>("'a\\\\\\'b' == a" ,"a\\'b","",T(1.0)),
test_ab<T>("'a\\'\\\\\\\\b' == a" ,"a'\\\\b","",T(1.0)), test_ab<T>("'a\\'\\\\\\\\b' == a" ,"a'\\\\b","",T(1.0)),
test_ab<T>("'a\\0x30\\'\\0x31\\\\\\0x32b' == a" ,"a0'1\\2b","",T(1.0)) test_ab<T>("'a\\0x30\\'\\0x31\\\\\\0x32b' == a" ,"a0'1\\2b","",T(1.0)),
test_ab<T>("var x := 3; x > 2 and 'abc' like '*bc'" ,"","",T(1.0)),
test_ab<T>("var x := 3; x > 2 and 'abc' ilike '*Bc'" ,"","",T(1.0)),
test_ab<T>("var x := 3; x > 2 and 'abc' in '123abc123'","","",T(1.0)),
test_ab<T>("var x := 3; var s := 'abc'; x > 2 and s like '*bc'" ,"","",T(1.0)),
test_ab<T>("var x := 3; var s := 'abc'; x > 2 and s ilike '*Bc'" ,"","",T(1.0)),
test_ab<T>("var x := 3; var s := 'abc'; x > 2 and s in '123abc123'","","",T(1.0)),
test_ab<T>("var x := 3; var s := 'abc'; var t := '*bc'; x > 2 and s like t" ,"","",T(1.0)),
test_ab<T>("var x := 3; var s := 'abc'; var t := '*Bc'; x > 2 and s ilike t" ,"","",T(1.0)),
test_ab<T>("var x := 3; var s := 'abc'; var t := '123abc123'; x > 2 and s in t","","",T(1.0)),
test_ab<T>("var x := 3; x > 2 and a like '*bc'" ,"abc","",T(1.0)),
test_ab<T>("var x := 3; x > 2 and a ilike '*Bc'" ,"abc","",T(1.0)),
test_ab<T>("var x := 3; x > 2 and a in '123abc123'","abc","",T(1.0)),
test_ab<T>("var x := 3; x > 2 and a like b ","abc","*bc",T(1.0)),
test_ab<T>("var x := 3; x > 2 and a ilike b","abc","*Bc",T(1.0)),
test_ab<T>("var x := 3; x > 2 and a in b ","abc","123abc123",T(1.0)),
test_ab<T>("a[] > 2 and a like '*bc'" ,"abc","",T(1.0)),
test_ab<T>("a[] > 2 and a ilike '*Bc'" ,"abc","",T(1.0)),
test_ab<T>("a[] > 2 and a in '123abc123'","abc","",T(1.0)),
test_ab<T>("a[] > 2 and a like b ","abc","*bc",T(1.0)),
test_ab<T>("a[] > 2 and a ilike b","abc","*Bc",T(1.0)),
test_ab<T>("a[] > 2 and a in b ","abc","123abc123",T(1.0))
}; };
static const std::size_t test_list_size = sizeof(test_list) / sizeof(test_ab<T>); static const std::size_t test_list_size = sizeof(test_list) / sizeof(test_ab<T>);
{
const std::size_t rounds = 50; const std::size_t rounds = 50;
for (std::size_t r = 0; r < rounds; ++r) for (std::size_t r = 0; r < rounds; ++r)
{ {
bool result = true; bool result = true;
@ -2346,6 +2383,7 @@ inline bool run_test02()
return false; return false;
} }
} }
}
{ {
std::string s0; std::string s0;
@ -2492,6 +2530,117 @@ inline bool run_test03()
expression.value(); expression.value();
} }
{
static const std::string invalid_expr[] =
{
"x y",
"x y z",
"x y z w",
"x 1",
"x 1 2",
"x 1 2 3",
"x 'abc'",
"x 1 'abc'",
"x 'abc' 1",
"1 2",
"1 2 3",
"1 2 3 4",
"'abc' 'xyz'",
"'abc' 1",
"1 'abc'",
"x sin(1)",
"s 'abc'",
"s x",
"s y",
"s 1",
"s 1 x",
"s 1 y",
"s x 1",
"s y 1",
"x s ",
"y s ",
"1 s ",
"1 s x",
"1 s y",
"x s 1",
"y s 1",
"v 'abc'",
"v x ",
"v y ",
"v s ",
"v 1 ",
"v 1 x",
"v 1 y",
"v 1 s",
"v x 1",
"v y 1",
"v s 1",
"x v ",
"y v ",
"1 v ",
"1 v x",
"1 v y",
"x v 1",
"y v 1"
};
const std::size_t invalid_expr_size = sizeof(invalid_expr) / sizeof(std::string);
{
for (std::size_t i = 0; i < invalid_expr_size; ++i)
{
exprtk::symbol_table<T> symbol_table;
exprtk::expression<T> expression;
T x = T(0);
std::string s;
std::vector<T> v(10, T(1.234));
symbol_table.add_variable ("x",x);
symbol_table.add_stringvar("s",s);
symbol_table.add_vector ("v",v);
exprtk::parser<T> parser;
if (parser.compile(invalid_expr[i],expression))
{
printf("run_test03() - Error: [1] Invalid expression compiled successfuly. Expression: %s\n",
invalid_expr[i].c_str());
return false;
}
}
}
{
T x = T(0);
std::string s;
std::vector<T> v(10, T(1.234));
exprtk::symbol_table<T> symbol_table;
symbol_table.add_variable ("x",x);
symbol_table.add_stringvar("s",s);
symbol_table.add_vector ("v",v);
exprtk::parser<T> parser;
for (std::size_t i = 0; i < invalid_expr_size; ++i)
{
exprtk::expression<T> expression;
if (parser.compile(invalid_expr[i],expression))
{
printf("run_test03() - Error: [2] Invalid expression compiled successfuly. Expression: %s\n",
invalid_expr[i].c_str());
return false;
}
}
}
}
return true; return true;
} }
@ -2977,8 +3126,15 @@ struct myfunc : public exprtk::ifunction<T>
} }
}; };
double foo1(double v0) { return v0; }
double foo2(double v0, double v1) { return v0 + v1; }
double foo3(double v0, double v1, double v2) { return v0 + v1 + v2; }
double foo4(double v0, double v1, double v2, double v3) { return v0 + v1 + v2 + v3; }
double foo5(double v0, double v1, double v2, double v3, double v4) { return v0 + v1 + v2 + v3 + v4; }
template <typename T> template <typename T>
inline bool run_test09() inline bool run_test09()
{
{ {
static const std::size_t rounds = 1000; static const std::size_t rounds = 1000;
for (std::size_t i = 0; i < rounds; ++i) for (std::size_t i = 0; i < rounds; ++i)
@ -3067,6 +3223,53 @@ inline bool run_test09()
return false; return false;
} }
} }
}
{
typedef exprtk::expression<T> expression_t;
typedef exprtk::symbol_table<T> symbol_table_t;
bool result = true;
const std::string expression_list[] =
{
"foo1(1) == 1",
"foo2(1,2) == (1 + 2)",
"foo3(1,2,3) == (1 + 2 + 3)",
"foo4(1,2,3,4) == (1 + 2 + 3 + 4)",
"foo5(1,2,3,4,5) == (1 + 2 + 3 + 4 + 5)"
};
const std::size_t expression_list_size = sizeof(expression_list) / sizeof(std::string);
symbol_table_t symbol_table;
symbol_table.add_function("foo1",foo1);
symbol_table.add_function("foo2",foo2);
symbol_table.add_function("foo3",foo3);
symbol_table.add_function("foo4",foo4);
symbol_table.add_function("foo5",foo5);
for (std::size_t i = 0; i < expression_list_size; ++i)
{
expression_t expression;
expression.register_symbol_table(symbol_table);
exprtk::parser<T> parser;
if (!parser.compile(expression_list[i],expression))
{
printf("run_test09() - Error: %s Expression: %s\n",
parser.error().c_str(),
expression_list[i].c_str());
result = false;
}
}
if (!result)
return false;
}
return true; return true;
} }
@ -3081,12 +3284,10 @@ inline bool run_test10()
T xx = T(3.3); T xx = T(3.3);
T yy = T(4.4); T yy = T(4.4);
std::string i = "A String"; std::string i_s = "A String";
std::string j = "Another String"; std::string j_s = "Another String";
std::string ii = "A String"; std::string ii_s = "A String";
std::string jj = "Another String"; std::string jj_s = "Another String";
exprtk::symbol_table<T> symbol_table;
struct test struct test
{ {
@ -3111,8 +3312,11 @@ inline bool run_test10()
} }
}; };
{
static const std::size_t rounds = 10; static const std::size_t rounds = 10;
exprtk::symbol_table<T> symbol_table;
for (std::size_t r = 0; r < rounds; ++r) for (std::size_t r = 0; r < rounds; ++r)
{ {
symbol_table.add_variable("x", x); symbol_table.add_variable("x", x);
@ -3215,11 +3419,11 @@ inline bool run_test10()
for (std::size_t r = 0; r < rounds; ++r) for (std::size_t r = 0; r < rounds; ++r)
{ {
symbol_table.add_stringvar("i",i); symbol_table.add_stringvar("i", i_s);
symbol_table.add_stringvar("j",j); symbol_table.add_stringvar("j", j_s);
symbol_table.add_stringvar("ii",ii); symbol_table.add_stringvar("ii", ii_s);
symbol_table.add_stringvar("jj",jj); symbol_table.add_stringvar("jj", jj_s);
if (!symbol_table.symbol_exists("i")) if (!symbol_table.symbol_exists("i"))
{ {
@ -3241,22 +3445,22 @@ inline bool run_test10()
printf("run_test10() - String 'jj' does not exist!\n"); printf("run_test10() - String 'jj' does not exist!\n");
return false; return false;
} }
else if (!test::string(symbol_table,"i",i)) else if (!test::string(symbol_table, "i", i_s))
{ {
printf("run_test10() - String 'i' value failure!\n"); printf("run_test10() - String 'i' value failure!\n");
return false; return false;
} }
else if (!test::string(symbol_table,"j",j)) else if (!test::string(symbol_table, "j", j_s))
{ {
printf("run_test10() - String 'j' value failure!\n"); printf("run_test10() - String 'j' value failure!\n");
return false; return false;
} }
else if (!test::string(symbol_table,"ii",ii)) else if (!test::string(symbol_table, "ii", ii_s))
{ {
printf("run_test10() - String 'ii' value failure!\n"); printf("run_test10() - String 'ii' value failure!\n");
return false; return false;
} }
else if (!test::string(symbol_table,"jj",jj)) else if (!test::string(symbol_table, "jj", jj_s))
{ {
printf("run_test10() - String 'jj' value failure!\n"); printf("run_test10() - String 'jj' value failure!\n");
return false; return false;
@ -3375,10 +3579,10 @@ inline bool run_test10()
for (std::size_t r = 0; r < rounds; ++r) for (std::size_t r = 0; r < rounds; ++r)
{ {
symbol_table.add_stringvar( "i", i); symbol_table.add_stringvar("i", i_s);
symbol_table.add_stringvar( "j", j); symbol_table.add_stringvar("j", j_s);
symbol_table.add_stringvar("ii",ii); symbol_table.add_stringvar("ii", ii_s);
symbol_table.add_stringvar("jj",jj); symbol_table.add_stringvar("jj", jj_s);
std::vector<std::string> expected_var_list; std::vector<std::string> expected_var_list;
@ -3420,10 +3624,10 @@ inline bool run_test10()
for (std::size_t r = 0; r < rounds; ++r) for (std::size_t r = 0; r < rounds; ++r)
{ {
symbol_table.add_stringvar( "i", i); symbol_table.add_stringvar("i", i_s);
symbol_table.add_stringvar( "j", j); symbol_table.add_stringvar("j", j_s);
symbol_table.add_stringvar("ii",ii); symbol_table.add_stringvar("ii", ii_s);
symbol_table.add_stringvar("jj",jj); symbol_table.add_stringvar("jj", jj_s);
std::vector<std::string> expected_var_list; std::vector<std::string> expected_var_list;
@ -3468,6 +3672,7 @@ inline bool run_test10()
return false; return false;
} }
} }
}
{ {
T x0 = T(0); T x0 = T(0);
@ -3977,6 +4182,9 @@ inline bool run_test10()
"2 == for (var i := 0; i < 10; i += 1) { if (i > 2) { continue; return [i * 8];" "2 == for (var i := 0; i < 10; i += 1) { if (i > 2) { continue; return [i * 8];"
"i += 1; i += 2; i += 3; } else i; }", "i += 1; i += 2; i += 3; } else i; }",
"var x[10] := [-1]; var y[10] := [-1]; for (var i := 0; i < 10; i += 1) { x[i] := i; "
"y[i] := 2 * x[i]; }; (sum(x) == 45) and (sum(y) == (2 * sum(x)));"
"7 == (for (var i := 0; i < 10; i += 1) { ~{break[7]; continue; i += i} })", "7 == (for (var i := 0; i < 10; i += 1) { ~{break[7]; continue; i += i} })",
"0 == (for (var i := 0; i < 10; i += 1) { ~{break[i]; continue; i += i} })", "0 == (for (var i := 0; i < 10; i += 1) { ~{break[i]; continue; i += i} })",
"0 == (for (var i := 0; i < 10; i += 1) { ~{continue; break[7]; i += i} })", "0 == (for (var i := 0; i < 10; i += 1) { ~{continue; break[7]; i += i} })",
@ -4932,6 +5140,8 @@ struct va_func : public exprtk::ivararg_function<T>
va_func() va_func()
{ {
exprtk::enable_zero_parameters(*this); exprtk::enable_zero_parameters(*this);
exprtk::set_min_num_args(*this, 0);
exprtk::set_max_num_args(*this, 20);
} }
inline T operator()(const std::vector<T>& arglist) inline T operator()(const std::vector<T>& arglist)
@ -5084,12 +5294,13 @@ struct inc_func : public exprtk::igeneric_function<T>
template <typename T> template <typename T>
struct rem_space_and_uppercase : public exprtk::igeneric_function<T> struct rem_space_and_uppercase : public exprtk::igeneric_function<T>
{ {
typedef typename exprtk::igeneric_function<T>::generic_type generic_type; typedef typename exprtk::igeneric_function<T> igenfunc_t;
typedef typename exprtk::igeneric_function<T>::parameter_list_t parameter_list_t; typedef typename igenfunc_t::generic_type generic_type;
typedef typename igenfunc_t::parameter_list_t parameter_list_t;
typedef typename generic_type::string_view string_t; typedef typename generic_type::string_view string_t;
rem_space_and_uppercase() rem_space_and_uppercase()
: exprtk::igeneric_function<T>("S") : igenfunc_t("S",igenfunc_t::e_rtrn_string)
{} {}
inline T operator()(std::string& result, parameter_list_t params) inline T operator()(std::string& result, parameter_list_t params)
@ -5104,7 +5315,7 @@ struct rem_space_and_uppercase : public exprtk::igeneric_function<T>
for (std::size_t i = 0; i < string.size(); ++i) for (std::size_t i = 0; i < string.size(); ++i)
{ {
if (' ' != (c = string[i])) if (' ' != (c = string[i]))
result += std::toupper(c); result += static_cast<char>(std::toupper(c));
} }
return T(0); return T(0);
@ -5613,7 +5824,7 @@ inline bool run_test18()
symbol_table.add_stringvar("s3", s3); symbol_table.add_stringvar("s3", s3);
symbol_table.add_stringvar("s4", s4); symbol_table.add_stringvar("s4", s4);
symbol_table.add_function("remspc_uc",rsauc,symbol_table_t::e_ft_strfunc); symbol_table.add_function("remspc_uc",rsauc);
std::string program = " s0 := 'How now '; " std::string program = " s0 := 'How now '; "
" s1 := 'brown cow?'; " " s1 := 'brown cow?'; "

View File

@ -610,9 +610,9 @@ appropriate may represent any of one the following:
ExprTk supports three fundamental types which can be used freely in ExprTk supports three fundamental types which can be used freely in
expressions. The types are as follows: expressions. The types are as follows:
1. Scalar (1) Scalar
2. Vector (2) Vector
3. String (3) String
(1) Scalar Type (1) Scalar Type
@ -706,7 +706,7 @@ current values assigned to the variables will be used.
expression.value(); // 3.7 * -9 + 3 expression.value(); // 3.7 * -9 + 3
// 'x * -9 + 3' for x in range of [0,100) in steps of 0.0001 // 'x * -9 + 3' for x in range of [0,100) in steps of 0.0001
for (x = 0; x < 100; x += 0.0001) for (x = 0.0; x < 100.0; x += 0.0001)
{ {
expression.value(); // x * -9 + 3 expression.value(); // x * -9 + 3
} }
@ -860,7 +860,10 @@ handle:
(i) '*' '=' ---> '*=' (multiplication assignment) (i) '*' '=' ---> '*=' (multiplication assignment)
(j) '/' '=' ---> '/=' (division assignment) (j) '/' '=' ---> '/=' (division assignment)
(k) '%' '=' ---> '%=' (modulo assignment) (k) '%' '=' ---> '%=' (modulo assignment)
(l) '<=' '>' ---> '<=>' (swap) (l) '+' '-' ---> '-' (subtraction)
(m) '-' '+' ---> '-' (subtraction)
(n) '-' '-' ---> '+' (addition)
(o) '<=' '>' ---> '<=>' (swap)
An example of the transformation that takes place is as follows: An example of the transformation that takes place is as follows:
@ -926,7 +929,7 @@ In the following example the given expression which represents an
attempt at computing the average between x and y will be transformed attempt at computing the average between x and y will be transformed
as follows: as follows:
(x * 0.5) + (y * 0.5) ---> 0.5 * (x + y) (0.5 * x) + (y * 0.5) ---> 0.5 * (x + y)
There may be situations where the above transformation will cause There may be situations where the above transformation will cause
numerical overflows and that the original form of the expression is numerical overflows and that the original form of the expression is
@ -1216,11 +1219,15 @@ embedded into the expression.
There are five types of function interface: There are five types of function interface:
(1) ifunction +---+----------------------+-------------+
(2) ivararg_function | # | Name | Return Type |
(3) igeneric_function +---+----------------------+-------------+
(4) igeneric_function II | 1 | ifunction | Scalar |
(5) function_compositor | 2 | ivararg_function | Scalar |
| 3 | igeneric_function | Scalar |
| 4 | igeneric_function II | String |
| 5 | function_compositor | Scalar |
+---+----------------------+-------------+
(1) ifunction (1) ifunction
@ -1446,17 +1453,21 @@ the string return type function operator being explicitly overridden:
typedef typename generic_t::string_view string_t; typedef typename generic_t::string_view string_t;
toupper() toupper()
: exprtk::igeneric_function<T>("S") : exprtk::igeneric_function<T>("S",igenfunct_t::e_rtrn_string)
{} {}
inline T operator()(std::string& result, inline T operator()(std::string& result,
parameter_list_t parameters) parameter_list_t parameters)
{ {
result.clear(); result.clear();
string_t string(params[0]);
for (std::size_t i = 0; i < string.size(); ++i) for (std::size_t i = 0; i < string.size(); ++i)
{ {
result += std::toupper(string[i]); result += std::toupper(string[i]);
} }
return T(0); return T(0);
} }
}; };
@ -1464,27 +1475,27 @@ the string return type function operator being explicitly overridden:
In the example above the generic function 'toupper' expects only one In the example above the generic function 'toupper' expects only one
input parameter of type string, as noted by the parameter sequence input parameter of type string, as noted by the parameter sequence
string passed during the constructor. When executed, the function will string passed during the constructor. Furthermore a second parameter
return as a result a copy of the input string converted to uppercase is passed to the constructor indicating that it should be treated as a
form. An example expression using the toupper function registered as string returning function - by default it is assumed to be a scalar
the symbol 'toupper' is as follows: returning function.
When executed, the function will return as a result a copy of the
input string converted to uppercase form. An example expression using
the toupper function registered as the symbol 'toupper' is as follows:
"'ABCDEF' == toupper('aBc') + toupper('DeF')" "'ABCDEF' == toupper('aBc') + toupper('DeF')"
Note: When adding a string type returning generic function to a symbol Note: When adding a string type returning generic function to a symbol
table, the 'add_function' is invoked with an extra parameter table the 'add_function' is invoked. The example below demonstrates
(e_ft_strfunc) that denotes the function should be treated as a string how this can be done:
returning function type. The following example demonstrates how this
is done:
toupper<T> tu; toupper<T> tu;
exprtk::symbol_table<T> symbol_table; exprtk::symbol_table<T> symbol_table;
symbol_table.add_function("toupper", symbol_table.add_function("toupper",tu);
tu,
symbol_table_t::e_ft_strfunc);
Note: Two further refinements to the type checking facility are the Note: Two further refinements to the type checking facility are the
@ -1689,7 +1700,7 @@ the function can be disabled.
{ {
foo() : exprtk::ifunction<T>(3) foo() : exprtk::ifunction<T>(3)
{ {
disable_has_side_effects(*this); exprtk::disable_has_side_effects(*this);
} }
T operator()(const T& v1, const T& v2, const T& v3) T operator()(const T& v1, const T& v2, const T& v3)
@ -1757,6 +1768,14 @@ parsing phase. Once the compilation process has successfully
completed, the caller can then obtain a list of symbols and their completed, the caller can then obtain a list of symbols and their
associated types from the DEC. associated types from the DEC.
The kinds of questions one can ask regarding the dependent entities
within an expression are as follows:
* What user defined or local variables, vectors or strings are used?
* What functions or custom user functions are used?
* Which variables, vectors or strings have values assigned to them?
The following example demonstrates usage of the DEC in determining the The following example demonstrates usage of the DEC in determining the
dependents of the given expression: dependents of the given expression:
@ -1766,9 +1785,15 @@ dependents of the given expression:
std::string expression_string = std::string expression_string =
"z := abs(x + sin(2 * pi / y))"; "z := abs(x + sin(2 * pi / y))";
T x,y,z;
parser_t parser; parser_t parser;
symbol_table_t symbol_table; symbol_table_t symbol_table;
symbol_table.add_variable("x",x);
symbol_table.add_variable("y",y);
symbol_table.add_variable("z",z);
expression_t expression; expression_t expression;
expression.register_symbol_table(symbol_table); expression.register_symbol_table(symbol_table);
@ -1799,7 +1824,7 @@ dependents of the given expression:
} }
Note: The 'symbol_t' type is a pair comprising of the symbol name Note: The 'symbol_t' type is a std::pair comprising of the symbol name
(std::string) and the associated type of the symbol as denoted by the (std::string) and the associated type of the symbol as denoted by the
cases in the switch statement. cases in the switch statement.
@ -1866,6 +1891,9 @@ grammar. The features fall into one of the following three categories:
(1) Base Functions (1) Base Functions
(2) Control Flow Structures (2) Control Flow Structures
(3) Logical Operators (3) Logical Operators
(4) Arithmetic Operators
(5) Inequality Operators
(6) Assignment Operators
(1) Base Functions (1) Base Functions
@ -1967,13 +1995,13 @@ flow structure:
" } "; " } ";
parser.settings() parser.settings()
.disable_all_control_structures(settings_t::e_ctrl_for_loop); .disable_control_structure(settings_t::e_ctrl_for_loop);
parser parser
.compile(program,expression); // failure .compile(program,expression); // failure
parser.settings() parser.settings()
.enable_all_control_structures(settings_t::e_ctrl_for_loop); .enable_control_structure(settings_t::e_ctrl_for_loop);
parser parser
.compile(program,expression); // success .compile(program,expression); // success
@ -2009,18 +2037,158 @@ example demonstrates the disabling of the 'and' logical operator:
expression_t expression; expression_t expression;
parser.settings() parser.settings()
.disable_base_function(settings_t::e_logic_and); .disable_logic_operation(settings_t::e_logic_and);
parser parser
.compile("1 or not(0 and 1)",expression); // failure .compile("1 or not(0 and 1)",expression); // failure
parser.settings() parser.settings()
.enable_base_function(settings_t::e_logic_and); .enable_logic_operation(settings_t::e_logic_and);
parser parser
.compile("1 or not(0 and 1)",expression); // success .compile("1 or not(0 and 1)",expression); // success
(4) Arithmetic Operators
The list of available arithmetic operators is as follows:
+, -, *, /, %, ^
The above mentioned arithmetic operators can be either enabled or
disabled 'all' at once, as is demonstrated below:
parser_t parser;
expression_t expression;
parser.settings().disable_all_arithmetic_ops();
parser
.compile("1 + 2 / 3",expression); // compilation failure
parser.settings().enable_all_arithmetic_ops();
parser
.compile("1 + 2 / 3",expression); // compilation success
One can also enable or disable specific arithmetic operators. The following
example demonstrates the disabling of the addition '+' arithmetic operator:
parser_t parser;
expression_t expression;
parser.settings()
.disable_arithmetic_operation(settings_t::e_arith_add);
parser
.compile("1 + 2 / 3",expression); // failure
parser.settings()
.enable_arithmetic_operation(settings_t::e_arith_add);
parser
.compile("1 + 2 / 3",expression); // success
(5) Inequality Operators
The list of available inequality operators is as follows:
<, <=, >, >=, ==, =, != <>
The above mentioned inequality operators can be either enabled or
disabled 'all' at once, as is demonstrated below:
parser_t parser;
expression_t expression;
parser.settings().disable_all_inequality_ops();
parser
.compile("1 < 3",expression); // compilation failure
parser.settings().enable_all_inequality_ops();
parser
.compile("1 < 3",expression); // compilation success
One can also enable or disable specific inequality operators. The following
example demonstrates the disabling of the less-than '<' inequality operator:
parser_t parser;
expression_t expression;
parser.settings()
.disable_inequality_operation(settings_t::e_ineq_lt);
parser
.compile("1 < 3",expression); // failure
parser.settings()
.enable_inequality_operation(settings_t::e_ineq_lt);
parser
.compile("1 < 3",expression); // success
(6) Assignment Operators
The list of available assignment operators is as follows:
:=, +=, -=, *=, /=, %=
The above mentioned assignment operators can be either enabled or
disabled 'all' at once, as is demonstrated below:
parser_t parser;
expression_t expression;
symbol_table_t symbol_table;
T x = T(0);
symbol_table.add_variable("x",x);
expression.register_symbol_table(symbol_table);
parser.settings().disable_all_assignment_ops();
parser
.compile("x := 3",expression); // compilation failure
parser.settings().enable_all_assignment_ops();
parser
.compile("x := 3",expression); // compilation success
One can also enable or disable specific assignment operators. The following
example demonstrates the disabling of the '+=' addition assignment operator:
parser_t parser;
expression_t expression;
symbol_table_t symbol_table;
T x = T(0);
symbol_table.add_variable("x",x);
expression.register_symbol_table(symbol_table);
parser.settings()
.disable_assignment_operation(settings_t::e_assign_addass);
parser
.compile("x += 3",expression); // failure
parser.settings()
.enable_assignment_operation(settings_t::e_assign_addass);
parser
.compile("x += 3",expression); // success
Note: In the event of a base function being disabled, one can redefine Note: In the event of a base function being disabled, one can redefine
the base function using the standard custom function definition the base function using the standard custom function definition
process. In the following example the 'sin' function is disabled then process. In the following example the 'sin' function is disabled then
@ -2161,7 +2329,7 @@ following example:
if (!parser.compile(expression_string,expression)) if (!parser.compile(expression_string,expression))
{ {
printf("Error: %s\n", parser.error().c_str()); printf("Error: %s\n", parser.error().c_str());
return 1; return false;
} }
@ -2189,7 +2357,7 @@ in the event of a failed compilation.
error.diagnostic.c_str()); error.diagnostic.c_str());
} }
return 1; return false;
} }
@ -2214,7 +2382,7 @@ demonstrated by the following example:
error.column_no); error.column_no);
} }
return 1; return false;
} }
@ -2530,7 +2698,15 @@ int main()
When building ExprTk there are a number of defines that will enable or When building ExprTk there are a number of defines that will enable or
disable certain features and capabilities. The defines can either be disable certain features and capabilities. The defines can either be
part of a compiler command line switch or scoped around the include to part of a compiler command line switch or scoped around the include to
the ExprTk header. the ExprTk header. The defines are as follows:
(1) exprtk_enable_debugging
(2) exprtk_disable_comments
(3) exprtk_disable_break_continue
(4) exprtk_disable_sc_andor
(5) exprtk_disable_enhanced_features
(6) exprtk_disable_string_capabilities
(1) exprtk_enable_debugging (1) exprtk_enable_debugging
This define will enable printing of debug information to stdout during This define will enable printing of debug information to stdout during