next up previous
Next: About this document

MASSACHVSETTS INSTITVTE OF TECHNOLOGY
Department of Electrical Engineering and Computer Science
6.001---Structure and Interpretation of Computer Programs
Spring Semester, 1999

Recitation -- Friday, April 30

1. Compilers

Here are some important ideas to understand about compilers.

  1. What is a compiler and how does it work?

    A compiler takes in a program in one language and produces a program in another language that does the same thing the original code did.

    One (simple but inefficient) way it can work is to just paste together code from an evaluator for the input language that is written in the output language.

  2. Why are some processes iterative and some recursive?

    If all procedures restore all the registers they save before making a call, it will lead to an iterative process.

    If a procedure calls itself while it has saved but not restored some registers, then it will lead to a recursive process.

  3. How does a compiler ``optimize'' the output program in ways that an interpreter cannot?

    The interpreter must both figure out what to do and also do it. This means the interpreter uses instructions to do the figuring out that the compiler does before the program runs.

    Also, the compiler can analyze the code sequences before combining them, so it can ``look into the future'' in a way that an interpreter cannot. (For example, it can figure out what registers do and don't need saved.)

  4. Given some compiled code, figure out what the original scheme expression was.

    We'll do an example of this later on.

2. Optimizing Saves and Restores

The explicit control evaluator always saves and restores the env register around the evaluation of the operator and each of the operands. Why?

For each of the following combinations, determine which of the save and restore operations are superfluous and thus could be eliminated by the compiler's ``preserving'' mechanism:

3. Compiling IFs

Here is the code from the explicit control evaluator for dealing with ifs.

A naive compiler would simply collect the used instructions. Compiling (if a b c) would yield:

By using stack discipline and targetting, we can create much more efficient registration machine code. Basic idea is to keep track of what registers are needed by an expression and what registers are changed by an expression, and combine these to decide what stack manipulations are actually necessary. What lines can be removed from the above compilation to more efficiently handle ifs?

Compiling (if a b c):

4. Decompiling Code - Short Examples

The following code results from the compilation of (define x 3).

The following code results from the compilation of (- x 2). For the evaluation of a combination, look for the procedure to be put into the proc register and the consing up of the argument list in the argl register. Remember that the arguments are evaluated right to left!

The following code results from the compilation of (if a b c). When you see labels like true-branch and false-branch, you should think if.

The following code results from the compilation of (lambda (x) x). Note that the body of the lambda (lines 3-7) are not evaluated. The label is just saved along with the current environment to make the procedure object.

5. More Decompiling Code

Below is a listing of code produced by the compiler. For each of the following sections of compiled code, determine the Scheme expression that produced it.

Lines 8--20:

Lines 30--40:

Lines 8--40:

Lines 1--46:





next up previous
Next: About this document



Michael E. Leventon
Fri Apr 30 10:04:15 EDT 1999