CSE 501: Implementation of Programming Languages
Course Project Information
[milestone 1 | milestone
2 | milestone 3 | code updates ]
Your project will consist of extending the Whirlwind
compiler developed here at UW with a few analyses and transformations.
The Whirlwind compiler is written in the Cecil
language, and the compiler for Cecil is called Vortex.
Milestone 0 (due by 5pm Friday Jan. 16th)
Task 1: Form groups
Form a group of 2 or 3 people, and send Craig and Sorin an email
with the names of the people in your group. He will assign you space in
the /projects/instr/04wi/cse501
directory. The sooner you do this, the sooner you will be able to get
started on Milestone 1.
Milestone 1 (due start of class on Monday
Jan. 26th)
Task 1: Experiment with Cecil (to be done
individually)
For small experimentation with simple Cecil code, the Cecil
evaluator is
a fine option. First, you need to log on to either a Linux or Solaris
machine;
you can use the instructional Linux machines (recycle, bicycle,
tricycle) or our
research project Linux machines (lagoon, swan, trifid, and helix) or
Solaris machines (monet,
matisse, vangogh, klee, rousseau). Now, you can run the Cecil evaluator
by
executing /cse/courses/misc_lang/vortex/run-cecil. At
the Cecil>
prompt, enter expressions you'd like to evaluate. You can invoke
any methods and instantiate any objects from the Cecil standard
library. You also can define your own objects, methods, fields,
and variables. You can write Cecil code in separate files, and
then evaluate
the contents of those files using Cecil include declarations.
(Cecil mode
for emacs is available here.) The
evaluator will perform typechecking of any expressions or declarations
you
enter. It's even possible to redefine methods and fields;
duplicate
declarations of variables and objects will be ignored. Some
additional information is available
in /cse/courses/misc_lang/vortex/notes/QUICK-START-CECIL; $VORTEX_HOME
in that file (and the rest of this page) refers to /cse/courses/misc_lang/vortex.
You should also look at the following manuals to get yourself familiar
with Cecil:
- The Cecil language reference manual:
postscript,
gzipped
postscript
- Sections 1 and 2 are the main parts
- Sections 3 and 4 should be skimmed to see how to read &
write simple type declarations, but you can skip over the typechecking
and constraint-solving details
- The Cecil standard library reference manual:
postscript,
gzipped
postscript
- A quick Cecil tutorial is available here.
- We will cover this kind of material in our tutorial session.
Task 2: Get a copy of the Vortex tree, run Vortex, and compile a
program in Vortex
The interpreter is useful for experimenting with small Cecil
programs, but for larger programs (like Whirlwind), the Vortex compiler
is the best tool. Vortex is an
optimizing compiler for Cecil, as well as a number of other
object-oriented languages like Java, C++, Modula-3, and
Smalltalk. (The Vortex compiler includes the functionality of the
Cecil evaluator, too, so if you start up Vortex, you can do all the
things at the Vortex> prompt that you could do at the Cecil>
prompt.)
First, each group needs to install a copy of the Vortex tree in a
CVS repository,
and then each group member needs to checkout a copy of the Vortex tree
from
that repository. We will be using the vendor branch feature of CVS to
get you set up.
We will provide you with a tar file and each group will create a CVS
repository with the contents of this tar file. Then each group will use
their CVS repository to manage the development of their local code. If
there are bug fixes that we wish to provide you with, we will give you
a new tar file, and each
group will import this tar file into their CVS repository. Instructions
on how to do this are here.
Now that each student has a copy of Vortex, you can start
experimenting. To compile a Cecil program using Vortex, follow these
steps (look at the How
to Use the Vortex Compiler manual for more information, or look
at $VORTEX_HOME/notes/QUICK-START-VORTEX):
- Create one (or more) files with Cecil code in some directory.
Let's say the directory is MYDIR and the main file is called mytest.cecil
.
There is a lot of Cecil code to look at for examples, all under $VORTEX_HOME/Cecil/src.
You may want to start by browsing benchmarks/tiny, contrib,
and stdlib (sources for the standard library except the
evaluator). The Vortex compiler source code is in the compiler
subdirectory. The Whirlwind compiler source code is in the whirlwind
subdirectory. The Cecil mode for emacs is here.
- In a shell window, cd to MYDIR .
- Start Vortex by running run-vortex.
- At the Vortex> prompt, type typecheck mytest (or tc
mytest) to typecheck your program. After doing program editing, you can do typecheck
(or tc) again to typecheck only the files you changed or that
had type errors previously, or fulltypecheck
to retypecheck everything. Although Vortex does not require you to
typecheck the code before compiling, it's always a good idea to
typecheck first, since it will help you catch errors earlier.
- To compile your program, type make. If you later make changes to
your program, just type tc and make again to recompile it. You
generally should keep Vortex running while doing editing, compiling, and
testing, so that Vortex will incrementally recompile your program rather than
starting from scratch to recompile your program. (And see the instructions
about saving and loading checkpoints, below.)
- Run your program by typing run at the Vortex>
prompt. Alternatively, you can run the program by going to another
shell, and running the executable MYDIR/gen/mytest. Hope it
works!
A good way to debug your program is, well, to use the debugger.
Put breakpoint(); as the last line in your program (or
wherever you want to suspend execution). When this expression is
executed, the program will give you the debugging prompt ( debug>
), and you can use the full capabilities of the Cecil
debugger/evaluator to interact with your program. In particular, you
can type in Cecil expressions and see
their values; if suspended at a breakpoint, your expression can
reference any of the local variables in scope of the suspended method.
Moreover, you can type in (or paste) the methods you want
to
add (or replace) to your program, and they will be available to you
without recompiling the program. Similarly, you can add variable
declarations. Press
Ctrl-D to exit the debugger (or type help for more
options). The print_line method, which takes a string
argument and prints it, followed by a newline, is another handy,
low-tech debugging tool, analogous to C's printf.
The way the evaluator prints out values is by sending them the print_string
message. By convention, this message returns a string that's a
printable representation of its argument, but does not print anything
itself. The debugger prints that string out. So if you define new kinds
of objects
in your program, you may also want to define the print_string
methods so they print out nicely. Here's an example:
method print_string(p@:pair[`A,`B]):string {
"(" || p.first.print_string || "," || p.second.print_string || ")" }
Remember that the debug> prompt is provided by your
running program (and this is the place to add new methods and evaluate
expressions), while the Vortex> prompt is printed by the
compiler, and you should only issue compiler commands (like make)
at that prompt.
- You can type help at the Vortex prompt to get a list of
commands that you can run.
- You can quit Vortex by typing quit or Ctrl-D at the
Vortex prompt.
- Vortex allows you to save a checkpoint (the state of Vortex) to a
file. Checkpointing is very important! Once Vortex has compiled a
program, it has done a lot of work that you don't want to repeat (for
example, parsing the files and compiling them). If you simply quit
Vortex,
and then run it again, Vortex will start everything from scratch. So
before you quit Vortex, you should checkpoint the state of the
compiler, so that you can restore it later. The command save
will save the state of the compiler to the file mytest.db,
assuming that the program being compiled is mytest. When you
restart Vortex later, the command load mytest.db will restore
the state of the compiler. Because you are sharing your machine
with others,
you should save and quit Vortex when you are done using it, and then
restore the state later when need to run Vortex again. However, you can
keep Vortex running while you debug and edit your program; you don't
need to exit Vortex after each make. Vortex has incremental
compilation: if you change a file in your source program, and type make
or tc, it will reparse/retypecheck/recompile only those parts
that have changed.
- There are several variations on the basic make command.
The makeo1
and makeo2 commands set of the optimization level to
1 and 2 respectively. Prepending the letter p to any make
command (for example pmakeo2) will perform the C compilation
phase in parallel on several machines; much faster!. (Type help
make for more details.)
Turning on optimization doesn't preclude debugging; Vortex does
work to try to preserve the illusion of unoptimized code in its
debugger, even in the face of Vortex's reams of inlining.
However, in the face of optimization, not all methods can have
breakpoints set on them, and not all methods can be replaced at the debug>
prompt. To avoid this problem, you can compile most of your
program with optimization, and recompile without optimization those
parts of your program that you want to debug heavily. Better, see
the manual below for information on how retain full debuggability for
files even in the face of full optimization using (**debug**)
pragmas.
You should look at the following manual for more details about how
Vortex works.
Task 3: Compile Whirlwind (to be done
individually)
You are now ready to compile Whirlwind. The source for Whirlwind
is located in $VORTEX_HOME/Cecil/src/whirlwind. Vortex
already has this directory in its source path list, so you can
compile Whirlwind from any directory. Thus pick a directory where you
want
your generated C files and object files to be stored for the whirlwind
program.
Let's
say you choose /projects/instr/04wi/cse501/cse501a/myName/ww.
Now run:
% mkdir /projects/instr/04wi/cse501/cse501a/myName/ww
% cd
/projects/instr/04wi/cse501/cse501a/myName/ww
% $VORTEX_HOME/run-vortex
Vortex> tc whirlwind
... lots of nice output ...
Vortex> makeo2
... more reams of output ...
Vortex> save
... saves whirlwind.db, for later reference ...
Task 4: Compile a WIL program using Whirlwind (to
be done individually)
The
file $VORTEX_HOME/Cecil/src/whirlwind/notes/ir.txt documents
the WIL
intermediate language. Whirlwind test files written in WIL are in
$VORTEX_HOME/Cecil/src/whirlwind/tests;
the file test.wil is the root file that includes and runs all
the tests. Test out your Whirlwind compiler by compiling and
running these tests.
Whirlwind already has the tests directory in its source path
list, so you can
compile test.wil from any directory. Thus, pick a directory
where you
want
your generated C files and object files to be stored for the test
program.
Let's
say you choose /projects/instr/04wi/cse501/cse501a/myName/test.
Now run:
% mkdir /projects/instr/04wi/cse501/cse501a/myName/test
% cd /projects/instr/04wi/cse501/cse501a/myName/test
% /projects/instr/04wi/cse501/cse501a/myName/ww/gen/whirlwind
Whirlwind> makeo2 test
... lots of nice output ...
Whirlwind> save
... saves test.db, for later reference ...
Whirlwind> run
... output of the gen/test program, hopefully all successful ...
The makeo2 command compiles with optimization level 2.
Anything above 0 will turn (Whirlwind) optimizations on.
Task 5: Implement propositional formulae in Cecil (to be done individually)
You will develop an implementation of propositional logic
formulae in Cecil. Instructions for this task can be found here.
Task 6: Implement factorial in WIL (to be
done individually)
Write the factorial function in WIL. You should start with the
following file.
To this file you should add:
- A factorial function. You can write it either recursively or
iteratively.
- Some code in main that continually asks the user for a
number n,
and prints "n! = ..." until the number n entered by the
user is -1.
You should not use any prim statements in the code that you
add. Compile your program using Whirlwind, and test it out.
Deliverables for Milestone 1
Each student should send an email to Craig and Sorin by the
beginning of class on Mon. Jan 26th with the following attachments:
- Your modified logic.cecil and logic-tests.cecil
files
- A file showing the output of running the test code in logic-tests.cecil
- The WIL file containing your factorial implementation
- A file showing some sample input/output runs for factorial program
Milestone 2 (due Wednesday Feb 18th)
Task 1: Understand Java WIL (To be done
individually)
Explain in your own words how Java objects are represented in WIL. To
learn how Java is translated into WIL, take a look at the simple Java
example in $VORTEX_HOME/Java/src/example/src. The WIL files
generated
for this example by the Java-to-WIL front-end are in /projects/cecil/vortex-root/vortex/Java/src/example/wil
(just take a look at the *.wil files in this directory). Don't forget
to also look at $VORTEX_HOME/Cecil/src/whirlwind/notes/ir.txt
for
documentation on the WIL intermediate language.
Task 2: Implement pointer analysis in Whirlwind
(To be done in groups)
Details about the pointer analysis can be found here.
Deliverables for Milestone 2
Each student should hand in their explanation of Java WIL by the beginning
of class on Wed. Feb 18th.
One member from each group should send an email to Craig and Sorin by
the beginning of class on Wed. Feb 18th with your modified pts-to.cecil file as an
attachment.
Milestone 3 (due Monday March 8th)
Implement Rapid Type Analysis in Whirlwind.
Details can be found here.