This goal of this lab is to practice writing operations for binary trees, as an application of and variation on linked lists.
As usual, make a new directory for this lab and cd into it. Copy all the files from a subdirectory for this lab.
cp /homes/tvandrun/Public/cs235/lab13/* .
One use for trees is in the grammatical (or syntactical) analysis (or "parsing") of languages, both human languages and programming languages. As a simple example, the following grammar describes the language of fully parenthesized arithmetic expressions:
expression --> integer | ( expression op expression)
op --> + | - | / | *
This means "An expression is either a single integer, or it is a left parenthesis, a (sub-)expression, an operator, another (sub-)expression, and a right parenthesis. An operator is a plus, a minu, a slash, or a star." According to this grammar, the following are expressions:
These can be represented as trees. (We can ignore the parentheses now, since the information they give about grouping is contained in the structure of the tree itself.)
15 - / + / \ / \ / \ 42 17 * 147 * - / \ / \ / \ 18 10 14 91 22 17
Expression can be modelled by a node-like interface with two implementing classes: one for leaf nodes containing integers, and one for nodes containing an operator and having two children. Evaluation of the expressions can be performed with a depth-first post-order traversal of the tree.
ExprNode
classesYour first task is to design classes that model the
two kinds of nodes, implementing the ExprNode
interface.
These nodes will have to have evaluate()
methods, but we'll deal with that later.
So, write two classes, one for leaf/integer nodes, the other for non-leaf/operation nodes. What instance variables will they have?
Next, you will need to write code to build
an expression tree given a String containing a fully-parenthesized
expression.
The driver program Interpreter
is intended to work so
that the user can write a expression in the commandline,
and the program will build an appropriate expression
tree, and then evaluate the expression using the tree.
Implement this in the main method of Interpreter
and the the constructors of the classes you wrote in
part B.
One thing you will find useful is a method I have written
and included in the code you copied.
In the class ExprStringSlicer
, the static method
slice()
takes a String, assumed to contain
an expression in our grammar.
It will return an array of Strings: if the String passed
to it is just an integer, then it will return an array
with exactly one element, a String version of that integer;
if it is passed a String with a parenthesized operation
over subexpressions, it will return an array with three elements,
the first subexpression, the operator, and the second subexpression.
For example, given "5"
, it will return
{ "5" }
.
Given "((14 * 91) + (22 - 17))"
,
it will return { "(14 * 91)", "+", "(22 - 17")}
.
(Extra credit: Do not use my ExprStringSlicer
class.
Write your own slice()
method.)
When you test out your program, you will need to put
quotes around the string you give to Interpreter
.
For example, you could run the program with
java Interpreter "((14 * 91) + (22 - 17))"
The quotes tell Java to treat ((14 * 91) + (22 - 17))
as a single String (it will be the zeroth item in args
).
Otherwise every space would be assumed to begin and end a separate
String; furthermore, the parentheses would really mess things up.
Finally, the interpreter calls the
evaluate()
method on the trees you have built.
Write the evaluate methods so that they return the integer
value of the given expression.
Create the script file as before (cat--only files you've written or changed, rm, compile, and run)
a2ps (the name of the script file)