The sine of angles x measured in degrees can be plotted with the function sin(x*pi/180), where π/180 is the conversion factor from degrees to radians. Of course it is easier to remember that π radians is half the circle than to recall the equivalent value 0,017453293, but it would be much more efficient to enter the function to plot as sin(x*0,017453293) to avoid performing the costly division of π by 180 each time the parse tree is evaluated. Replacing the expression pi/180 with the equivalent constant when parsing the mathematical expression is a type of optimization called constant folding. This procedure will be implemented.
HasVariables
The brute force approach to identifying expressions that can be replaced by a constant is to call the corresponding tree’s Eval method. If an answer is obtained then it would be tempting to conclude that a constant has been found. Unfortunately, this could be wrong; it just happened that reasonable data was stored in a variable when the tree was evaluated.
There is no real solution to identifying expressions that potentially could be reduced to a constant other than to scan the tree looking for variables. To that end, a virtual boolean function called HasVariables is added to TTree, the ancestor class of all nodes in the parse tree. By default, that function returns false.
Of course, this is the proper result for a TNumberNode which, by definition, is a constant. It is not correct for TParameterNode because that does represent an unknown value such as x in the assignment f(x):= 2*x.
The function is also overridden in the abstract class TParentNode. A parent node cannot be a variable when it represents an operation such as a sum or a product. All that needs be done is to check if any child node has variables.
This will be sufficient to handle all binary and unary nodes. However when the node is actually a TCallNode then it's target may be a TVariable which is obviously a variable.
There remains the class TIfNode. If the condition has variables, then there is no need to look further. Otherwise, the appropriate node needs to be looked at.
Constant Folding
...to be completed - note that the archive contains the completed source code implementing constant folding.
Source code
The source code for all units making up the parser is available along with a simple demonstration programme and test code. It is in the archive ParsingMathExpr-7.zip.
The demonstration program compiles with Delphi version 2 and up. It should also compile with Lazarus/FreePascal with minimal changes. As before, unit tests require DUnit.pas which works with newer versions of Delphi only. Unit testing was done with Delphi 2010.
Part 6 – Adding Boolean Operations