Project 4: The MiniJava Evaluator and Intermediate Code Generator

Due: Friday, November 18, 12:30 pm, by email.

In this assignment you will extend the initial MiniJava evaluator (partially) and intermediate code generator (fully) with the extensions described in the course project description handout.  This will complete your extended MiniJava compiler!


Evaluator

You should implement the evaluate operations for the new array-oriented constructs: array creation, array indexing (both reading and assigning), and array length extraction. You should implement a way to represent array values. Your array creation operation should throw an EvalCompilerException if the size of the array being created is negative, or if the array expression being accessed by indexing or length extraction is null, or if the index expression is out-of-bounds of the array being indexed.

You should extend the evaluate operations for variable reads and assignments to allow static class variables to be read and assigned. You should extend the declareVariable operation for static class variable declarations to declare the static class variable in the ClassEnvironment and initialize it to the variable's type's default value.

You should implement the evaluate operations for the double-related constructs: double literals, double overloads of unary and binary arithmetic and comparison operations and System.out.println.  You should allow ints to be used wherever doubles are expected, including in assignments, parameter passing, result returning, and in mixed double-and-int operations, by implicitly converting the int to a double.

You do not need to implement other MiniJava extensions, including for statements, break statements, the boolean or (||) operator, and if statements without else clauses.

In all cases, as long as the MiniJava language restrictions are satisfied and an unimplemented feature is not being used, a MiniJava program should evaluate the same as the equivalent Java program.


Intermediate Code Generator

You should implement the lower operations for all the new language constructs and features in the extended MiniJava language. This includes inserting explicit coercions from integers to doubles wherever necessary, and for generating tests for null array references and out-of-bounds array references and negative-sized array creations. To support System.out.println on doubles, a new runtime function should be added to the CodeGen/Runtime/runtime.c file. The lower operations should use the IL classes defined in the IL subdirectory, but you should not make any changes to these IL classes.

After lowering, your lowered IL program should be able to be translated into x86 target code which then compiles, links, and runs correctly. (The x86 code generator is already fully implemented; you should not make any changes to it.)

In all cases, as long as the MiniJava language restrictions are satisfied, a MiniJava program should compile into an executable program that runs the same as the equivalent Java program.


Do the following:

  1. Add and/or modify classes in the AST, Typechecker, and/or Evaluator subdirectories to perform evaluation and lowering, and modify the CodeGen/Runtime/runtime.c file to include any new runtime functions you need. (You should not modify any files in the IL or other CodeGen subdirectories.)
  2. Develop test cases that demonstrate that your extended evaluator works properly, both in cases that should now evaluate correctly and in cases that should now evaluate to run-time exceptions. (Since evaluation ends with the first exception, you'll likely need several excepting test case files to test the different excepting cases.) You may assume that your test cases pass all lexical, syntactic, and semantic checks, and you may assume that evaluation of all MiniJava constructs from the initial language (before your extensions) evaluate correctly; you only need to test evaluation of the new language features. The SamplePrograms directory contains some files that should evaluate successfully after you make your changes; some of the files should evaluate successfully with the initial version of the MiniJava compiler.
  3. Develop test cases that demonstrate that your extended intermediate code generator works properly, both in cases that should now compile and run successfully and in cases that should now compile successfully but throw exceptions when run. (Since execution ends with the first exception, you'll likely need several excepting test case files to test the different excepting cases.) You may assume that your test cases pass all lexical, syntactic, and semantic checks, and you may assume that all MiniJava constructs from the initial language (before your extensions) are compiled and executed correctly; you only need to test compilation and execution of the new language features. The SamplePrograms directory contains some files that should compile and execute successfully after you make your changes; some of the files should compile and execute successfully with the initial version of the MiniJava compiler.

You can use the -evaluate option to the MiniJava compiler to run the evaluation phase; you can add the -printCalls option to print out a trace of  the calls and returns that the evaluated program makes.  See the test_evaluator target in the Makefile for an example, and feel free to make your own target(s) to make running the tests you like easier and more mechanical.

You can use the -lower -printIL options to the MiniJava compiler to just run the lowering phase and print out the IL program that it produces.  See the test_lowering target in the Makefile for an example.  You can use the -printCode option (the -codegen option is the default) to the MiniJava compiler to run the full compiler and print out the assembly code that it produces.  See the test_codegen target in the Makefile for an example, which also compiles the runtime.c file, runs the assembler on the generated assembly file, links it with the compiled runtime.c file, and finally runs the linked executable program. (This target should be run only on an x86 machine, so that the generated x86 assembly code can be compiled and run successfully.)  Feel free to make your own target(s) to make running the tests you like easier and more mechanical.


Turn in the following:

  1. Your new and/or modified AST/*.java, Typechecker/*.java, Evaluator/*.java, and/or CodeGen/Runtime/runtime.c files. Clearly identify any modifications to existing files using comments.
  2. Your evaluator test cases, with names of the form name.eval.legal.java for test cases that should evaluate successfully and name.eval.illegal.java for test cases that should throw evaluation exceptions.
  3. Your intermediate code generator test cases, with names of the form name.lower.legal.java for test cases that should compile and run successfully and name.lower.illegal.java for test cases that should compile successfully but throw exceptions when run.
  4. A transcript of running your evaluator (without call tracing) on each of your evaluator test cases.
  5. A transcript of running your intermediate code generator and printing out the resulting IL program (not the final assembly code) on each of your intermediate code generator test cases.
  6. A transcript of running the compiled code for each of your intermediate code generator test cases.

Put a copy of all these files into a single directory named lastname-firstname-proj4 (if you're working alone) or groupletter-proj4 (if you're working in a group).  Create a single tar or zip file containing this directory (so that unpacking this tar/zip file will create a directory with that name containing your files), named lastname-firstname-proj4.ext or groupletter-proj4.ext (where ext is something like zip or tar).  Email this file as an attachment to marius at cs.washington.edu by the due date.


chambers@cs.washington.edu