Jeremy Siek 4 年之前
父节点
当前提交
2229f55d7c
共有 1 个文件被更改,包括 157 次插入166 次删除
  1. 157 166
      book.tex

+ 157 - 166
book.tex

@@ -134,7 +134,7 @@ showstringspaces=false
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
 
 \title{\Huge \textbf{Essentials of Compilation} \\
 \title{\Huge \textbf{Essentials of Compilation} \\
-  \huge An Incremental Approach}
+  \huge The Incremental, Nano-Pass Approach}
 
 
 \author{\textsc{Jeremy G. Siek} \\
 \author{\textsc{Jeremy G. Siek} \\
 %\thanks{\url{http://homes.soic.indiana.edu/jsiek/}} \\
 %\thanks{\url{http://homes.soic.indiana.edu/jsiek/}} \\
@@ -188,15 +188,19 @@ The compiler course evolved to incorporate novel pedagogical ideas
 while also including elements of effective real-world compilers.  One
 while also including elements of effective real-world compilers.  One
 of Friedman's ideas was to split the compiler into many small
 of Friedman's ideas was to split the compiler into many small
 ``passes'' so that the code for each pass would be easy to understood
 ``passes'' so that the code for each pass would be easy to understood
-in isolation.  (In contrast, most compilers of the time were organized
+in isolation.  In contrast, most compilers of the time were organized
 into only a few monolithic passes for reasons of compile-time
 into only a few monolithic passes for reasons of compile-time
-efficiency.)  Dybvig, with later help from his students Dipanwita
-Sarkar and Andrew Keep, developed infrastructure to support this
-approach and evolved the course, first to use smaller micro-passes and
-then into even smaller
-nano-passes~\citep{Sarkar:2004fk,Keep:2012aa}. I was a student in this
-compiler course in the early 2000's as part of his Ph.D. studies at
-Indiana University. Needless to say, I enjoyed the course immensely!
+efficiency. Another idea, called ``the game'', was to test the code
+generated by each pass on interpreters for each intermediate language,
+thereby helping to pinpoint errors in individual passes.
+%
+Dybvig, with later help from his students Dipanwita Sarkar and Andrew
+Keep, developed infrastructure to support this approach and evolved
+the course, first to use smaller micro-passes and then into even
+smaller nano-passes~\citep{Sarkar:2004fk,Keep:2012aa}. I was a student
+in this compiler course in the early 2000's as part of my
+Ph.D. studies at Indiana University. Needless to say, I enjoyed the
+course immensely!
 
 
 During that time, another graduate student named Abdulaziz Ghuloum
 During that time, another graduate student named Abdulaziz Ghuloum
 observed that the front-to-back organization of the course made it
 observed that the front-to-back organization of the course made it
@@ -219,30 +223,28 @@ same content from the Indiana compiler course. I very much enjoyed
 teaching the course organized in this way, and even better, many of
 teaching the course organized in this way, and even better, many of
 the students learned a lot and got excited about compilers.
 the students learned a lot and got excited about compilers.
 
 
-I returned to teach at Indiana University in 2013.  In my absence the
-compiler course had switched from the front-to-back organization to a
-back-to-front organization. Seeing how well the incremental approach
-worked at Colorado, I started porting and adapting the structure of
-the Colorado course back into the land of Scheme. In the meantime
-Indiana University had moved on from Scheme to Racket, so the course
-is now about compiling a subset of Racket (and Typed Racket) to the
-x86 assembly language. The compiler is implemented in
-Racket~\citep{plt-tr}.
+I returned to Indiana University in 2013.  In my absence the compiler
+course had switched from the front-to-back organization to a
+back-to-front organization~\cite{Dybvig:2010aa}. Seeing how well the
+incremental approach worked at Colorado, I started porting and
+adapting the structure of the Colorado course back into the land of
+Scheme. In the meantime Indiana University had moved on from Scheme to
+Racket~\citep{plt-tr}, so the course is now about compiling a subset
+of Racket (and Typed Racket) to the x86 assembly language.
 
 
 This is the textbook for the incremental version of the compiler
 This is the textbook for the incremental version of the compiler
-course at Indiana University (Spring 2016 - present) and it is the
-first open textbook for an Indiana compiler course.  With this book I
-hope to make the Indiana compiler course available to people that have
-not had the chance to study compilers at Indiana University.  Many of
-the compiler design decisions in this book are drawn from the
-assignment descriptions of \cite{Dybvig:2010aa}. I have captured what
-I think are the most important topics from \cite{Dybvig:2010aa} but
-have omitted topics that are less interesting conceptually. I have
-also made simplifications to reduce complexity.  In this way, this
-book leans more towards pedagogy than towards the efficiency of the
-generated code. Also, the book differs in places where we I the
-opportunity to make the topics more fun, such as in relating register
-allocation to Sudoku (Chapter~\ref{ch:register-allocation-r1}).
+course at Indiana University (Spring 2016 - present).  With this book
+I hope to make the Indiana compiler course available to people that
+have not had the chance to study compilers at Indiana University.
+
+%% I have captured what
+%% I think are the most important topics from \cite{Dybvig:2010aa} but
+%% have omitted topics that are less interesting conceptually. I have
+%% also made simplifications to reduce complexity.  In this way, this
+%% book leans more towards pedagogy than towards the efficiency of the
+%% generated code. Also, the book differs in places where we I the
+%% opportunity to make the topics more fun, such as in relating register
+%% allocation to Sudoku (Chapter~\ref{ch:register-allocation-r1}).
 
 
 \section*{Prerequisites}
 \section*{Prerequisites}
 
 
@@ -289,11 +291,12 @@ is to run a virtual machine with Linux as the guest operating system.
 \section*{Acknowledgments}
 \section*{Acknowledgments}
 
 
 Many people have contributed to the ideas, techniques, and
 Many people have contributed to the ideas, techniques, and
-organization of this book and have taught courses based on it. We
-especially thank John Clements, Bor-Yuh Evan Chang, Kent Dybvig,
-Daniel P. Friedman, Ronald Garcia, Abdulaziz Ghuloum, Andrew Keep, Jay
-McCarthy, Nate Nystrom, Dipanwita Sarkar, Oscar Waddell, and Michael
-Wollowski.
+organization of this book and have taught courses based on it.  Many
+of the compiler design decisions in this book are drawn from the
+assignment descriptions of \cite{Dybvig:2010aa}.  We also would like
+to thank John Clements, Bor-Yuh Evan Chang, Daniel P. Friedman, Ronald
+Garcia, Abdulaziz Ghuloum, Jay McCarthy, Nate Nystrom, Dipanwita
+Sarkar, Oscar Waddell, and Michael Wollowski.
 
 
 \mbox{}\\
 \mbox{}\\
 \noindent Jeremy G. Siek \\
 \noindent Jeremy G. Siek \\
@@ -313,44 +316,37 @@ called \emph{concrete syntax}. We use concrete syntax to concisely
 write down and talk about programs. Inside the compiler, we use
 write down and talk about programs. Inside the compiler, we use
 \emph{abstract syntax trees} (ASTs) to represent programs in a way
 \emph{abstract syntax trees} (ASTs) to represent programs in a way
 that efficiently supports the operations that the compiler needs to
 that efficiently supports the operations that the compiler needs to
-perform.
-\index{concrete syntax}
-\index{abstract syntax}
-\index{abstract syntax tree}
-\index{AST}
-\index{program}
-\index{parse}
-%
-The translation from concrete syntax to abstract syntax is a process
-called \emph{parsing}~\cite{Aho:1986qf}. We do not cover the theory
-and implementation of parsing in this book. A parser is provided in
-the supporting materials for translating from concrete syntax to
-abstract syntax for the languages used in this book.
+perform.\index{concrete syntax}\index{abstract syntax}\index{abstract
+  syntax tree}\index{AST}\index{program}\index{parse} The translation
+from concrete syntax to abstract syntax is a process called
+\emph{parsing}~\citep{Aho:1986qf}. We do not cover the theory and
+implementation of parsing in this book. A parser is provided in the
+supporting materials for translating from concrete to abstract syntax.
 
 
 ASTs can be represented in many different ways inside the compiler,
 ASTs can be represented in many different ways inside the compiler,
 depending on the programming language used to write the compiler.
 depending on the programming language used to write the compiler.
 %
 %
-We use Racket's \href{https://docs.racket-lang.org/guide/define-struct.html}{\code{struct}}
+We use Racket's
+\href{https://docs.racket-lang.org/guide/define-struct.html}{\code{struct}}
 feature to represent ASTs (Section~\ref{sec:ast}). We use grammars to
 feature to represent ASTs (Section~\ref{sec:ast}). We use grammars to
-define the abstract syntax of programming languages (Section~\ref{sec:grammar})
-and pattern matching to inspect individual nodes in an AST
-(Section~\ref{sec:pattern-matching}).  We use recursion to construct
-and deconstruct entire ASTs (Section~\ref{sec:recursion}).  This
-chapter provides an brief introduction to these ideas.
-\index{struct}
+define the abstract syntax of programming languages
+(Section~\ref{sec:grammar}) and pattern matching to inspect individual
+nodes in an AST (Section~\ref{sec:pattern-matching}).  We use
+recursive functions to construct and deconstruct entire ASTs
+(Section~\ref{sec:recursion}).  This chapter provides an brief
+introduction to these ideas.  \index{struct}
 
 
 \section{Abstract Syntax Trees and Racket Structures}
 \section{Abstract Syntax Trees and Racket Structures}
 \label{sec:ast}
 \label{sec:ast}
 
 
-Compilers use abstract syntax trees to represent programs because
-compilers often need to ask questions like: for a given part of a
-program, what kind of language feature is it? What are the sub-parts
-of this part of the program? Consider the program on the left and its
-AST on the right. This program is an addition and it has two
-sub-parts, a read operation and a negation. The negation has another
-sub-part, the integer constant \code{8}. By using a tree to represent
-the program, we can easily follow the links to go from one part of a
-program to its sub-parts.
+Compilers use abstract syntax trees to represent programs because they
+often need to ask questions like: for a given part of a program, what
+kind of language feature is it? What are its sub-parts? Consider the
+program on the left and its AST on the right. This program is an
+addition and it has two sub-parts, a read operation and a
+negation. The negation has another sub-part, the integer constant
+\code{8}. By using a tree to represent the program, we can easily
+follow the links to go from one part of a program to its sub-parts.
 \begin{center}
 \begin{center}
 \begin{minipage}{0.4\textwidth}
 \begin{minipage}{0.4\textwidth}
 \begin{lstlisting}
 \begin{lstlisting}
@@ -452,10 +448,10 @@ We say that the value created by \code{(Int 8)} is an
 
 
 The following is the \code{struct} definition for primitives operations.
 The following is the \code{struct} definition for primitives operations.
 \begin{lstlisting}
 \begin{lstlisting}
-(struct Prim (op arg*))
+(struct Prim (op args))
 \end{lstlisting}
 \end{lstlisting}
 A primitive operation node includes an operator symbol \code{op}
 A primitive operation node includes an operator symbol \code{op}
-and a list of children \code{arg*}. For example, to create
+and a list of children \code{args}. For example, to create
 an AST that negates the number $8$, we write \code{(Prim '- (list eight))}.
 an AST that negates the number $8$, we write \code{(Prim '- (list eight))}.
 \begin{lstlisting}
 \begin{lstlisting}
 (define neg-eight (Prim '- (list eight)))
 (define neg-eight (Prim '- (list eight)))
@@ -521,13 +517,12 @@ instance of the \code{Int} structure is an expression:
 \end{equation}
 \end{equation}
 %
 %
 Each rule has a left-hand-side and a right-hand-side. The way to read
 Each rule has a left-hand-side and a right-hand-side. The way to read
-a rule is that if you have all the program parts on the
-right-hand-side, then you can create an AST node and categorize it
-according to the left-hand-side.
+a rule is that if you have an AST node that matches the
+right-hand-side, then you can categorize it according to the
+left-hand-side.
 %
 %
-A name such as $\Exp$ that is
-defined by the grammar rules is a \emph{non-terminal}.
-\index{non-terminal}
+A name such as $\Exp$ that is defined by the grammar rules is a
+\emph{non-terminal}.  \index{non-terminal}
 %
 %
 The name $\Int$ is a also a non-terminal, but instead of defining it
 The name $\Int$ is a also a non-terminal, but instead of defining it
 with a grammar rule, we define it with the following explanation.  We
 with a grammar rule, we define it with the following explanation.  We
@@ -557,10 +552,9 @@ Symbols in typewriter font such as \key{-} and \key{read} are
 the rule to be applicable.
 the rule to be applicable.
 \index{terminal}
 \index{terminal}
 
 
-We can apply the rules to build ASTs in the $R_0$
-language. For example, by rule \eqref{eq:arith-int}, \texttt{(Int 8)} is an
-$\Exp$, then by rule \eqref{eq:arith-neg}, the following AST is
-an $\Exp$.
+We can apply these rules to build ASTs in the $R_0$ language. By rule
+\eqref{eq:arith-int}, \texttt{(Int 8)} is an $\Exp$, then by rule
+\eqref{eq:arith-neg}, the following AST is an $\Exp$.
 \begin{center}
 \begin{center}
 \begin{minipage}{0.4\textwidth}
 \begin{minipage}{0.4\textwidth}
 \begin{lstlisting}
 \begin{lstlisting}
@@ -586,8 +580,8 @@ The next grammar rule defines addition expressions:
 \end{equation}
 \end{equation}
 We can now justify that the AST \eqref{eq:arith-prog} is an $\Exp$ in
 We can now justify that the AST \eqref{eq:arith-prog} is an $\Exp$ in
 $R_0$.  We know that \lstinline{(Prim 'read '())} is an $\Exp$ by rule
 $R_0$.  We know that \lstinline{(Prim 'read '())} is an $\Exp$ by rule
-\eqref{eq:arith-read} and we have already shown that \code{(Prim '-
-  (list (Int 8)))} is an $\Exp$, so we apply rule \eqref{eq:arith-add}
+\eqref{eq:arith-read} and we have already categorized \code{(Prim '-
+  (list (Int 8)))} as an $\Exp$, so we apply rule \eqref{eq:arith-add}
 to show that
 to show that
 \begin{lstlisting}
 \begin{lstlisting}
 (Prim '+ (list (Prim 'read '()) (Prim '- (list (Int 8)))))
 (Prim '+ (list (Prim 'read '()) (Prim '- (list (Int 8)))))
@@ -636,7 +630,7 @@ Appendix~\ref{appendix:utilities} for more details.
 \[
 \[
 \begin{array}{rcl}
 \begin{array}{rcl}
 \begin{array}{rcl}
 \begin{array}{rcl}
-  \Exp &::=& \Int \mid (\key{read}) \mid (\key{-}\;\Exp) \mid (\key{+} \; \Exp\;\Exp)\\
+  \Exp &::=& \Int \mid \LP\key{read}\RP \mid \LP\key{-}\;\Exp\RP \mid \LP\key{+} \; \Exp\;\Exp\RP\\
   R_0 &::=& \Exp
   R_0 &::=& \Exp
 \end{array}
 \end{array}
 \end{array}
 \end{array}
@@ -704,14 +698,15 @@ Reference\footnote{\url{https://docs.racket-lang.org/reference/match.html}}
 for a complete description of \code{match}.)
 for a complete description of \code{match}.)
 %
 %
 The body of a match clause may contain arbitrary Racket code.  The
 The body of a match clause may contain arbitrary Racket code.  The
-pattern variables can be used in the scope of the body.
+pattern variables can be used in the scope of the body, such as
+\code{op} in \code{(print op)}.
 
 
 A \code{match} form may contain several clauses, as in the following
 A \code{match} form may contain several clauses, as in the following
-function \code{leaf?} that recognizes when an $R_0$ node is
-a leaf. The \code{match} proceeds through the clauses in order,
-checking whether the pattern can match the input AST. The
-body of the first clause that matches is executed. The output of
-\code{leaf?} for several ASTs is shown on the right.
+function \code{leaf?} that recognizes when an $R_0$ node is a leaf in
+the AST. The \code{match} proceeds through the clauses in order,
+checking whether the pattern can match the input AST. The body of the
+first clause that matches is executed. The output of \code{leaf?} for
+several ASTs is shown on the right.
 \begin{center}
 \begin{center}
 \begin{minipage}{0.6\textwidth}
 \begin{minipage}{0.6\textwidth}
 \begin{lstlisting}
 \begin{lstlisting}
@@ -719,8 +714,8 @@ body of the first clause that matches is executed. The output of
   (match arith
   (match arith
     [(Int n) #t]
     [(Int n) #t]
     [(Prim 'read '()) #t]
     [(Prim 'read '()) #t]
-    [(Prim '- (list c1)) #f]
-    [(Prim '+ (list c1 c2)) #f]))
+    [(Prim '- (list e1)) #f]
+    [(Prim '+ (list e1 e2)) #f]))
 
 
 (leaf? (Prim 'read '()))
 (leaf? (Prim 'read '()))
 (leaf? (Prim '- (list (Int 8))))
 (leaf? (Prim '- (list (Int 8))))
@@ -753,13 +748,13 @@ in the \code{leaf?} function, we refer to the grammar for $R_0$ in
 Figure~\ref{fig:r0-syntax}. The $\Exp$ non-terminal has 4
 Figure~\ref{fig:r0-syntax}. The $\Exp$ non-terminal has 4
 alternatives, so the \code{match} has 4 clauses.  The pattern in each
 alternatives, so the \code{match} has 4 clauses.  The pattern in each
 clause corresponds to the right-hand side of a grammar rule. For
 clause corresponds to the right-hand side of a grammar rule. For
-example, the pattern \code{(Prim '+ (list c1 c2))} corresponds to the
+example, the pattern \code{(Prim '+ (list e1 e2))} corresponds to the
 right-hand side $\ADD{\Exp}{\Exp}$. When translating from grammars to
 right-hand side $\ADD{\Exp}{\Exp}$. When translating from grammars to
 patterns, replace non-terminals such as $\Exp$ with pattern variables
 patterns, replace non-terminals such as $\Exp$ with pattern variables
-of your choice (e.g. \code{c1} and \code{c2}).
+of your choice (e.g. \code{e1} and \code{e2}).
 
 
 
 
-\section{Recursion}
+\section{Recursive Functions}
 \label{sec:recursion}
 \label{sec:recursion}
 \index{recursive function}
 \index{recursive function}
 
 
@@ -770,17 +765,16 @@ such a recursive function, we define \texttt{exp?} below, which takes
 an arbitrary value and determines whether or not it is an $R_0$
 an arbitrary value and determines whether or not it is an $R_0$
 expression.
 expression.
 %
 %
-When a recursive function is defined using a sequence of match clauses
-that correspond to a grammar, and the body of each clause makes a
-recursive call on each child node, then we say the function is defined
-by \emph{structural recursion}\footnote{This principle of structuring
-  code according to the data definition is advocated in the book
-  \emph{How to Design Programs}
-  \url{http://www.ccs.neu.edu/home/matthias/HtDP2e/}.}. Below we also
-define a second function, named \code{R0?}, that determines whether a
-value is an $R_0$ program.  In general we can expect to write one
-recursive function to handle each non-terminal in a grammar.
-\index{structural recursion}
+We say that a function is defined by \emph{structural recursion} when
+it is defined using a sequence of match clauses that correspond to a
+grammar, and the body of each clause makes a recursive call on each
+child node.\footnote{This principle of structuring code according to
+  the data definition is advocated in the book \emph{How to Design
+    Programs}\url{http://www.ccs.neu.edu/home/matthias/HtDP2e/}.}.
+Below we also define a second function, named \code{R0?}, that
+determines whether an AST is an $R_0$ program.  In general we can
+expect to write one recursive function to handle each non-terminal in
+a grammar.\index{structural recursion}
 %
 %
 \begin{center}
 \begin{center}
 \begin{minipage}{0.7\textwidth}
 \begin{minipage}{0.7\textwidth}
@@ -850,27 +844,23 @@ it comes to the \code{Program} wrapper.  Yet this style is generally
 %
 %
 For example, the above function is subtly wrong:
 For example, the above function is subtly wrong:
 \lstinline{(R0? (Program '() (Program '() (Int 3))))}
 \lstinline{(R0? (Program '() (Program '() (Int 3))))}
-will return true, when it should return false.
-
-%% NOTE FIXME - must check for consistency on this issue throughout.
+would return true, when it should return false.
 
 
 
 
 \section{Interpreters}
 \section{Interpreters}
 \label{sec:interp-R0}
 \label{sec:interp-R0}
 \index{interpreter}
 \index{interpreter}
 
 
-The meaning, or semantics, of a program is typically defined in the
+In general, the intended behavior of a program is defined by the
 specification of the language. For example, the Scheme language is
 specification of the language. For example, the Scheme language is
 defined in the report by \cite{SPERBER:2009aa}. The Racket language is
 defined in the report by \cite{SPERBER:2009aa}. The Racket language is
-defined in its reference manual~\citep{plt-tr}. In this book we use an
-interpreter to define the meaning of each language that we consider,
-following Reynolds' advice~\citep{reynolds72:_def_interp}. An
-interpreter that is designated (by some people) as the definition of a
-language is called a \emph{definitional interpreter}.
-\index{definitional interpreter}
-We warm up by creating a definitional interpreter for the $R_0$ language, which
-serves as a second example of structural recursion. The
-\texttt{interp-R0} function is defined in
+defined in its reference manual~\citep{plt-tr}. In this book we use
+interpreters to specify each language that we consider. An interpreter
+that is designated as the definition of a language is called a
+\emph{definitional interpreter}~\citep{reynolds72:_def_interp}.
+\index{definitional interpreter} We warm up by creating a definitional
+interpreter for the $R_0$ language, which serves as a second example
+of structural recursion. The \texttt{interp-R0} function is defined in
 Figure~\ref{fig:interp-R0}. The body of the function is a match on the
 Figure~\ref{fig:interp-R0}. The body of the function is a match on the
 input program followed by a call to the \lstinline{interp-exp} helper
 input program followed by a call to the \lstinline{interp-exp} helper
 function, which in turn has one match clause per grammar rule for
 function, which in turn has one match clause per grammar rule for
@@ -1197,7 +1187,7 @@ interpreters. We want to write down those common parts just once
 instead of many times. A naive approach would be to have, for example,
 instead of many times. A naive approach would be to have, for example,
 the interpreter for $R_2$ handle all of the new features in that
 the interpreter for $R_2$ handle all of the new features in that
 language and then have a default case that dispatches to the
 language and then have a default case that dispatches to the
-interpreter for $R_1$. The follow code sketches this idea.
+interpreter for $R_1$. The following code sketches this idea.
 \begin{center}
 \begin{center}
   \begin{minipage}{0.45\textwidth}
   \begin{minipage}{0.45\textwidth}
 \begin{lstlisting}
 \begin{lstlisting}
@@ -1242,7 +1232,7 @@ To make our intepreters extensible we need something called \emph{open
 always invoke the ``top'' interpreter, even if the recursive call is
 always invoke the ``top'' interpreter, even if the recursive call is
 made from interpreters that are lower down.  Object-oriented languages
 made from interpreters that are lower down.  Object-oriented languages
 provide open recursion in the form of method overriding\index{method
 provide open recursion in the form of method overriding\index{method
-  overriding}. The follow code sketches this idea for interpreting
+  overriding}. The following code sketches this idea for interpreting
 $R_1$ and $R_2$ using the
 $R_1$ and $R_2$ using the
 \href{https://docs.racket-lang.org/guide/classes.html}{\code{class}}
 \href{https://docs.racket-lang.org/guide/classes.html}{\code{class}}
 \index{class} feature of Racket.  We define one class for each
 \index{class} feature of Racket.  We define one class for each
@@ -1297,12 +1287,13 @@ expression by creating an object of the $R_2$ class and sending it the
 \begin{lstlisting}
 \begin{lstlisting}
 (send (new interp-R2-class) interp-exp e0)
 (send (new interp-R2-class) interp-exp e0)
 \end{lstlisting}
 \end{lstlisting}
-This will again hit the default case and dispatch to the
-\code{interp-exp} method for $R_1$, which will handle the \code{-}
-operator. But then for the recursive method call, it will dispatch
-back to \code{interp-exp} for $R_2$, where the \code{If} will be
-correctly handled. Thus, method overriding gives us the open recursion
-that we need to implement our interpreters in an extensible way.
+This will again hit the default case of \code{interp-exp} in $R_2$ and
+dispatch to the \code{interp-exp} method for $R_1$, which will handle
+the \code{-} operator. But then for the recursive method call, it will
+dispatch back to \code{interp-exp} for $R_2$, where the \code{If} will
+be correctly handled. Thus, method overriding gives us the open
+recursion that we need to implement our interpreters in an extensible
+way.
 
 
 \newpage
 \newpage
 
 
@@ -3840,9 +3831,9 @@ shown in Figure~\ref{fig:reg-alloc-passes}.
 \path[->,bend left=15] (R1-2) edge [above] node {\ttfamily\footnotesize remove-complex.} (R1-3);
 \path[->,bend left=15] (R1-2) edge [above] node {\ttfamily\footnotesize remove-complex.} (R1-3);
 \path[->,bend left=15] (R1-3) edge [right] node {\ttfamily\footnotesize explicate-control} (C0-1);
 \path[->,bend left=15] (R1-3) edge [right] node {\ttfamily\footnotesize explicate-control} (C0-1);
 \path[->,bend right=15] (C0-1) edge [left] node {\ttfamily\footnotesize select-instr.} (x86-2);
 \path[->,bend right=15] (C0-1) edge [left] node {\ttfamily\footnotesize select-instr.} (x86-2);
-\path[->,bend left=15] (x86-2) edge [right] node {\ttfamily\footnotesize\color{red} uncover-live} (x86-2-1);
-\path[->,bend right=15] (x86-2-1) edge [below] node {\ttfamily\footnotesize\color{red} build-inter.} (x86-2-2);
-\path[->,bend right=15] (x86-2-2) edge [right] node {\ttfamily\footnotesize\color{red} allocate-reg.} (x86-3);
+\path[->,bend left=15] (x86-2) edge [right] node {\ttfamily\footnotesize uncover-live} (x86-2-1);
+\path[->,bend right=15] (x86-2-1) edge [below] node {\ttfamily\footnotesize build-inter.} (x86-2-2);
+\path[->,bend right=15] (x86-2-2) edge [right] node {\ttfamily\footnotesize allocate-reg.} (x86-3);
 \path[->,bend left=15] (x86-3) edge [above] node {\ttfamily\footnotesize patch-instr.} (x86-4);
 \path[->,bend left=15] (x86-3) edge [above] node {\ttfamily\footnotesize patch-instr.} (x86-4);
 \path[->,bend left=15] (x86-4) edge [right] node {\ttfamily\footnotesize print-x86} (x86-5);
 \path[->,bend left=15] (x86-4) edge [right] node {\ttfamily\footnotesize print-x86} (x86-5);
 \end{tikzpicture}
 \end{tikzpicture}
@@ -5518,17 +5509,17 @@ Test your compiler using your previously created programs on the
 \node (x86-2-1) at (3,-4)  {\large $\text{x86}^{*}_1$};
 \node (x86-2-1) at (3,-4)  {\large $\text{x86}^{*}_1$};
 \node (x86-2-2) at (6,-4)  {\large $\text{x86}^{*}_1$};
 \node (x86-2-2) at (6,-4)  {\large $\text{x86}^{*}_1$};
 
 
-\path[->,bend left=15] (R2) edge [above] node {\ttfamily\footnotesize\color{red} type-check} (R2-2);
-\path[->,bend left=15] (R2-2) edge [above] node {\ttfamily\footnotesize\color{red} shrink} (R2-3);
+\path[->,bend left=15] (R2) edge [above] node {\ttfamily\footnotesize type-check} (R2-2);
+\path[->,bend left=15] (R2-2) edge [above] node {\ttfamily\footnotesize shrink} (R2-3);
 \path[->,bend left=15] (R2-3) edge [above] node {\ttfamily\footnotesize uniquify} (R2-4);
 \path[->,bend left=15] (R2-3) edge [above] node {\ttfamily\footnotesize uniquify} (R2-4);
 \path[->,bend left=15] (R2-4) edge [above] node {\ttfamily\footnotesize remove-complex.} (R2-5);
 \path[->,bend left=15] (R2-4) edge [above] node {\ttfamily\footnotesize remove-complex.} (R2-5);
-\path[->,bend left=15] (R2-5) edge [left] node {\ttfamily\footnotesize\color{red} explicate-control} (C1-1);
-\path[->,bend right=15] (C1-1) edge [left] node {\ttfamily\footnotesize\color{red} select-instructions} (x86-2);
-\path[->,bend left=15] (x86-2) edge [right] node {\ttfamily\footnotesize\color{red} uncover-live} (x86-2-1);
+\path[->,bend left=15] (R2-5) edge [left] node {\ttfamily\footnotesize explicate-control} (C1-1);
+\path[->,bend right=15] (C1-1) edge [left] node {\ttfamily\footnotesize select-instructions} (x86-2);
+\path[->,bend left=15] (x86-2) edge [right] node {\ttfamily\footnotesize uncover-live} (x86-2-1);
 \path[->,bend right=15] (x86-2-1) edge [below] node {\ttfamily\footnotesize build-inter.} (x86-2-2);
 \path[->,bend right=15] (x86-2-1) edge [below] node {\ttfamily\footnotesize build-inter.} (x86-2-2);
 \path[->,bend right=15] (x86-2-2) edge [right] node {\ttfamily\footnotesize allocate-reg.} (x86-3);
 \path[->,bend right=15] (x86-2-2) edge [right] node {\ttfamily\footnotesize allocate-reg.} (x86-3);
-\path[->,bend left=15] (x86-3) edge [above] node {\ttfamily\footnotesize\color{red} patch-instr.} (x86-4);
-\path[->,bend left=15] (x86-4) edge [right] node {\ttfamily\footnotesize\color{red} print-x86 } (x86-5);
+\path[->,bend left=15] (x86-3) edge [above] node {\ttfamily\footnotesize patch-instr.} (x86-4);
+\path[->,bend left=15] (x86-4) edge [right] node {\ttfamily\footnotesize print-x86 } (x86-5);
 \end{tikzpicture}
 \end{tikzpicture}
 \caption{Diagram of the passes for $R_2$, a language with conditionals.}
 \caption{Diagram of the passes for $R_2$, a language with conditionals.}
  \label{fig:R2-passes}
  \label{fig:R2-passes}
@@ -7029,18 +7020,18 @@ conclusion:
 \node (x86-2-1) at (3,-4)  {\large $\text{x86}^{*}_2$};
 \node (x86-2-1) at (3,-4)  {\large $\text{x86}^{*}_2$};
 \node (x86-2-2) at (6,-4)  {\large $\text{x86}^{*}_2$};
 \node (x86-2-2) at (6,-4)  {\large $\text{x86}^{*}_2$};
 
 
-%\path[->,bend left=15] (R3) edge [above] node {\ttfamily\footnotesize\color{red} type-check} (R3-2);
+%\path[->,bend left=15] (R3) edge [above] node {\ttfamily\footnotesize type-check} (R3-2);
 \path[->,bend left=15] (R3) edge [above] node {\ttfamily\footnotesize shrink} (R3-2);
 \path[->,bend left=15] (R3) edge [above] node {\ttfamily\footnotesize shrink} (R3-2);
 \path[->,bend left=15] (R3-2) edge [above] node {\ttfamily\footnotesize uniquify} (R3-3);
 \path[->,bend left=15] (R3-2) edge [above] node {\ttfamily\footnotesize uniquify} (R3-3);
-\path[->,bend left=15] (R3-3) edge [above] node {\ttfamily\footnotesize\color{red} expose-alloc.} (R3-4);
+\path[->,bend left=15] (R3-3) edge [above] node {\ttfamily\footnotesize expose-alloc.} (R3-4);
 \path[->,bend left=15] (R3-4) edge [above] node {\ttfamily\footnotesize remove-complex.} (R3-5);
 \path[->,bend left=15] (R3-4) edge [above] node {\ttfamily\footnotesize remove-complex.} (R3-5);
 \path[->,bend left=20] (R3-5) edge [left] node {\ttfamily\footnotesize explicate-control} (C2-4);
 \path[->,bend left=20] (R3-5) edge [left] node {\ttfamily\footnotesize explicate-control} (C2-4);
-\path[->,bend left=15] (C2-4) edge [right] node {\ttfamily\footnotesize\color{red} select-instr.} (x86-2);
+\path[->,bend left=15] (C2-4) edge [right] node {\ttfamily\footnotesize select-instr.} (x86-2);
 \path[->,bend right=15] (x86-2) edge [left] node {\ttfamily\footnotesize uncover-live} (x86-2-1);
 \path[->,bend right=15] (x86-2) edge [left] node {\ttfamily\footnotesize uncover-live} (x86-2-1);
-\path[->,bend right=15] (x86-2-1) edge [below] node {\ttfamily\footnotesize\color{red} build-inter.} (x86-2-2);
-\path[->,bend right=15] (x86-2-2) edge [right] node {\ttfamily\footnotesize\color{red} allocate-reg.} (x86-3);
+\path[->,bend right=15] (x86-2-1) edge [below] node {\ttfamily\footnotesize build-inter.} (x86-2-2);
+\path[->,bend right=15] (x86-2-2) edge [right] node {\ttfamily\footnotesize allocate-reg.} (x86-3);
 \path[->,bend left=15] (x86-3) edge [above] node {\ttfamily\footnotesize patch-instr.} (x86-4);
 \path[->,bend left=15] (x86-3) edge [above] node {\ttfamily\footnotesize patch-instr.} (x86-4);
-\path[->,bend left=15] (x86-4) edge [right] node {\ttfamily\footnotesize\color{red} print-x86} (x86-5);
+\path[->,bend left=15] (x86-4) edge [right] node {\ttfamily\footnotesize print-x86} (x86-5);
 \end{tikzpicture}
 \end{tikzpicture}
 \caption{Diagram of the passes for $R_3$, a language with tuples.}
 \caption{Diagram of the passes for $R_3$, a language with tuples.}
 \label{fig:R3-passes}
 \label{fig:R3-passes}
@@ -8253,8 +8244,8 @@ previously created test programs.
 \begin{figure}[tbp]
 \begin{figure}[tbp]
 \begin{tikzpicture}[baseline=(current  bounding  box.center)]
 \begin{tikzpicture}[baseline=(current  bounding  box.center)]
 \node (R4) at (0,2)  {\large $R_4$};
 \node (R4) at (0,2)  {\large $R_4$};
-\node (R4-2) at (3,2)  {\large $R_4$};
-%\node (R4-3) at (6,2)  {\large $R_4$};
+\node (R4-1) at (3,2)  {\large $R_4$};
+\node (R4-2) at (6,2)  {\large $R_4$};
 \node (F1-1) at (12,0)  {\large $F_1$};
 \node (F1-1) at (12,0)  {\large $F_1$};
 \node (F1-2) at (9,0)  {\large $F_1$};
 \node (F1-2) at (9,0)  {\large $F_1$};
 \node (F1-3) at (6,0)  {\large $F_1$};
 \node (F1-3) at (6,0)  {\large $F_1$};
@@ -8269,31 +8260,31 @@ previously created test programs.
 \node (x86-2-1) at (3,-6)  {\large $\text{x86}^{*}_3$};
 \node (x86-2-1) at (3,-6)  {\large $\text{x86}^{*}_3$};
 \node (x86-2-2) at (6,-6)  {\large $\text{x86}^{*}_3$};
 \node (x86-2-2) at (6,-6)  {\large $\text{x86}^{*}_3$};
 
 
-%\path[->,bend left=15] (R4) edge [above] node
-%     {\ttfamily\footnotesize\color{red} type-check} (R4-2);
 \path[->,bend left=15] (R4) edge [above] node
 \path[->,bend left=15] (R4) edge [above] node
+     {\ttfamily\footnotesize shrink} (R4-1);
+\path[->,bend left=15] (R4-1) edge [above] node
      {\ttfamily\footnotesize uniquify} (R4-2);
      {\ttfamily\footnotesize uniquify} (R4-2);
 \path[->,bend left=15] (R4-2) edge [right] node
 \path[->,bend left=15] (R4-2) edge [right] node
-     {\ttfamily\footnotesize\color{red} reveal-functions} (F1-1);
+     {\ttfamily\footnotesize ~~reveal-functions} (F1-1);
 \path[->,bend left=15] (F1-1) edge [below] node
 \path[->,bend left=15] (F1-1) edge [below] node
-     {\ttfamily\footnotesize\color{red} limit-functions} (F1-2);
+     {\ttfamily\footnotesize limit-functions} (F1-2);
 \path[->,bend right=15] (F1-2) edge [above] node
 \path[->,bend right=15] (F1-2) edge [above] node
      {\ttfamily\footnotesize expose-alloc.} (F1-3);
      {\ttfamily\footnotesize expose-alloc.} (F1-3);
 \path[->,bend right=15] (F1-3) edge [above] node
 \path[->,bend right=15] (F1-3) edge [above] node
-     {\ttfamily\footnotesize\color{red} remove-complex.} (F1-4);
+     {\ttfamily\footnotesize remove-complex.} (F1-4);
 \path[->,bend left=15] (F1-4) edge [right] node
 \path[->,bend left=15] (F1-4) edge [right] node
-     {\ttfamily\footnotesize\color{red} explicate-control} (C3-2);
+     {\ttfamily\footnotesize explicate-control} (C3-2);
 \path[->,bend right=15] (C3-2) edge [left] node
 \path[->,bend right=15] (C3-2) edge [left] node
-     {\ttfamily\footnotesize\color{red} select-instr.} (x86-2);
+     {\ttfamily\footnotesize select-instr.} (x86-2);
 \path[->,bend left=15] (x86-2) edge [left] node
 \path[->,bend left=15] (x86-2) edge [left] node
-     {\ttfamily\footnotesize\color{red} uncover-live} (x86-2-1);
+     {\ttfamily\footnotesize uncover-live} (x86-2-1);
 \path[->,bend right=15] (x86-2-1) edge [below] node 
 \path[->,bend right=15] (x86-2-1) edge [below] node 
-     {\ttfamily\footnotesize \color{red}build-inter.} (x86-2-2);
+     {\ttfamily\footnotesize build-inter.} (x86-2-2);
 \path[->,bend right=15] (x86-2-2) edge [left] node
 \path[->,bend right=15] (x86-2-2) edge [left] node
      {\ttfamily\footnotesize allocate-reg.} (x86-3);
      {\ttfamily\footnotesize allocate-reg.} (x86-3);
 \path[->,bend left=15] (x86-3) edge [above] node
 \path[->,bend left=15] (x86-3) edge [above] node
-     {\ttfamily\footnotesize\color{red} patch-instr.} (x86-4);
-\path[->,bend right=15] (x86-4) edge [left] node {\ttfamily\footnotesize\color{red} print-x86} (x86-5);
+     {\ttfamily\footnotesize patch-instr.} (x86-4);
+\path[->,bend right=15] (x86-4) edge [left] node {\ttfamily\footnotesize print-x86} (x86-5);
 \end{tikzpicture}
 \end{tikzpicture}
 \caption{Diagram of the passes for $R_4$, a language with functions.}
 \caption{Diagram of the passes for $R_4$, a language with functions.}
 \label{fig:R4-passes}
 \label{fig:R4-passes}
@@ -8949,19 +8940,19 @@ shift it by $57$ bits to the right.
 \path[->,bend left=15] (R4-2) edge [above] node
 \path[->,bend left=15] (R4-2) edge [above] node
      {\ttfamily\footnotesize uniquify} (R4-3);
      {\ttfamily\footnotesize uniquify} (R4-3);
 \path[->,bend left=15] (R4-3) edge [right] node
 \path[->,bend left=15] (R4-3) edge [right] node
-     {\ttfamily\footnotesize\color{red} reveal-functions} (F1-1);
+     {\ttfamily\footnotesize reveal-functions} (F1-1);
 \path[->,bend left=15] (F1-1) edge [below] node
 \path[->,bend left=15] (F1-1) edge [below] node
-     {\ttfamily\footnotesize\color{red} convert-to-clos.} (F1-2);
+     {\ttfamily\footnotesize convert-to-clos.} (F1-2);
 \path[->,bend right=15] (F1-2) edge [above] node
 \path[->,bend right=15] (F1-2) edge [above] node
      {\ttfamily\footnotesize limit-fun.} (F1-3);
      {\ttfamily\footnotesize limit-fun.} (F1-3);
 \path[->,bend right=15] (F1-3) edge [above] node
 \path[->,bend right=15] (F1-3) edge [above] node
-     {\ttfamily\footnotesize\color{red} expose-alloc.} (F1-4);
+     {\ttfamily\footnotesize expose-alloc.} (F1-4);
 \path[->,bend right=15] (F1-4) edge [above] node
 \path[->,bend right=15] (F1-4) edge [above] node
      {\ttfamily\footnotesize remove-complex.} (F1-5);
      {\ttfamily\footnotesize remove-complex.} (F1-5);
 \path[->,bend right=15] (F1-5) edge [right] node
 \path[->,bend right=15] (F1-5) edge [right] node
      {\ttfamily\footnotesize explicate-control} (C3-2);
      {\ttfamily\footnotesize explicate-control} (C3-2);
 \path[->,bend left=15] (C3-2) edge [left] node
 \path[->,bend left=15] (C3-2) edge [left] node
-     {\ttfamily\footnotesize\color{red} select-instr.} (x86-2);
+     {\ttfamily\footnotesize select-instr.} (x86-2);
 \path[->,bend right=15] (x86-2) edge [left] node
 \path[->,bend right=15] (x86-2) edge [left] node
      {\ttfamily\footnotesize uncover-live} (x86-2-1);
      {\ttfamily\footnotesize uncover-live} (x86-2-1);
 \path[->,bend right=15] (x86-2-1) edge [below] node 
 \path[->,bend right=15] (x86-2-1) edge [below] node 
@@ -9998,7 +9989,7 @@ The \code{analyze-dataflow} function has four parameters.
 \node (x86-2-2) at (6,-6)  {\large $\text{x86}^{*}_3$};
 \node (x86-2-2) at (6,-6)  {\large $\text{x86}^{*}_3$};
 
 
 %% \path[->,bend left=15] (R4) edge [above] node
 %% \path[->,bend left=15] (R4) edge [above] node
-%%      {\ttfamily\footnotesize\color{red} type-check} (R4-2);
+%%      {\ttfamily\footnotesize type-check} (R4-2);
 \path[->,bend left=15] (R4) edge [above] node
 \path[->,bend left=15] (R4) edge [above] node
      {\ttfamily\footnotesize shrink} (R4-2);
      {\ttfamily\footnotesize shrink} (R4-2);
 \path[->,bend left=15] (R4-2) edge [above] node
 \path[->,bend left=15] (R4-2) edge [above] node
@@ -10006,7 +9997,7 @@ The \code{analyze-dataflow} function has four parameters.
 \path[->,bend left=15] (R4-3) edge [above] node
 \path[->,bend left=15] (R4-3) edge [above] node
      {\ttfamily\footnotesize reveal-functions} (R4-4);
      {\ttfamily\footnotesize reveal-functions} (R4-4);
 \path[->,bend left=15] (R4-4) edge [right] node
 \path[->,bend left=15] (R4-4) edge [right] node
-     {\ttfamily\footnotesize\color{red} convert-assignments} (F1-1);
+     {\ttfamily\footnotesize convert-assignments} (F1-1);
 \path[->,bend left=15] (F1-1) edge [below] node
 \path[->,bend left=15] (F1-1) edge [below] node
      {\ttfamily\footnotesize convert-to-clos.} (F1-2);
      {\ttfamily\footnotesize convert-to-clos.} (F1-2);
 \path[->,bend right=15] (F1-2) edge [above] node
 \path[->,bend right=15] (F1-2) edge [above] node
@@ -10014,13 +10005,13 @@ The \code{analyze-dataflow} function has four parameters.
 \path[->,bend right=15] (F1-3) edge [above] node
 \path[->,bend right=15] (F1-3) edge [above] node
      {\ttfamily\footnotesize expose-alloc.} (F1-4);
      {\ttfamily\footnotesize expose-alloc.} (F1-4);
 \path[->,bend right=15] (F1-4) edge [above] node
 \path[->,bend right=15] (F1-4) edge [above] node
-     {\ttfamily\footnotesize\color{red} remove-complex.} (F1-5);
+     {\ttfamily\footnotesize remove-complex.} (F1-5);
 \path[->,bend right=15] (F1-5) edge [right] node
 \path[->,bend right=15] (F1-5) edge [right] node
-     {\ttfamily\footnotesize\color{red} explicate-control} (C3-2);
+     {\ttfamily\footnotesize explicate-control} (C3-2);
 \path[->,bend left=15] (C3-2) edge [left] node
 \path[->,bend left=15] (C3-2) edge [left] node
-     {\ttfamily\footnotesize\color{red} select-instr.} (x86-2);
+     {\ttfamily\footnotesize select-instr.} (x86-2);
 \path[->,bend right=15] (x86-2) edge [left] node
 \path[->,bend right=15] (x86-2) edge [left] node
-     {\ttfamily\footnotesize\color{red} uncover-live} (x86-2-1);
+     {\ttfamily\footnotesize uncover-live} (x86-2-1);
 \path[->,bend right=15] (x86-2-1) edge [below] node 
 \path[->,bend right=15] (x86-2-1) edge [below] node 
      {\ttfamily\footnotesize build-inter.} (x86-2-2);
      {\ttfamily\footnotesize build-inter.} (x86-2-2);
 \path[->,bend right=15] (x86-2-2) edge [left] node
 \path[->,bend right=15] (x86-2-2) edge [left] node
@@ -11051,11 +11042,11 @@ completion without error.
 \path[->,bend left=15] (R4-3) edge [above] node
 \path[->,bend left=15] (R4-3) edge [above] node
      {\ttfamily\footnotesize reveal-functions} (R4-4);
      {\ttfamily\footnotesize reveal-functions} (R4-4);
 \path[->,bend right=15] (R4-4) edge [left] node
 \path[->,bend right=15] (R4-4) edge [left] node
-     {\ttfamily\footnotesize\color{red} cast-insert} (R4-5);
+     {\ttfamily\footnotesize cast-insert} (R4-5);
 \path[->,bend left=15] (R4-5) edge [above] node
 \path[->,bend left=15] (R4-5) edge [above] node
-     {\ttfamily\footnotesize\color{red} check-bounds} (R4-6);
+     {\ttfamily\footnotesize check-bounds} (R4-6);
 \path[->,bend left=15] (R4-6) edge [left] node
 \path[->,bend left=15] (R4-6) edge [left] node
-     {\ttfamily\footnotesize\color{red} reveal-casts} (R4-7);
+     {\ttfamily\footnotesize reveal-casts} (R4-7);
      
      
 \path[->,bend left=15] (R4-7) edge [below] node
 \path[->,bend left=15] (R4-7) edge [below] node
      {\ttfamily\footnotesize convert-to-clos.} (F1-2);
      {\ttfamily\footnotesize convert-to-clos.} (F1-2);
@@ -11068,7 +11059,7 @@ completion without error.
 \path[->,bend right=15] (F1-5) edge [right] node
 \path[->,bend right=15] (F1-5) edge [right] node
      {\ttfamily\footnotesize explicate-control} (C3-2);
      {\ttfamily\footnotesize explicate-control} (C3-2);
 \path[->,bend left=15] (C3-2) edge [left] node
 \path[->,bend left=15] (C3-2) edge [left] node
-     {\ttfamily\footnotesize\color{red} select-instr.} (x86-2);
+     {\ttfamily\footnotesize select-instr.} (x86-2);
 \path[->,bend right=15] (x86-2) edge [left] node
 \path[->,bend right=15] (x86-2) edge [left] node
      {\ttfamily\footnotesize uncover-live} (x86-2-1);
      {\ttfamily\footnotesize uncover-live} (x86-2-1);
 \path[->,bend right=15] (x86-2-1) edge [below] node 
 \path[->,bend right=15] (x86-2-1) edge [below] node