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

This commit is contained in:
Arash Partow 2014-05-28 07:10:40 +10:00
parent baa1feb6d2
commit 02d2402ca5
6 changed files with 3054 additions and 1304 deletions

View File

@ -103,20 +103,20 @@ strip_bin:
strip -s exprtk_simple_example_12 strip -s exprtk_simple_example_12
valgrind_check: valgrind_check:
valgrind --leak-check=full --show-reachable=yes --track-origins=yes -v ./exprtk_test valgrind --leak-check=full --show-reachable=yes --track-origins=yes --log-file=exprtk_test_valgrind.log -v ./exprtk_test
valgrind --leak-check=full --show-reachable=yes --track-origins=yes -v ./exprtk_benchmark valgrind --leak-check=full --show-reachable=yes --track-origins=yes --log-file=exprtk_benchmark_valgrind.log -v ./exprtk_benchmark
valgrind --leak-check=full --show-reachable=yes --track-origins=yes -v ./exprtk_simple_example_01 valgrind --leak-check=full --show-reachable=yes --track-origins=yes --log-file=exprtk_simple_example_01_valgrind.log -v ./exprtk_simple_example_01
valgrind --leak-check=full --show-reachable=yes --track-origins=yes -v ./exprtk_simple_example_02 valgrind --leak-check=full --show-reachable=yes --track-origins=yes --log-file=exprtk_simple_example_02_valgrind.log -v ./exprtk_simple_example_02
valgrind --leak-check=full --show-reachable=yes --track-origins=yes -v ./exprtk_simple_example_03 valgrind --leak-check=full --show-reachable=yes --track-origins=yes --log-file=exprtk_simple_example_03_valgrind.log -v ./exprtk_simple_example_03
valgrind --leak-check=full --show-reachable=yes --track-origins=yes -v ./exprtk_simple_example_04 valgrind --leak-check=full --show-reachable=yes --track-origins=yes --log-file=exprtk_simple_example_04_valgrind.log -v ./exprtk_simple_example_04
valgrind --leak-check=full --show-reachable=yes --track-origins=yes -v ./exprtk_simple_example_05 valgrind --leak-check=full --show-reachable=yes --track-origins=yes --log-file=exprtk_simple_example_05_valgrind.log -v ./exprtk_simple_example_05
valgrind --leak-check=full --show-reachable=yes --track-origins=yes -v ./exprtk_simple_example_06 valgrind --leak-check=full --show-reachable=yes --track-origins=yes --log-file=exprtk_simple_example_06_valgrind.log -v ./exprtk_simple_example_06
valgrind --leak-check=full --show-reachable=yes --track-origins=yes -v ./exprtk_simple_example_07 valgrind --leak-check=full --show-reachable=yes --track-origins=yes --log-file=exprtk_simple_example_07_valgrind.log -v ./exprtk_simple_example_07
valgrind --leak-check=full --show-reachable=yes --track-origins=yes -v ./exprtk_simple_example_08 valgrind --leak-check=full --show-reachable=yes --track-origins=yes --log-file=exprtk_simple_example_08_valgrind.log -v ./exprtk_simple_example_08
valgrind --leak-check=full --show-reachable=yes --track-origins=yes -v ./exprtk_simple_example_09 valgrind --leak-check=full --show-reachable=yes --track-origins=yes --log-file=exprtk_simple_example_09_valgrind.log -v ./exprtk_simple_example_09
valgrind --leak-check=full --show-reachable=yes --track-origins=yes -v ./exprtk_simple_example_10 valgrind --leak-check=full --show-reachable=yes --track-origins=yes --log-file=exprtk_simple_example_10_valgrind.log -v ./exprtk_simple_example_10
valgrind --leak-check=full --show-reachable=yes --track-origins=yes -v ./exprtk_simple_example_11 valgrind --leak-check=full --show-reachable=yes --track-origins=yes --log-file=exprtk_simple_example_11_valgrind.log -v ./exprtk_simple_example_11
valgrind --leak-check=full --show-reachable=yes --track-origins=yes -v ./exprtk_simple_example_12 valgrind --leak-check=full --show-reachable=yes --track-origins=yes --log-file=exprtk_simple_example_12_valgrind.log -v ./exprtk_simple_example_12
clean: clean:
rm -f core.* *~ *.o *.bak *stackdump gmon.out *.gcda *.gcno *.gcnor *.gch rm -f core.* *~ *.o *.bak *stackdump gmon.out *.gcda *.gcno *.gcnor *.gch

3458
exprtk.hpp

File diff suppressed because it is too large Load Diff

View File

@ -28,7 +28,8 @@ void square_wave2()
typedef exprtk::expression<T> expression_t; typedef exprtk::expression<T> expression_t;
typedef exprtk::parser<T> parser_t; typedef exprtk::parser<T> parser_t;
std::string expr_string = " r := 0; " std::string wave_program =
" r := 0; "
" for(i := 0; i < 1000; i += 1) " " for(i := 0; i < 1000; i += 1) "
" { " " { "
" r += (1 / (2i + 1)) * sin((4i + 2) * pi * f * t); " " r += (1 / (2i + 1)) * sin((4i + 2) * pi * f * t); "
@ -53,7 +54,7 @@ void square_wave2()
parser_t parser; parser_t parser;
parser.enable_unknown_symbol_resolver(); parser.enable_unknown_symbol_resolver();
parser.compile(expr_string,expression); parser.compile(wave_program,expression);
const T delta = (T(4) * pi) / T(1000); const T delta = (T(4) * pi) / T(1000);

View File

@ -28,7 +28,7 @@ void bubble_sort()
typedef exprtk::expression<T> expression_t; typedef exprtk::expression<T> expression_t;
typedef exprtk::parser<T> parser_t; typedef exprtk::parser<T> parser_t;
std::string expr_string = std::string bubblesort_program =
" upper_bound := v[]; " " upper_bound := v[]; "
" repeat " " repeat "
" swapped := false; " " swapped := false; "
@ -38,9 +38,7 @@ void bubble_sort()
" { " " { "
" if (v[i] > v[j]) " " if (v[i] > v[j]) "
" { " " { "
" temp := v[i]; " " v[i] <=> v[j]; "
" v[i] := v[j]; "
" v[j] := temp; "
" swapped := true; " " swapped := true; "
" }; " " }; "
" }; " " }; "
@ -59,7 +57,7 @@ void bubble_sort()
parser_t parser; parser_t parser;
parser.enable_unknown_symbol_resolver(); parser.enable_unknown_symbol_resolver();
parser.compile(expr_string,expression); parser.compile(bubblesort_program,expression);
expression.value(); expression.value();
} }

View File

@ -27,6 +27,7 @@
#include "exprtk.hpp" #include "exprtk.hpp"
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;
@ -1128,7 +1129,7 @@ inline bool test_expression(const std::string& expression_string, const T& expec
} }
} }
if (!exprtk::expression_helper<T>::is_head_constant(expression)) if (!exprtk::expression_helper<T>::is_constant(expression))
{ {
printf("test_expression() - Error: Expression did not compile to a constant! Expression: %s\n", printf("test_expression() - Error: Expression did not compile to a constant! Expression: %s\n",
expression_string.c_str()); expression_string.c_str());
@ -2736,6 +2737,8 @@ inline bool run_test09()
template <typename T> template <typename T>
inline bool run_test10() inline bool run_test10()
{ {
typedef exprtk::expression<T> expression_t;
T x = T(1.1); T x = T(1.1);
T y = T(2.2); T y = T(2.2);
T xx = T(3.3); T xx = T(3.3);
@ -2748,8 +2751,6 @@ inline bool run_test10()
exprtk::symbol_table<T> symbol_table; exprtk::symbol_table<T> symbol_table;
typedef exprtk::expression<T> expression_t;
struct test struct test
{ {
static inline bool variable(exprtk::symbol_table<T>& symbol_table, const std::string& variable_name, const T& value) static inline bool variable(exprtk::symbol_table<T>& symbol_table, const std::string& variable_name, const T& value)
@ -3241,6 +3242,96 @@ inline bool run_test10()
} }
} }
{
exprtk::symbol_table<T> symbol_table0;
exprtk::symbol_table<T> symbol_table1;
if (symbol_table0 == symbol_table1)
{
printf("run_test10() - Error symbol_table0 and symbol_table1 are equal\n");
return false;
}
symbol_table0 = symbol_table1;
symbol_table1 = symbol_table0;
if (!(symbol_table0 == symbol_table1))
{
printf("run_test10() - Error symbol_table0 and symbol_table1 are not equal\n");
return false;
}
}
{
std::string expression_list[] =
{
"var x := 1; var y := 2; swap(x,y); (x == 2) and (y == 1)",
"var x := 1; var y := 2; x <=> y ; (x == 2) and (y == 1)",
"var v[2] := {1,2}; swap(v[0],v[1]); (v[0] == 2) and (v[1] == 1)",
"var v[2] := {1,2}; v[0] <=> v[1] ; (v[0] == 2) and (v[1] == 1)",
"var x := 1; var y := 2; ~(swap(x,y),(x == 2) and (y == 1))",
"var x := 1; var y := 2; ~(x <=> y , (x == 2) and (y == 1))",
"var v[2] := {1,2}; ~(swap(v[0],v[1]), (v[0] == 2) and (v[1] == 1))",
"var v[2] := {1,2}; ~(v[0] <=> v[1] , (v[0] == 2) and (v[1] == 1))",
"var v[2] := {1,2}; swap(v[zero],v[one]); (v[zero] == 2) and (v[one] == 1)",
"var v[2] := {1,2}; v[zero] <=> v[one] ; (v[zero] == 2) and (v[one] == 1)",
"var v[2] := {1,2}; ~(swap(v[zero],v[one]), (v[zero] == 2) and (v[one] == 1))",
"var v[2] := {1,2}; ~(v[zero] <=> v[one] , (v[zero] == 2) and (v[one] == 1))",
"var v[2] := {1,2}; swap(v[2 * zero],v[(2 * one) / (1 + 1)]); (v[2 * zero] == 2) and (v[(2 * one) / (1 + 1)] == 1)",
"var v[2] := {1,2}; v[2 * zero] <=> v[(2*one)/(1+1)] ; (v[2 * zero] == 2) and (v[(2 * one) / (1 + 1)] == 1)",
"var v[2] := {1,2}; ~(swap(v[2 * zero],v[(2 * one) / (1 + 1)]), (v[2 * zero] == 2) and (v[(2 * one) / (1 + 1)] == 1))",
"var v[2] := {1,2}; ~(v[2 * zero] <=> v[(2 * one) / (1 + 1)] , (v[2 * zero] == 2) and (v[(2 * one) / (1 + 1)] == 1))",
"var x := 1; var y := 2; var v[2] := {3,4}; swap(x,v[0]); swap(v[1],y); (x == 3) and (y == 4)",
"var x := 1; var y := 2; var v[2] := {3,4}; x <=> v[0]; v[1] <=> y; (x == 3) and (y == 4)",
"var x := 1; var y := 2; var v[2] := {3,4}; swap(x,v[zero]); swap(v[one],y); (x == 3) and (y == 4)",
"var x := 1; var y := 2; var v[2] := {3,4}; x <=> v[zero]; v[one] <=> y; (x == 3) and (y == 4)",
"var x := 1; var y := 2; var v[2] := {3,4}; swap(x,v[2 * zero]); swap(v[(2 * one) / (1 + 1)],y); (x == 3) and (y == 4)",
"var x := 1; var y := 2; var v[2] := {3,4}; x <=> v[zero / 3]; v[(2 * one)/(1 + 1)] <=> y; (x == 3) and (y == 4)"
};
const std::size_t expression_list_size = sizeof(expression_list) / sizeof(std::string);
exprtk::symbol_table<T> symbol_table;
T zero = T(0);
T one = T(1);
symbol_table.add_variable("zero",zero);
symbol_table.add_variable("one" , one);
bool failed = false;
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_test10() - swaps Error: %s Expression: %s\n",
parser.error().c_str(),
expression_list[i].c_str());
return false;
}
}
T result = expression.value();
if (T(1) != result)
{
printf("run_test10() - swaps evaluation error Expression: %s\n",
expression_list[i].c_str());
failed = true;
}
}
if (failed)
return false;
}
return true; return true;
} }
@ -4035,6 +4126,8 @@ inline bool run_test18()
static const std::string expr_str_list[] = static const std::string expr_str_list[] =
{ {
"equal(va_func,(0))",
"equal(va_func(),(0))",
"equal(va_func(1,2,3,4,5,6,7,8,9),(1+2+3+4+5+6+7+8+9))", "equal(va_func(1,2,3,4,5,6,7,8,9),(1+2+3+4+5+6+7+8+9))",
"equal(va_func(1,x,3,y,5,z,7,w,9),(1+x+3+y+5+z+7+w+9))", "equal(va_func(1,x,3,y,5,z,7,w,9),(1+x+3+y+5+z+7+w+9))",
"equal(va_func(x,2,y,4,z,6,w,8,u),(x+2+y+4+z+6+w+8+u))", "equal(va_func(x,2,y,4,z,6,w,8,u),(x+2+y+4+z+6+w+8+u))",
@ -4201,7 +4294,7 @@ inline bool run_test19()
compositor compositor
.add("f2","7 * (f1(x) + f1(y))","x","y"); .add("f2","7 * (f1(x) + f1(y))","x","y");
// f3(x,y,z) = 9 * (2(x,y) + f2(y,z) + f2(x,z)) // f3(x,y,z) = 9 * (f2(x,y) + f2(y,z) + f2(x,z))
compositor compositor
.add("f3","9 * (f2(x,y) + f2(y,z) + f2(x,z))","x","y","z"); .add("f3","9 * (f2(x,y) + f2(y,z) + f2(x,z))","x","y","z");
@ -4711,6 +4804,70 @@ inline bool run_test19()
return false; return false;
} }
{
symbol_table_t symbol_table;
symbol_table.add_constants();
compositor_t compositor(symbol_table);
compositor
.add("mandelbrot",
" var width := 118; "
" var height := 41; "
" var imag_max := +1; "
" var imag_min := -1; "
" var real_max := +1; "
" var real_min := -2.5; "
" var x_step := (real_max - real_min) / width; "
" var y_step := (imag_max - imag_min) / height; "
" for (y := 0; y < height; y += 1) "
" { "
" var imag := imag_min + (y_step * y); "
" for (x := 0; x < width; x += 1) "
" { "
" var real := real_min + x_step * x; "
" var z_real := real; "
" var z_imag := imag; "
" var plot_value; "
" for (n := 0; n < 30; n += 1) "
" { "
" var a := z_real^2; "
" var b := z_imag^2; "
" plot_value := n; "
" if ((a + b) < 4) "
" { "
" z_imag := 2 * z_real * z_imag + imag; "
" z_real := a - b + real; "
" } "
" else "
" break; "
" }; "
" }; "
" } ");
std::string expression_str = "mandelbrot()";
expression_t expression;
expression.register_symbol_table(symbol_table);
parser_t parser;
if (!parser.compile(expression_str,expression))
{
printf("run_test19() - Error: %s Expression: %s\n",
parser.error().c_str(),
expression_str.c_str());
return false;
}
for (std::size_t i = 0; i < 100; ++i)
{
expression.value();
}
}
return true; return true;
} }

View File

@ -18,11 +18,11 @@ arithmetic operations, functions and processes:
(01) Functions: abs, avg, ceil, clamp, equal, erf, erfc, exp, (01) Functions: abs, avg, ceil, clamp, equal, erf, erfc, exp,
expm1, floor, frac, log, log10, log1p, log2, expm1, floor, frac, log, log10, log1p, log2,
logn, max, min, mul, nequal, root, round, logn, max, min, mul, nequal, root, round,
roundn, sgn, sqrt, sum, trunc roundn, sgn, sqrt, sum, swap, trunc
(02) Trigonometry: acos, acosh, asin, asinh, atan, atanh, atan2, (02) Trigonometry: acos, acosh, asin, asinh, atan, atanh, atan2,
cos, cosh, cot, csc, sec, sin, sinc, sinh, tan, cos, cosh, cot, csc, sec, sin, sinc, sinh,
tanh, hypot, rad2deg, deg2grad, deg2rad, tan, tanh, hypot, rad2deg, deg2grad, deg2rad,
grad2deg grad2deg
(03) Equalities & (03) Equalities &
@ -36,7 +36,7 @@ arithmetic operations, functions and processes:
(06) Loop statements: while, for, repeat-until, break, continue (06) Loop statements: while, for, repeat-until, break, continue
(07) Assignment: :=, +=, -=, *=, /= (07) Assignment: :=, +=, -=, *=, /=, %=
(08) String (08) String
processing: in, like, ilike processing: in, like, ilike
@ -108,6 +108,9 @@ include path (e.g: /usr/include/).
[07 - COMPILER COMPATIBILITY] [07 - COMPILER COMPATIBILITY]
ExprTk has been built error and warning free using the following set
of C++ compilers:
(*) GNU Compiler Collection (3.3+) (*) GNU Compiler Collection (3.3+)
(*) Intel C++ Compiler (8.x+) (*) Intel C++ Compiler (8.x+)
(*) Clang/LLVM (1.1+) (*) Clang/LLVM (1.1+)
@ -150,13 +153,17 @@ include path (e.g: /usr/include/).
+----------+---------------------------------------------------------+ +----------+---------------------------------------------------------+
| *= | Assign the multiplication of x by the value of the | | *= | Assign the multiplication of x by the value of the |
| | expression on the righthand side to x. Where x is either| | | expression on the righthand side to x. Where x is either|
| | variable or vector type. | | | a variable or vector type. |
| | (eg: x *= abs(y / z)) | | | (eg: x *= abs(y / z)) |
+----------+---------------------------------------------------------+ +----------+---------------------------------------------------------+
| /= | Assign the division of x by the value of the expression | | /= | Assign the division of x by the value of the expression |
| | on the right-hand side to x. Where x is either a | | | 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 |
| | type. (eg: x[2] %= y ^ 2) |
+----------+---------------------------------------------------------+
(1) Equalities & Inequalities (1) Equalities & Inequalities
+----------+---------------------------------------------------------+ +----------+---------------------------------------------------------+
@ -292,6 +299,9 @@ include path (e.g: /usr/include/).
| sum | Sum of all the inputs. | | 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)) |
+----------+---------------------------------------------------------+ +----------+---------------------------------------------------------+
| swap | Swap the values of the variables x and y and return the |
| <=> | current value of y. (eg: swap(x,y) or x <=> y) |
+----------+---------------------------------------------------------+
| trunc | Integer portion of x. (eg: trunc(x)) | | trunc | Integer portion of x. (eg: trunc(x)) |
+----------+---------------------------------------------------------+ +----------+---------------------------------------------------------+
@ -453,7 +463,7 @@ include path (e.g: /usr/include/).
| | The conditional is mandatory whereas the initializer | | | The conditional is mandatory whereas the initializer |
| | and incrementing expressions are optional. | | | and incrementing expressions are optional. |
| | eg: | | | eg: |
| | for (x := 0; x < n && (x != y); x += 1) | | | for (x := 0; (x < n) and (x != y); x += 1) |
| | { | | | { |
| | y := y + x / 2 - z; | | | y := y + x / 2 - z; |
| | w := u + y; | | | w := u + y; |
@ -511,6 +521,12 @@ include path (e.g: /usr/include/).
| | case (x + 3) = (y * 4) : y := abs(z / 6) + 7y; | | | case (x + 3) = (y * 4) : y := abs(z / 6) + 7y; |
| | } | | | } |
+----------+---------------------------------------------------------+ +----------+---------------------------------------------------------+
| [] | The vector size operator returns the size of the vector |
| | being actioned. |
| | eg: |
| | 1. v[] |
| | 2. max_size := max(v0[],v1[],v2[],v3[]) |
+----------+---------------------------------------------------------+
Note: In the above tables, the symbols x, y, z, w, u and v where Note: In the above tables, the symbols x, y, z, w, u and v where
appropriate may represent any of one the following: appropriate may represent any of one the following:
@ -518,7 +534,7 @@ appropriate may represent any of one the following:
1. Literal numeric/string value 1. Literal numeric/string value
2. A variable 2. A variable
3. A vector element 3. A vector element
3. An expression comprised of [1], [2] or [3] (eg: 2 + x / vec[3]) 4. An expression comprised of [1], [2] or [3] (eg: 2 + x / vec[3])
@ -582,11 +598,19 @@ current values assigned to the variables will be used.
x = 1.0; x = 1.0;
y = 2.0; y = 2.0;
parser.value(); // 1 * 2 + 3 expression.value(); // 1 * 2 + 3
x = 3.7; x = 3.7;
parser.value(); // 3.7 * 2 + 3 expression.value(); // 3.7 * 2 + 3
y = -9.0; y = -9.0;
parser.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
for (x = 0; x < 100; x += 0.0001)
{
expression.value(); // x * -9 + 3
}
(2) Expression (2) Expression
@ -680,8 +704,7 @@ handle:
(h) '-' '=' ---> '-=' (subtraction assignment) (h) '-' '=' ---> '-=' (subtraction assignment)
(i) '*' '=' ---> '*=' (multiplication assignment) (i) '*' '=' ---> '*=' (multiplication assignment)
(j) '/' '=' ---> '/=' (division assignment) (j) '/' '=' ---> '/=' (division assignment)
(j) '%' '=' ---> '%=' (modulo assignment)
An example of the transformation that takes place is as follows: An example of the transformation that takes place is as follows:
@ -825,108 +848,295 @@ correctly optimize such expressions for a given architecture.
[12 - EXPRTK NOTES] [12 - VARIABLE & VECTOR DEFINITION]
ExprTk supports the definition of expression local variables and
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>;
(1) Variable Definition
Variables are of numeric type denoting a single value. They can be
explicitly initialised to a value, otherwise they will be defaulted to
zero. The following are examples of variable definitions:
(a) Initialise x to zero
var x;
(b) Initialise y to three
var y := 3;
(c) Initialise z to the expression
var z := if(max(1,x + y) > 2,w,v);
(2) Vector Definition
Vectors are arrays of a common numeric type. The elements in a vector
can be explicitly initialised, otherwise they will all be defaulted to
zero. The following are examples of vector definitions:
(a) Initialise all values to zero
var x[3];
(b) Initialise all values to zero
var x[3] := {};
(c) Initialise all values to given expression
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};
(e) Initialise the first three (all) values
var x[3] := {1,2,3};
(f) Error as there are too many initializers
var x[3] := {1,2,3,4};
(g) Error as a vector of size zero is not allowed.
var x[0];
(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
will be returned. Where as for vectors, the value of the first element
(eg: v[0]) will be returned.
[13 - USER DEFINED FUNCTIONS]
ExprTk provides a means whereby custom functions can be defined and
utilized within expressions. The concept requires the user to
provide a reference to the function coupled with an associated name
that will be invoked within expressions. Function can take in numerous
inputs but will always return one value.
During expression compilation when required the reference to the
function will be obtained from the associated symbol_table and be
embedded into the expression.
There are two types of function interface:
(1) ifunction
(2) ivararg_function
(1) ifunction
This interface supports zero to 20 input parameters. The usage
requires a custom function be derived from ifunction and to override
one of the 21 function operators. As part of the constructor the
custom function will define how many parameters it expects to handle.
The following example defines a 3 parameter function called 'foo':
template <typename T>
struct foo : public exprtk::ifunction<T>
{
foo() : exprtk::ifunction<T>(3)
{}
T operator()(const T& v1, const T& v2, const T& v3)
{
return T(1) + (v1 * v2) / T(v3);
}
};
(2) ivararg_function
This interface supports a variable number of arguments as input into
the function. The function operator interface uses a std::vector
specialized upon type T to facilitate parameter passing. The following
example defines a vararg function called 'boo':
template <typename T>
struct boo : 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] / 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
demonstrations 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;
foo<double> f;
boo<double> b;
symbol_table_t symbol_table;
symbol_table.add_function("foo",f);
symbol_table.add_function("boo",b);
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)";
parser_t parser;
parser.compile(expression_str,expression);
expression.value();
(4) Function Side-Effects
All function calls are assumed to have side-effects by default. What
that means is that a certain type of optimisation will not be carried
out when the function is being called. The optimisation in question
is: constant folding. Normally during compilation this optimisation
would be invoked when all the parameters being passed into the
function are literals, the function will be evaluated at that point
and a new literal will replace the function call node in the AST.
If it is certain that the function being registered does not have any
side effects and can be correctly constant folded where appropriate,
then during the construction of the function a 'false' can be passed
to the constructor to denote the lack of side-effects.
template <typename T>
struct foo : public exprtk::ifunction<T>
{
foo() : exprtk::ifunction<T>(3,false)
{}
T operator()(const T& v1, const T& v2, const T& v3)
{ ... }
};
(5) Zero Parameter Functions
When an ifunction 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 zero input parameters the
calling styles are as follows:
(1) x + sin(foo()- 2) / y
(2) x + sin(foo - 2) / y
[14 - EXPRTK NOTES]
The following is a list of facts and suggestions one may want to take
into account when using Exprtk:
(00) Precision and performance of expression evaluations are the (00) Precision and performance of expression evaluations are the
dominant principles of the ExprTk library. dominant principles of the ExprTk library.
(01) Supported types are float, double and long double. (01) ExprTk uses a rudimentary imperative programming model with
syntax based on languages such as Pascal and C.
(02) Standard mathematical operator precedence is applied (BEDMAS). (02) Supported types are float, double and long double.
(03) Results of expressions that are deemed as being 'valid' are to (03) Standard mathematical operator precedence is applied (BEDMAS).
(04) Results of expressions that are deemed as being 'valid' are to
exist within the set of Real numbers. All other results will be exist within the set of Real numbers. All other results will be
of the value: Not-A-Number (NaN). of the value: Not-A-Number (NaN).
(04) Supported user defined types are numeric and string variables (05) Supported user defined types are numeric and string variables
and functions. and functions.
(05) All variable and function names are case-insensitive. (06) All variable and function names are case-insensitive.
(06) Variable and function names must begin with a letter (07) Variable and function names must begin with a letter
(A-Z or a-z), then can be comprised of any combination of (A-Z or a-z), then can be comprised of any combination of
letters, digits and underscores. (eg: x, var1 or power_func99) letters, digits and underscores. (eg: x, var1 or power_func99)
(07) Expression lengths and sub-expression lists are limited only by (08) Expression lengths and sub-expression lists are limited only by
storage capacity. storage capacity.
(08) The life-time of objects registered with or created from a (09) The life-time of objects registered with or created from a
specific symbol-table must span at least the life-time of the specific symbol-table must span at least the life-time of the
compiled expressions which utilize objects, such as variables, compiled expressions which utilize objects, such as variables,
of that symbol-table, otherwise the result will be undefined of that symbol-table, otherwise the result will be undefined
behavior. behavior.
(09) Equal/Nequal are normalized equality routines, which use (10) Equal/Nequal are normalized equality routines, which use
epsilons of 0.0000000001 and 0.000001 for double and float epsilons of 0.0000000001 and 0.000001 for double and float
types respectively. types respectively.
(10) All trigonometric functions assume radian input unless (11) All trigonometric functions assume radian input unless
stated otherwise. stated otherwise.
(11) Expressions may contain white-space characters such as (12) Expressions may contain white-space characters such as
space, tabs, new-lines, control-feed et al. space, tabs, new-lines, control-feed et al.
('\n', '\r', '\t', '\b', '\v', '\f') ('\n', '\r', '\t', '\b', '\v', '\f')
(12) Strings may be constructed from any letters, digits or special (13) Strings may be constructed from any letters, digits or special
characters such as (~!@#$%^&*()[]|=+ ,./?<>;:"`~_), and must characters such as (~!@#$%^&*()[]|=+ ,./?<>;:"`~_), and must
be enclosed with single-quotes. be enclosed with single-quotes.
eg: 'Frankly my dear, I do not give a damn!' eg: 'Frankly my dear, I do not give a damn!'
(13) User defined normal functions can have up to 20 parameters, (14) User defined normal functions can have up to 20 parameters,
where as user defined vararg-functions can have an unlimited where as user defined vararg-functions can have an unlimited
number of parameters. number of parameters.
(14) The inbuilt polynomial functions can be at most of degree 12. (15) The inbuilt polynomial functions can be at most of degree 12.
(15) Where appropriate constant folding optimisations may be (16) Where appropriate constant folding optimisations may be
applied. (eg: The expression '2+(3-(x/y))' becomes '5-(x/y)') applied. (eg: The expression '2+(3-(x/y))' becomes '5-(x/y)')
(16) If the strength reduction compilation option has been enabled, (17) If the strength reduction compilation option has been enabled,
then where applicable strength reduction optimisations may be then where applicable strength reduction optimisations may be
applied. applied.
(17) String processing capabilities are available by default. (18) String processing capabilities are available by default.
To turn them off, the following needs to be defined at To turn them off, the following needs to be defined at
compile time: exprtk_disable_string_capabilities compile time: exprtk_disable_string_capabilities
(18) Composited functions can call themselves or any other functions (19) Composited functions can call themselves or any other functions
that have been defined prior to their own definition. that have been defined prior to their own definition.
(19) Recursive calls made from within composited functions will have (20) Recursive calls made from within composited functions will have
a stack size bound by the stack of the executing architecture. a stack size bound by the stack of the executing architecture.
(20) User defined functions by default are assumed to have side (21) User defined functions by default are assumed to have side
effects. As such an "all constant parameter" invocation of such effects. As such an "all constant parameter" invocation of such
functions wont result in constant folding. If the function has functions wont result in constant folding. If the function has
no side effects then that can be noted during the constructor no side effects then that can be noted during the constructor
of the ifunction allowing it to be constant folded where of the ifunction allowing it to be constant folded where
appropriate. appropriate.
(21) The entity relationship between symbol_table and an expression (22) The entity relationship between symbol_table and an expression
is one-to-many. Hence the intended use case is to have a single is one-to-many. Hence the intended use case is to have a single
symbol table manage the variable and function requirements of symbol table manage the variable and function requirements of
multiple expressions. multiple expressions.
(22) The common use-case for an expression is to have it compiled (23) The common use-case for an expression is to have it compiled
only ONCE and then subsequently have it evaluated multiple only ONCE and then subsequently have it evaluated multiple
times. An extremely inefficient and suboptimal approach would times. An extremely inefficient and suboptimal approach would
be to recompile an expression from its string form every time be to recompile an expression from its string form every time
it requires evaluating. it requires evaluating.
(23) The following are examples of compliant floating point value (24) The following are examples of compliant floating point value
representations: representations:
(a) 12345 (b) -123.456 (a) 12345 (e) -123.456
(c) +123.456e+12 (d) 123.456E-12 (b) +123.456e+12 (f) 123.456E-12
(e) +012.045e+07 (f) .1234 (c) +012.045e+07 (g) .1234
(g) 123.456f (h) -321.654E+3L (d) 123.456f (h) -321.654E+3L
(24) Expressions may contain any of the following comment styles: (25) Expressions may contain any of the following comment styles:
1. // .... \n 1. // .... \n
2. # .... \n 2. # .... \n
3. /* .... */ 3. /* .... */
[13 - SIMPLE EXPRTK EXAMPLE] [15 - SIMPLE EXPRTK EXAMPLE]
--- snip --- --- snip ---
#include <cstdio> #include <cstdio>
#include <string> #include <string>
@ -974,8 +1184,8 @@ int main()
if (!parser.compile(expression_str,expression)) if (!parser.compile(expression_str,expression))
{ {
// A compilation error has occured. Attempt to // A compilation error has occurred. Attempt to
// print all errors to the stdout. // print all errors to stdout.
printf("Error: %s\tExpression: %s\n", printf("Error: %s\tExpression: %s\n",
parser.error().c_str(), parser.error().c_str(),
@ -1014,7 +1224,7 @@ int main()
[14 - FILES] [16 - FILES]
(00) Makefile (00) Makefile
(01) readme.txt (01) readme.txt
(02) exprtk.hpp (02) exprtk.hpp
@ -1032,3 +1242,149 @@ int main()
(14) exprtk_simple_example_10.cpp (14) exprtk_simple_example_10.cpp
(15) exprtk_simple_example_11.cpp (15) exprtk_simple_example_11.cpp
(16) exprtk_simple_example_12.cpp (16) exprtk_simple_example_12.cpp
[17 - LANGUAGE STRUCTURE]
+-------------------------------------------------------------+
|00 - If Statement |
| |
| [if] ---> [(] ---> [condition] -+-> [,] -+ |
| | | |
| +---------------<---------------+ | |
| | | |
| | +------------------<------------------+ |
| | | |
| | +--> [consequent] ---> [,] ---> [alternative] ---> [)] |
| | |
| +--> [)] --+-> [{] ---> [expression*] ---> [}] --+ |
| | | |
| | +---------<----------+ |
| +----<-----+ | |
| | v |
| +--> [consequent] --> [;] -{*}-> [else-statement] |
| |
+-------------------------------------------------------------+
|01 - Else Statement |
| |
| [else] -+-> [alternative] ---> [;] |
| | |
| +--> [{] ---> [expression*] ---> [}] |
| | |
| +--> [if-statement] |
| |
+-------------------------------------------------------------+
|02 - Ternary Statement |
| |
| [condition] ---> [?] ---> [consequent] ---> [:] --+ |
| | |
| +------------------------<------------------------+ |
| | |
| +--> [alternative] --> [;] |
| |
+-------------------------------------------------------------+
|03 - While Loop |
| |
| [while] ---> [(] ---> [condition] ---> [)] ---+ |
| | |
| +----------------------<----------------------+ |
| | |
| +--> [{] ---> [expression*] ---> [}] |
| |
+-------------------------------------------------------------+
|04 - Repeat Until Loop |
| |
| [repeat] ---> [expression*] ---+ |
| | |
| +--------------<---------------+ |
| | |
| +--> [until] ---> [(] ---> [condition] --->[)] |
| |
+-------------------------------------------------------------+
|05 - For Loop |
| |
| [for] ---> [(] -+-> [initialise expression] --+--+ |
| | | | |
| +------------->---------------+ v |
| | |
| +-----------------------<------------------------+ |
| | |
| +--> [,] -+-> [condition] -+-> [,] ---+ |
| | | | |
| +------->--------+ v |
| | |
| +------------------<---------+--------+ |
| | | |
| +--> [increment expression] -+-> [)] --+ |
| | |
| +------------------<-------------------+ |
| | |
| +--> [{] ---> [expression*] ---> [}] |
| |
+-------------------------------------------------------------+
|06 - Switch Statement |
| |
| [switch] ---> [{] ---+ |
| | |
| +---------<----------+-----------<-----------+ |
| | | |
| +--> [case] ---> [condition] ---> [:] ---+ | |
| | | |
| +-------------------<--------------------+ | |
| | | |
| +--> [consequent] ---> [;] --------->--------+ |
| | | |
| | | |
| +--> [default] ---> [consequent] ---> [;] ---+ |
| | | |
| +---------------------<----------------------+ |
| | |
| +--> [}] |
| |
+-------------------------------------------------------------+
|07 - Multi Subexpression Statement |
| |
| +--------------<---------------+ |
| | | |
| [~] ---> [{\(] -+-> [expression] -+-> [;\,] ---+ |
| | |
| +----------------<----------------+ |
| | |
| +--> [}\)] |
| |
+-------------------------------------------------------------+
|08 - Multi Case-Consequent Statement |
| |
| [[*]] ---> [{] ---+ |
| | |
| +--------<--------+--------------<----------+ |
| | | |
| +--> [case] ---> [condition] ---> [:] ---+ | |
| | | |
| +-------------------<--------------------+ | |
| | | |
| +--> [consequent] ---> [;] ---+------>------+ |
| | |
| +--> [}] |
| |
+-------------------------------------------------------------+
|09 - Variable Definition Statement |
| |
| [var] ---> [symbol] -+-> [:=] ---> [expression] -+-> [;] |
| | | |
| +------------->-------------+ |
| |
+-------------------------------------------------------------+
|10 - Vector Definition Statement |
| |
| [var] ---> [symbol] ---> [[] ---> [constant] ---> []] --+ |
| | |
| +---------------------------<---------------------------+ |
| | |
| | +--------->---------+ |
| | | | |
| +--> [:=] ---> [{] -+-+-> [expression] -+-> [}] -+-> [;] |
| | | |
| +--<--- [,] <-----+ |
| |
+-------------------------------------------------------------+