资源说明:C++ Mathematical Expression Parsing And Evaluation Library
C++ Mathematical Expression Toolkit Library Documentation Section 00 - Introduction Section 01 - Capabilities Section 02 - Example Expressions Section 03 - Copyright Notice Section 04 - Downloads & Updates Section 05 - Installation Section 06 - Compilation Section 07 - Compiler Compatibility Section 08 - Built-In Operations & Functions Section 09 - Fundamental Types Section 10 - Components Section 11 - Compilation Options Section 12 - Expression Structures Section 13 - Variable, Vector & String Definition Section 14 - Vector Processing Section 15 - User Defined Functions Section 16 - Expression Dependents Section 17 - Hierarchies Of Symbol Tables Section 18 - Unknown Unknowns Section 19 - Enabling & Disabling Features Section 20 - Expression Return Values Section 21 - Compilation Errors Section 22 - Runtime Library Packages Section 23 - Helpers & Utils Section 24 - Benchmarking Section 25 - Exprtk Notes Section 26 - Simple Exprtk Example Section 27 - Build Options Section 28 - Files Section 29 - Language Structure [SECTION 00 - INTRODUCTION] The C++ Mathematical Expression Toolkit Library (ExprTk) is a simple to use, easy to integrate and extremely efficient run-time mathematical expression parsing and evaluation engine. The parsing engine supports numerous forms of functional and logic processing semantics and is easily extensible. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ [SECTION 01 - CAPABILITIES] The ExprTk expression evaluator supports the following fundamental arithmetic operations, functions and processes: (00) Types: Scalar, Vector, String (01) Basic operators: +, -, *, /, %, ^ (02) Assignment: :=, +=, -=, *=, /=, %= (03) Equalities & Inequalities: =, ==, <>, !=, <, <=, >, >= (04) Logic operators: and, mand, mor, nand, nor, not, or, shl, shr, xnor, xor, true, false (05) Functions: abs, avg, ceil, clamp, equal, erf, erfc, exp, expm1, floor, frac, log, log10, log1p, log2, logn, max, min, mul, ncdf, not_equal, root, round, roundn, sgn, sqrt, sum, swap, trunc (06) Trigonometry: acos, acosh, asin, asinh, atan, atanh, atan2, cos, cosh, cot, csc, sec, sin, sinc, sinh, tan, tanh, hypot, rad2deg, deg2grad, deg2rad, grad2deg (07) Control structures: if-then-else, ternary conditional, switch-case, return-statement (08) Loop statements: while, for, repeat-until, break, continue (09) String processing: in, like, ilike, concatenation (10) Optimisations: constant-folding, simple strength reduction and dead code elimination (11) Calculus: numerical integration and differentiation ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ [SECTION 02 - EXAMPLE EXPRESSIONS] The following is a short listing of infix format based mathematical expressions that can be parsed and evaluated using the ExprTk library. (01) sqrt(1 - (3 / x^2)) (02) clamp(-1, sin(2 * pi * x) + cos(y / 2 * pi), +1) (03) sin(2.34e-3 * x) (04) if(((x[2] + 2) == 3) and ((y + 5) <= 9),1 + w, 2 / z) (05) inrange(-2,m,+2) == if(({-2 <= m} and [m <= +2]),1,0) (06) ({1/1}*[1/2]+(1/3))-{1/4}^[1/5]+(1/6)-({1/7}+[1/8]*(1/9)) (07) a * exp(2.2 / 3.3 * t) + c (08) z := x + sin(2.567 * pi / y) (09) u := 2.123 * {pi * z} / (w := x + cos(y / pi)) (10) 2x + 3y + 4z + 5w == 2 * x + 3 * y + 4 * z + 5 * w (11) 3(x + y) / 2.9 + 1.234e+12 == 3 * (x + y) / 2.9 + 1.234e+12 (12) (x + y)3.3 + 1 / 4.5 == [x + y] * 3.3 + 1 / 4.5 (13) (x + y[i])z + 1.1 / 2.7 == (x + y[i]) * z + 1.1 / 2.7 (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) while (x <= 100) { x -= 1; } (18) x <= 'abc123' and (y in 'AString') or ('1x2y3z' != z) (19) ((x + 'abc') like '*123*') or ('a123b' ilike y) (20) sgn(+1.2^3.4z / -5.6y) <= {-7.8^9 / -10.11x } ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ [SECTION 03 - COPYRIGHT NOTICE] Free use of the C++ Mathematical Expression Toolkit Library is permitted under the guidelines and in accordance with the most current version of the MIT License. http://www.opensource.org/licenses/MIT ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ [SECTION 04 - DOWNLOADS & UPDATES] The most recent version of the C++ Mathematical Expression Toolkit Library including all updates and tests can be found at the following locations: (a) Download: https://www.partow.net/programming/exprtk/index.html (b) Repository: https://github.com/ArashPartow/exprtk https://github.com/ArashPartow/exprtk-extras ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ [SECTION 05 - INSTALLATION] The header file exprtk.hpp should be placed in a project or system include path (e.g: /usr/include/). ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ [SECTION 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 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ [SECTION 07 - COMPILER COMPATIBILITY] ExprTk has been built error and warning free using the following set of C++ compilers: (*) GNU Compiler Collection (3.5+) (*) Intel C++ Compiler (8.x+) (*) Clang/LLVM (1.1+) (*) PGI C++ (10.x+) (*) Microsoft Visual Studio C++ Compiler (8.1+) (*) IBM XL C/C++ (9.x+) (*) C++ Builder (XE4+) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ [SECTION 08 - BUILT-IN OPERATIONS & FUNCTIONS] (0) Arithmetic & Assignment Operators +----------+---------------------------------------------------------+ | OPERATOR | DEFINITION | +----------+---------------------------------------------------------+ | + | Addition between x and y. (eg: x + y) | +----------+---------------------------------------------------------+ | - | Subtraction between x and y. (eg: x - y) | +----------+---------------------------------------------------------+ | * | Multiplication between x and y. (eg: x * y) | +----------+---------------------------------------------------------+ | / | Division between x and y. (eg: x / y) | +----------+---------------------------------------------------------+ | % | Modulus of x with respect to y. (eg: x % y) | +----------+---------------------------------------------------------+ | ^ | x to the power of y. (eg: x ^ y) | +----------+---------------------------------------------------------+ | := | Assign the value of x to y. Where y is either a variable| | | or vector type. (eg: y := x) | +----------+---------------------------------------------------------+ | += | Increment x by the value of the expression on the right | | | hand side. Where x is either a variable or vector type. | | | (eg: x += abs(y - z)) | +----------+---------------------------------------------------------+ | -= | Decrement x by the value of the expression on the right | | | hand side. Where x is either a variable or vector type. | | | (eg: x[i] -= abs(y + z)) | +----------+---------------------------------------------------------+ | *= | Assign the multiplication of x by the value of the | | | expression on the righthand side to x. Where x is either| | | a variable or vector type. | | | (eg: x *= abs(y / z)) | +----------+---------------------------------------------------------+ | /= | 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)) | +----------+---------------------------------------------------------+ | %= | 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 +----------+---------------------------------------------------------+ | OPERATOR | DEFINITION | +----------+---------------------------------------------------------+ | == or = | True only if x is strictly equal to y. (eg: x == y) | +----------+---------------------------------------------------------+ | <> or != | True only if x does not equal y. (eg: x <> y or x != y) | +----------+---------------------------------------------------------+ | < | True only if x is less than y. (eg: x < y) | +----------+---------------------------------------------------------+ | <= | True only if x is less than or equal to y. (eg: x <= y) | +----------+---------------------------------------------------------+ | > | True only if x is greater than y. (eg: x > y) | +----------+---------------------------------------------------------+ | >= | True only if x greater than or equal to y. (eg: x >= y) | +----------+---------------------------------------------------------+ (2) Boolean Operations +----------+---------------------------------------------------------+ | OPERATOR | DEFINITION | +----------+---------------------------------------------------------+ | true | True state or any value other than zero (typically 1). | +----------+---------------------------------------------------------+ | false | False state, value of exactly zero. | +----------+---------------------------------------------------------+ | and | Logical AND, True only if x and y are both true. | | | (eg: x and y) | +----------+---------------------------------------------------------+ | mand | Multi-input logical AND, True only if all inputs are | | | true. Left to right short-circuiting of expressions. | | | (eg: mand(x > y, z < w, u or v, w and x)) | +----------+---------------------------------------------------------+ | mor | Multi-input logical OR, True if at least one of the | | | inputs are true. Left to right short-circuiting of | | | expressions. (eg: mor(x > y, z < w, u or v, w and x)) | +----------+---------------------------------------------------------+ | nand | Logical NAND, True only if either x or y is false. | | | (eg: x nand y) | +----------+---------------------------------------------------------+ | nor | Logical NOR, True only if the result of x or y is false | | | (eg: x nor y) | +----------+---------------------------------------------------------+ | not | Logical NOT, Negate the logical sense of the input. | | | (eg: not(x and y) == x nand y) | +----------+---------------------------------------------------------+ | or | Logical OR, True if either x or y is true. (eg: x or y) | +----------+---------------------------------------------------------+ | xor | Logical XOR, True only if the logical states of x and y | | | differ. (eg: x xor y) | +----------+---------------------------------------------------------+ | xnor | Logical XNOR, True iff the biconditional of x and y is | | | satisfied. (eg: x xnor y) | +----------+---------------------------------------------------------+ | & | Similar to AND but with left to right expression short | | | circuiting optimisation. (eg: (x & y) == (y and x)) | +----------+---------------------------------------------------------+ | | | Similar to OR but with left to right expression short | | | circuiting optimisation. (eg: (x | y) == (y or x)) | +----------+---------------------------------------------------------+ (3) General Purpose Functions +----------+---------------------------------------------------------+ | FUNCTION | DEFINITION | +----------+---------------------------------------------------------+ | abs | Absolute value of x. (eg: abs(x)) | +----------+---------------------------------------------------------+ | avg | Average of all the inputs. | | | (eg: avg(x,y,z,w,u,v) == (x + y + z + w + u + v) / 6) | +----------+---------------------------------------------------------+ | ceil | Smallest integer that is greater than or equal to x. | +----------+---------------------------------------------------------+ | clamp | Clamp x in range between r0 and r1, where r0 < r1. | | | (eg: clamp(r0,x,r1)) | +----------+---------------------------------------------------------+ | equal | Equality test between x and y using normalised epsilon | +----------+---------------------------------------------------------+ | erf | Error function of x. (eg: erf(x)) | +----------+---------------------------------------------------------+ | erfc | Complimentary error function of x. (eg: erfc(x)) | +----------+---------------------------------------------------------+ | exp | e to the power of x. (eg: exp(x)) | +----------+---------------------------------------------------------+ | expm1 | e to the power of x minus 1, where x is very small. | | | (eg: expm1(x)) | +----------+---------------------------------------------------------+ | floor | Largest integer that is less than or equal to x. | | | (eg: floor(x)) | +----------+---------------------------------------------------------+ | frac | Fractional portion of x. (eg: frac(x)) | +----------+---------------------------------------------------------+ | hypot | Hypotenuse of x and y (eg: hypot(x,y) = sqrt(x*x + y*y))| +----------+---------------------------------------------------------+ | iclamp | Inverse-clamp x outside of the range r0 and r1. Where | | | r0 < r1. If x is within the range it will snap to the | | | closest bound. (eg: iclamp(r0,x,r1) | +----------+---------------------------------------------------------+ | inrange | In-range returns 'true' when x is within the range r0 | | | and r1. Where r0 < r1. (eg: inrange(r0,x,r1) | +----------+---------------------------------------------------------+ | log | Natural logarithm of x. (eg: log(x)) | +----------+---------------------------------------------------------+ | log10 | Base 10 logarithm of x. (eg: log10(x)) | +----------+---------------------------------------------------------+ | log1p | Natural logarithm of 1 + x, where x is very small. | | | (eg: log1p(x)) | +----------+---------------------------------------------------------+ | log2 | Base 2 logarithm of x. (eg: log2(x)) | +----------+---------------------------------------------------------+ | logn | Base N logarithm of x. where n is a positive integer. | | | (eg: logn(x,8)) | +----------+---------------------------------------------------------+ | max | Largest value of all the inputs. (eg: max(x,y,z,w,u,v)) | +----------+---------------------------------------------------------+ | min | Smallest value of all the inputs. (eg: min(x,y,z,w,u)) | +----------+---------------------------------------------------------+ | mul | Product of all the inputs. | | | (eg: mul(x,y,z,w,u,v,t) == (x * y * z * w * u * v * t)) | +----------+---------------------------------------------------------+ | ncdf | Normal cumulative distribution function. (eg: ncdf(x)) | +----------+---------------------------------------------------------+ | not_equal| Not-equal test between x and y using normalised epsilon | +----------+---------------------------------------------------------+ | pow | x to the power of y. (eg: pow(x,y) == x ^ y) | +----------+---------------------------------------------------------+ | root | Nth-Root of x. where n is a positive integer. | | | (eg: root(x,3) == x^(1/3)) | +----------+---------------------------------------------------------+ | round | Round x to the nearest integer. (eg: round(x)) | +----------+---------------------------------------------------------+ | roundn | Round x to n decimal places (eg: roundn(x,3)) | | | where n > 0 and is an integer. | | | (eg: roundn(1.2345678,4) == 1.2346) | +----------+---------------------------------------------------------+ | sgn | Sign of x, -1 where x < 0, +1 where x > 0, else zero. | | | (eg: sgn(x)) | +----------+---------------------------------------------------------+ | sqrt | Square root of x, where x >= 0. (eg: sqrt(x)) | +----------+---------------------------------------------------------+ | sum | Sum of all the inputs. | | | (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)) | +----------+---------------------------------------------------------+ (4) Trigonometry Functions +----------+---------------------------------------------------------+ | FUNCTION | DEFINITION | +----------+---------------------------------------------------------+ | acos | Arc cosine of x expressed in radians. Interval [-1,+1] | | | (eg: acos(x)) | +----------+---------------------------------------------------------+ | acosh | Inverse hyperbolic cosine of x expressed in radians. | | | (eg: acosh(x)) | +----------+---------------------------------------------------------+ | asin | Arc sine of x expressed in radians. Interval [-1,+1] | | | (eg: asin(x)) | +----------+---------------------------------------------------------+ | asinh | Inverse hyperbolic sine of x expressed in radians. | | | (eg: asinh(x)) | +----------+---------------------------------------------------------+ | atan | Arc tangent of x expressed in radians. Interval [-1,+1] | | | (eg: atan(x)) | +----------+---------------------------------------------------------+ | atan2 | Arc tangent of (x / y) expressed in radians. [-pi,+pi] | | | eg: atan2(x,y) | +----------+---------------------------------------------------------+ | atanh | Inverse hyperbolic tangent of x expressed in radians. | | | (eg: atanh(x)) | +----------+---------------------------------------------------------+ | cos | Cosine of x. (eg: cos(x)) | +----------+---------------------------------------------------------+ | cosh | Hyperbolic cosine of x. (eg: cosh(x)) | +----------+---------------------------------------------------------+ | cot | Cotangent of x. (eg: cot(x)) | +----------+---------------------------------------------------------+ | csc | Cosecant of x. (eg: csc(x)) | +----------+---------------------------------------------------------+ | sec | Secant of x. (eg: sec(x)) | +----------+---------------------------------------------------------+ | sin | Sine of x. (eg: sin(x)) | +----------+---------------------------------------------------------+ | sinc | Sine cardinal of x. (eg: sinc(x)) | +----------+---------------------------------------------------------+ | sinh | Hyperbolic sine of x. (eg: sinh(x)) | +----------+---------------------------------------------------------+ | tan | Tangent of x. (eg: tan(x)) | +----------+---------------------------------------------------------+ | tanh | Hyperbolic tangent of x. (eg: tanh(x)) | +----------+---------------------------------------------------------+ | deg2rad | Convert x from degrees to radians. (eg: deg2rad(x)) | +----------+---------------------------------------------------------+ | deg2grad | Convert x from degrees to gradians. (eg: deg2grad(x)) | +----------+---------------------------------------------------------+ | rad2deg | Convert x from radians to degrees. (eg: rad2deg(x)) | +----------+---------------------------------------------------------+ | grad2deg | Convert x from gradians to degrees. (eg: grad2deg(x)) | +----------+---------------------------------------------------------+ (5) String Processing +----------+---------------------------------------------------------+ | FUNCTION | DEFINITION | +----------+---------------------------------------------------------+ | = , == | All common equality/inequality operators are applicable | | !=, <> | to strings and are applied in a case sensitive manner. | | <=, >= | In the following example x, y and z are of type string. | | < , > | (eg: not((x <= 'AbC') and ('1x2y3z' <> y)) or (z == x) | +----------+---------------------------------------------------------+ | in | True only if x is a substring of y. | | | (eg: x in y or 'abc' in 'abcdefgh') | +----------+---------------------------------------------------------+ | like | True only if the string x matches the pattern y. | | | Available wildcard characters are '*' and '?' denoting | | | zero or more and zero or one matches respectively. | | | (eg: x like y or 'abcdefgh' like 'a?d*h') | +----------+---------------------------------------------------------+ | ilike | True only if the string x matches the pattern y in a | | | case insensitive manner. Available wildcard characters | | | are '*' and '?' denoting zero or more and zero or one | | | matches respectively. | | | (eg: x ilike y or 'a1B2c3D4e5F6g7H' ilike 'a?d*h') | +----------+---------------------------------------------------------+ | [r0:r1] | The closed interval [r0,r1] of the specified string. | | | eg: Given a string x with a value of 'abcdefgh' then: | | | 1. x[1:4] == 'bcde' | | | 2. x[ :5] == x[:10 / 2] == 'abcdef' | | | 3. x[2 + 1: ] == x[3:] =='defgh' | | | 4. x[ : ] == x[:] == 'abcdefgh' | | | 5. x[4/2:3+2] == x[2:5] == 'cdef' | | | | | | Note: Both r0 and r1 are assumed to be integers, where | | | r0 <= r1. They may also be the result of an expression, | | | in the event they have fractional components truncation | | | will be performed. (eg: 1.67 --> 1) | +----------+---------------------------------------------------------+ | := | Assign the value of x to y. Where y is a mutable string | | | or string range and x is either a string or a string | | | range. eg: | | | 1. y := x | | | 2. y := 'abc' | | | 3. y := x[:i + j] | | | 4. y := '0123456789'[2:7] | | | 5. y := '0123456789'[2i + 1:7] | | | 6. y := (x := '0123456789'[2:7]) | | | 7. y[i:j] := x | | | 8. y[i:j] := (x + 'abcdefg'[8 / 4:5])[m:n] | | | | | | Note: For options 7 and 8 the shorter of the two ranges | | | will denote the number characters that are to be copied.| +----------+---------------------------------------------------------+ | + | Concatenation of x and y. Where x and y are strings or | | | string ranges. eg | | | 1. x + y | | | 2. x + 'abc' | | | 3. x + y[:i + j] | | | 4. x[i:j] + y[2:3] + '0123456789'[2:7] | | | 5. 'abc' + x + y | | | 6. 'abc' + '1234567' | | | 7. (x + 'a1B2c3D4' + y)[i:2j] | +----------+---------------------------------------------------------+ | += | Append to x the value of y. Where x is a mutable string | | | and y is either a string or a string range. eg: | | | 1. x += y | | | 2. x += 'abc' | | | 3. x += y[:i + j] + 'abc' | | | 4. x += '0123456789'[2:7] | +----------+---------------------------------------------------------+ | <=> | Swap the values of x and y. Where x and y are mutable | | | strings. (eg: x <=> y) | +----------+---------------------------------------------------------+ | [] | The string size operator returns the size of the string | | | being actioned. | | | eg: | | | 1. 'abc'[] == 3 | | | 2. var max_str_length := max(s0[],s1[],s2[],s3[]) | | | 3. ('abc' + 'xyz')[] == 6 | | | 4. (('abc' + 'xyz')[1:4])[] == 4 | +----------+---------------------------------------------------------+ (6) Control Structures +----------+---------------------------------------------------------+ |STRUCTURE | DEFINITION | +----------+---------------------------------------------------------+ | if | If x is true then return y else return z. | | | eg: | | | 1. if (x, y, z) | | | 2. if ((x + 1) > 2y, z + 1, w / v) | | | 3. if (x > y) z; | | | 4. if (x <= 2*y) { z + w }; | +----------+---------------------------------------------------------+ | if-else | The if-else/else-if statement. Subject to the condition | | | branch the statement will return either the value of the| | | consequent or the alternative branch. | | | 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; | | | 4. if ((x != y) and (z > w)) | | | { | | | y := sin(x) / u; | | | z := w + 1; | | | } | | | else if (x > (z + 1)) | | | { | | | w := abs (x - y) + z; | | | u := (x + 1) > 2y ? 2u : 3u; | | | } | +----------+---------------------------------------------------------+ | switch | The first true case condition that is encountered will | | | determine the result of the switch. If none of the case | | | conditions hold true, the default action is assumed as | | | the final return value. This is sometimes also known as | | | a multi-way branch mechanism. | | | eg: | | | switch | | | { | | | case x > (y + z) : 2 * x / abs(y - z); | | | case x < 3 : sin(x + y); | | | default : 1 + x; | | | } | +----------+---------------------------------------------------------+ | while | The structure will repeatedly evaluate the internal | | | statement(s) 'while' the condition is true. The final | | | statement in the final iteration will be used as the | | | return value of the loop. | | | eg: | | | while ((x -= 1) > 0) | | | { | | | y := x + z; | | | w := u + y; | | | } | +----------+---------------------------------------------------------+ | repeat/ | The structure will repeatedly evaluate the internal | | until | statement(s) 'until' the condition is true. The final | | | statement in the final iteration will be used as the | | | return value of the loop. | | | eg: | | | repeat | | | y := x + z; | | | w := u + y; | | | until ((x += 1) > 100) | +----------+---------------------------------------------------------+ | 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 initialiser | | | and incrementing expressions are optional. | | | eg: | | | for (var x := 0; (x < n) and (x != y); x += 1) | | | { | | | y := y + x / 2 - z; | | | w := u + y; | | | } | +----------+---------------------------------------------------------+ | break | Break terminates the execution of the nearest enclosed | | break[] | loop, allowing for the execution to continue on external| | | to the loop. The default break statement will set the | | | return value of the loop to NaN, where as the return | | | based form will set the value to that of the break | | | expression. | | | eg: | | | while ((i += 1) < 10) | | | { | | | if (i < 5) | | | j -= i + 2; | | | else if (i % 2 == 0) | | | break; | | | else | | | break[2i + 3]; | | | } | +----------+---------------------------------------------------------+ | continue | Continue results in the remaining portion of the nearest| | | enclosing loop body to be skipped. | | | eg: | | | for (var i := 0; i < 10; i += 1) | | | { | | | if (i < 5) | | | continue; | | | j -= i + 2; | | | } | +----------+---------------------------------------------------------+ | return | Return immediately from within the current expression. | | | With the option of passing back a variable number of | | | values (scalar, vector or string). eg: | | | 1. return [1]; | | | 2. return [x, 'abx']; | | | 3. return [x, x + y,'abx']; | | | 4. return []; | | | 5. if (x < y) | | | return [x, x - y, 'result-set1', 123.456]; | | | else | | | return [y, x + y, 'result-set2']; | +----------+---------------------------------------------------------+ | ?: | Ternary conditional statement, similar to that of the | | | above denoted if-statement. | | | eg: | | | 1. x ? y : z | | | 2. x + 1 > 2y ? z + 1 : (w / v) | | | 3. min(x,y) > z ? (x < y + 1) ? x : y : (w * v) | +----------+---------------------------------------------------------+ | ~ | Evaluate each sub-expression, then return as the result | | | the value of the last sub-expression. This is sometimes | | | known as multiple sequence point evaluation. | | | eg: | | | ~(i := x + 1, j := y / z, k := sin(w/u)) == (sin(w/u))) | | | ~{i := x + 1; j := y / z; k := sin(w/u)} == (sin(w/u))) | +----------+---------------------------------------------------------+ | [*] | Evaluate any consequent for which its case statement is | | | true. The return value will be either zero or the result| | | of the last consequent to have been evaluated. | | | eg: | | | [*] | | | { | | | case (x + 1) > (y - 2) : x := z / 2 + sin(y / pi); | | | case (x + 2) < abs(y + 3) : w / 4 + min(5y,9); | | | 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 tables above, the symbols x, y, z, w, u and v where appropriate may represent any of one the following: 1. Literal numeric/string value 2. A variable 3. A vector element 4. A vector 5. A string 6. An expression comprised of [1], [2] or [3] (eg: 2 + x / vec[3]) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ [SECTION 09 - FUNDAMENTAL TYPES] ExprTk supports three fundamental types which can be used freely in expressions. The types are as follows: (1) Scalar (2) Vector (3) String (1) Scalar Type The scalar type is a singular numeric value. The underlying type is that used to specialise the ExprTk components (float, double, long double, MPFR et al). (2) Vector Type The vector type is a fixed size sequence of contiguous scalar values. A vector can be indexed resulting in a scalar value. Operations between a vector and scalar will result in a vector with a size equal to that of the original vector, whereas operations between vectors will result in a vector of size equal to that of the smaller of the two. In both mentioned cases, the operations will occur element-wise. (3) String Type The string type is a variable length sequence of 8-bit chars. Strings can be assigned and concatenated to one another, they can also be manipulated via sub-ranges using the range definition syntax. Strings however can not interact with scalar or vector types. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ [SECTION 10 - COMPONENTS] There are three primary components, that are specialised upon a given numeric type, which make up the core of ExprTk. The components are as follows: (1) Symbol Table exprtk::symbol_table(2) Expression exprtk::expression (3) Parser exprtk::parser (1) Symbol Table A structure that is used to store references to variables, constants and functions that are to be used within expressions. Furthermore in the context of composited recursive functions the symbol table can also be thought of as a simple representation of a stack specific for the expression(s) that reference it. The following is a list of the types a symbol table can handle: (a) Numeric variables (b) Numeric constants (c) Numeric vector elements (d) String variables (e) String constants (f) Functions (g) Vararg functions During the compilation process if an expression is found to require any of the elements noted above, the expression's associated symbol_table will be queried for the element and if present a reference to the element will be embedded within the expression's AST. This allows for the original element to be modified independently of the expression instance and to also allow the expression to be evaluated using the current value of the element. Note: Any variable reference provided to a given symbol_table instance, must have a life time at least as long as the life-time of the symbol_table instance. In the event the variable reference is invalidated before the symbol_table or any dependent expression instances have been destructed, then any associated expression evaluations or variable referencing via the symbol_table instance will result in undefined behaviour. The following bit of code instantiates a symbol_table and expression instance, then proceeds to demonstrate various ways in which references to variables can be added to the symbol_table, and how those references are subsequently invalidated resulting in various forms of undefined behaviour. typedef exprtk::symbol_table symbol_table_t; symbol_table_t symbol_table; expression_t expression; { double x = 123.4567; symbol_table.add_variable("x", x); } // Reference to variable x has been invalidated std::deque y {1.1, 2.2, 3.3}; symbol_table.add_variable("y", y.back()); y.pop_back(); // Reference to variable y has been invalidated std::vector z {4.4, 5.5, 6.6}; symbol_table.add_variable("z", z.front()); z.erase(z.begin()); // Reference to variable z has been invalidated double* w = new double(123.456); symbol_table.add_variable("w", *w); delete w; // Reference to variable w has been invalidated const std::string expression_str = "x + y / z * w"; // Compilation of expression will succeed parser.compile(expression_str,expression); expression.value(); // Evaluation will result in undefined behaviour symbol_table.get_variable("x")->ref() = 135.791; // Assignment will result in undefined behaviour The example below demonstrates the relationship between variables, symbol_table and expression. Note the variables are modified as they normally would in a program, and when the expression is evaluated the current values assigned to the variables will be used. typedef exprtk::symbol_table symbol_table_t; typedef exprtk::expression expression_t; typedef exprtk::parser parser_t; symbol_table_t symbol_table; expression_t expression; parser_t parser; double x = 0; double y = 0; std::string expression_string = "x * y + 3"; symbol_table.add_variable("x",x); symbol_table.add_variable("y",y); expression.register_symbol_table(symbol_table); parser.compile(expression_string,expression); x = 1.0; y = 2.0; expression.value(); // 1 * 2 + 3 x = 3.7; expression.value(); // 3.7 * 2 + 3 y = -9.0; expression.value(); // 3.7 * -9 + 3 // 'x * -9 + 3' for x in range of [0,100) in steps of 0.0001 for (x = 0.0; x < 100.0; x += 0.0001) { expression.value(); // x * -9 + 3 } Note: It is possible to register multiple symbol_tables with a single expression object. In the event an expression has multiple symbol tables, and where there exists conflicts between symbols, the compilation stage will resolve the conflicts based on the order of registration of the symbol_tables to the expression. For a more expansive discussion please review section [17 - Hierarchies Of Symbol Tables] typedef exprtk::symbol_table symbol_table_t; typedef exprtk::expression expression_t; typedef exprtk::parser parser_t; symbol_table_t symbol_table0; symbol_table_t symbol_table1; expression_t expression; parser_t parser; double x0 = 123.0; double x1 = 678.0; std::string expression_string = "x + 1"; symbol_table0.add_variable("x",x0); symbol_table1.add_variable("x",x1); expression.register_symbol_table(symbol_table0); expression.register_symbol_table(symbol_table1); parser.compile(expression_string,expression); expression.value(); // 123 + 1 The symbol table supports adding references to external instances of types that can be accessed within expressions via the following methods: 1. bool add_variable (const std::string& name, scalar_t&) 2. bool add_constant (const std::string& name, const scalar_t&) 3. bool add_stringvar(const std::string& name, std::string&) 4. bool add_vector (const std::string& name, vector_type&) Note: The 'vector' type must be comprised from a contiguous array of scalars with a size that is larger than zero. The vector type itself can be any one of the following: 1. std::vector 2. scalar_t(&v)[N] 3. scalar_t* and array size 4. exprtk::vector_view When registering a variable, vector, string or function with an instance of a symbol_table, the call to 'add_...' may fail and return a false result due to one or more of the following reasons: 1. Variable name contains invalid characters or is ill-formed 2. Variable name conflicts with a reserved word (eg: 'while') 3. Variable name conflicts with a previously registered variable 4. A vector of size (length) zero is being registered 5. A free function exceeding fifteen parameters is being registered 6. The symbol_table instance is in an invalid state (2) Expression A structure that holds an Abstract Syntax Tree or AST for a specified expression and is used to evaluate said expression. Evaluation of the expression is accomplished by performing a post-order traversal of the AST. If a compiled Expression uses variables or user defined functions, it will have an associated Symbol Table, which will contain references to said variables, functions or strings. An example AST structure for the denoted expression is as follows: Expression: z := (x + y^-2.345) * sin(pi / min(w - 7.3,v)) [Root] | [Assignment] ________/ \_____ / \ Variable(z) [Multiplication] ____________/ \___________ / \ / [Unary-Function(sin)] [Addition] | ____/ \____ [Division] / \ ___/ \___ Variable(x) [Exponentiation] / \ ______/ \______ Constant(pi) [Binary-Function(min)] / \ ____/ \____ Variable(y) [Negation] / \ | / Variable(v) Constant(2.345) / / [Subtraction] ____/ \____ / \ Variable(w) Constant(7.3) The above denoted AST will be evaluated in the following order: (01) Load Variable (z) (10) Load Constant (7.3) (02) Load Variable (x) (11) Subtraction (09 & 10) (03) Load Variable (y) (12) Load Variable (v) (04) Load Constant (2.345) (13) Min (11 & 12) (05) Negation (04) (14) Division (08 & 13) (06) Exponentiation (03 & 05) (15) Sin (14) (07) Addition (02 & 06) (16) Multiplication (07 & 15) (08) Load Constant (pi) (17) Assignment (01 & 16) (09) Load Variable (w) Generally an expression in ExprTk can be thought of as a free function similar to those found in imperative languages. This form of pseudo function will have a name, it may have a set of one or more inputs and will return at least one value as its result. Furthermore the function when invoked, may cause a side-effect that changes the state of the host program. As an example the following is a pseudo-code definition of a free function that performs a computation taking four inputs, modifying one of them and returning a value based on some arbitrary calculation: ResultType foo(InputType x, InputType y, InputType z, InputType w) { w = 2 * x^y + z; // Side-Effect return abs(x - y) / z; // Return Result } Given the above definition the following is a functionally equivalent version using ExprTk: const std::string foo_str = " w := 2 * x^y + z; " " abs(x - y) / z; "; T x, y, z, w; symbol_table_t symbol_table; symbol_table.add_variable("x",x); symbol_table.add_variable("y",y); symbol_table.add_variable("z",z); symbol_table.add_variable("w",w); expression_t foo; foo.register_symbol_table(symbol_table); parser_t parser; if (!parser.compile(foo_str,foo)) { // Error in expression... return; } T result = foo.value(); (3) Parser A component which takes as input a string representation of an expression and attempts to compile said input with the result being an instance of Expression. If an error is encountered during the compilation process, the parser will stop compiling and return an error status code, with a more detailed description of the error(s) and its location within the input provided by the 'get_error' interface. Note: The exprtk::expression and exprtk::symbol_table components are reference counted entities. Copy constructing or assigning to or from either component will result in a shallow copy and a reference count increment, rather than a complete replication. Furthermore the expression and symbol_table components being Default-Constructible, Copy-Constructible and Copy-Assignable make them compatible with various C++ standard library containers and adaptors such as std::vector, std::map, std::stack etc. The following is an example of two unique expressions, after having being instantiated and compiled, one expression is assigned to the other. The diagrams depict their initial and post assignment states, including which control block each expression references and their associated reference counts. exprtk::expression e0; // constructed expression, eg: x + 1 exprtk::expression e1; // constructed expression, eg: 2z + y +-----[ e0 cntrl block]----+ +-----[ e1 cntrl block]-----+ | 1. Expression Node 'x+1' | | 1. Expression Node '2z+y' | | 2. Ref Count: 1 |<-+ | 2. Ref Count: 1 |<-+ +--------------------------+ | +---------------------------+ | | | +--[ e0 expression]--+ | +--[ e1 expression]--+ | | 1. Reference to ]------+ | 1. Reference to ]-------+ | e0 Control Block | | e1 Control Block | +--------------------+ +--------------------+ e0 = e1; // e0 and e1 are now 2z+y +-----[ e1 cntrl block]-----+ | 1. Expression Node '2z+y' | +----------->| 2. Ref Count: 2 |<----------+ | +---------------------------+ | | | | +--[ e0 expression]--+ +--[ e1 expression]--+ | +---[ 1. Reference to | | 1. Reference to ]---+ | e1 Control Block | | e1 Control Block | +--------------------+ +--------------------+ The reason for the above complexity and restrictions of deep copies for the expression and symbol_table components is because expressions may include user defined variables or functions. These are embedded as references into the expression's AST. When copying an expression, said references need to also be copied. If the references are blindly copied, it will then result in two or more identical expressions utilizing the exact same references for variables. This obviously is not the default assumed scenario and will give rise to non-obvious behaviours when using the expressions in various contexts such as multi-threading et al. The prescribed method for cloning an expression is to compile it from its string form. Doing so will allow the 'user' to properly consider the exact source of user defined variables and functions. Note: The exprtk::parser is a non-copyable and non-thread safe component, and should only be shared via either a reference, a shared pointer or a std::ref mechanism, and considerations relating to synchronisation taken into account where appropriate. The parser represents an object factory, specifically a factory of expressions, and generally should not be instantiated solely on a per expression compilation basis. The following diagram and example depicts the flow of data and operations for compiling multiple expressions via the parser and inserting the newly minted exprtk::expression instances into a std::vector. +----[exprtk::parser]---+ | Expression Factory | | parser_t::compile(...)| +--> ~.~.~.~.~.~.~.~.~.~ ->--+ | +-----------------------+ | Expressions in | | Expressions as string form A V exprtk::expression | | instances [s0:'x+1']--->--+ | | +-[e0: x+1] | | | | [s1:'2z+y']-->--+--+ +->+-[e1: 2z+y] | | [s2:'sin(k+w)']-+ +-[e2: sin(k+w)] const std::string expression_str[3] = { "x + 1", "2x + y", "sin(k + w)" }; std::vector expression_list; parser_t parser; expression_t expression; symbol_table_t symbol_table; expression.register_symbol_table(symbol_table); for (std::size_t i = 0; i < 3; ++i) { if (parser.compile(expression_str[i],expression)) { expression_list.push_back(expression); } else std::cout << "Error in " << expression_str[i] << "\n"; } for (auto& e : expression_list) { e.value(); } ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ [SECTION 11 - COMPILATION OPTIONS] The exprtk::parser when being instantiated takes as input a set of options to be used during the compilation process of expressions. An example instantiation of exprtk::parser where only the joiner, commutative and strength reduction options are enabled is as follows: typedef exprtk::parser ::settings_t settings_t; std::size_t compile_options = settings_t::e_joiner + settings_t::e_commutative_check + settings_t::e_strength_reduction; parser_t parser(compile_options); Currently seven types of compile time options are supported, and enabled by default. The options and their explanations are as follows: (1) Replacer (2) Joiner (3) Numeric Check (4) Bracket Check (5) Sequence Check (6) Commutative Check (7) Strength Reduction Check (1) Replacer (e_replacer) Enable replacement of specific tokens with other tokens. For example the token "true" of type symbol will be replaced with the numeric token of value one. (a) (x < y) == true ---> (x < y) == 1 (b) false == (x > y) ---> 0 == (x > y) (2) Joiner (e_joiner) Enable joining of multi-character operators that may have been incorrectly disjoint in the string representation of the specified expression. For example the consecutive tokens of ">" "=" will become ">=" representing the "greater than or equal to" operator. If not properly resolved the original form will cause a compilation error. The following is a listing of the scenarios that the joiner can handle: (a) '>' '=' ---> '>=' (gte) (b) '<' '=' ---> '<=' (lte) (c) '=' '=' ---> '==' (equal) (d) '!' '=' ---> '!=' (not-equal) (e) '<' '>' ---> '<>' (not-equal) (f) ':' '=' ---> ':=' (assignment) (g) '+' '=' ---> '+=' (addition assignment) (h) '-' '=' ---> '-=' (subtraction assignment) (i) '*' '=' ---> '*=' (multiplication assignment) (j) '/' '=' ---> '/=' (division assignment) (k) '%' '=' ---> '%=' (modulo assignment) (l) '+' '-' ---> '-' (subtraction) (m) '-' '+' ---> '-' (subtraction) (n) '-' '-' ---> '+' (addition) (o) '<=' '>' ---> '<=>' (swap) An example of the transformation that takes place is as follows: (a) (x > = y) and (z ! = w) ---> (x >= y) and (z != w) (3) Numeric Check (e_numeric_check) Enable validation of tokens representing numeric types so as to catch any errors prior to the costly process of the main compilation step commencing. (4) Bracket Check (e_bracket_check) Enable the check for validating the ordering of brackets in the specified expression. (5) Sequence Check (e_sequence_check) Enable the check for validating that sequences of either pairs or triplets of tokens make sense. For example the following sequence of tokens when encountered will raise an error: (a) (x + * 3) ---> sequence error (6) Commutative Check (e_commutative_check) Enable the check that will transform sequences of pairs of tokens that imply a multiplication operation. The following are some examples of such transformations: (a) 2x ---> 2 * x (b) 25x^3 ---> 25 * x^3 (c) 3(x + 1) ---> 3 * (x + 1) (d) (x + 1)4 ---> (x + 1) * 4 (e) 5foo(x,y) ---> 5 * foo(x,y) (f) foo(x,y)6 + 1 ---> foo(x,y) * 6 + 1 (g) (4((2x)3)) ---> 4 * ((2 * x) * 3) (h) w(x) + (y)z ---> w * x + y * z (7) Strength Reduction Check (e_strength_reduction) Enable the use of strength reduction optimisations during the compilation process. In ExprTk strength reduction optimisations predominantly involve transforming sub-expressions into other forms that are algebraically equivalent yet less costly to compute. The following are examples of the various transformations that can occur: (a) (x / y) / z ---> x / (y * z) (b) (x / y) / (z / w) ---> (x * w) / (y * z) (c) (2 * x) - (2 * y) ---> 2 * (x - y) (d) (2 / x) / (3 / y) ---> (2 / 3) / (x * y) (e) (2 * x) * (3 * y) ---> (2 * 3) * (x * y) Note: When using strength reduction in conjunction with expressions whose inputs or sub-expressions may result in values nearing either of the bounds of the underlying numeric type (eg: double), there may be the possibility of a decrease in the precision of results. In the following example the given expression which represents an attempt at computing the average between x and y will be transformed as follows: (0.5 * x) + (y * 0.5) ---> 0.5 * (x + y) There may be situations where the above transformation will cause numerical overflows and that the original form of the expression is desired over the strength reduced form. In these situations it is best to turn off strength reduction optimisations or to use a type with a larger numerical bound. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ [SECTION 12 - EXPRESSION STRUCTURES] Exprtk supports mathematical expressions in numerous forms based on a simple imperative programming model. This section will cover the following topics related to general structure and programming of expression using ExprTk: (1) Multi-Statement Expressions (2) Statements And Side-Effects (3) Conditional Statements (4) Special Functions (1) Multi-Statement Expressions Expressions in ExprTk can be comprised of one more statements, which may sometimes be called sub-expressions. The following are two examples of expressions stored in std::string variables, the first a single statement and the second a multi-statement expression: std::string single_statement = " z := x + y "; std::string multi_statement = " var temp := x; " " x := y + z; " " y := temp; "; In a multi-statement expression, the final statement will determine the overall result of the expression. In the following multi-statement expression, the result of the expression when evaluated will be '2.3', which will also be the value stored in the 'y' variable. z := x + y; y := 2.3; As demonstrated in the expression above, statements within an expression are separated using the semi-colon ';' operator. In the event two statements are not separated by a semi-colon, and the implied multiplication feature is active (enabled by default), the compiler will assume a multiplication operation between the two statements. In the following example we have a multi-statement expression composed of two variable definitions and initialisations for variables x and y and two seemingly separate mathematical operations. var x:= 2; var y:= 3; x + 1 y * 2 However the result of the expression will not be 6 as may have been assumed based on the calculation of 'y * 2', but rather the result will be 8. This is because the compiler will have conjoined the two mathematical statements into one via a multiplication operation. The expression when compiled will actually evaluate as the following: var x:= 2; var y:= 3; x + 1 * y * 2; // 2 + 1 * 3 * 2 == 8 In ExprTk any valid statement will itself return a value. This value can further be used in conjunction with other statements. This includes language structures such as if-statements, loops (for, while) and the switch statement. Typically the last statement executed in the given construct (conditional, loop etc), will be the value that is returned. In the following example, the return value of the expression will be 11, which is the sum of the variable 'x' and the final value computed within the loop body on its last iteration: var x := 1; x + for (var i := x; i < 10; i += 1) { i / 2; i + 1; } (2) Statements And Side-Effects Statements themselves may have side effects, which in-turn effect the proceeding statements in multi-statement expressions. A statement is said to have a side-effect if it causes the state of the expression to change in some way - this includes but is not limited to the modification of the state of external variables used within the expression. Currently the following actions being present in a statement will cause it to have a side-effect: (a) Assignment operation (explicit or potentially) (b) Invoking a user-defined function that has side-effects The following are examples of expressions where the side-effect status of the statements (sub-expressions) within the expressions have been noted: +-+----------------------+------------------------------+ |#| Expression | Side Effect Status | +-+----------------------+------------------------------+ |0| x + y | False | +-+----------------------+------------------------------+ |1| z := x + y | True - Due to assignment | +-+----------------------+------------------------------+ |2| abs(x - y) | False | +-+----------------------+------------------------------+ |3| abs(x - y); | False | | | z := (x += y); | True - Due to assignments | +-+----------------------+------------------------------+ |4| abs(x - y); | False | | | z := (x += y); | True - Due to assignments | +-+----------------------+------------------------------+ |5| var t := abs(x - y); | True - Due to initialisation | | | t + x;
本源码包内暂不包含可直接显示的源代码文件,请下载源码包。