You can receive 2 units of extra credits by turning in your solution to Problem 3 by Jan. 19.
To do the programming assignments in this course you will need to download some Java source files and modify them. Links to these files will always appear at the top of the assignment page. As well as linking from the assignment page, you can copy the files directly; the files for this assignment are in ~cs160/project/pa1/. Sometimes they will have to be kept in separate sub-directories; if that is not explicitly specified they can be in the same directory. All the files and/or subdirectories for a programming assignment should be under one main directory - to hand in your work (see below) you will submit the entire directory.
The indenting style used for the code examples is the "Whitesmith" style. If this drives you crazy, feel free to change it.
You will be using the UNIX program turnin to submit your Java files. Suppose you have been working on this assignment in a directory called my_dir. When you are satisfied that you have solved Problems 1-3 correctly, cd to the directory above my_dir and execute the following instruction:
% turnin pa1@cs160 my_dirturnin ignores binary files; that includes any .class files present in your directory. It will ask you if it is OK to skip those files. It is OK.
This assignment is intended to get you familiarized (or re-familiarized) with writing Java code and using the Java compiler and interpreter. It also serves as a reminder of the CS 130A topics of data structures, in particular tree structures and traversals.
P1.java to create an abstract syntax tree (we will call it syntax tree for short) for the following program:a = 1 + 2 * 3;main() method to print out the tree.P1.java to create a syntax tree for the
following program:a = (1 + 2) * 3;main() method to print out the tree.DecrementStmt that represents the statementa = a - 1;First, download the file P1.java. Then enter the following commands at your Unix prompt:
% javac P1.java % java P1You should get an output consisting of two copies of the following line:
(CompoundStmt,(AssignStmt,a,(+,5,3)),(CompoundStmt,(AssignStmt,b,(Product,7,2)),(CompoundStmt,(AssignStmt,c,(Sum,a,b)),null)))
It will take some time for us to be able to translate a source program from ASCII text to a syntax tree, but for this assignment we can use a shortcut: we hard-wire the source program into the compiler's code. (This means we have to recompile the compiler to change the source program -- not so good for a commercial product, but just fine for this assignment.)
The code constructs (twice) a tree for the following program:
a = 5 + 3; b = 7 * 2; c = a + b;The tree has this structure:
CompoundStmt
/ \
AssignStmt CompoundStmt
/ \ / \
a + AssignStmt CompoundStmt
/ \ / \ / \
5 3 b * AssignStmt null
/ \ / \
7 2 c +
/ \
a b
The first time the code constructs this tree it uses nested constructors, in a style reminiscent of functional languages like Lisp, ML, or Scheme. The second time the code uses temporary variables to reduce the amount of nesting. Which do you prefer?
There are several separate classes defined to represent nodes in the syntax tree. Each class has a toString() method defined for it, which gives us a way to print out the syntax tree. The simplest way to do this is using a list format:
( <node name> , child1 , child2 , ...)State.java to represent the current values of variables, and copy the code below for value() and interp() into P1.java and fill in the gaps.There is no file P2.java; you can continue to use P1.java for Problem 2. Now you will add to your program the ability to execute the statements in the syntax tree. Execution of each statement changes the value of some variable. We represent the set of all values by a class called State, which is provided for you in State.java. It provides two methods:
int valueOf(String s) // Look up and return the value of variable named s. State update(String s, int v) // Set variable s to value v.
What you will need to do is write a routine that walks through the syntax tree, evaluating the right-hand side of the assignments and updating the variable in the left-hand side. You will need to add the following two methods to P1.java:
// Evaluation maps a state and an expression to a value. (No side-effects.)
// Fill in the code to return something other than 0!
static int value(State s, Expression e)
{
if (e instanceof IdExpr)
return 0;
else if (e instanceof NumExpr)
return 0;
else // It's an OpExpr.
return 0;
}
// Interpretation maps a state and a statement to another state.
// Fill in the code to return something other than the input state!
// This method will call the value() method.
static State interp(State state, Statement stmt)
{
if (stmt == null)
return state;
else if (stmt instanceof CompoundStmt)
return state;
else if (stmt instanceof DecrementStmt)
return state;
else // It's an AssignStmt.
return state;
}
and add to the main() routine the following line:
State S = interp(new State(), prog1); System.out.println(S);
P3.java to create a syntax tree for the following program:a = 1; b = 2; c = 1 + (2 * 3);Add a line to the
main() method to print out the tree.if a == 0 then b = 1 else b = 2;The file P3.java shows another approach to building syntax trees. In this case, there is just one class for a node, and it contains a tag, which is a string that identifies its type. The advantage of this kind of tree is that it is easier to generate a readable printout. (Even with a source-level debugger it is very difficult to traverse big syntax trees, so printouts will be your chief debugging tools.) The disadvantage is that nodes don't know about their contents: instead of asking a node for its members by name, you just have to ask for child 1, child 2, etc.