In this project, you will complete a compiler for SwiJay (called
JaySea, inspired by javac
) which
produces Java VM assembly (which can then be used to
generate classfiles).
You should mainly think of this as a compiler for Jay, except that one extra tricky part--switch statements---is added at the end.
Many other pieces are provided for you, and can be found in a tar file.
cp ~tvandrun/Public/cs365/proj6.tar .
The system works like this.
The program swijay/jaysea.py
reads in a swijay file and parses it.
Then the CompilerVisitor
(which your task is to finish implementing)
transforms that into Java assembly as defined for the
Jasmin tool (the output here is a .jj
file).
Then JaySea feeds the Java assembly into
Jasmin (whose output is a .class
file).
Finally JaySea executes the classfile using the Java VM.
Assembling and running the swijay program are optional.
The --no-run
flag makes JaySea produce
a .class
file supresses execution of the resulting file.
The --no-assem
flag supresses Jasmin
(and hence also supresses execution, since we wouldn't have a
.class
file to execute)
Your task is finishing the visit methods in
compilerVisitor.py
.
For all Jay statements and expressions, what series of
instructions needs to be emitted, and how does that
affect the stack?
Some specifics:
gen_lab()
.
Each label needs to have a consistent stack depth in the final version,
and the instance variable lab_tab
associates
labels with stack depths.
You can interact with this table using get_depth()
and
set_depth()
, but I recommend you mainly use
mark_lab()
, which associates a given lable
with the current stack depth.
Specifically, any time you emit an instruction that jumps to a label,
you should mark that label.
The variables of the program are stored as a list in
sym_tab
.
What you really want is the number for each variable, which
you can get from the index of that variable in sym_tab
emit()
function
takes a string and an integer;
the integer is the effect that the instruction has on the stack.
This keeps track of stack depth consistency and
the maximum stack depth.
If you emit a goto, you should adjust the stack by its current height
so that the resulting height is zero, since the instruction after
a goto must be the target of a jump or branch.
emit_lab()
to emit labels.
Make use of these resources:
Make your changes to JaySea incrementally.
Then gradually add statements and expressions.
Do switch statements last.
Switch statements can be compiled to the instruction
lookupswitch
(or, if you're really ambitious, tableswitch
).
Remember that the statements inside a switch are
called InSwitchStatements, and there are "regular" statements,
cases, breaks, and defaults.
You will need to do some processing of the whole switch statement
at the beginning to generate the switch instruction, and then
visit the InSwitchStatements.
As you work, I recommend you have
both Jay and Java versions of your test files.
Compile the Java versions and disassemble them with
javap
to see what the result might look like.
Your output does not have to be identical to what javac
produces--often there is an equivalent series of instructions that
you'll find are easier to produce---but javac
can guide you through some of the knottier statements.
All you need is a compiler that produces programs that work
to get full credit.
But there are some optimizations you could perform for which
I will award extra credit.
For example, if (x > 0)...
would naively
be complied by loading x, pushing 0, generating the
sequence for >, and then ifne
,
but a more efficient version would load x and use if_icmpgt
.
Also, x = x + 1;
could be done using the
iinc
instruction.
Some switch statements can be compiled to a tableswitch
instead of a lookupswitch
.
To turn in this project, please copy your compilerVisitor.py
and, if you did any optimizations for extra credit,
a text file describing what you did
to
/cslab.all/linux/class/cs365/(your id)/proj6
I will grade your project by running it against a collection of test files.
Due: Mon, April 4, 5:00 pm.