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:

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):

  1. 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 .
  2. 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.

  3. In a shell window, cd to MYDIR
  4. Start Vortex by running run-vortex.
  5. 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.
  6. 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.)
  7. 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!
  8. 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.

  9. You can type help at the Vortex prompt to get a list of commands that you can run.
  10. You can quit Vortex by typing quit or Ctrl-D at the Vortex prompt.
  11. 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.
  12. 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:
  1. A factorial function. You can write it either recursively or iteratively.
  2. 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:

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.