Now that we have generated the code for a parser, the next natural question is: how do we use it? In a first example, we'll write a little program that reads the input text from stdin and then outputs the following to stdout:
-
A tree representation of the input. (This is called the AST, which is short for abstract syntax tree.)
-
The result. In other words, it will evaluate the arithmetic expression that was input. (Gee, it's hard to talk about this at an abstract level. What I mean is that if the input is 2+2 it outputs 4, okay?)
Now, in your text editor, start a new file and input the following java code:
![]() | ![]() | ![]() | |
![]() |
| ![]() | |
![]() | ![]() | ![]() |
Save this as ArithmeticTest.java in the same directory where you have all the other (generated) java code. At the command-line, enter:
javac ArithmeticTest.java
Now, to run the test from the command line with some input, try the following (or something reasonably similar, it hardly matters):
echo 7 | java ArithmeticTest
and then something like:
echo 2+2 | java ArithmeticTest
and then something like:
echo 5 + 0.7 + 3.14 | java ArithmeticTest
Let's examine the code in ArithmeticTest.java a bit more closely. Basically, the first two lines of the main method are what unleash the parser machinery on the input from stdin. The first line instantiates a new ArithmeticParser object that will get its input from stdin. The second line tells it to parse this as an AdditiveExpression construct -- which, it so happens is the only syntactical construct this parser knows about. Note that, at this point, after those two lines, the parser has done its job. It has read in the input, parsed it, and built up a tree. All the rest of the code basically operates on this tree that was built.
The third line in the main method simply returns the root Node object of the generated AST. The Nodes.dump method we call then is simply a little utility routine that FreeCC provides you for debugging purposes. It recursively dumps a node to stdout. Note that the root node here must be either a NUMBER object or an AdditiveExpression object. The former case is the simple, trivial one. This is when the the input string was just a number, like 7 or 2.3 or something. And then our AST is trivial: it is just a single node, with no descendants. As you could see running the above examples, the parse tree is a bit more interesting in the second case. In that case, the root node is an AdditiveExpression object that has various NUMBER and PLUS objects as child nodes.
Now, as for the evaluate method, it takes a Node as an argument. In this concrete case, the Node passed in can be one of two types: NUMBER or an AdditiveExpression. Again, the first case is trivial and should not require much comment. It uses the handy little fact that (unless you override it) a Token's toString() method simply returns the text that was matched. So, node.toString() simply returns the text of the number. The core java API method Double.parseDouble(...) is used to turn that into an actual number. Now, in the other case, when the Node input is an instance of AdditiveExpression, we make use of a utility method that FreeCC provides us, which is Nodes.childrenOfType. This gives us a List of all the child nodes of a certain type, in this case, NUMBER. Note that in this case, we can just ignore all the PLUS nodes; our task is simplified by the fact that we are only handling one kind of arithmetic operation. Later, as we develop the example, we'll have more operators, so we'll have to look at them to know whether to add or subtract, for example. Or whether to multiply or divide. This will complicate matters somewhat, but hardly takes this to the level of rocket science.