Parser of mathematical expressions
The MathExpressionParser class is an implementation of the ParserI interface that can read systems of mathematical expressions in infix form and transform them in a machine-readable form. The current implementation converts the infix form into a stack machine instruction set very similar to reverse Polish notation (RPN).
The expression in RPN-like syntax can then be executed by the runtime evaluator.
Syntax
The parser accepts C-like mathematical expressions in the form:
y1 = sin(A + B) > (pow(C + D, E)tan((bool)F + (float)15));
y2 = 2*y1;
Each expression must be terminated with a comma or a semicolon. Multiple expressions are allowed (provided that each is terminated with a comma or semicolon). Accepted operators are the following:
Operator |
Meaning |
---|---|
|
Assignment |
|
AND |
|
OR |
|
Exclusive OR |
|
NOT |
|
Less than |
|
Greater than |
|
Less ot equal |
|
Greater or equal |
|
Equal |
|
Not equal |
|
Sum |
|
Subtraction |
|
Multiplication |
|
Division |
|
End of expression |
Functions in the form sin(x)
, pow(x,y)
etc are supported.
However, the function name is passed as-is to the evaluation engine,
so please verify that the evaluation engine (typically
RuntimeEvaluator) supports the required function.
The mathematical expression must be provided to the parser at construction time. The instance of the parser is then bound to that specific expression.
The constructor requires:
an input stream of characters containing the mathematical expression in infix form,
an output stream of characters where the parser will write all the errors found on the input stream of characters (optional).
To make the parser parse the expression, users should call the Parse() method. Provided that the Parse() method was called, the expression in stack machine form is then availabe as the output of the GetStackMachineExpression() method.
Example usage with the following expression: retVar = pow(sin(theta), 2) + pow(cos(theta), 2)
#include "MathExpressionParser.h"
StreamString expr = "retVar = pow(sin(theta), 2) + pow(cos(theta), (int64) 2);"
expr.Seek(0);
MathExpressionParser mathParser(expr);
bool parseOk = mathParser.Parse();
if (parseOk) {
StreamString outputExpr;
outputExpr = mathParser.GetStackMachineExpression();
REPORT_ERROR(ErrorManagement::Information, "\n%s", outputExpr.Buffer());
}
This prints:
READ theta
SIN
CONST float64 2
POW
READ theta
COS
CONST int64 2
POW
ADD
WRITE retVar
All the instances of this parser use the lexical elements defined in the MathGrammar of GrammarInfo and apply the parsing rules defined in MathGrammar.ll:
1system:
2 assignment { assignment }
3
4
5assignment:
6 __StoreAssignment STRING = logic_expr delimitator __PopAssignment
7
8delimitator:
9 ;
10 ,
11
12
13logic_expr:
14 comparison_expr { __PushOperator logic_op comparison_expr __PopOperator }
15
16logic_op:
17 ||
18 &&
19 ^
20
21
22comparison_expr:
23 addition_expr { __PushOperator comp_op addition_expr __PopOperator }
24
25comp_op:
26 >
27 <
28 >=
29 <=
30 ==
31 !=
32
33
34addition_expr:
35 multiplication_expr { __PushOperator add_op multiplication_expr __PopOperator }
36
37add_op:
38 +
39 -
40
41
42multiplication_expr:
43 unary_expr { __PushOperator mul_op unary_expr __PopOperator }
44
45mul_op:
46 *
47 /
48
49
50unary_expr:
51 typecast_expr
52 __PushOperator add_op typecast_expr __PopOperatorAlternate
53 __PushOperator unary_op typecast_expr __PopOperator
54
55unary_op:
56 !
57
58
59typecast_expr:
60 function_expr
61 ( __PushTypecast STRING ) function_expr __PopTypecast
62 ( __PushTypecast STRING ) __AddOperandTypecast NUMBER // NUMBER token must be treated differently (see below)
63 __AddOperand NUMBER
64
65
66function_expr:
67 primary_expr
68 __PushOperator STRING ( logic_expr { , logic_expr } ) __PopOperator
69
70
71primary_expr:
72 ( logic_expr )
73 __AddOperand STRING
74
75
76/*
77 * NUMBER must be treated differently. If treated just like STRING the following:
78 * (float) 10.5
79 * is seen as
80 * CONST 10.5
81 * CAST float
82 * but we want typecasts of constants to be translated in
83 * CONST float 10.5
84 * since we want the second behaviour for numbers and the first for
85 * variables, the two tokens must be handled in different productions
86 */
Hint
This grammar is written in the SLK language and refers to functions declared in MathExpressionParser.