Sunteți pe pagina 1din 3

Programming Project #3

CS 3510

Due: 10:30am

Develop a Code Generator that can take an AST and convert it into low-level code. Your
Code Generator should use the Scanner and Parser code you wrote on the first two
projects to create the AST. Your Code Generator should then convert this AST into a
low-level code format and print it to an output file. I will provide you with the internal
data representation for the low-level code; I will also provide a print method that will
print out the low-level code in a readable format.

Specific guidelines:
a. You will work in teams of 2 (or 3).
b. Since you now have several pieces, recommend you create an Compiler interface,
and instantiate a CMinusCompiler. Use main() within this class as your top-level
routine. It should open an input file containing C- code, call the Parser to create the
AST, then call the CodeGen module to create the low-level code.
c. Your routines will create low-level objects, in a tree-like structure, based on the
low-level classes I provide. For example, if you are generating code for a
binaryExpression which does an add, you will want to generate a low-level
Operation, which is of type add, has a new register destination, and uses register
sources as defined by your left and right children.
d. Your code does not have to handle arrays. You can also assume that a variable
name cannot be re-used in another scope. This will make your symbol table very
simple.
e. You should use the small test programs you wrote for Project #1/#2 to test the
output of your Code Generator.
f. If you wish, you can use the provided code to create an X86 assembly language
output file. This file can be copied over to Linux, compiled, and executed. For the
sequence of commands to generate this file, see the sample CMinusCompiler class
attached. However, the only I/O available (that I know how to do) is using the
function putchar. See the sample function I provided.
g. Here’s a quick description of the provided classes: At the top level are Data (global
vars) and Functions, which are both derived from CodeItem. Functions have
FuncParams and are made up of BasicBlocks. BasicBlocks contain Operations,
which are made up of source and destination Operands.
Discussion: There are at least 3 significant complexities you need to handle:
a. Register assignment. – You can assume that the target architecture has infinite
registers. (This is how compilers frequently handle the problem at this stage of
compilation). You will need to assign registers to each variable (and keep track of
this assignment in a poor-man’s symbol table; maybe just a linked list of variable
names and their register). You will also have to assign registers to hold temporary
results. Suggest you record these register assignments in an Integer field within
each AST node. You can do register assignment during the Code Generation pass,
or as a separate pass prior to Code Generation.
b. Function creation and stack frame management – Each function will be a self-
contained unit. Since we are not defining a format for passing parameters (i.e., via
register or via stack), you can use a generic Pass (R1) operation to indicate that
register 1 is to be passed to the subroutine. To return values, you should more the
result into the macro register “RetReg” before jumping to the return block. Then,
you can use a R1 = (RetReg) operation to receive the parameter within the called
function. You should also use generic FunctionEntry and FunctionExit operations
at the beginning and end of the function. (All of these generic functions would be
replaced in subsequent passes, when the code is tailored to a specific target
architecture. For now, we want to create target-independent code.) For frame
management, assume a Frame Pointer (FP) is available and will be initialized set
up properly by the FunctionEntry and FunctionExit operations. Since we are just
using integers, hopefully you won’t need to do much with FP.
c. Basic block layout – If and While statements cause complexity for code layout.
You need to generate code for the initial decision (which branch of If or whether to
enter While). For While, not entering the body requires a branch to the basic block
following the body, e.g., JNZ (BB4). The While body should terminate with a
JMP to the initial test. An If statement requires an initial test of which direction to
go, followed by the Then block (ended with a JMP to after the entire If statement).
The Else block will have to be generated after the Then block.
d. There is one thing I need to you to do to make the backend of my compiler work.
When you are generating a function call (from a CallExpr), you need to add an
Attribute to the actual call operation. An Attribute is like a name-value pair. You
need to add an Attribute called "numParams" ... and it's value will be String with a
count of the parameters passed to the function (new String(2)). I use this info to
generate the SP = SP+paramsize operation which has to follow function calls to fix
the stackframe.
e. If you are using X64, there’s another attribute you have to set, this time on the
PASS operation. The PASS operations need to be marked with PARAM_NUM,
which is an attribute specifying which parameter it is. You should number starting
in forward order (i.e., first parameter of function is marked 0, not in reverse order
like we discussed for X86. The command you need will be something like:
pass.addAttribute(new Attribute("PARAM_NUM", Integer.toString(argNum)));
Required for turn-in:
a. Listings of your Compiler and CodeGen package (properly commented, and in
compliance with CS Java style guide). If you have made significant changes to the
Scanner or Parser package, please include it also.
b. Listings of test input files and the output they created.
c. A signed statement regarding how well your final code worked. For example, “My
code compiled and ran properly, and produced the correct output” or “My code
compiled correctly, but core dumps when executed.”

S-ar putea să vă placă și