Sample: A Desktop Calculator

This example implements a desktop calculator. The user enters an arithmetic expression into the text box on the calculator window, either by typing it, or by using the calculator buttons. When pressing the '=' button, the expression is passed to an instance of an expression parser written as a ParseLR grammar. The parser computes the result while parsing the expression, and displays this result in the same text box as the expression was entered.

This sample demonstrates the use of an offline parser, with reduction actions built into the grammar directly. The grammar will be found in the file Calculator.g and is converted to a C# source file using ParseLR.exe. An example of the output source file is to be found in Calculator.designer.cs. Its application-specific part of the parser class is to be found in Calculator.cs. This class has a static method called Calculate that converts a parsable expression into a calculated result. If there is a grammar fault in the parsable expression, the parser's own detailed error messages are made available through the static Error property, and the Calculate method returns the simple string "Error".

The sample code for the application is divided into three projects. CalculatorDemo contains the actual parser-driven calculator implementation as described above. CalculatorDemoApp is the Windows Forms application that provides a GUI onto the calculator. The third project, is an example of a unit-testing project that exercises the CalculatorDemo class library. This unit-testing project is designed to use the Microsoft test libraries, as found in Visual Studio.

Notice too that the example demonstrates the use of strongly typed terminal and non-terminal tokens. Numbers are returned as type double in the grammar, and consequently the non-terminal expression nodes in the constructed expression trees are also typed to be double floating point.

GLR Parsing Calculator

The example also contains an alternative implementation that uses a GLR parser to parse an arithmetic expression. The GLR version of the grammar, along with inline source code for a GLR merge function, will be found in GLRCalculator.g. The implementation of the parser class is in GLRCalculator.cs. The merge function's role is to deal with operator precedence in this example. Multiple candidate parse trees are built for arithmetic expressions, but the merge function ensures it selects the tree that uses the correct operator precedence.

To toggle between LR(1) and GLR parsing, there are two options for selecting the appropriate kind of parser beneath the Options menu. Once an expression has been entered and calculated (the '=' key has been pressed to compute the result), the full debug output from the parser can be seen by selection Options|View parser output. For the GLR parser, this shows the state of the various stacks and expression trees after each input token shift, and each reduction. Part way through the parse, the multiple expression stacks can be seen. Similarly the calls to the merge function are clearly identified, with the subsequent reduction in the number of candidate parser stacks.

The source code and grammar files for the projects in this example are included in the parser toolkit download file ParseLR.zip, and when unzipped will be found in the CalculatorDemoExample folder.