Jeremy Siek пре 9 година
родитељ
комит
3f13070c98
2 измењених фајлова са 352 додато и 190 уклоњено
  1. 331 172
      book.tex
  2. 21 18
      s-expr-example.rkt

+ 331 - 172
book.tex

@@ -106,7 +106,7 @@ University.
 \end{dedication}
 
 \tableofcontents
-%\listoffigures
+\listoffigures
 %\listoftables
 
 \mainmatter
@@ -408,7 +408,7 @@ R_0  &::=& (\key{program} \; \Exp)
 \]
 \end{minipage}
 }
-\caption{The syntax of the $R_0$ language.}
+\caption{The syntax of $R_0$, a language of integer arithmetic.}
 \label{fig:r0-syntax}
 \end{figure}
 
@@ -580,13 +580,17 @@ 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 Reynold's advice in this
 regard~\citep{reynolds72:_def_interp}. Here we will warm up by writing
-an interpreter for the $R_0$ language, which will also serve
-as a second example of structural recursion. The \texttt{interp-R0}
+an interpreter for the $R_0$ language, which will also serve 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 input expression \texttt{e} and there is
-one clause per grammar rule for $R_0$. The clauses for
-internal AST nodes make recursive calls to \texttt{interp-R0} on
-each child node.
+one clause per grammar rule for $R_0$. The clauses for internal AST
+nodes make recursive calls to \texttt{interp-R0} on each child
+node. Here we make use of the \key{app} feature of Racket's
+\key{match} to concisely apply a function and bind the result.  For
+example, in the case for negation, we use \key{app} to recursively
+apply \texttt{interp-R0} to the child node and bind the result value
+to variable \texttt{v}.
 
 \begin{figure}[tbp]
 \begin{lstlisting}
@@ -594,14 +598,14 @@ each child node.
      (match e
        [(? fixnum?) e]
        [`(read)
-        (define r (read))
-        (cond [(fixnum? r) r]
-              [else (error 'interp-R0 "expected an integer" r)])]
-       [`(- ,e)
-        (fx- 0 (interp-R0 e))]
-       [`(+ ,e1 ,e2)
-        (fx+ (interp-R0 e1) (interp-R0 e2))]
-       [`(program ,e) (interp-R0 e)]
+        (let ([r (read)])
+          (cond [(fixnum? r) r]
+                 [else (error 'interp-R0 "input not an integer" r)]))]
+       [`(- ,(app interp-R0 v))
+        (fx- 0 v)]
+       [`(+ ,(app interp-R0 v1) ,(app interp-R0 v2))
+        (fx+ v1 v2)]
+       [`(program ,(app interp-R0 v)) v]
        ))
 \end{lstlisting}
 \caption{Interpreter for the $R_0$ language.}
@@ -700,15 +704,19 @@ partially evaluating the children nodes.
    (define (pe-neg r)
      (cond [(fixnum? r) (fx- 0 r)]
            [else `(- ,r)]))
+
    (define (pe-add r1 r2)
      (cond [(and (fixnum? r1) (fixnum? r2)) (fx+ r1 r2)]
            [else `(+ ,r1 ,r2)]))
+
    (define (pe-arith e)
      (match e
        [(? fixnum?) e]
        [`(read) `(read)]
-       [`(- ,e1) (pe-neg (pe-arith e1))]
-       [`(+ ,e1 ,e2) (pe-add (pe-arith e1) (pe-arith e2))]))   
+       [`(- ,(app pe-arith r1))
+         (pe-neg r1)]
+       [`(+ ,(app pe-arith r1) ,(app pe-arith r2))
+         (pe-add r1 r2)]))   
 \end{lstlisting}
 \caption{A partial evaluator for the $R_0$ language.}
 \label{fig:pe-arith}
@@ -788,17 +796,17 @@ some fun and creativity.
 The $R_1$ language extends the $R_0$ language
 (Figure~\ref{fig:r0-syntax}) with variable definitions.  The syntax of
 the $R_1$ language is defined by the grammar in
-Figure~\ref{fig:r1-syntax}. As in $R_0$, \key{read} is a nullary
-operator, \key{-} is a unary operator, and \key{+} is a binary
-operator. In addition to variable definitions, the $R_1$ language
-includes the \key{program} form to mark the top of the program, which
-is helpful in some of the compiler passes.  The $R_1$ language is rich
-enough to exhibit several compilation techniques but simple enough so
-that the reader can implement a compiler for it in a week of part-time
-work.  To give the reader a feeling for the scale of this first
-compiler, the instructor solution for the $R_1$ compiler consists of 6
-recursive functions and a few small helper functions that together
-span 256 lines of code.
+Figure~\ref{fig:r1-syntax}.  The non-terminal \Var{} may be any Racket
+identifier. As in $R_0$, \key{read} is a nullary operator, \key{-} is
+a unary operator, and \key{+} is a binary operator. In addition to
+variable definitions, the $R_1$ language includes the \key{program}
+form to mark the top of the program, which is helpful in some of the
+compiler passes.  The $R_1$ language is rich enough to exhibit several
+compilation techniques but simple enough so that the reader can
+implement a compiler for it in a week of part-time work.  To give the
+reader a feeling for the scale of this first compiler, the instructor
+solution for the $R_1$ compiler consists of 6 recursive functions and
+a few small helper functions that together span 256 lines of code.
 
 \begin{figure}[btp]
 \centering
@@ -813,8 +821,7 @@ R_1  &::=& (\key{program} \; \Exp)
 \]
 \end{minipage}
 }
-\caption{The syntax of the $R_1$ language. 
-  The non-terminal \Var{} may be any Racket identifier.}
+\caption{The syntax of $R_1$, a language of integers and variables.}
 \label{fig:r1-syntax}
 \end{figure}
 
@@ -869,24 +876,25 @@ to the variable, then evaluates the body of the \key{let}.
 
 \begin{figure}[tbp]
 \begin{lstlisting}
-   (define (interp-R1 env e)
-     (match e
-       [(? symbol?) (lookup e env)]
-       [`(let ([,x ,e]) ,body)
-        (define v (interp-R1 env e))
-        (define new-env (cons (cons x v) env))
-        (interp-R1 new-env body)]
-       [(? fixnum?) e]
-       [`(read)
-        (define r (read))
-        (cond [(fixnum? r) r]
-              [else (error 'interp-R1 "expected an integer" r)])]
-       [`(- ,e)
-        (fx- 0 (interp-R1 env e))]
-       [`(+ ,e1 ,e2)
-        (fx+ (interp-R1 env e1) (interp-R1 env e2))]
-       [`(program ,e) (interp-R1 '() e)]
-       ))
+   (define (interp-R1 env)
+     (lambda (e)
+       (define recur (interp-R1 env))
+       (match e
+         [(? symbol?) (lookup e env)]
+         [`(let ([,x ,(app recur v)]) ,body)
+          (define new-env (cons (cons x v) env))
+          ((interp-R1 new-env) body)]
+         [(? fixnum?) e]
+         [`(read)
+          (define r (read))
+          (cond [(fixnum? r) r]
+                [else (error 'interp-R1 "expected an integer" r)])]
+         [`(- ,(app recur v))
+          (fx- 0 v)]
+         [`(+ ,(app recur v1) ,(app recur v2))
+          (fx+ v1 v2)]
+         [`(program ,e) ((interp-R1 '()) e)]
+         )))
 \end{lstlisting}
 \caption{Interpreter for the $R_1$ language.}
 \label{fig:interp-R1}
@@ -1403,18 +1411,17 @@ implement the clauses for variables and for the \key{let} construct.
 
 \begin{figure}[tbp]
 \begin{lstlisting}
-   (define uniquify
-     (lambda (alist)
-       (lambda (e)
-         (match e
-           [(? symbol?) ___]
-           [(? integer?) e]
-           [`(let ([,x ,e]) ,body) ___]
-           [`(program ,e)
-            `(program ,((uniquify alist) e))]
-           [`(,op ,es ...)
-            `(,op ,@(map (uniquify alist) es))]
-           ))))
+   (define (uniquify alist)
+     (lambda (e)
+       (match e
+         [(? symbol?) ___]
+         [(? integer?) e]
+         [`(let ([,x ,e]) ,body) ___]
+         [`(program ,e)
+          `(program ,((uniquify alist) e))]
+         [`(,op ,es ...)
+          `(,op ,@(map (uniquify alist) es))]
+         )))
 \end{lstlisting}
 \caption{Skeleton for the \key{uniquify} pass.}
 \label{fig:uniquify-s0}
@@ -1816,17 +1823,14 @@ programs.
 \path[->,bend left=15] (x86-4) edge [above] node {\ttfamily\footnotesize print-x86} (x86-5);
 \end{tikzpicture}
 
-\caption{Overview of the passes for compiling $R_1$.  The x86$^{*}$
-  language extends x86 with variables and looser rules regarding
-  instruction arguments. The x86$^{\dagger}$ language is the concrete
-  syntax (string) for x86.}
+\caption{Overview of the passes for compiling $R_1$. }
 \label{fig:R1-passes}
 \end{figure}
 
-
 Figure~\ref{fig:R1-passes} provides an overview of all the compiler
-passes described in this Chapter.
-
+passes described in this Chapter.  The x86$^{*}$ language extends x86
+with variables and looser rules regarding instruction arguments. The
+x86$^{\dagger}$ language is the concrete syntax (string) for x86.
 
 
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -1877,7 +1881,7 @@ After instruction selection:
   (movq (var t.2) (reg rax)))
 \end{lstlisting}
 \end{minipage}
-\caption{Running example for this chapter.}
+\caption{An example program for register allocation.}
 \label{fig:reg-eg}
 \end{figure}
 
@@ -1984,7 +1988,7 @@ $L_{\mathtt{after}}$ set to make the figure easy to read.
 \end{lstlisting}
 \end{minipage}
 
-\caption{The running example and its live-after sets.}
+\caption{An example program annotated with live-after sets.}
 \label{fig:live-eg}
 \end{figure}
 
@@ -2096,7 +2100,7 @@ Figure~\ref{fig:interfere}.
 \draw (t2) to (t1);
 \end{tikzpicture}
 \]
-\caption{Interference graph for the running example.}
+\caption{The interference graph of the example program.}
 \label{fig:interfere}
 \end{figure}
 
@@ -2160,16 +2164,15 @@ out of an initial Sudoku board.
 If you can color the remaining nodes in the graph with the nine
 colors, then you have also solved the corresponding game of Sudoku.
 Figure~\ref{fig:sudoku-graph} shows an initial Sudoku game board and
-the corresponding graph with colored vertices.
+the corresponding graph with colored vertices.  We map the Sudoku
+number 1 to blue, 2 to yellow, and 3 to red.  We only show edges for a
+sampling of the vertices (those that are colored) because showing
+edges for all of the vertices would make the graph unreadable.
 
 \begin{figure}[tbp]
 \includegraphics[width=0.45\textwidth]{sudoku}
 \includegraphics[width=0.5\textwidth]{sudoku-graph}
-\caption{A Sudoku game board and the corresponding colored graph.  We
-  map the Sudoku number 1 to blue, 2 to yellow, and 3 to red.  We only
-  show edges for a sampling of the vertices (those that are colored)
-  because showing edges for all of the vertices would make the graph
-  unreadable.}
+\caption{A Sudoku game board and the corresponding colored graph.}
 \label{fig:sudoku-graph}
 \end{figure}
 
@@ -2240,7 +2243,7 @@ while |$W \neq \emptyset$| do
     |$\mathrm{color}[u] \gets c$|
     |$W \gets W - \{u\}$|
 \end{lstlisting}
-  \caption{Saturation-based greedy graph coloring algorithm.}
+  \caption{The saturation-based greedy graph coloring algorithm.}
   \label{fig:satur-algo}
 \end{figure}
 
@@ -2528,8 +2531,7 @@ shown in Figure~\ref{fig:reg-alloc-passes}.
 \path[->,bend left=15] (x86-3) edge [above] node {\ttfamily\footnotesize patch-instr.} (x86-4);
 \path[->,bend left=15] (x86-4) edge [above] node {\ttfamily\footnotesize print-x86} (x86-5);
 \end{tikzpicture}
-\caption{Diagram of the passes for compiling $R_1$, including the
-  three new passes for register allocation.}
+\caption{Diagram of the passes for $R_1$ with register allocation.}
 \label{fig:reg-alloc-passes}
 \end{figure}
 
@@ -2843,22 +2845,23 @@ programs to make sure that your move biasing is working properly.
 
 Up until now the input languages have only included a single kind of
 value, the integers. In this Chapter we add a second kind of value,
-the Booleans (true and false), together with some new operations
-(\key{and}, \key{not}, \key{eq?}) and conditional expressions to create
-the $R_2$ language.  With the addition of conditional expressions,
-programs can have non-trivial control flow which has an impact on
-several parts of the compiler. Also, because we now have two kinds of
-values, we need to worry about programs that apply an operation to the
-wrong kind of value, such as \code{(not 1)}.
+the Booleans (true and false, written \key{\#t} and \key{\#f}
+respectively), together with some new operations (\key{and},
+\key{not}, \key{eq?}, \key{<}, etc.) and conditional expressions to
+create the $R_2$ language.  With the addition of conditional
+expressions, programs can have non-trivial control flow which has an
+impact on several parts of the compiler. Also, because we now have two
+kinds of values, we need to worry about programs that apply an
+operation to the wrong kind of value, such as \code{(not 1)}.
 
 There are two language design options for such situations.  One option
 is to signal an error and the other is to provide a wider
 interpretation of the operation. The Racket language uses a mixture of
-these two options, depending on the operation and on the kind of
+these two options, depending on the operation and the kind of
 value. For example, the result of \code{(not 1)} in Racket is
-\code{\#f} (that is, false) because Racket treats non-zero integers as
-true. On the other hand, \code{(car 1)} results in a run-time error in
-Racket, which states that \code{car} expects a pair.
+\code{\#f} because Racket treats non-zero integers as true. On the
+other hand, \code{(car 1)} results in a run-time error in Racket,
+which states that \code{car} expects a pair.
 
 The Typed Racket language makes similar design choices as Racket,
 except much of the error detection happens at compile time instead of
@@ -2912,8 +2915,8 @@ comparing two integers and for comparing two Booleans.
 \]
 \end{minipage}
 }
-\caption{The $R_2$ language, an extension of $R_1$
-  (Figure~\ref{fig:r1-syntax}).}
+\caption{The syntax of $R_2$, extending $R_1$ with Booleans and
+  conditionals.}
 \label{fig:r2-syntax}
 \end{figure}
 
@@ -2969,23 +2972,26 @@ the order of evaluation of its arguments.
                         (<= v1 v2)]))]
 	 [else (error 'interp-op "unknown operator")]))
 
-   (define (interp-R2 env e)
-     (match e
-       ...
-       [(? boolean?) e]
-       [`(if ,cnd ,thn ,els)
-        (match (interp-R2 env cnd)
-          [#t (interp-R2 env thn)]
-          [#f (interp-R2 env els)])]
-       [`(not ,e)
-        (match (interp-R2 env e) [#t #f] [#f #t])]
-       [`(and ,e1 ,e2)
-         (match (interp-R2 env e1)
-           [#t (match (interp-R2 env e2) [#t #t] [#f #f])]
-           [#f #f])]
-       [`(,op ,args ...) #:when (set-member? primitives op)
-         (apply (interp-op op) (map (interp-R2 env) args))]
-       ))
+   (define (interp-R2 env)
+     (lambda (e)
+       (define recur (interp-R2 env))
+       (match e
+         ...
+         [(? boolean?) e]
+         [`(if ,(app recur cnd) ,thn ,els)
+          (match cnd
+            [#t (recur thn)]
+            [#f (recur els)])]
+         [`(not ,(app recur v))
+          (match v [#t #f] [#f #t])]
+         [`(and ,(app recur v1) ,e2)
+           (match v1
+             [#t (match (recur e2) [#t #t] [#f #f])]
+             [#f #f])]
+         [`(,op ,(app recur args) ...)
+           #:when (set-member? primitives op)
+           (apply (interp-op op) args)]
+         )))
 \end{lstlisting}
 \caption{Interpreter for the $R_2$ language.}
 \label{fig:interp-R2}
@@ -3035,25 +3041,26 @@ use of a variable, it can lookup its type in the association list.
 
 \begin{figure}[tbp]
 \begin{lstlisting}
-   (define (typecheck-R2 env e)
-     (match e
-       [(? fixnum?) 'Integer]
-       [(? boolean?) 'Boolean]
-       [(? symbol?) (lookup e env)]
-       [`(let ([,x ,e]) ,body)
-        (define T (typecheck-R2 env e))
-        (define new-env (cons (cons x T) env))
-        (typecheck-R2 new-env body)]
-       ...
-       [`(not ,e)
-        (match (typecheck-R2 env e)
-          ['Boolean 'Boolean]
-          [else (error 'typecheck-R2 "'not' expects a Boolean" e)])]
-       ...
-       [`(program ,body)
-         (let ([ty (typecheck-R2 '() body)])
-           `(program (type ,ty) ,body))]
-       ))
+   (define (typecheck-R2 env)
+     (lambda (e)
+       (define recur (typecheck-R2 env e))
+       (match e
+         [(? fixnum?) 'Integer]
+         [(? boolean?) 'Boolean]
+         [(? symbol?) (lookup e env)]
+         [`(let ([,x ,(app recur T)]) ,body)
+          (define new-env (cons (cons x T) env))
+          (typecheck-R2 new-env body)]
+         ...
+         [`(not ,(app (typecheck-R2 env) T))
+          (match T
+            ['Boolean 'Boolean]
+            [else (error 'typecheck-R2 "'not' expects a Boolean" e)])]
+         ...
+         [`(program ,body)
+          (define ty ((typecheck-R2 '()) body))
+          `(program (type ,ty) ,body)]
+         )))
 \end{lstlisting}
 \caption{Skeleton of a type checker for the $R_2$ language.}
 \label{fig:type-check-R2}
@@ -3121,8 +3128,7 @@ C_1 & ::= & (\key{program}\;(\Var^{*})\;(\key{type}\;\textit{type})\;\Stmt^{+})
 \]
 \end{minipage}
 }
-\caption{The $C_1$ intermediate language, an extension of $C_0$
-  (Figure~\ref{fig:c0-syntax}).}
+\caption{The $C_1$ language, extending $C_0$ with Booleans and conditionals.}
 \label{fig:c1-syntax}
 \end{figure}
 
@@ -3626,8 +3632,7 @@ if_end21289:
 \path[->,bend left=15] (x86-4) edge [above] node {\ttfamily\footnotesize patch-instr.} (x86-5);
 \path[->,bend right=15] (x86-5) edge [left] node {\ttfamily\footnotesize print-x86} (x86-6);
 \end{tikzpicture}
-\caption{Diagram of the passes for compiling $R_2$, including the
-  new type checking pass.}
+\caption{Diagram of the passes for $R_2$.}
 \label{fig:R2-passes}
 \end{figure}
 
@@ -3795,9 +3800,6 @@ which we add the $2$, the element at index $0$ of the 1-tuple.
         44))
 \end{lstlisting}
 
-\marginpar{\tiny to do: propagate the use of 'app' to earlier in the book
-  and explain it. \\ --Jeremy}
-
 Figure~\ref{fig:interp-R3} shows the definitional interpreter for the
 $R_3$ language and Figure~\ref{fig:typecheck-R3} shows the type
 checker.
@@ -3825,8 +3827,7 @@ checker.
 \]
 \end{minipage}
 }
-\caption{Syntax of the $R_3$ language, an extension of $R_2$
-  (Figure~\ref{fig:r2-syntax}).}
+\caption{The syntax of $R_3$, extending $R_2$ with tuples.}
 \label{fig:r3-syntax}
 \end{figure}
 
@@ -3849,7 +3850,7 @@ checker.
          [else (error 'interp-R3 "unrecognized expression")]
          )))
 \end{lstlisting}
-\caption{Definitional interpreter for the $R_3$ language.}
+\caption{Interpreter for the $R_3$ language.}
 \label{fig:interp-R3}
 \end{figure}
 
@@ -4036,8 +4037,8 @@ with the back.
 
 \begin{figure}[tbp]
 \centering \includegraphics[width=0.9\textwidth]{cheney}
-\caption{Depiction of the ToSpace as the Cheney algorithm copies and
-  compacts the live objects.}
+\caption{Depiction of the Cheney algorithm copying
+   the live objects.}
 \label{fig:cheney}
 \end{figure}
 
@@ -4087,7 +4088,7 @@ pointed-to objects will have changed.
 
 \begin{figure}[tbp]
 \centering \includegraphics[width=0.7\textwidth]{root-stack}
-\caption{Maintaining a root stack for pointers to facilitate garbage collection.}
+\caption{Maintaining a root stack to facilitate garbage collection.}
 \label{fig:shadow-stack}
 \end{figure}
 
@@ -4200,8 +4201,7 @@ C_2 & ::= & \gray{ (\key{program}\;(\Var^{*})\;(\key{type}\;\textit{type})\;\Stm
 \]
 \end{minipage}
 }
-\caption{The $C_2$ intermediate language, an extension of $C_1$
-  (Figure~\ref{fig:c1-syntax}).}
+\caption{The $C_2$ language, extending $C_1$ with tuples.}
 \label{fig:c2-syntax}
 \end{figure}
 
@@ -4565,7 +4565,10 @@ Figure~\ref{fig:select-instr-output-gc} shows the output of the
 \marginpar{\scriptsize We need to show the translation to x86 and what
   to do about global-value. \\ --Jeremy}
 
-\begin{figure}[tbp]
+Figure~\ref{fig:print-x86-output-gc} shows the output of the
+\code{print-x86} pass.
+
+\begin{figure}[htbp]
 \begin{minipage}[t]{0.5\textwidth}
 \begin{lstlisting}[basicstyle=\ttfamily\scriptsize]
 	.globl _main
@@ -4715,8 +4718,7 @@ inside each other; they can only be defined at the top level.
 \]
 \end{minipage}
 }
-\caption{The $R_4$ language, an extension of $R_3$
-  (Figure~\ref{fig:r3-syntax}).}
+\caption{Syntax of $R_4$, extending $R_3$ with functions.}
 \label{fig:r4-syntax}
 \end{figure}
 
@@ -4969,8 +4971,7 @@ C_3 & ::= & (\key{program}\;(\Var^{*})\;(\key{type}\;\textit{type})\;(\key{defin
 \]
 \end{minipage}
 }
-\caption{The $C_3$ intermediate language, an extension of $C_2$
-  (Figure~\ref{fig:c2-syntax}).}
+\caption{The $C_3$ language, extending $C_2$ with functions.}
 \label{fig:c3-syntax}
 \end{figure}
 
@@ -5117,7 +5118,7 @@ haven't already done that.
 Figure~\ref{fig:add-fun} shows an example translation of a simple
 function in $R_4$ to x86. The figure includes the results of the
 \code{flatten} and \code{select-instructions} passes.  Can you see any
-obvious ways to improve the translation?
+ways to improve the translation?
 
 \begin{figure}[tbp]
 \begin{tabular}{lll}
@@ -5324,8 +5325,7 @@ $R_3$).
 \]
 \end{minipage}
 }
-\caption{The $R_5$ language, an extension of $R_4$
-  (Figure~\ref{fig:r4-syntax}).}
+\caption{Syntax of $R_5$, extending $R_4$ with \key{lambda}.}
 \label{fig:r5-syntax}
 \end{figure}
 
@@ -5421,7 +5421,7 @@ top-level environment.
            [else (error "interp-R5, expected function, not" fun-val)])]
        )))
 \end{lstlisting}
-\caption{Definitional interpreter for $R_5$.}
+\caption{Interpreter for $R_5$.}
 \label{fig:interp-R5}
 \end{figure}
 
@@ -5595,8 +5595,7 @@ $\Downarrow$
 \end{lstlisting}
 \end{minipage}
 
-\caption{Example showing the result of \code{reveal-functions}
-  and \code{convert-to-closures}.}
+\caption{Example of closure conversion.}
 \label{fig:lexical-functions-example}
 \end{figure}
 
@@ -5715,8 +5714,7 @@ compilation of $R_6$ and $R_7$ in the remainder of this chapter.
 \]
 \end{minipage}
 }
-\caption{The syntax of the $R_6$ language, an extension of $R_5$
-  (Figure~\ref{fig:r5-syntax}).}
+\caption{Syntax of $R_6$, extending $R_5$ with \key{Any}.}
 \label{fig:r6-syntax}
 \end{figure}
 
@@ -5736,33 +5734,57 @@ otherwise.
 The type checker for $R_6$ is given in Figure~\ref{fig:typecheck-R6}.
 
 \begin{figure}[tbp]
-\begin{lstlisting}
-(define type-predicates (set 'boolean? 'integer? 'vector? 'procedure?))
+\begin{lstlisting}[basicstyle=\ttfamily\footnotesize]
+(define type-predicates
+  (set 'boolean? 'integer? 'vector? 'procedure?))
 
 (define (typecheck-R6 env)
   (lambda (e)
+    (define recur (typecheck-R6 env))
     (match e
-       [`(inject ,e ,ty)
-        (define-values (new-e e-ty) ((typecheck-R6 env) e))
+       [`(inject ,(app recur new-e e-ty) ,ty)
         (cond
          [(equal? e-ty ty)
           (values `(has-type (inject ,new-e ,ty) Any) 'Any)]
          [else
           (error "inject expected ~a to have type ~a" e ty)])]
-       [`(project ,e ,ty)
-        (define-values (new-e e-ty) ((typecheck-R6 env) e))
+       [`(project ,(app recur new-e e-ty) ,ty)
         (cond
          [(equal? e-ty 'Any)
           (values `(has-type (project ,new-e ,ty) ,ty) ty)]
          [else
           (error "project expected ~a to have type Any" e)])]
        [`(,pred ,e) #:when (set-member? type-predicates pred)
-        (define-values (new-e e-ty) ((typecheck-R6 env) e))
+        (define-values (new-e e-ty) (recur e))
         (cond
          [(equal? e-ty 'Any)
           (values `(has-type (,pred ,new-e) Boolean) 'Boolean)]
          [else
-          (error "~a expected arg. of type Any, not ~a" pred e-ty)])]
+          (error "predicate expected arg of type Any, not" e-ty)])]
+       [`(vector-ref ,(app recur e t) ,i)
+        (match t
+          [`(Vector ,ts ...) ...]
+          [`(Vectorof ,t)
+           (unless (exact-nonnegative-integer? i)
+             (error 'type-check "invalid index ~a" i))
+           (values `(has-type (vector-ref ,e (has-type ,i Integer)) ,t) t)]
+          [else (error "expected a vector in vector-ref, not" t)])]
+       [`(vector-set! ,(app recur e-vec^ t-vec) ,i
+                       ,(app recur e-arg^ t-arg))
+        (match t-vec
+          [`(Vector ,ts ...) ...]
+          [`(Vectorof ,t)
+           (unless (exact-nonnegative-integer? i)
+             (error 'type-check "invalid index ~a" i))
+           (unless (equal? t t-arg)
+             (error 'type-check "type mismatch in vector-set! ~a ~a" 
+                    t t-arg))
+           (values `(has-type (vector-set! ,e-vec^
+                                           (has-type ,i Integer)
+                                           ,e-arg^) Void) 'Void)]
+          [else (error 'type-check
+                       "expected a vector in vector-set!, not ~a"
+                       t-vec)])]
         ...
       )))
 \end{lstlisting}
@@ -5807,7 +5829,7 @@ for $R_6$.
             (error "in project, expected tagged value" v)])]
        ...)))
 \end{lstlisting}
-\caption{Definitional interpreter for $R_6$.}
+\caption{Interpreter for $R_6$.}
 \label{fig:interp-R6}
 \end{figure}
 
@@ -5815,7 +5837,7 @@ for $R_6$.
 \section{The $R_7$ Language: Untyped Racket}
 \label{sec:r7-lang}
 
-\begin{figure}[btp]
+\begin{figure}[tp]
 \centering
 \fbox{
 \begin{minipage}{0.97\textwidth}
@@ -5837,19 +5859,86 @@ R_7  &::=& (\key{program} \; \Def^{*}\; \Exp)
 \]
 \end{minipage}
 }
-\caption{The syntax of the $R_7$ language.}
+\caption{Syntax of $R_7$, an untyped language (a subset of Racket).}
 \label{fig:r7-syntax}
 \end{figure}
 
-Figure~\ref{fig:r7-syntax}
+The syntax of $R_7$, our subset of Racket, is defined in
+Figure~\ref{fig:r7-syntax}.
+%
+The definitional interpreter for $R_7$ is given in
+Figure~\ref{fig:interp-R7}.
+
+\begin{figure}[tbp]
+\begin{lstlisting}[basicstyle=\ttfamily\scriptsize]
+(define (interp-r7 env)
+  (lambda (ast)
+    (define recur (interp-r7 env))
+    (match ast
+      [(? symbol?) (lookup ast env)]
+      [(? integer?) `(inject ,ast Integer)]
+      [#t `(inject #t Boolean)]
+      [#f `(inject #f Boolean)]
+      [`(read) `(inject ,(read-fixnum) Integer)]
+      [`(lambda (,xs ...) ,body)
+       `(inject (lambda ,xs ,body ,env) (,@(map (lambda (x) 'Any) xs) -> Any))]
+      [`(define (,f ,xs ...) ,body)
+       (mcons f `(lambda ,xs ,body))]
+      [`(program ,ds ... ,body)
+       (let ([top-level (map (interp-r7 '()) ds)])
+         (for/list ([b top-level])
+           (set-mcdr! b (match (mcdr b)
+                          [`(lambda ,xs ,body)
+                           `(inject (lambda ,xs ,body ,top-level) 
+                                    (,@(map (lambda (x) 'Any) xs) -> Any))])))
+         ((interp-r7 top-level) body))]
+      [`(vector ,es ...)
+       (let* ([elts (map recur es)]
+              [tys (map get-injected-type elts)])
+         `(inject ,(apply vector (map recur es)) (Vector ,@tys)))]
+      [`(vector-set! ,e1 ,n ,e2)
+       (let ([e1^ (recur e1)]
+             [e2^ (recur e2)])
+         (match e1^ 
+           [`(inject ,vec ,ty) 
+            (vector-set! vec n e2^)
+            `(inject (void) Void)]))]
+      [`(vector-ref ,e ,n)
+       (let ([e^ (recur e)])
+         (match e^ 
+           [`(inject ,vec ,ty) 
+            (vector-ref vec n)]))]
+      [`(let ([,x ,e]) ,body)
+       (let ([v (recur e)])
+         ((interp-r7 (cons (cons x v) env)) body))]
+      [`(,op ,es ...) #:when (valid-op? op)
+       (interp-r7-op op (map recur es))]
+      [`(eq? ,l ,r)
+       `(inject ,(equal? (recur l) (recur r)) Boolean)]
+      [`(if ,q ,t ,f)
+       (match (recur q)
+         [`(inject #f Boolean)
+          (recur f)]
+         [else (recur t)])]
+      [`(,f ,es ...)
+       (define new-args (map recur es))
+       (let ([f-val (recur f)])
+         (match f-val 
+           [`(inject (lambda (,xs ...) ,body ,lam-env) ,ty)
+            (define new-env (append (map cons xs new-args) lam-env))
+            ((interp-r7 new-env) body)]
+           [else (error "interp-r7, expected function, not" f-val)]))])))
+\end{lstlisting}
+\caption{Interpreter for the $R_7$ language.}
+\label{fig:interp-R7}
+\end{figure}
 
-UNDER CONSTRUCTION
 
 
 \section{Compiling $R_6$}
 \label{sec:compile-r6}
 
-Most of the compiler passes only require obvious changes.  The
+Most of the compiler passes only require straightforward changes.  The
 interesting part is in instruction selection.
 
 \paragraph{Inject}
@@ -6125,7 +6214,7 @@ $\Rightarrow$
 \end{minipage} \\\hline
 \end{tabular}  \\
 
-\caption{Compiling $R_7$ (Untyped Racket) to $R_6$.}
+\caption{Compiling $R_7$ to $R_6$.}
 \label{fig:compile-r7-r6}
 \end{figure}
 
@@ -6253,7 +6342,77 @@ as the program file name but with \key{.scm} replaced with \key{.s}.
 \section{x86 Instruction Set Quick-Reference}
 \label{sec:x86-quick-reference}
 
-UNDER CONSTRUCTION
+
+Table~\ref{tab:x86-instr} lists some x86 instructions and what they
+do. We write $A \to B$ to mean that the value of $A$ is written into
+location $B$.  Address offsets are given in bytes. The instruction
+arguments $A, B, C$ can be immediate constants (such as $\$4$),
+registers (such as $\%rax$), or memory references (such as
+$-4(\%ebp)$). Most x86 instructions only allow at most one memory
+reference per instruction.  Other operands must be immediates or
+registers.
+
+
+\begin{table}[tbp]
+  \centering
+\begin{tabular}{l|l}
+\textbf{Instruction} & \textbf{Operation} \\ \hline
+\texttt{addq} $A$, $B$ &  $A + B \to B$\\
+\texttt{negq} $A$ & $- A \to A$ \\
+\texttt{subq} $A$, $B$ &  $B - A \to B$\\
+\texttt{callq} $L$ & Pushes the return address and jumps to label $L$ \\
+\texttt{callq} *$A$ & Calls the function at the address $A$. \\
+%\texttt{leave} & $\texttt{ebp} \to \texttt{esp};$ \texttt{popl \%ebp} \\
+\texttt{retq} & Pops the return address and jumps to it \\
+\texttt{popq} $A$ & $*\mathtt{rsp} \to A; \mathtt{rsp} + 8 \to \mathtt{rsp}$ \\
+\texttt{pushq} $A$ & $\texttt{rsp} - 8 \to \texttt{rsp}; A \to *\texttt{rsp}$\\
+\texttt{leaq} $A$,$B$ & $A \to B$ ($C$ must be a register) \\
+\texttt{cmpq} $A$, $B$ & compare $A$ and $B$ and set flag \\
+\texttt{je} $L$ & If the flag is set to ``equal'', jump to
+  label $L$ \\ 
+\texttt{jl} $L$ & If the flag is set to ``less'', jump to
+  label $L$ \\ 
+\texttt{jle} $L$ & If the flag is set to ``less or equal'', jump to
+  label $L$ \\ 
+\texttt{jg} $L$ & If the flag is set to ``greater'', jump to
+  label $L$ \\ 
+\texttt{jge} $L$ & If the flag is set to ``greater or equal'', jump to
+  label $L$ \\ 
+\texttt{jmp} $L$ & Jump to label $L$ \\
+\texttt{movq} $A$, $B$ &  $A \to B$ \\
+\texttt{movzbq} $A$, $B$ & $A \to B$ \\
+ & \text{where } $A$ is a single-byte register (e.g., \texttt{al} or \texttt{cl}), $B$ is a 8-byte register, \\
+ & and the extra bytes of $B$ are set to zero \\
+\texttt{notq} $A$ & $\sim A \to A$ \qquad (bitwise complement)\\
+\texttt{orq} $A$, $B$ & $A | B \to B$ \qquad (bitwise-or)\\
+\texttt{andq} $A$, $B$ & $A \& B \to B$ \qquad (bitwise-and)\\
+\texttt{salq} $A$, $B$ & $B$ \texttt{<<} $A \to B$ (where $A$ is a constant)\\
+\texttt{sarq} $A$, $B$ & $B$ \texttt{>>} $A \to B$ (where $A$ is a constant)\\
+\texttt{sete} $A$ & If the flag is set to ``equal'', then
+   $1 \to A$, else $0 \to A$. \\
+ & $A$ must be a single byte register (e.g., \texttt{al} or \texttt{cl}). \\
+\texttt{setne} $A$ & If the flag is set to ``not equal'', then
+   $1 \to A$, else $0 \to A$. \\
+ & $A$ must be a single byte register (e.g., \texttt{al} or \texttt{cl}). \\
+\texttt{setl} $A$ & If the flag is set to ``less'', then
+   $1 \to A$, else $0 \to A$. \\
+ & $A$ must be a single byte register (e.g., \texttt{al} or \texttt{cl}). \\
+\texttt{setle} $A$ & If the flag is set to ``less or equal'', then
+   $1 \to A$, else $0 \to A$. \\
+ & $A$ must be a single byte register (e.g., \texttt{al} or \texttt{cl}). \\
+\texttt{setg} $A$ & If the flag is set to ``greater, then
+   $1 \to A$, else $0 \to A$. \\
+ & $A$ must be a single byte register (e.g., \texttt{al} or \texttt{cl}). \\
+\texttt{setge} $A$ & If the flag is set to ``greater or equal'', then
+   $1 \to A$, else $0 \to A$. \\
+ & $A$ must be a single byte register (e.g., \texttt{al} or \texttt{cl}). 
+\end{tabular}
+\vspace{5pt}
+  \caption{Quick-reference for the x86 instructions used in this book.}
+  \label{tab:x86-instr}
+\end{table}
+
+
 
 \bibliographystyle{plainnat}
 \bibliography{all}

+ 21 - 18
s-expr-example.rkt

@@ -41,21 +41,21 @@
 (arith? `(+ 50 (- 8)))
 (arith? `(- 50 (+ 8)))
 
-(define (interp-arith e)
+(define (interp-R0 e)
   (match e
     [(? fixnum?) e]
     [`(read)
      (let ([r (read)])
        (cond [(fixnum? r) r]
-             [else (error 'interp-arith "input was not an integer" r)]))]
-    [`(- ,e)
-     (fx- 0 (interp-arith e))]
-    [`(+ ,e1 ,e2)
-     (fx+ (interp-arith e1) (interp-arith e2))]
+              [else (error 'interp-R0 "input was not an integer" r)]))]
+    [`(- ,(app interp-R0 v))
+     (fx- 0 v)]
+    [`(+ ,(app interp-R0 v1) ,(app interp-R0 v2))
+     (fx+ v1 v2)]
     ))
 
-(interp-arith ast1.1)
-;(interp-arith `(+ (read) (- 8)))
+(interp-R0 ast1.1)
+;(interp-R0 `(+ (read) (- 8)))
 
 (define (pe-neg r)
   (match r
@@ -131,13 +131,16 @@
 
 
 (define (test-pe pe p)
-  (assert "testing pe-arith" (equal? (interp-arith p)
-                                     (interp-arith (pe p)))))
-
-(test-pe pe-arith `(+ (read) (- (+ 5 3))))
-(test-pe pe-arith `(+ 1 (+ (read) 1)))
-(test-pe pe-arith `(- (+ (read) (- 5))))
-
-(test-pe pe-arith2 `(+ (read) (- (+ 5 3))))
-(test-pe pe-arith2 `(+ 1 (+ (read) 1)))
-(test-pe pe-arith2 `(- (+ (read) (- 5))))
+  (assert "testing pe-arith" (equal? (interp-R0 p)
+                                     (interp-R0 (pe p)))))
+(if #f 
+    (begin
+      (test-pe pe-arith `(+ (read) (- (+ 5 3))))
+      (test-pe pe-arith `(+ 1 (+ (read) 1)))
+      (test-pe pe-arith `(- (+ (read) (- 5))))
+      
+      (test-pe pe-arith2 `(+ (read) (- (+ 5 3))))
+      (test-pe pe-arith2 `(+ 1 (+ (read) 1)))
+      (test-pe pe-arith2 `(- (+ (read) (- 5))))
+      )
+    (void))