Lab: BugsWorld Virtual Machine ByteCode Generator


Objective

In this lab you will complete the code generation phase of the BL compiler by writing and testing the Program generatedCode secondary method.

Setup

To get started, import the project for this lab, ProgramCodeGenerator, from the ProgramCodeGenerator.zip file available at this link. If you don't remember how to do this, see the Setup instructions in an earlier lab.

Method

  1. First carefully look through the file Program1GeneratedCode1.java, which is an extension for Program1 that overrides the ProgramSecondary implementation of the generatedCode method, and make sure that you familiarize yourself with the methods provided. Note that it includes a main method that can be used to test your implementation and to display the code generated by generatedCode.
  2. In Program1GeneratedCode1.java, complete the body of the generateCodeForStatement static method by pasting the code you wrote for the homework and coding the case that takes care of generating code for a CALL statement. Write the body of the generatedCode instance method specified in the Program interface. Here are a few things to keep in mind:
    • The contracts for generatedCode and generateCodeForStatement are informal and vague. The details of the code to generate for each kind of statement are provided in the Code Generation slides (39-47, in particular). The code generated by your implementation must match the code-generation patterns described in the slides. To generate code for a given Program (this), generatedCode needs to generate code for the body of the program and append a HALT instruction at the end of that.
    • generatedCode must restore the value of this.
    • generateCodeForStatement has to be recursive, while generatedCode will not use recursion.
    • The code generator is responsible for catching the two possible remaining syntax errors, which are not checked by the parser, namely, undefined instructions and direct and/or indirect use of recursion. To check for these errors use the Reporter.assertElseFatalError(boolean, String) utility method you are using in the parser project.
    • When making a (recursive) call to generateCodeForStatement, be careful to follow best practice with aliases. In particular, if the reference for a Statement block is an alias provided by a Map context, perhaps by use of a call to context's value method, then it would be wrong to pass both block and context to the same method. You can avoid doing so by obtaining block using context's remove method instead. Of course, context's value will need to be restored by later adding this name-statement pair back to it. You should then ponder the happy accident that being thus careful about aliases has made it easier for you to catch the syntax errors discussed in the immediately preceding item.
  3. You can test your code generator implementation in a couple different ways. First use JUnit. Open the file Program1GeneratedCode1Test.java in the test folder and review the test cases provided to see how they are set up and how they attempt to test your implementation of the code generator. Run the JUnit test fixture and carefully review any test cases that fail. If that is not enough information to help you find the bug(s), you can also run the main program in Program1GeneratedCode1 and display the code generated by your implementation (but only for inputs that do not have any errors, including those that the code generator is supposed to catch). You can use the TestProgram1.bl file in the data folder in your project as test input. The main program generates two output files (both in the data folder): expected-output.txt that contains the correct output for the given input and actual-output.txt that is the output generated by your implementation. Use Eclipse's file compare feature you learned about in the previous labs to compare the two outputs. If your code does not work, you should create smaller test inputs that try to expose the bug(s) and make it easier to identify them. Fix all the bugs and make sure your code generator passes all the test cases to complete this lab.

Additional Activities

  1. Although it is a requirement of this lab (and a similar requirement will be in effect on the final exam) to generate code according to the patterns discussed in class, there are some optimizations that could, in principle, be applied to make the generated code shorter and more efficient. Discuss any such optimizations with your partner. Would you implement these optimizations as part of the code generator or as a separate phase following the code generation? What are the trade-offs between the two approaches?