Macquarie University
Department of Computing

COMP332 Programming Languages 2012

Assignment Three

MiniJava Translation to the Java Virtual Machine

Due: 11am Monday 5 November (Week 13)
Worth: 10%

This assignment asks you to finish the MiniJava implementation we started in the first two assignments by implementing translation from MiniJava source constructs to Java Virtual Machine class files. By the end of this assignment you will have a working MiniJava compiler and wil be able to produce class files that can be run on the Java Virtual Machine.

The assignment uses the syntax and semantic analysis phases from the first two assignments with some minor changes (described below). The translation and code generation scheme is heavily based on that used in the practical exercises for weeks 9 and 10. If you have not completed those exercises, we strongly encourage you to do so before starting work on this assignment. In many cases, the work required here is the same or very similar to that required in the practical exercises. You should also make sure that you have read the "Translation and Code Generation" lecture notes from week 9 since they give an overview of the processes you will need to implement.

Updates from Assignment Two

The semantic analysis from Assignment Two did not distinguish between the entities that represent instance variables (fields declared inside a class but outside all methods) and local variables (those declared inside a method). To do translation properly we need to make this distinction since the JVM uses different operations to access fields and to access local variables. Thus, the semantic analysis phases from Assignment Two has been extended to add a new FieldEntity which is used to represent fields. VariableEntity is only used for local variables now.

Also, note that the semantic analysis phase from Assignment Two does not deal properly with classes whose names are used either before the declaration of the class, or within the class itself. Ultimately, it would be best to support these structures, but for the purposes of this unit, we will just assume that classes are defined before they are used. For this reason, we have removed the treevisitor.java example since it has a class that refers to itself. Some other examples have been changed to reorder the class definitions so that they work with the restriction.

What you have to do

You have to write, document and test a Scala translator for the MiniJava language to the Java virtual machine. Your translator should support all of the features of the MiniJava language and translate them to equivalent JVM operations.

A skeleton sbt project for the assignment has been provided on BitBucket as the inkytonik/comp332-ass3 repository. The skeleton implements quite a lot of the translation for you. Look for FIXME to find places where you have to extend the skeleton.

There is only one part in this assignment. Within that part it is advisable to solve small portions at a time rather than trying to code the whole solution in one go. As a first step you should consider working on simple expressions and use the Println statement in a MiniJava main class to print out the expression values for testing. Translation of Println statements has already been done for you in the skeleton.

We have not provided an automated testing setup for this assignment, because the main tests would be to compile real programs and run them to make sure that they do what they are supposed to do. This is hard to automate using our previous techniques. You will probably find it useful to write scripts to run your compiler, use Jasmin to convert the resulting .j files into .class files and then use the java command to run the relevant main class. To help with testing, the test/*.exp files contain the expected output when you run the different test programs.

MiniJava translation and code generation

The assignment skeleton contains the outline of a translator (in Translator.scala) and the implementation of a code generator (in CodeGenerator.scala). You should not have to modify the code generator to complete this assignment. Just finish the implementation of the translator.

The skeleton translator contains much of the code you will need. In particular, the skeleton already knows how to translate classes and methods into the JVM tree representation. Your focus will be to implement translateStmt and translateExp which translate statements and expressions, respectively.

As in the practical exercises for the expression language, you will build trees that represent the class files that you want to generate. The structure of those trees is defined in JVMTree.scala. The skeleton contains definitions for many of the JVM operations in the JVM tree definition (see the section labelled "JVM instructions"). You may want to add more instructions, if the operations you want to use are not already present. Follow the explanation in the code to add new instructions.

You may also find it useful to use the Java compiler to help you work out the appropriate operations to use. For example, you can write simple Java programs, compile them with the javac compiler and then use the javap -c command to look at the class file(s) and the instructions that are produced by the Java compiler.

To see the full range of operations that are available on the JVM, consult the Java virtual machine specification, particularly the section labelled "Instruction Set Summary", "The Java Virtual Machine Instruction Set" and "Compiling for the Java Virtual Machine". Bear in mind that many JVM operations are not needed for the simple MiniJava language, particularly those dealing with floating-point numbers and exceptions.

The following useful links point to the documentation for Java 5, which should be sufficient for this assignment. We would not expect that you will need to read all of this documentation, but it will probably be useful as a reference, particularly the instruction set information, if you are unsure about what an instruction does.

For examples on the type of code that you might generate, consult the lecture notes "Translation and Code Generation" (week 9) and the "Compiling for the Java Virtual Machine" link above which both contain examples. Part of this assignment is to explore the JVM, so you may need more features of the JVM than are covered in the lecture notes. Use the documentation above or other resources you can find on the net to explore this space. In most cases, the JVM has operations that directly correspond to the MiniJava source constructs, so the code that you generate should be quite simple.

As an example, consider the generation of code for a plus expression. We need to generate the translations of the two operands of the expression. That JVM code will leave those two values on the top of the operand stack. Thus, we only need to append an iadd instruction to add them together and leave the result on the stack instead. The translator code in translateExp for this case looks like this:

case PlusExp (left, right) =>
    translateExp (left)
    translateExp (right)
    gen (Iadd ())

As a more complex example, consider generating code for a less expression whose value is assigned to a Boolean variable. E.g., MiniJava code like this: b := i1 < i2 where b is a Boolean variable and the other two variables are integers. Here is the translation code that first evaluates the two operands, then uses a conditional branch to jump to either code that pushes a one value (for true) or a zero value (for false). This code also illustrates using the makeLabel method to generate unique labels.

case LessExp (left, right) =>
    val label1 = makeLabel ()
    val label2 = makeLabel ()
    translateExp (left)
    translateExp (right)
    gen (If_icmpge (label1))
    gen (Iconst_1 ())
    gen (Goto (label2))
    gen (Label (label1))
    gen (Iconst_0 ())
    gen (Label (label2))

Similarly simple schemes can be used to translate all of the MiniJava constructs. The following notes provide some guidance for the translation schemes or special cases. The skeleton also contains some comments to guide your coding.

  1. The and operation needs to be short-circuited, so you will have to use a scheme to make sure that the right operand is not evaluated if the left operand is false.

  2. The JVM has quite a few operations for dealing with arrays directly, including operations for loading and storing from integer arrays, and for calculating the length of an array. It also has operations for dealing with arrays whose elements are references, but these are not needed for MiniJava.

  3. The JVM doesn't really have operations on Boolean values, so you should use integers to represent Boolean. Choose zero for false and one for true.

  4. To call a (virtual) method, we must first push the object on which the call is being made, then we push the actual argument values in the order of their declaration, and then we use the invokevirtual instruction passing a method specification that specifies the method that we want to call.

  5. A method specification identifies a particular method b giving its class, name, list of argument types and return type. See the translation of the println statements for an example of how to construct a method specification.

  6. When a virtual method body is being executed, the first local variable slot (number 0) holds the reference to the object on which the call is being made. If the method has n arguments, then the local variable slots 1 to n hold the values of the arguments in the order of the declaration. After the arguments in slots n + 1 and following come any other local variables that the method has.

  7. There are a few instructions for returning from methods: one for returning an integer (ireturn), one for returning an object or array reference (areturn), and one for returning from a void method (return).

What you must hand in and how

  1. All of the code for your compiler. To make this clear, submit every file that is needed to build your program from source, including files in the skeleton that you have not changed. Do not add any new files or include multiple versions of your files. Do not include any libraries. We will compile all of the files that you submit using sbt, so you should avoid any other build mechanisms.

  2. Your submission should include all of the tests that you have used to make sure that your program is working correctly. Note that just testing one or two simple cases is not enough for many marks. You should test as comprehensively as you can.

  3. A type-written report that describes how you have achieved the goals of the assignment. Your report must contain the following components or sections:

Submit your code and report electronically as a single zip file called ass3.zip using the appropriate submission link on the COMP332 iLearn website by the due date and time. Your report should be in PDF format. DO NOT SUBMIT YOUR ASSIGNMENT OR DOCUMENTATION IN ANY OTHER FORMAT THAN ZIP and PDF, RESPECTIVELY.

Marking

The assignment will be assessed according to the assessment standards for Learning Outcomes 2, 3 and 4 as specified in the Unit Guide.

Marks will be allocated equally to the code and to the report. Your code will be assessed for correctness and quality with respect to the assignment description. Marking of the report will assess the clarity and accuracy of your description and the adequacy of your testing. Marks allocated to testing will be 30% of the marks for the assignment.


Tony Sloane

Copyright (c) 2012-2014 by Anthony Sloane, Macquarie University. All rights reserved.