CS 453 Programming Assignment #6 — MiniJava: functions and function calls

Due Wednesday April 21th (by 11:59pm)

Introduction

This assignment is to be done in groups of two or three. In this assignment you will be extending your MiniJava compiler from PA5 to handle programs with syntax using all of the MiniJava grammar except for those dealing with arrays and class reference declarations. Your PA6 MiniJava compiler will also need to add another scoping level to enable functions in the global scope and local variables within each function. Also, you will be implementing type checking and code generation for function calls and function declarations. The goals of this assignment are for you to learn how to

The Assignment

You should create a jar file, PA6_groupname.jar, that can be executed as follows:
   java -jar PA6_groupname.jar --two-pass-mips input_file
   
When called with the --two-pass-mips option, the program should generate a MIPS program in the input_file.s file. The generated MIPS program must be capable of being interpreted by the MARS interpreter.

The input_file to your compiler will contain a legal MiniJava/Java program. For example, the assign2.txt example from PA5 could become the following:

  class Assign2 {
    public static void main(String[] whatever){
        System.out.println( new Foo().testing() );
    }
  }

  class Foo {

    public int testing() {
    
        int b;
        int a;
        
        a = 56;
        b = 20;
        System.out.println(a + b * 2);
        System.out.println(2 * (6 - 1) + 2);

        return 1;
    }
  }
For this assignment, the all methods (e.g., the testing method) will be treated like functions with no relationship to classes. Think of there only being one global namespace in which all of the method definitions exist. Your compiler will ignore the constructor calls needed to provide a receiver to the method calls (e.g., new Foo()).

The method definitions will still be put into class definitions so that we can use the Java compiler and virtual machine as our oracle (NOTE: java will interpret java byte code and MARS will interpret your generated MIPS code). See the MJFuncStart/TestCases/regress.sh file for an example of how to compare your compiler with the javac compiler. Note that your error messages will be syntactically different and fewer, but conceptually quite similar.

You also need to be able to handle fuctions that are declared in other classes. For example, the following program:

  class ParamClash {
    public static void main(String[] whatever){
        System.out.println( new Foo().testing() );
    }
  }

  class Foo {

    public int testing() {
    
        int b;
        int a;
        
        a = 56;
        b = 20;
        System.out.println(a + b * 2);
        System.out.println(2 * (6 - 1) + 2);
        System.out.println(new Bar().another(100));
        if (new Baz().lotsaParams(10, 20, 30)) {
            System.out.println(1);    
        } else {
            System.out.println(0);
        }
        System.out.println(b);
        return 42;
    }
        
  }

  class Bar {
    public int another(int x) {
        return 2 + x;
    }

  }

  class Baz {
    public boolean lotsaParams(int x, int q, int r) {
        int b;
        b = 3;
        System.out.println(x-q-r+b);
        return true;
    }
  }


should result in the following output from the MARS interpreter:

96
12
102
-37
1
20
42

For this assignment, you need to maintain the semantic analysis from the previous assignment and additionally catch the following errors:

[LINENUM,POSNUM] Invalid type returned from method METHODNAME
    // any method declaration

[LINENUM,POSNUM] Method METHODNAME does not exist

[LINENUM,POSNUM] Method METHODNAME requires exactly NUM arguments

[LINENUM,POSNUM] Invalid argument type for method METHODNAME
    // any call to a method (note that println is a method)
The above errors are all considered inappropriate type usage errors and therefore it is only necessary to report the first error.

As always you should start this assignment right away. We recommend the following progression:

  1. Add the tokens, grammar rules, and AST building actions for all grammar rules except for those dealing with arrays. Test that your compiler can parse and create ASTs for such programs.
  2. Extend your symbol table data structure and the visitor that creates it to include method symbol table entries. Each method symbol table entry should contain its own scope. Each function scope should have its own set of local variable offsets.
  3. Extend your check types visitor so that it finds function-related type errors.
  4. Implement code generation for each of the following program constructs:
    1. the main class, which is just the main function
    2. method declarations including returns
    3. function calls
The remainder of this writeup provides details about each of the recommended phases.

Phase 1: Adding Grammar Rules and New Tokens

Start by taking away the special main construct grammar rule. Then implement all of the grammar productions for the MiniJava grammar EXCEPT for the following:
    Exp -> new []
    Exp -> Exp . length
    Exp -> [ E ]
   
    Type -> INT [ ] 
    Type -> ID

    Stm -> ID [ exp ] = exp ;
Use the same precedence and associativity as Java for any new expression operators.

The only variable types you need to handle for this assignment are the "int" and "boolean" types.

As in previous assignments, all of the AST nodes needed have been provided in MJFuncStart/src/ast/nodes. Also, the ast/analysis package has been updated.

Phase 2: The Symbol Table

Extend your symbol table package to include a symbol table entry for methods (MethodSTE). For each method, you will need to store signature information. A method's signature includes information about the types of each of its parameters and its return value.

Method STEs should also contain a scope that can then contain local variables. When local variables are inserted into the symbol table, they should be inserted into the most current scope (i.e. the method being visited). Keep in mind that the formal parameters also need offsets in a methods scope, but those offsets must be calculated differently than the other local variables.

The symbol table data structure needs to be extended to manipulate more than one level of scoping. Here are some additional routines you might want to implement:

    void pushScope(String)
    
    void insertAndPushScope(NamedScopeSTE)
    
    void popScope()

NOTE: The reference compile generates an error if you attempt to declare a variable with the same name as the function that encloses it. Javac does not. Feel free to make your implementation work either way.

Phase 3: Type Checking

Your compiler will need to perform some additional type checking. The following is a list of ALL the error messages that will be expected. If one or more errors are checed at the same node in the AST, then check them in the order they are listed below.
    [LINENUM,POSNUM] Invalid type returned from method METHODNAME
        // any method declaration

    [LINENUM,POSNUM] Method METHODNAME does not exist

    [LINENUM,POSNUM] Method METHODNAME requires exactly NUM arguments

    [LINENUM,POSNUM] Invalid argument type for method METHODNAME
        // any call to a method (note that println is a method)


    // Errors from previous assignment that are still relevant

    [LINENUM,POSNUM] Undeclared variable VARNAME
        // anywhere an id token could be a variable name

    [LINENUM,POSNUM] Invalid expression type assigned to variable VARNAME
        // assignment statements

    [LINENUM,POSNUM] Invalid left operand type for operator OP

    [LINENUM,POSNUM] Invalid right operand type for operator OP

    [LINENUM,POSNUM] Invalid operand type for operator !

    [LINENUM,POSNUM] Invalid condition type for if statement
    
    [LINENUM,POSNUM] Invalid condition type for while statement

where LINENUM is the line number for the symbol, POSNUM is the position number for the symbol, OP is a specific binary operator, and VARNAME is a specific variable name.

To enable easier testing and grading, do not change the phrasing of the error messages.

Method calls in the MiniJava grammar include an expression on the left-hand-side of the ".". Those expressions are going to be completely ignored by your PA6 type checker and code generator. We will handle those in PA7.

Phase 3: Implementing New Language Features

At this point, your compiler should have a lexer, a parser, a visitor that creates the symbol table, a check types visitor, an interpreter visitor, and a MIPS code generator visitor. For function calls, it is a bit more difficult to implement each of the features separately. For the main class, you need to generate the same prologue and epilogue MIPS code you are currently generating for special main in the outMainClass method. Method calls, declarations, and returns need to be implemented at the same time.

For a method call, you need to generate MIPS code that evaluates the actual parameters in the correct order (left-to-right) and make it so that the parameter values will be on the stack as is expected by the Patt and Pattel calling convention (i.e. the one we used in the MIPS assignment). After the jump and link is generated, you then need to generate code that pops the parameters and places the return value back at the top of the runtime stack.

For method declarations, you need to generate prologue code that saves the return address and old frame pointer, sets up the frame pointer, and allocates space for local variables. The epilogue code needs to ensure that the return value is placed in the return value slot according to the calling convention and that the return address and old frame pointer values are restored.

Getting Started

Download the MJFuncStart.tgz file and untar it. As for previous assignments, we have given you all of the needed AST nodes and the DepthFirstAdapter class that is capable of visiting all the AST nodes.

The TestCases directory includes some test cases and an example regression script.

Start working through the phases as outlined above.

Submitting the Assignment

Late Policy

Late assignments will be accepted up to 24 hours past the due date and time for a deduction of 20% and will not accepted past this period.


mstrout@cs.colostate.edu .... April 21, 2009