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:

Math grammar used by MathExpressionParser
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
system:
    assignment { assignment }


assignment:
   __StoreAssignment STRING = logic_expr delimitator __PopAssignment
   
delimitator:
    ;
    ,


logic_expr:
    comparison_expr { __PushOperator logic_op comparison_expr __PopOperator }

logic_op:
    ||
    &&
    ^


comparison_expr:
    addition_expr { __PushOperator comp_op addition_expr __PopOperator }

comp_op:
    >
    <
    >=
    <=
    ==
    !=


addition_expr:
    multiplication_expr { __PushOperator add_op multiplication_expr __PopOperator }

add_op:
    +
    -


multiplication_expr:
    unary_expr { __PushOperator mul_op unary_expr __PopOperator }

mul_op:
    *
    /


unary_expr:
    typecast_expr
    __PushOperator add_op   typecast_expr __PopOperatorAlternate
    __PushOperator unary_op typecast_expr __PopOperator

unary_op:
    !


typecast_expr:
    function_expr
    ( __PushTypecast STRING ) function_expr __PopTypecast
    ( __PushTypecast STRING ) __AddOperandTypecast NUMBER    // NUMBER token must be treated differently (see below)
    __AddOperand NUMBER


function_expr:
    primary_expr
    __PushOperator STRING ( logic_expr { , logic_expr } ) __PopOperator


primary_expr:
    ( logic_expr )
    __AddOperand   STRING


/*
 * NUMBER must be treated differently. If treated just like STRING the following:
 * (float) 10.5
 * is seen as
 * CONST 10.5
 * CAST float
 * but we want typecasts of constants to be translated in
 * CONST float 10.5
 * since we want the second behaviour for numbers and the first for
 * variables, the two tokens must be handled in different productions
 */

Hint

This grammar is written in the SLK language and refers to functions declared in MathExpressionParser.