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.
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.