|
@@ -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}
|