Homework 6
|
Frames hold the activation record for calling a method. Though the frame is used at runtime, the location of parameters and local variables is performed at compile time. Chapter 6 examined a general approach to frame generation, we will simplify to problem by targeting the JVM.
Homework 3 defined the concrete grammar necessary for SableCC to generate a parser, however an abstract grammar results in a simpler solution for the type checker.
Homework 4 introduced the concrete to abstract grammar transformations of SableCC3 which will be applied to the MiniJava language. The implementation of the interpreter used the the DepthFirstAdapter class to visit nodes of the AST.
Homework 5 combined those ideas with that of a symbol table to implement a type checker based on the complete abstract grammar definition of MiniJava in SableCC3 form and skeleton classes for the necessary Java.
Homework 6 combines these ideas to determine where data is located in the frame (offset) required for each method and update the symbol table with that information. Much of the previous work will be used. The basic idea is build upon that work to add frame location information to the symbol table.
JVM FRAME Construction
Since the target machine is the JVM, the machine specific elements of the compiler should be placed in a separate directory. The organization of the frame is illustrated and described below.
- Main calls BuildSymbolTableVisitor to visit each AST node.
- BuildSymbolTableVisitor visits each type declaration node, adding each declared symbol and type to the SymbolTable. Classes, methods, parameters and local variables and type are added to the SymbolTable.
- SymbolTable package contains a set of 4 classes:
- SymbolTable - manages adding classes to the symbol table and getting information about classes, methods and variables from symbol table.
- Class - definition of classes including parent
- Variable - definition of variables (parameters and locals)
- Method - definition of methods
- TypeCheckVisitor has two main parts:
- Visits nodes for each program element (program definition, class definition, method call, array assignment, etc.) and checks that the type defined agrees with use. Checking is generally performed by checking typing of each non-terminal of the production.
- Visits expression nodes such as +, -, &&, method calls, etc. to check that all expressions (e.g. exp + exp) are valid type.
- Frame construction has two main parts for compatibility with the text discussion:
- FrameVisitor - Visits program, class and method declaration syntax tree nodes; retrieves from SymbolTable the method parameter and local variable lists, passes these lists and symbol table to JVMFrame which calculates the offsets within the frame and updates the symbol table with the offsets. Note that FrameVisitor has no knowledge of JVM frames so should be in a separate package (directory).
- JVMFrame - Given parameters and variables lists, compute the offset of each within a frame and update the symbol table. Since the parameter and local variable lists are Variable objects, the Variable class setOffset() mutator and getOffset() accessor methods of the SymbolTable package can be used to manipulate the offsets.
Computing the frame offset for each parameter and variable is a matter of assigning each a number from 1 to n where n is the total number of parameters + local variables. Frame offset 0 is predefined as the location for this parameter.
Note that class instance variables (i.e. fields) are not part of the frame and can be ignored.
Symbol table printing
The symbol table is a key source of information to the compiler, understanding its contents is critical. The following is a display of the important symbol table data for the MiniJava program at left.
class Factorial {
public static void main(String [] a) {
System.out.println(new Fac().ComputeFac(10));
}
}
class Fac {
int z1;
int z2;
public int ComputeFac(int num) {
int num_aux;
if (num < 1)
num_aux = 1;
else
num_aux = num * (this.ComputeFac(num-1));
return num_aux;
}
public int test1 (int x, int y) {
int q;
int r;
return x;
}
}
Classes
Factorial
Fields
Methods
Fac
Fields
z1 <class minijava.node.AIntType>
z2 <class minijava.node.AIntType>
Methods
test1 <class minijava.node.AIntType>
Parameters
x 1 <class minijava.node.AIntType>
y 2 <class minijava.node.AIntType>
Variables
q 3 <class minijava.node.AIntType>
r 4 <class minijava.node.AIntType>
ComputeFac
Parameters
num 1 <class minijava.node.AIntType>
Variables
num_aux 2 <class minijava.node.AIntType>The basic approach begins with the SymbolTable object constructed by BuildSymbolTableVisitor, it contains all the symbol table data; a getSymbolTable() accessor of BuildSymbolTableVisitor returns the SymbolTable object constructed.
Printing the classes, methods, etc. from the symbol table is a mainly a matter of understanding the 4 classes of the SymbolTable package: SymbolTable, Class, Method, Variable. Each has accessor methods (usually named getId(), getParams(), getVars(), etc.) which returns data from the object.
The symbol table organization parallels that of a Java program in that there are multiple classes, each class can have multiple methods; each method multiple parameters and variables; etc. These are returned as an enumeration which can be accessed sequentially. For example, the following iterates through all classes and the globals (fields) of the class:
public void Print() {
System.out.println("Classes");
Enumeration ce = symbolTable.getClasses();
while(ce.hasMoreElements()) {
Class c = (Class)ce.nextElement();
System.out.println(c.getId());
System.out.println("\t"+"Fields");
Enumeration ge = c.getGlobals();
while(ge.hasMoreElements()) {
Variable v = (Variable)ge.nextElement();
System.out.println("\t"+"\t"+v.id()+"\t<"+v.Type().getClass()+">");
}
}
}Main.java will need modification to call your printing class.
Use HW5 as a starting point, add JVM and FrameVisitor packages.
Home: java -jar \sablecc-3-beta.3.altgen.20041114\lib\sablecc.jar minijava.js
IUS: java -jar
v:\common\user\C431\sablecc.jar minijava.js
del Main.class
del minijava\*.class
javac -classpath . Main.java
java -cp . Main Factorial.java
The HW5 directory contained a BlueJ project that can be used as a starting point for HW6. To execute:
- Generate the minijava parser as described above.
- Start BlueJ and open the project.
- Right click on Main and compile (or Select | Tools | Compile Selected).
- Right click on Main and void main(arguments).
- Enter the name of a test file as: {"Factorial.java"}
- Cover sheet with your name, C431, date, and Homework 6.
- Print out of FrameVisitor, JVMFrame and the symbol table printer.
- Print out of symbol table produced from the 3 tests.