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

This commit is contained in:
Arash Partow 2014-11-17 22:03:10 +11:00
parent d95db43aa9
commit ce23204895
4 changed files with 788 additions and 459 deletions

File diff suppressed because it is too large Load Diff

View File

@ -63,19 +63,24 @@ bool load_expression(exprtk::symbol_table<T>& symbol_table,
Sequence<exprtk::expression<T>,Allocator>& expr_seq)
{
exprtk::parser<double> parser;
for (std::size_t i = 0; i < expression_list_size; ++i)
{
exprtk::expression<double> expression;
expression.register_symbol_table(symbol_table);
if (!parser.compile(expression_list[i],expression))
{
printf("[load_expression] - Parser Error: %s\tExpression: %s\n",
parser.error().c_str(),
expression_list[i].c_str());
return false;
}
expr_seq.push_back(expression);
}
return true;
}
@ -86,8 +91,10 @@ void run_exprtk_benchmark(T& x, T& y,
{
T total = T(0);
unsigned int count = 0;
exprtk::timer timer;
timer.start();
for (x = lower_bound_x; x <= upper_bound_x; x += delta)
{
for (y = lower_bound_y; y <= upper_bound_y; y += delta)
@ -96,7 +103,9 @@ void run_exprtk_benchmark(T& x, T& y,
++count;
}
}
timer.stop();
if (T(0) != total)
printf("[exprtk] Total Time:%12.8f Rate:%14.3fevals/sec Expression: %s\n",
timer.time(),
@ -113,8 +122,10 @@ void run_native_benchmark(T& x, T& y, NativeFunction f, const std::string& expr_
{
T total = T(0);
unsigned int count = 0;
exprtk::timer timer;
timer.start();
for (x = lower_bound_x; x <= upper_bound_x; x += delta)
{
for (y = lower_bound_y; y <= upper_bound_y; y += delta)
@ -123,7 +134,9 @@ void run_native_benchmark(T& x, T& y, NativeFunction f, const std::string& expr_
++count;
}
}
timer.stop();
if (T(0) != total)
printf("[native] Total Time:%12.8f Rate:%14.3fevals/sec Expression: %s\n",
timer.time(),
@ -146,6 +159,7 @@ bool run_parse_benchmark(exprtk::symbol_table<T>& symbol_table)
{
exprtk::timer timer;
timer.start();
for (std::size_t r = 0; r < rounds; ++r)
{
if (!parser.compile(expression_list[i],expression))
@ -153,15 +167,19 @@ bool run_parse_benchmark(exprtk::symbol_table<T>& symbol_table)
printf("[run_parse_benchmark] - Parser Error: %s\tExpression: %s\n",
parser.error().c_str(),
expression_list[i].c_str());
return false;
}
}
timer.stop();
printf("[parse] Total Time:%12.8f Rate:%14.3fparse/sec Expression: %s\n",
timer.time(),
rounds / timer.time(),
expression_list[i].c_str());
}
return true;
}
@ -278,10 +296,12 @@ int main(int argc, char* argv[])
if (argc >= 2)
{
const std::string file_name = argv[1];
if (argc == 2)
perform_file_based_benchmark(file_name);
else
perform_file_based_benchmark(file_name,atoi(argv[2]));
return 0;
}
@ -379,16 +399,20 @@ void pgo_primer()
std::size_t load_expression_file(const std::string& file_name, std::deque<std::string>& expression_list)
{
std::ifstream stream(file_name.c_str());
if (!stream) return 0;
std::string buffer;
buffer.reserve(1024);
std::size_t line_count = 0;
while (std::getline(stream,buffer))
{
if (buffer.empty())
continue;
else if ('#' == buffer[0])
continue;
++line_count;
expression_list.push_back(buffer);
}
@ -399,6 +423,7 @@ std::size_t load_expression_file(const std::string& file_name, std::deque<std::s
void perform_file_based_benchmark(const std::string& file_name, const std::size_t& rounds)
{
std::deque<std::string> expr_str_list;
if (0 == load_expression_file(file_name,expr_str_list))
{
std::cout << "Failed to load any expressions from: " << file_name << "\n";
@ -463,17 +488,21 @@ void perform_file_based_benchmark(const std::string& file_name, const std::size_
{
parser_t parser;
for (std::size_t i = 0; i < expr_str_list.size(); ++i)
{
expression_t expression;
expression.register_symbol_table(symbol_table);
if (!parser.compile(expr_str_list[i],expression))
{
printf("[perform_file_based_benchmark] - Parser Error: %s\tExpression: %s\n",
parser.error().c_str(),
expr_str_list[i].c_str());
return;
}
expression_list.push_back(expression);
}
}
@ -483,6 +512,7 @@ void perform_file_based_benchmark(const std::string& file_name, const std::size_
double single_eval_total_time = 0.0;
total_timer.start();
for (std::size_t i = 0; i < expression_list.size(); ++i)
{
expression_t& e = expression_list[i];
@ -499,12 +529,14 @@ void perform_file_based_benchmark(const std::string& file_name, const std::size_
timer.start();
double sum = 0.0;
for (std::size_t r = 0; r < rounds; ++r)
{
sum += e.value();
std::swap(a,b);
std::swap(x,y);
}
timer.stop();
printf("Expression %3d of %3d %9.3f ns\t%10d ns\t(%30.10f) '%s'\n",
@ -519,6 +551,7 @@ void perform_file_based_benchmark(const std::string& file_name, const std::size_
single_eval_total_time += (timer.time() * 1000000000.0) / (1.0 * rounds);
}
total_timer.stop();
printf("[*] Number Of Evals: %15.0f\n",

View File

@ -1129,6 +1129,7 @@ inline bool test_expression(const std::string& expression_string, const T& expec
printf("test_expression() - Error: %s Expression: %s\n",
parser.error().c_str(),
expression_string.c_str());
return false;
}
}
@ -1137,6 +1138,7 @@ inline bool test_expression(const std::string& expression_string, const T& expec
{
printf("test_expression() - Error: Expression did not compile to a constant! Expression: %s\n",
expression_string.c_str());
return false;
}
@ -1148,6 +1150,7 @@ inline bool test_expression(const std::string& expression_string, const T& expec
expression_string.c_str(),
(double)expected_result,
(double)result);
return false;
}
@ -1170,7 +1173,9 @@ inline bool run_test00()
}
if (!result)
{
return false;
}
}
return true;
@ -1538,6 +1543,7 @@ inline bool run_test01()
for (std::size_t r = 0; r < rounds; ++r)
{
bool loop_result = true;
for (std::size_t i = 0; i < test_list_size; ++i)
{
test_xy<T>& test = const_cast<test_xy<T>&>(test_list[i]);
@ -1554,12 +1560,15 @@ inline bool run_test01()
{
exprtk::parser<T> parser;
if (!parser.compile(test.expr,expression))
{
printf("run_test01() - Error: %s Expression: %s\n",
parser.error().c_str(),
test.expr.c_str());
loop_result = false;
continue;
}
}
@ -1572,6 +1581,7 @@ inline bool run_test01()
test.expr.c_str(),
(double)test.result,
(double)result);
loop_result = false;
}
}
@ -1662,12 +1672,15 @@ inline bool run_test01()
{
exprtk::parser<T> parser;
if (!parser.compile(test.expr,expression))
{
printf("run_test01() - Error: %s Expression: %s\n",
parser.error().c_str(),
test.expr.c_str());
loop_result = false;
continue;
}
}
@ -1741,12 +1754,15 @@ inline bool run_test01()
{
exprtk::parser<T> parser;
if (!parser.compile(expr_list[i],expression))
{
printf("run_test01() - Error: %s Expression: %s\n",
parser.error().c_str(),
expr_list[i].c_str());
loop_result = false;
continue;
}
}
@ -2077,6 +2093,7 @@ inline bool run_test02()
printf("run_test02() - Error: %s Expression: %s\n",
parser.error().c_str(),
test.expr.c_str());
return false;
}
}
@ -2098,7 +2115,9 @@ inline bool run_test02()
}
if (!result)
{
return false;
}
}
return true;
@ -2161,6 +2180,7 @@ inline bool run_test03()
printf("run_test03() - Error - Invalid number of variables in symbol_table! Expected: %d got: %d\n",
static_cast<unsigned int>(variable_list_size),
static_cast<unsigned int>(symbol_table.variable_count()));
return false;
}
@ -2176,6 +2196,7 @@ inline bool run_test03()
printf("run_test03() - Error: %s Expression: %s\n",
parser.error().c_str(),
expression_string.c_str());
return false;
}
}
@ -2217,6 +2238,7 @@ inline bool run_test04()
printf("run_test04() - Error: %s Expression: %s\n",
parser.error().c_str(),
expression_string.c_str());
return false;
}
}
@ -2237,6 +2259,7 @@ inline bool run_test04()
(double)result2,
(double)x,
(double)y);
return false;
}
@ -2277,6 +2300,7 @@ inline bool run_test05()
printf("run_test05() - Error: %s Expression: %s\n",
parser.error().c_str(),
expression_string.c_str());
return false;
}
}
@ -2306,6 +2330,7 @@ inline bool run_test05()
(double)x,
(double)y,
static_cast<unsigned int>(i));
return false;
}
}
@ -2339,6 +2364,7 @@ inline bool run_test06()
printf("run_test06() - Error: %s Expression: %s\n",
parser.error().c_str(),
expression_string.c_str());
return false;
}
}
@ -2358,6 +2384,7 @@ inline bool run_test06()
printf("run_test06() - Integration Error: Expected: %19.15f\tResult: %19.15f\n",
(double)(pi / T(2)),
(double)total_area1);
return false;
}
@ -2410,6 +2437,7 @@ inline bool run_test07()
(double)x,
(double)deriv1_real_result,
(double)deriv1_result1);
return false;
}
}
@ -2431,6 +2459,7 @@ inline bool run_test07()
(double)x,
(double)deriv2_real_result,
(double)deriv2_result1);
return false;
}
}
@ -2452,6 +2481,7 @@ inline bool run_test07()
(double)x,
(double)deriv3_real_result,
(double)deriv3_result1);
return false;
}
}
@ -2636,6 +2666,7 @@ inline bool run_test08()
printf("run_test08() - Error: %s Expression: %s\n",
parser.error().c_str(),
expr_str[j].c_str());
return false;
}
}
@ -2716,6 +2747,7 @@ inline bool run_test09()
printf("run_test09() - Error: %s Expression: %s\n",
parser.error().c_str(),
expression_string.c_str());
return false;
}
}
@ -2743,6 +2775,7 @@ inline bool run_test09()
printf("run_test09() - Error Expected: %19.15f\tResult: %19.15f\n",
(double)expected,
(double)result);
return false;
}
}
@ -2772,6 +2805,7 @@ inline bool run_test10()
static inline bool variable(exprtk::symbol_table<T>& symbol_table, const std::string& variable_name, const T& value)
{
exprtk::details::variable_node<T>* var = symbol_table.get_variable(variable_name);
if (var)
return (!not_equal(var->ref(),value));
else
@ -2781,6 +2815,7 @@ inline bool run_test10()
static inline bool string(exprtk::symbol_table<T>& symbol_table, const std::string& string_name, const std::string& str)
{
exprtk::details::stringvar_node<T>* str_node = symbol_table.get_stringvar(string_name);
if (str_node)
return (str_node->ref() == str);
else
@ -3173,11 +3208,13 @@ inline bool run_test10()
{
exprtk::parser<T> parser;
if (!parser.compile(expression_string,expression0))
{
printf("run_test10() - Error: %s Expression: %s\n",
parser.error().c_str(),
expression_string.c_str());
return false;
}
}
@ -3189,11 +3226,13 @@ inline bool run_test10()
{
exprtk::parser<T> parser;
if (!parser.compile(expression_string,expression1))
{
printf("run_test10() - Error: %s Expression: %s\n",
parser.error().c_str(),
expression_string.c_str());
return false;
}
}
@ -3230,14 +3269,18 @@ inline bool run_test10()
{
exprtk::parser<T> parser;
parser.cache_symbols() = true;
if (!parser.compile(expression_string,expression))
{
printf("run_test10() - Error: %s Expression: %s\n",
parser.error().c_str(),
expression_string.c_str());
return false;
}
parser.expression_symbols(variable_list);
}
@ -3553,11 +3596,13 @@ inline bool run_test10()
{
exprtk::parser<T> parser;
if (!parser.compile(expression_list[i],expression))
{
printf("run_test10() - swaps Error: %s Expression: %s\n",
parser.error().c_str(),
expression_list[i].c_str());
return false;
}
}
@ -3573,7 +3618,9 @@ inline bool run_test10()
}
if (failed)
{
return false;
}
}
}
@ -3602,11 +3649,13 @@ inline bool run_test11()
{
{
exprtk::parser<T> parser;
if (!parser.compile(expression_string,expression))
{
printf("run_test11() - Error: %s Expression: %s\n",
parser.error().c_str(),
expression_string.c_str());
return false;
}
}
@ -3627,6 +3676,7 @@ inline bool run_test11()
{
exprtk::parser<T> parser;
if (!parser.compile(expression_string,expression))
{
printf("run_test11() - Error: %s Expression: %s\n",
@ -3732,11 +3782,13 @@ inline bool run_test12()
{
exprtk::parser<T> parser;
if (!parser.compile(expr_str,expression))
{
printf("run_test12() - Error: %s Expression: %s\n",
parser.error().c_str(),
expr_str.c_str());
return false;
}
}
@ -3827,6 +3879,7 @@ inline bool run_test13()
printf("run_test13() - Error: %s Expression: %s\n",
parser.error().c_str(),
expr_str.c_str());
return false;
}
}
@ -3848,16 +3901,21 @@ inline std::size_t load_expressions(const std::string& file_name,
Sequence<std::string,Allocator>& sequence)
{
std::ifstream stream(file_name.c_str());
if (!stream) return 0;
std::string buffer;
buffer.reserve(1024);
std::size_t line_count = 0;
while (std::getline(stream,buffer))
{
if (buffer.empty())
continue;
else if ('#' == buffer[0])
continue;
++line_count;
sequence.push_back(buffer);
}
@ -3939,6 +3997,7 @@ inline bool run_test14()
printf("run_test14() - Error: %s Expression: %s\n",
parser.error().c_str(),
expr_str_list[i].c_str());
failure = true;
}
else
@ -3951,9 +4010,11 @@ inline bool run_test14()
for (std::size_t i = 0; i < expression_list.size(); ++i)
{
T result = expression_list[i].value();
if (result != T(1))
{
failure = true;
printf("run_test14() - Error with evaluation of expression: %s\n",
expr_str_list[i].c_str());
}
@ -4020,6 +4081,7 @@ inline bool run_test15()
printf("run_test15() - Error: %s Expression: %s\n",
parser.error().c_str(),
expr_str_list[i].c_str());
return false;
}
else
@ -4039,6 +4101,7 @@ inline bool run_test15()
printf("run_test15() - Error: %s Expression: %s\n",
parser.error().c_str(),
base_expr_str.c_str());
return false;
}
}
@ -4056,6 +4119,7 @@ inline bool run_test15()
(double)base_result,
(double)result,
expr_str_list[i].c_str());
failure = true;
}
}
@ -4198,6 +4262,7 @@ inline bool run_test16()
printf("run_test16() - Error: %s Expression: %s\n",
parser.error().c_str(),
expr_str_list[i].c_str());
return false;
}
else
@ -4212,6 +4277,7 @@ inline bool run_test16()
{
printf("run_test16() - Error in evaluation! (1) Expression: %s\n",
expr_str_list[i].c_str());
failure = true;
}
}
@ -4314,6 +4380,7 @@ inline bool run_test17()
printf("run_test17() - Error: %s Expression: %s\n",
parser.error().c_str(),
expr_str_list[i].c_str());
return false;
}
else
@ -4328,6 +4395,7 @@ inline bool run_test17()
{
printf("run_test17() - Error in evaluation! (1) Expression: %s\n",
expr_str_list[i].c_str());
failure = true;
}
}
@ -4341,10 +4409,12 @@ struct va_func : public exprtk::ivararg_function<T>
inline T operator()(const std::vector<T>& arglist)
{
T result = T(0);
for (std::size_t i = 0; i < arglist.size(); ++i)
{
result += arglist[i];
}
return result;
}
};
@ -4409,6 +4479,7 @@ inline bool run_test18()
printf("run_test18() - Error: %s Expression: %s\n",
parser.error().c_str(),
expr_str_list[i].c_str());
return false;
}
else
@ -4423,6 +4494,7 @@ inline bool run_test18()
{
printf("run_test18() - Error in evaluation! (1) Expression: %s\n",
expr_str_list[i].c_str());
failure = true;
}
}
@ -4499,6 +4571,7 @@ inline bool run_test19()
printf("run_test19() - Error: %s Expression: %s\n",
parser.error().c_str(),
expr_str_list[i].c_str());
return false;
}
else
@ -4513,6 +4586,7 @@ inline bool run_test19()
{
printf("run_test19() - Error in evaluation! (1) Expression: %s\n",
expr_str_list[i].c_str());
failure = true;
}
}
@ -4621,6 +4695,7 @@ inline bool run_test19()
printf("run_test19() - Error: %s Expression: %s\n",
parser.error().c_str(),
expr_str_list[i].c_str());
return false;
}
@ -4632,6 +4707,7 @@ inline bool run_test19()
expr_str_list[i].c_str(),
result_list[i],
result);
return false;
}
}
@ -4760,6 +4836,7 @@ inline bool run_test19()
parser.error().c_str(),
static_cast<unsigned int>(i),
expression_str[i].c_str());
return false;
}
else
@ -4945,6 +5022,7 @@ inline bool run_test19()
parser.error().c_str(),
static_cast<unsigned int>(i),
expression_str[i].c_str());
return false;
}
else
@ -5066,6 +5144,7 @@ inline bool run_test19()
printf("run_test19() - Error: %s Expression: %s\n",
parser.error().c_str(),
expression_str.c_str());
return false;
}
@ -5083,6 +5162,7 @@ inline bool run_test19()
expression_str.c_str(),
(double)std::sqrt(x),
(double)result);
failure = true;
}
}
@ -5146,6 +5226,7 @@ inline bool run_test19()
printf("run_test19() - Error: %s Expression: %s\n",
parser.error().c_str(),
expression_str.c_str());
return false;
}
@ -5186,6 +5267,7 @@ inline bool run_test19()
printf("run_test19() - Error: %s Expression: %s\n",
parser.error().c_str(),
expression_str.c_str());
return false;
}
@ -5203,6 +5285,7 @@ inline bool run_test19()
x,
sum,
result);
return false;
}
}
@ -5215,7 +5298,6 @@ inline bool run_test19()
template <typename T>
struct my_usr : public exprtk::parser<T>::unknown_symbol_resolver
{
typedef typename exprtk::parser<T>::unknown_symbol_resolver usr_t;
bool process(const std::string& unknown_symbol,
@ -5228,6 +5310,7 @@ struct my_usr : public exprtk::parser<T>::unknown_symbol_resolver
st = usr_t::e_variable_type;
default_value = next_value();
error_message = "";
return true;
}
else if (unknown_symbol[0] == 'c')
@ -5235,6 +5318,7 @@ struct my_usr : public exprtk::parser<T>::unknown_symbol_resolver
st = usr_t::e_constant_type;
default_value = next_value();
error_message = "";
return true;
}
else
@ -5247,6 +5331,7 @@ struct my_usr : public exprtk::parser<T>::unknown_symbol_resolver
T next_value(const bool reset = false)
{
static T value = 0;
if (reset)
return (value = 0);
else
@ -5282,6 +5367,7 @@ inline bool run_test20()
printf("run_test20() - Error: %s Expression: %s\n",
parser.error().c_str(),
expr_str.c_str());
return false;
}
@ -5292,6 +5378,7 @@ inline bool run_test20()
{
printf("run_test20() - Error in evaluation! (1) Expression: %s\n",
expr_str.c_str());
return false;
}
}

View File

@ -67,10 +67,10 @@ expressions that can be parsed and evaluated using the ExprTk library.
(14) (sin(x / pi) cos(2y) + 1) == (sin(x / pi) * cos(2 * y) + 1)
(15) 75x^17 + 25.1x^5 - 35x^4 - 15.2x^3 + 40x^2 - 15.3x + 1
(16) (avg(x,y) <= x + y ? x - y : x * y) + 2.345 * pi / x
(17) fib_i := fib_i + (x := y + 0 * (fib_i := x + (y := fib_i)))
(18) while (x <= 100) { x -= 1; }
(19) x <= 'abc123' and (y in 'AString') or ('1x2y3z' != z)
(20) (x like '*123*') or ('a123b' ilike y)
(17) while (x <= 100) { x -= 1; }
(18) x <= 'abc123' and (y in 'AString') or ('1x2y3z' != z)
(19) (x like '*123*') or ('a123b' ilike y)
(20) sgn(+1.2^3.4z / -5.6y) <= {-7.8^9 / -10.11x }
@ -88,8 +88,8 @@ The most recent version of the C++ Mathematical Expression Toolkit
Library including all updates and tests can be found at the following
locations:
(1) Download: http://www.partow.net/programming/exprtk/index.html
(2) Repository: https://exprtk.googlecode.com/svn/
(a) Download: http://www.partow.net/programming/exprtk/index.html
(b) Repository: https://exprtk.googlecode.com/svn/
@ -100,10 +100,10 @@ include path (e.g: /usr/include/).
[06 - COMPILATION]
(a) For a complete build: make clean all
(b) For a PGO build: make clean pgo
(c) To strip executables: make strip_bin
(d) Execute valgrind check: make valgrind_check
(a) For a complete build: make clean all
(b) For a PGO build: make clean pgo
(c) To strip executables: make strip_bin
(d) Execute valgrind check: make valgrind_check
@ -158,7 +158,7 @@ of C++ compilers:
+----------+---------------------------------------------------------+
| /= | Assign the division of x by the value of the expression |
| | on the right-hand side to x. Where x is either a |
| | variable or vector type. (eg: x[i+j] /= abs(y * z)) |
| | variable or vector type. (eg: x[i + j] /= abs(y * z)) |
+----------+---------------------------------------------------------+
| %= | Assign x modulo the value of the expression on the right|
| | hand side to x. Where x is either a variable or vector |
@ -422,11 +422,11 @@ of C++ compilers:
| | eg: |
| | 1. if (x > y) z; else w; |
| | 2. if (x > y) z; else if (w != u) v; |
| | 3. if (x < y) {z; w+1;} else u; |
| | 3. if (x < y) {z; w + 1;} else u; |
| | 4. if ((x != y) and (z > w)) |
| | { |
| | y := sin(x) / u; |
| | z := w+1; |
| | z := w + 1; |
| | } |
| | else if (x > (z + 1)) |
| | { |
@ -471,7 +471,7 @@ of C++ compilers:
| for | The structure will repeatedly evaluate the internal |
| | statement(s) while the condition is true. On each loop |
| | iteration, an 'incrementing' expression is evaluated. |
| | The conditional is mandatory whereas the initializer |
| | The conditional is mandatory whereas the initialiser |
| | and incrementing expressions are optional. |
| | eg: |
| | for (var x := 0; (x < n) and (x != y); x += 1) |
@ -868,7 +868,7 @@ vectors. The definitions must be unique as shadowing is not allowed
and object life-times are based on scope. Definitions use the
following general form:
var <name> := <initializer>;
var <name> := <initialiser>;
(1) Variable Definition
Variables are of numeric type denoting a single value. They can be
@ -900,13 +900,13 @@ zero. The following are examples of vector definitions:
var x[3] := [123 + 3y + sin(w/z)];
(d) Initialise the first two values, other elements to zero
var x[3] := {1 + x[2], sin(y[0] / x[]) + 3};
var x[3] := { 1 + x[2], sin(y[0] / x[]) + 3 };
(e) Initialise the first three (all) values
var x[3] := {1,2,3};
var x[3] := { 1, 2, 3 };
(f) Error as there are too many initializers
var x[3] := {1,2,3,4};
(f) Error as there are too many initialisers
var x[3] := { 1, 2, 3, 4 };
(g) Error as a vector of size zero is not allowed.
var x[0];
@ -914,7 +914,7 @@ zero. The following are examples of vector definitions:
(3) Return Value
Variable and vector definitions have a return value. In the case of
variable definitions, the value to which the variable is initialized
variable definitions, the value to which the variable is initialised
will be returned. Where as for vectors, the value of the first element
(eg: v[0]) will be returned.
@ -927,14 +927,14 @@ vector expression can be assigned to a variable.
Every element of the vector is assigned the value of the variable
or expression.
var x := 3;
var y[3] := {1,2,3};
var y[3] := { 1, 2, 3 };
y := x + 1;
(b) Vector To Variable:
The variable is assigned the value of the first element of the
vector (aka vec[0])
var x := 3;
var y[3] := {1,2,3};
var y[3] := { 1, 2, 3 };
x := y + 1;
@ -972,16 +972,16 @@ The following simple example demonstrates the vector processing
capabilities by computing the dot-product of the vectors v0 and v1 and
then assigning it to the variable v0dotv1:
var v0[3] := {1,2,3};
var v1[3] := {4,5,6};
var v0[3] := { 1, 2, 3 };
var v1[3] := { 4, 5, 6 };
var v0dotv1 := sum(v0 * v1);
The following is a for-loop based implementation that is equivalent to
the previously mentioned dot-product computation expression:
var v0[3] := {1,2,3};
var v1[3] := {4,5,6};
var v0[3] := { 1, 2, 3 };
var v1[3] := { 4, 5, 6 };
var v0dotv1;
for (var i := 0; i < min(v0[],v1[]); i += 1)
@ -995,8 +995,8 @@ is not a vector but rather a singular variable denoting a boolean
state of either 'true' or 'false' depending on the nature of the
inequality.
var x[3] := {1,1,1};
var y[3] := {3,2,1};
var x[3] := { 1, 1, 1 };
var y[3] := { 3, 2, 1 };
y > x == false
@ -1005,10 +1005,12 @@ Note: When the aggregate operations denoted above are used in
conjunction with a vector or vector expression, the return value is
not a vector but rather a single value.
var x[3] := {1,2,3};
var x[3] := { 1, 2, 3 };
sum(1 + 2x) == 15
7 == avg(3x + 1)
avg(3x + 1) == 7
min(1 / x) == (1 / 3)
max(x / 2) == (3 / 2)
@ -1027,6 +1029,7 @@ There are two types of function interface:
(1) ifunction
(2) ivararg_function
(3) function_compositor
(1) ifunction
@ -1061,24 +1064,62 @@ example defines a vararg function called 'boo':
inline T operator()(const std::vector<T>& arglist)
{
T result = T(0);
for (std::size_t i = 0; i < arglist.size(); ++i)
{
result += arglist[i] / arglist[i > 0 ? (i - 1) : 0];
}
return result;
}
};
(3) Using Functions In Expressions
For the above denoted custom functions to be used in an expression, an
instance of each function needs to be registered with a symbol_table
that has been associated with the expression instance. The following
demonstrates how all the pieces are put together:
(3) function_compositor
The function compositor interface allows a user to define a function
using ExprTk syntax. The functions are limited to returning a single
scalar value and consuming up to six parameters as input.
typedef exprtk::symbol_table<double> symbol_table_t;
typedef exprtk::expression<double> expression_t;
typedef exprtk::parser<double> parser_t;
All composited functions are registered with a symbol table, allowing
them to call other functions that have been registered with the symbol
table instance, furthermore the functions can be recursive in nature.
The following example defines, using two different methods, composited
functions then implicitly registers the functions with the denoted
symbol table.
typedef exprtk::symbol_table<T> symbol_table_t;
typedef exprtk::function_compositor<T> compositor_t;
typedef typename compositor_t::function function_t;
symbol_table_t symbol_table;
compositor_t compositor(symbol_table);
// define function koo0(v1,v2) { ... }
compositor
.add("koo0",
" 1 + cos(v1 * v2) / 3;",
"v1","v2");
// define function koo1(x,y,z) { ... }
compositor
.add(function_t()
.name("koo1")
.var("x").var("y").var("z")
.expression("1 + cos(x * y) / z;"));
(4) Using Functions In Expressions
For the above denoted custom and composited functions to be used in an
expression, an instance of each function needs to be registered with a
symbol_table that has been associated with the expression instance.
The following demonstrates how all the pieces are put together:
typedef exprtk::symbol_table<double> symbol_table_t;
typedef exprtk::expression<double> expression_t;
typedef exprtk::parser<double> parser_t;
typedef exprtk::function_compositor<T> compositor_t;
typedef typename compositor_t::function function_t;
foo<double> f;
boo<double> b;
@ -1087,11 +1128,18 @@ demonstrates how all the pieces are put together:
symbol_table.add_function("foo",f);
symbol_table.add_vararg_function("boo",b);
compositor
.add(function_t()
.name("koo")
.var("v1")
.var("v2")
.expression("1 + cos(v1 * v2) / 3;"));
expression_t expression;
expression.register_symbol_table(symbol_table);
std::string expression_str =
"foo(1,2,3) + boo(1) / boo(1/2,2/3,3/4,4/5,5/6)";
"foo(1,2,3) + boo(1) / boo(1/2,2/3,3/4,4/5) + koo(3,4)";
parser_t parser;
parser.compile(expression_str,expression);
@ -1099,7 +1147,7 @@ demonstrates how all the pieces are put together:
expression.value();
(4) Function Side-Effects
(5) Function Side-Effects
All function calls are assumed to have side-effects by default. This
assumption implicitly disables constant folding optimisations when all
parameters being passed to the function are deduced as being constants
@ -1121,7 +1169,7 @@ to the constructor to denote the lack of side-effects.
};
(5) Zero Parameter Functions
(6) Zero Parameter Functions
When either an ifunction or ivararg_function derived type is defined
with zero number of parameters, there are two calling conventions
within expressions that are allowed. For a function named 'foo' with
@ -1132,7 +1180,116 @@ zero input parameters the calling styles are as follows:
[15 - EXPRTK NOTES]
[15 - COMPILATION ERRORS]
When attempting to compile a malformed or otherwise erroneous ExprTk
expression, the compilation process will result in an error, as is
indicated by the 'compile' method returning a false value. A
diagnostic indicating the first error encountered and its cause can be
obtained by invoking the 'error' method, as is demonstrated in the
following example:
if (!parser.compile(expression_string,expression))
{
printf("Error: %s\n", parser.error().c_str());
return 1;
}
Any error(s) resulting from a failed compilation will be stored in the
parser instance until the next time a compilation is performed. Before
then errors can be enumerated in the order they occurred by invoking
the 'get_error' method which itself will return a 'parser_error' type.
A parser_error object will contain an error diagnostic, an error mode
(or class), and the character position of the error in the expression
string. The following example demonstrates the enumeration of error(s)
in the event of a failed compilation.
if (!parser.compile(expression_string,expression))
{
for (std::size_t i = 0; i < parser.error_count(); ++i)
{
typedef exprtk::parser_error::type error_t;
error_t error = parser.get_error(i);
printf("Error[%02d] Position: %02d Type: [%14s] Msg: %s\n",
i,
error.token.position,
exprtk::parser_error::to_str(error.mode).c_str(),
error.diagnostic.c_str());
}
return 1;
}
For expressions comprised of multiple lines, the error position
provided in the parser_error object can be converted into a pair of
line and column numbers by invoking the 'update_error' function as is
demonstrated by the following example:
if (!parser.compile(program_str,expression))
{
for (std::size_t i = 0; i < parser.error_count(); ++i)
{
typedef exprtk::parser_error::type error_t;
error_t error = parser.get_error(i);
exprtk::parser_error::update_error(error,program_str);
printf("Error[%02d] at line: %d column: %d\n",
i,
error.line_no,
error.column_no);
}
return 1;
}
Note: The are five distinct error modes in ExprTk which denote the
class of an error. These classes are as follows:
(a) Syntax
(b) Token
(c) Numeric
(d) Symbol Table
(e) Lexer
(a) Syntax Errors
These are errors related to invalid syntax found within the denoted
expression. Examples are invalid sequences of operators and variables,
incorrect number of parameters to functions, invalid conditional or
loop structures and invalid use of keywords.
eg: 'for := sin(x,y,z) + 2 * equal > until[2 - x,3]'
(b) Token Errors
Errors in this class relate to token level errors detected by one or
more of the following checkers:
(1) Bracket Checker
(2) Numeric Checker
(3) Sequence Checker
(c) Numeric Errors
This class of error is related to conversion of numeric values from
their string form to the underlying numerical type (float, double
etc).
(d) Symbol Table Errors
This is the class of errors related to failures when interacting with
the registered symbol_table instance. Errors such as not being able to
find, within the symbol_table, symbols representing variables or
functions, to being unable to create new variables in the symbol_table
via the 'unknown symbol resolver' mechanism.
[16 - EXPRTK NOTES]
The following is a list of facts and suggestions one may want to take
into account when using Exprtk:
@ -1268,17 +1425,17 @@ into account when using Exprtk:
sum, swap, switch, tanh, tan, true, trunc, until, var,
while, xnor, xor, xor
(28) Every ExprTk statement is a "value returning" expression. Unlike
some languages that limit the types of expressions that can be
performed in certain situations, in ExprTk any valid expression
can be used in any "value consuming" context. Eg:
(28) Every valid ExprTk statement is a "value returning" expression.
Unlike some languages that limit the types of expressions that
can be performed in certain situations, in ExprTk any valid
expression can be used in any "value consuming" context. Eg:
var y := 3;
for (var x := switch
{
case 1 : 7;
case 2 : -1 + ~{var x{};};
default: y > 2 ? 3 : 4;
case 1 : 7;
case 2 : -1 + ~{var x{};};
default: y > 2 ? 3 : 4;
};
x != while (y > 0) { y -= 1; };
x -= {if(min(x,y) < 2 * max(x,y))
@ -1292,7 +1449,7 @@ into account when using Exprtk:
[16 - SIMPLE EXPRTK EXAMPLE]
[17 - SIMPLE EXPRTK EXAMPLE]
--- snip ---
#include <cstdio>
#include <string>
@ -1380,7 +1537,7 @@ int main()
[17 - BUILD OPTIONS]
[18 - BUILD OPTIONS]
When building ExprTk there are a number of defines that will enable or
disable certain features and capabilities. The defines can either be
part of a compiler command line switch or scoped around the include to
@ -1418,32 +1575,35 @@ in a compilation failure.
[18 - FILES]
(00) Makefile
(01) readme.txt
(02) exprtk.hpp
(03) exprtk_test.cpp
(04) exprtk_benchmark.cpp
(05) exprtk_simple_example_01.cpp
(06) exprtk_simple_example_02.cpp
(07) exprtk_simple_example_03.cpp
(08) exprtk_simple_example_04.cpp
(09) exprtk_simple_example_05.cpp
(10) exprtk_simple_example_06.cpp
(11) exprtk_simple_example_07.cpp
(12) exprtk_simple_example_08.cpp
(13) exprtk_simple_example_09.cpp
(14) exprtk_simple_example_10.cpp
(15) exprtk_simple_example_11.cpp
(16) exprtk_simple_example_12.cpp
(17) exprtk_simple_example_13.cpp
(18) exprtk_simple_example_14.cpp
(19) exprtk_simple_example_15.cpp
(20) exprtk_simple_example_16.cpp
[19 - FILES]
The source distribution of ExprTk is comprised of the following set of
files:
(00) Makefile
(01) readme.txt
(02) exprtk.hpp
(03) exprtk_test.cpp
(04) exprtk_benchmark.cpp
(05) exprtk_simple_example_01.cpp
(06) exprtk_simple_example_02.cpp
(07) exprtk_simple_example_03.cpp
(08) exprtk_simple_example_04.cpp
(09) exprtk_simple_example_05.cpp
(10) exprtk_simple_example_06.cpp
(11) exprtk_simple_example_07.cpp
(12) exprtk_simple_example_08.cpp
(13) exprtk_simple_example_09.cpp
(14) exprtk_simple_example_10.cpp
(15) exprtk_simple_example_11.cpp
(16) exprtk_simple_example_12.cpp
(17) exprtk_simple_example_13.cpp
(18) exprtk_simple_example_14.cpp
(19) exprtk_simple_example_15.cpp
(20) exprtk_simple_example_16.cpp
[19 - LANGUAGE STRUCTURE]
[20 - LANGUAGE STRUCTURE]
+-------------------------------------------------------------+
|00 - If Statement |
| |