Ver Fonte

proof reading ch 1

Jeremy Siek há 3 anos atrás
pai
commit
7bd53b5358
2 ficheiros alterados com 121 adições e 115 exclusões
  1. 110 106
      book.tex
  2. 11 9
      defs.tex

+ 110 - 106
book.tex

@@ -177,7 +177,7 @@ colleagues in the 1950s, computer scientists discovered techniques for
 constructing programs, called \emph{compilers}, that automatically
 constructing programs, called \emph{compilers}, that automatically
 translate high-level programs into machine code.
 translate high-level programs into machine code.
 
 
-We take you on a journey by constructing your own compiler for a small
+We take you on a journey of constructing your own compiler for a small
 but powerful language. Along the way we explain the essential
 but powerful language. Along the way we explain the essential
 concepts, algorithms, and data structures that underlie compilers. We
 concepts, algorithms, and data structures that underlie compilers. We
 develop your understanding of how programs are mapped onto computer
 develop your understanding of how programs are mapped onto computer
@@ -195,17 +195,18 @@ A compiler is typically organized as a sequence of stages that
 progressively translate a program to the code that runs on
 progressively translate a program to the code that runs on
 hardware. We take this approach to the extreme by partitioning our
 hardware. We take this approach to the extreme by partitioning our
 compiler into a large number of \emph{nanopasses}, each of which
 compiler into a large number of \emph{nanopasses}, each of which
-performs a single task. This allows us to test the output of each pass
-in isolation, and furthermore, allows us to focus our attention which
-makes the compiler far easier to understand.
-
-The most familiar approach to describing compilers is with one pass
-per chapter.  The problem with that approach is it obfuscates how
-language features motivate design choices in a compiler. We instead
-take an \emph{incremental} approach in which we build a complete
-compiler in each chapter, starting with a small input language that
-includes only arithmetic and variables and we add new language
-features in subsequent chapters.
+performs a single task. This enables the testing of each pass in
+isolation and focuses our attention, making the compiler far easier to
+understand.
+
+The most familiar approach to describing compilers is with each
+chapter dedicated to one pass.  The problem with that approach is it
+obfuscates how language features motivate design choices in a
+compiler. We instead take an \emph{incremental} approach in which we
+build a complete compiler in each chapter, starting with a small input
+language that includes only arithmetic and variables. We add new
+language features in subsequent chapters, extending the compiler as
+necessary.
 
 
 Our choice of language features is designed to elicit fundamental
 Our choice of language features is designed to elicit fundamental
 concepts and algorithms used in compilers.
 concepts and algorithms used in compilers.
@@ -216,23 +217,22 @@ concepts and algorithms used in compilers.
     syntax trees} and \emph{recursive functions}. 
     syntax trees} and \emph{recursive functions}. 
 \item In Chapter~\ref{ch:register-allocation-Lvar} we apply
 \item In Chapter~\ref{ch:register-allocation-Lvar} we apply
   \emph{graph coloring} to assign variables to machine registers.
   \emph{graph coloring} to assign variables to machine registers.
-\item Chapter~\ref{ch:Lif} adds \code{if} expressions, which motivates
-  an elegant recursive algorithm for translating them into conditional
-  \code{goto}'s.
-\item Chapter~\ref{ch:Lwhile} fleshes out support for imperative
-  programming languages with the addition of loops\racket{ and mutable
+\item Chapter~\ref{ch:Lif} adds conditional expressions, which
+  motivates an elegant recursive algorithm for translating them into
+  conditional \code{goto}'s.
+\item Chapter~\ref{ch:Lwhile} adds loops\racket{ and mutable
   variables}. This elicits the need for \emph{dataflow
   variables}. This elicits the need for \emph{dataflow
     analysis} in the register allocator.
     analysis} in the register allocator.
 \item Chapter~\ref{ch:Lvec} adds heap-allocated tuples, motivating
 \item Chapter~\ref{ch:Lvec} adds heap-allocated tuples, motivating
   \emph{garbage collection}.
   \emph{garbage collection}.
-\item Chapter~\ref{ch:Lfun} adds functions that are first-class values
-  but lack lexical scoping, similar to the C programming
-  language~\citep{Kernighan:1988nx} except that we generate efficient
-  tail calls. The reader learns about the procedure call stack,
-  \emph{calling conventions}, and their interaction with register
-  allocation and garbage collection.
+\item Chapter~\ref{ch:Lfun} adds functions as first-class values but
+  without lexical scoping, similar to functions in the C programming
+  language~\citep{Kernighan:1988nx}. The reader learns about the
+  procedure call stack and \emph{calling conventions} and how they interact
+  with register allocation and garbage collection. The chapter also
+  describes how to generate efficient tail calls.
 \item Chapter~\ref{ch:Llambda} adds anonymous functions with lexical
 \item Chapter~\ref{ch:Llambda} adds anonymous functions with lexical
-  scoping, i.e., \emph{lambda abstraction}. The reader learns about
+  scoping, i.e., \emph{lambda} expressions. The reader learns about
   \emph{closure conversion}, in which lambdas are translated into a
   \emph{closure conversion}, in which lambdas are translated into a
   combination of functions and tuples.
   combination of functions and tuples.
 % Chapter about classes and objects?  
 % Chapter about classes and objects?  
@@ -276,8 +276,8 @@ that we assign to the graduate students. The last two weeks of the
 course involve a final project in which students design and implement
 course involve a final project in which students design and implement
 a compiler extension of their choosing.  The later chapters can be
 a compiler extension of their choosing.  The later chapters can be
 used in support of these projects.  For compiler courses at
 used in support of these projects.  For compiler courses at
-universities on the quarter system that are about 10 weeks in length,
-we recommend completing up through Chapter~\ref{ch:Lvec} or
+universities on the quarter system (about 10 weeks in length), we
+recommend completing up through Chapter~\ref{ch:Lvec} or
 Chapter~\ref{ch:Lfun} and providing some scafolding code to the
 Chapter~\ref{ch:Lfun} and providing some scafolding code to the
 students for each compiler pass.
 students for each compiler pass.
 %
 %
@@ -291,7 +291,7 @@ dynamically typed languages by including Chapter~\ref{ch:Ldyn}.
 %
 %
 Figure~\ref{fig:chapter-dependences} depicts the dependencies between
 Figure~\ref{fig:chapter-dependences} depicts the dependencies between
 chapters. Chapter~\ref{ch:Lfun} (functions) depends on
 chapters. Chapter~\ref{ch:Lfun} (functions) depends on
-Chapter~\ref{ch:Lvec} (tuples) in the implementation of efficient
+Chapter~\ref{ch:Lvec} (tuples) only in the implementation of efficient
 tail calls.
 tail calls.
 
 
 This book has been used in compiler courses at California Polytechnic
 This book has been used in compiler courses at California Polytechnic
@@ -391,8 +391,8 @@ the following location:
 
 
 The compiler targets x86 assembly language~\citep{Intel:2015aa}, so it
 The compiler targets x86 assembly language~\citep{Intel:2015aa}, so it
 is helpful but not necessary for the reader to have taken a computer
 is helpful but not necessary for the reader to have taken a computer
-systems course~\citep{Bryant:2010aa}. This book introduces the parts
-of x86-64 assembly language that are needed.
+systems course~\citep{Bryant:2010aa}. We introduce the parts of x86-64
+assembly language that are needed in the compiler.
 %
 %
 We follow the System V calling
 We follow the System V calling
 conventions~\citep{Bryant:2005aa,Matz:2013aa}, so the assembly code
 conventions~\citep{Bryant:2005aa,Matz:2013aa}, so the assembly code
@@ -434,12 +434,11 @@ incremental approach~\citep{Ghuloum:2006bh} that this book is based
 on.
 on.
 
 
 We thank the many students who served as teaching assistants for the
 We thank the many students who served as teaching assistants for the
-compiler course at IU and made suggestions for improving the book
-including Carl Factora, Ryan Scott, Cameron Swords, and Chris
-Wailes. We thank Andre Kuhlenschmidt for work on the garbage collector
-and x86 interpreter, Michael Vollmer for work on efficient tail calls,
-and Michael Vitousek for help running the first offering of the
-incremental compiler course at IU.
+compiler course at IU including Carl Factora, Ryan Scott, Cameron
+Swords, and Chris Wailes. We thank Andre Kuhlenschmidt for work on the
+garbage collector and x86 interpreter, Michael Vollmer for work on
+efficient tail calls, and Michael Vitousek for help with the first
+offering of the incremental compiler course at IU.
 
 
 We thank professors Bor-Yuh Chang, John Clements, Jay McCarthy, Joseph
 We thank professors Bor-Yuh Chang, John Clements, Jay McCarthy, Joseph
 Near, Ryan Newton, Nate Nystrom, Peter Thiemann, Andrew Tolmach, and
 Near, Ryan Newton, Nate Nystrom, Peter Thiemann, Andrew Tolmach, and
@@ -606,7 +605,8 @@ node it is the child of). If a node has no children, it is a
 We define a Racket \code{struct} for each kind of node.  For this
 We define a Racket \code{struct} for each kind of node.  For this
 chapter we require just two kinds of nodes: one for integer constants
 chapter we require just two kinds of nodes: one for integer constants
 and one for primitive operations.  The following is the \code{struct}
 and one for primitive operations.  The following is the \code{struct}
-definition for integer constants.
+definition for integer constants.\footnote{All of the AST structures are
+defined in the file \code{utilities.rkt} in the support code.}
 \begin{lstlisting}
 \begin{lstlisting}
 (struct Int (value))
 (struct Int (value))
 \end{lstlisting}
 \end{lstlisting}
@@ -625,16 +625,16 @@ The following is the \code{struct} definition for primitive operations.
 \end{lstlisting}
 \end{lstlisting}
 A primitive operation node includes an operator symbol \code{op} and a
 A primitive operation node includes an operator symbol \code{op} and a
 list of child \code{args}. For example, to create an AST that negates
 list of child \code{args}. For example, to create an AST that negates
-the number $8$, we write \code{(Prim '- (list eight))}.
+the number $8$, we write the following.
 \begin{lstlisting}
 \begin{lstlisting}
 (define neg-eight (Prim '- (list eight)))
 (define neg-eight (Prim '- (list eight)))
 \end{lstlisting}
 \end{lstlisting}
 Primitive operations may have zero or more children. The \code{read}
 Primitive operations may have zero or more children. The \code{read}
-operator has zero children:
+operator has zero:
 \begin{lstlisting}
 \begin{lstlisting}
 (define rd (Prim 'read '()))
 (define rd (Prim 'read '()))
 \end{lstlisting}
 \end{lstlisting}
-whereas the addition operator has two children:
+The addition operator has two children:
 \begin{lstlisting}
 \begin{lstlisting}
 (define ast1_1 (Prim '+ (list rd neg-eight)))
 (define ast1_1 (Prim '+ (list rd neg-eight)))
 \end{lstlisting}
 \end{lstlisting}
@@ -726,9 +726,9 @@ we need to be able to access its two children. \racket{Racket}\python{Python}
 provides pattern matching to support these kinds of queries, as we see in
 provides pattern matching to support these kinds of queries, as we see in
 Section~\ref{sec:pattern-matching}.
 Section~\ref{sec:pattern-matching}.
 
 
-In this book, we often write down the concrete syntax of a program
-even when we really have in mind the AST because the concrete syntax
-is more concise.  We recommend that, in your mind, you always think of
+We often write down the concrete syntax of a program even when we
+really have in mind the AST because the concrete syntax is more
+concise.  We recommend that, in your mind, you always think of
 programs as abstract syntax trees.
 programs as abstract syntax trees.
 
 
 \section{Grammars}
 \section{Grammars}
@@ -739,10 +739,10 @@ programs as abstract syntax trees.
 
 
 A programming language can be thought of as a \emph{set} of programs.
 A programming language can be thought of as a \emph{set} of programs.
 The set is typically infinite (one can always create larger and larger
 The set is typically infinite (one can always create larger and larger
-programs), so one cannot simply describe a language by listing all of
+programs) so one cannot simply describe a language by listing all of
 the programs in the language. Instead we write down a set of rules, a
 the programs in the language. Instead we write down a set of rules, a
 \emph{grammar}, for building programs. Grammars are often used to
 \emph{grammar}, for building programs. Grammars are often used to
-define the concrete syntax of a language, but they can also be used to
+define the concrete syntax of a language but they can also be used to
 describe the abstract syntax. We write our rules in a variant of
 describe the abstract syntax. We write our rules in a variant of
 Backus-Naur Form (BNF)~\citep{Backus:1960aa,Knuth:1964aa}.
 Backus-Naur Form (BNF)~\citep{Backus:1960aa,Knuth:1964aa}.
 \index{subject}{Backus-Naur Form}\index{subject}{BNF}
 \index{subject}{Backus-Naur Form}\index{subject}{BNF}
@@ -779,7 +779,7 @@ $\Int$ is a sequence of decimals ($0$ to $9$), possibly starting with
 $-$ (for negative integers), such that the sequence of decimals
 $-$ (for negative integers), such that the sequence of decimals
 represent an integer in range $-2^{62}$ to $2^{62}-1$.  This enables
 represent an integer in range $-2^{62}$ to $2^{62}-1$.  This enables
 the representation of integers using 63 bits, which simplifies several
 the representation of integers using 63 bits, which simplifies several
-aspects of compilation. \racket{Thus, these integers corresponds to
+aspects of compilation. \racket{Thus, these integers correspond to
   the Racket \texttt{fixnum} datatype on a 64-bit machine.}
   the Racket \texttt{fixnum} datatype on a 64-bit machine.}
 \python{In contrast, integers in Python have unlimited precision, but
 \python{In contrast, integers in Python have unlimited precision, but
   the techniques needed to handle unlimited precision fall outside the
   the techniques needed to handle unlimited precision fall outside the
@@ -791,8 +791,8 @@ input integer from the user of the program.
   \Exp ::= \READ{} \label{eq:arith-read}
   \Exp ::= \READ{} \label{eq:arith-read}
 \end{equation}
 \end{equation}
 
 
-The third rule says that, given an $\Exp$ node, the negation of that
-node is also an $\Exp$.
+The third rule categorizes the negation of an $\Exp$ node as an
+$\Exp$.
 \begin{equation}
 \begin{equation}
   \Exp ::= \NEG{\Exp}  \label{eq:arith-neg}
   \Exp ::= \NEG{\Exp}  \label{eq:arith-neg}
 \end{equation}
 \end{equation}
@@ -836,7 +836,7 @@ is an $\Exp$ in the \LangInt{} language.
 If you have an AST for which the above rules do not apply, then the
 If you have an AST for which the above rules do not apply, then the
 AST is not in \LangInt{}. For example, the program \racket{\code{(*
 AST is not in \LangInt{}. For example, the program \racket{\code{(*
     (read) 8)}} \python{\code{input\_int() * 8}} is not in \LangInt{}
     (read) 8)}} \python{\code{input\_int() * 8}} is not in \LangInt{}
-because there are no rules for the \key{*} operator.  Whenever we
+because there is no rule for the \key{*} operator.  Whenever we
 define a language with a grammar, the language only includes those
 define a language with a grammar, the language only includes those
 programs that are justified by the grammar rules.
 programs that are justified by the grammar rules.
 
 
@@ -1026,18 +1026,17 @@ match ast1_1:
 {\if\edition\racketEd
 {\if\edition\racketEd
 %
 %
 In the above example, the \texttt{match} form checks whether the AST
 In the above example, the \texttt{match} form checks whether the AST
-\eqref{eq:arith-prog} is a binary operator, binds its parts to the
+\eqref{eq:arith-prog} is a binary operator and binds its parts to the
 three pattern variables \texttt{op}, \texttt{child1}, and
 three pattern variables \texttt{op}, \texttt{child1}, and
-\texttt{child2}, and then prints out the operator. In general, a match
-clause consists of a \emph{pattern} and a
-\emph{body}.\index{subject}{pattern} Patterns are recursively defined
-to be either a pattern variable, a structure name followed by a
-pattern for each of the structure's arguments, or an S-expression
-(symbols, lists, etc.).  (See Chapter 12 of The Racket
+\texttt{child2}. In general, a match clause consists of a
+\emph{pattern} and a \emph{body}.\index{subject}{pattern} Patterns are
+recursively defined to be either a pattern variable, a structure name
+followed by a pattern for each of the structure's arguments, or an
+S-expression (symbols, lists, etc.).  (See Chapter 12 of The Racket
 Guide\footnote{\url{https://docs.racket-lang.org/guide/match.html}}
 Guide\footnote{\url{https://docs.racket-lang.org/guide/match.html}}
 and Chapter 9 of The Racket
 and Chapter 9 of The Racket
 Reference\footnote{\url{https://docs.racket-lang.org/reference/match.html}}
 Reference\footnote{\url{https://docs.racket-lang.org/reference/match.html}}
-for a complete description of \code{match}.)
+for complete descriptions 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, such as
 pattern variables can be used in the scope of the body, such as
@@ -1143,19 +1142,22 @@ print(leaf(Constant(8)))
 \end{minipage}
 \end{minipage}
 \end{center}
 \end{center}
 
 
-When writing a \code{match}, we refer to the grammar definition to
-identify which non-terminal we are expecting to match against, then we
-make sure that 1) we have one \racket{clause}\python{case} for each alternative of that
-non-terminal and 2) that the pattern in each \racket{clause}\python{case} corresponds to the
-corresponding right-hand side of a grammar rule. For the \code{match}
-in the \code{leaf} function, we refer to the grammar for \LangInt{} in
-Figure~\ref{fig:r0-syntax}. The $\Exp$ non-terminal has 4
-alternatives, so the \code{match} has 4 \racket{clauses}\python{cases}.
-The pattern in each \racket{clause}\python{case} corresponds to the right-hand side
-of a grammar rule. For example, the pattern \ADD{\code{e1}}{\code{e2}} corresponds to the
-right-hand side $\ADD{\Exp}{\Exp}$. When translating from grammars to
-patterns, replace non-terminals such as $\Exp$ with pattern variables
-of your choice (e.g. \code{e1} and \code{e2}).
+When constructing a \code{match} expression, we refer to the grammar
+definition to identify which non-terminal we are expecting to match
+against, then we make sure that 1) we have one
+\racket{clause}\python{case} for each alternative of that non-terminal
+and 2) that the pattern in each \racket{clause}\python{case}
+corresponds to the corresponding right-hand side of a grammar
+rule. For the \code{match} in the \code{leaf} function, we refer to
+the grammar for \LangInt{} in Figure~\ref{fig:r0-syntax}. The $\Exp$
+non-terminal has 4 alternatives, so the \code{match} has 4
+\racket{clauses}\python{cases}.  The pattern in each
+\racket{clause}\python{case} corresponds to the right-hand side of a
+grammar rule. For example, the pattern \ADDP{\code{e1}}{\code{e2}}
+corresponds to the right-hand side $\ADD{\Exp}{\Exp}$. When
+translating from grammars to patterns, replace non-terminals such as
+$\Exp$ with pattern variables of your choice (e.g. \code{e1} and
+\code{e2}).
 
 
 
 
 \section{Recursive Functions}
 \section{Recursive Functions}
@@ -1165,7 +1167,7 @@ of your choice (e.g. \code{e1} and \code{e2}).
 Programs are inherently recursive. For example, an expression is often
 Programs are inherently recursive. For example, an expression is often
 made of smaller expressions. Thus, the natural way to process an
 made of smaller expressions. Thus, the natural way to process an
 entire program is with a recursive function.  As a first example of
 entire program is with a recursive function.  As a first example of
-such a recursive function, we define the function \code{exp} in
+such a recursive function, we define the function \code{is\_exp} in
 Figure~\ref{fig:exp-predicate}, which takes an arbitrary value and
 Figure~\ref{fig:exp-predicate}, which takes an arbitrary value and
 determines whether or not it is an expression in \LangInt{}.
 determines whether or not it is an expression in \LangInt{}.
 %
 %
@@ -1175,74 +1177,74 @@ that correspond to a grammar, and the body of each
 \racket{clause}\python{case} makes a recursive call on each child
 \racket{clause}\python{case} makes a recursive call on each child
 node.\footnote{This principle of structuring code according to the
 node.\footnote{This principle of structuring code according to the
   data definition is advocated in the book \emph{How to Design
   data definition is advocated in the book \emph{How to Design
-    Programs} \url{https://htdp.org/2020-8-1/Book/index.html}.}
-\python{We define a second function, named \code{stmt}, that
-  recognizes whether a value is a \LangInt{} statement.}
-\python{Finally, } Figure~\ref{fig:exp-predicate} \racket{also}
-defines \code{Lint}, which determines whether an AST is a program in
-\LangInt{}.  In general we can expect to write one recursive function
-to handle each non-terminal in a grammar.\index{subject}{structural
-  recursion} Of the two examples at the bottom of the figure, the
-first is in \code{Lint} and the second is not.
+    Programs} by \citet{Felleisen:2001aa}.}  \python{We define a
+  second function, named \code{stmt}, that recognizes whether a value
+  is a \LangInt{} statement.}  \python{Finally, }
+Figure~\ref{fig:exp-predicate} \racket{also} defines \code{is\_Lint},
+which determines whether an AST is a program in \LangInt{}.  In
+general we can write one recursive function to handle each
+non-terminal in a grammar.\index{subject}{structural recursion} Of the
+two examples at the bottom of the figure, the first is in
+\LangInt{} and the second is not.
 
 
 \begin{figure}[tp]
 \begin{figure}[tp]
 {\if\edition\racketEd
 {\if\edition\racketEd
 \begin{lstlisting}
 \begin{lstlisting}
-(define (exp ast)
+(define (is_exp ast)
   (match ast
   (match ast
     [(Int n) #t]
     [(Int n) #t]
     [(Prim 'read '()) #t]
     [(Prim 'read '()) #t]
-    [(Prim '- (list e)) (exp e)]
+    [(Prim '- (list e)) (is_exp e)]
     [(Prim '+ (list e1 e2))
     [(Prim '+ (list e1 e2))
-      (and (exp e1) (exp e2))]
+      (and (is_exp e1) (is_exp e2))]
     [else #f]))
     [else #f]))
 
 
-(define (Lint ast)
+(define (is_Lint ast)
   (match ast
   (match ast
-    [(Program '() e) (exp e)]
+    [(Program '() e) (is_exp e)]
     [else #f]))
     [else #f]))
 
 
-(Lint (Program '() ast1_1)
-(Lint (Program '()
+(is_Lint (Program '() ast1_1)
+(is_Lint (Program '()
        (Prim '- (list (Prim 'read '())
        (Prim '- (list (Prim 'read '())
                       (Prim '+ (list (Int 8)))))))
                       (Prim '+ (list (Int 8)))))))
 \end{lstlisting}
 \end{lstlisting}
 \fi}
 \fi}
 {\if\edition\pythonEd
 {\if\edition\pythonEd
 \begin{lstlisting}
 \begin{lstlisting}
-def exp(e):
+def is_exp(e):
   match e:
   match e:
     case Constant(n):
     case Constant(n):
       return True
       return True
     case Call(Name('input_int'), []):
     case Call(Name('input_int'), []):
       return True
       return True
     case UnaryOp(USub(), e1):
     case UnaryOp(USub(), e1):
-      return exp(e1)
+      return is_exp(e1)
     case BinOp(e1, Add(), e2):
     case BinOp(e1, Add(), e2):
-      return exp(e1) and exp(e2)
+      return is_exp(e1) and is_exp(e2)
     case BinOp(e1, Sub(), e2):
     case BinOp(e1, Sub(), e2):
-      return exp(e1) and exp(e2)
+      return is_exp(e1) and is_exp(e2)
     case _:
     case _:
       return False
       return False
 
 
 def stmt(s):
 def stmt(s):
   match s:
   match s:
     case Expr(Call(Name('print'), [e])):
     case Expr(Call(Name('print'), [e])):
-      return exp(e)
+      return is_exp(e)
     case Expr(e):
     case Expr(e):
-      return exp(e)
+      return is_exp(e)
     case _:
     case _:
       return False
       return False
   
   
-def Lint(p):
+def is_Lint(p):
   match p:
   match p:
     case Module(body):
     case Module(body):
       return all([stmt(s) for s in body])
       return all([stmt(s) for s in body])
     case _:
     case _:
       return False
       return False
 
 
-print(Lint(Module([Expr(ast1_1)])))
-print(Lint(Module([Expr(BinOp(read, Sub(),
+print(is_Lint(Module([Expr(ast1_1)])))
+print(is_Lint(Module([Expr(BinOp(read, Sub(),
                   UnaryOp(Add(), Constant(8))))])))
                   UnaryOp(Add(), Constant(8))))])))
 \end{lstlisting}
 \end{lstlisting}
 \fi}
 \fi}
@@ -1292,14 +1294,15 @@ programming language.
 \python{For example, the Python language is defined in the Python
 \python{For example, the Python language is defined in the Python
   Language Reference~\citep{PSF21:python_ref} and the CPython interpreter~\citep{PSF21:cpython}.}
   Language Reference~\citep{PSF21:python_ref} and the CPython interpreter~\citep{PSF21:cpython}.}
 %
 %
-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}.
+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{subject}{definitional interpreter} We warm up by creating a
 \index{subject}{definitional interpreter} We warm up by creating a
-definitional interpreter for the \LangInt{} language, which serves as
-a second example of structural recursion. The \code{interp\_Lint}
-function is defined in Figure~\ref{fig:interp_Lint}.
+definitional interpreter for the \LangInt{} language. This interpreter
+serves as a second example of structural recursion. The
+\code{interp\_Lint} function is defined in
+Figure~\ref{fig:interp_Lint}.
 %
 %
 \racket{The body of the function is a match on the input program
 \racket{The body of the function is a match on the input program
   followed by a call to the \lstinline{interp_exp} helper function,
   followed by a call to the \lstinline{interp_exp} helper function,
@@ -1384,9 +1387,10 @@ following program adds two integers.
 print(10 + 32)
 print(10 + 32)
 \end{lstlisting}
 \end{lstlisting}
 \fi}
 \fi}
-The result is \key{42}, the answer to life, the universe, and
-everything: \code{42}!\footnote{\emph{The Hitchhiker's Guide to the
-    Galaxy} by Douglas Adams.}
+%
+\noindent The result is \key{42}, the answer to life, the universe,
+and everything: \code{42}!\footnote{\emph{The Hitchhiker's Guide to
+    the Galaxy} by Douglas Adams.}
 %
 %
 We wrote the above program in concrete syntax whereas the parsed
 We wrote the above program in concrete syntax whereas the parsed
 abstract syntax is:
 abstract syntax is:
@@ -1625,7 +1629,7 @@ def pe_P_int(p):
 
 
 
 
 To gain some confidence that the partial evaluator is correct, we can
 To gain some confidence that the partial evaluator is correct, we can
-test whether it produces programs that get the same result as the
+test whether it produces programs that produce the same result as the
 input programs. That is, we can test whether it satisfies Diagram
 input programs. That is, we can test whether it satisfies Diagram
 \ref{eq:compile-correct}.
 \ref{eq:compile-correct}.
 %
 %

+ 11 - 9
defs.tex

@@ -127,11 +127,12 @@
 \if\edition\racketEd
 \if\edition\racketEd
 \newcommand{\INT}[1]{{\key{(Int}~#1\key{)}}}
 \newcommand{\INT}[1]{{\key{(Int}~#1\key{)}}}
 \newcommand{\READOP}{{\key{read}}}
 \newcommand{\READOP}{{\key{read}}}
-\newcommand{\READ}{{\key{(Prim}~\code{read}~\key{())}}}
+\newcommand{\READ}{{\key{(Prim}~\code{'read}~\key{())}}}
 \newcommand{\CREAD}{\key{(read)}}
 \newcommand{\CREAD}{\key{(read)}}
-\newcommand{\NEG}[1]{{\key{(Prim}~\code{-}~\code{(}#1\code{))}}}
-\newcommand{\ADD}[2]{{\key{(Prim}~\code{+}~\code{(}#1~#2\code{))}}}
-\newcommand{\SUB}[2]{\key{(Prim}~\code{-}~\code{(}#1~#2\code{))}}
+\newcommand{\NEG}[1]{{\key{(Prim}~\code{'-}~\code{(}#1\code{))}}}
+\newcommand{\ADD}[2]{{\key{(Prim}~\code{'+}~\code{(}#1~#2\code{))}}}
+\newcommand{\ADDP}[2]{{\key{(Prim}~\code{'+}~\code{(list}~#1~#2\code{))}}}
+\newcommand{\SUB}[2]{\key{(Prim}~\code{'-}~\code{(}#1~#2\code{))}}
 \newcommand{\PROGRAM}[2]{\LP\code{Program}~#1~#2\RP}
 \newcommand{\PROGRAM}[2]{\LP\code{Program}~#1~#2\RP}
 \newcommand{\VAR}[1]{\key{(Var}~#1\key{)}}
 \newcommand{\VAR}[1]{\key{(Var}~#1\key{)}}
 \newcommand{\BOOL}[1]{\key{(Bool}~#1\key{)}}
 \newcommand{\BOOL}[1]{\key{(Bool}~#1\key{)}}
@@ -144,10 +145,10 @@
 \newcommand{\CEQ}[2]{\LP\key{eq?}~#1~#2\RP}
 \newcommand{\CEQ}[2]{\LP\key{eq?}~#1~#2\RP}
 \newcommand{\IF}[3]{\key{(If}\,#1~#2~#3\key{)}}
 \newcommand{\IF}[3]{\key{(If}\,#1~#2~#3\key{)}}
 \newcommand{\CIF}[3]{\LP\key{if}~#1~#2~#3\RP}
 \newcommand{\CIF}[3]{\LP\key{if}~#1~#2~#3\RP}
-\newcommand{\AND}[2]{\key{(Prim}~\code{and}~\code{(}#1~#2\code{))}}
-\newcommand{\OR}[2]{\key{(Prim}~\code{or}~\code{(}#1~#2\code{))}}
-\newcommand{\CAND}[2]{\CBINOP{\key{and}}{#1}{#2}}
-\newcommand{\COR}[2]{\CBINOP{\key{or}}{#1}{#2}}
+\newcommand{\AND}[2]{\key{(Prim}~\code{'and}~\code{(}#1~#2\code{))}}
+\newcommand{\OR}[2]{\key{(Prim}~\code{'or}~\code{(}#1~#2\code{))}}
+\newcommand{\CAND}[2]{\CBINOP{\key{'and}}{#1}{#2}}
+\newcommand{\COR}[2]{\CBINOP{\key{'or}}{#1}{#2}}
 \newcommand{\INTTY}{{\key{Integer}}}
 \newcommand{\INTTY}{{\key{Integer}}}
 \newcommand{\INTTYPE}{{\key{Integer}}}
 \newcommand{\INTTYPE}{{\key{Integer}}}
 \newcommand{\BOOLTY}{{\key{Boolean}}}
 \newcommand{\BOOLTY}{{\key{Boolean}}}
@@ -165,7 +166,7 @@
 \newcommand{\CGLOBAL}[1]{#1\key{(\%rip)}}
 \newcommand{\CGLOBAL}[1]{#1\key{(\%rip)}}
 \newcommand{\GLOBALVALUE}[1]{\LP\key{GlobalValue}~#1\RP}
 \newcommand{\GLOBALVALUE}[1]{\LP\key{GlobalValue}~#1\RP}
 \newcommand{\CGLOBALVALUE}[1]{\LP\key{global-value}~#1\RP}
 \newcommand{\CGLOBALVALUE}[1]{\LP\key{global-value}~#1\RP}
-\newcommand{\ARITY}[1]{\LP\key{Prim}~\code{procedure-arity}~\LP#1\RP\RP}
+\newcommand{\ARITY}[1]{\LP\key{Prim}~\code{'procedure-arity}~\LP#1\RP\RP}
 \newcommand{\CARITY}[1]{\LP\key{procedure-arity}~#1\RP}
 \newcommand{\CARITY}[1]{\LP\key{procedure-arity}~#1\RP}
 \fi
 \fi
 
 
@@ -179,6 +180,7 @@
 \newcommand{\CREAD}{\key{input\_int()}}
 \newcommand{\CREAD}{\key{input\_int()}}
 \newcommand{\NEG}[1]{{\key{UnaryOp(USub(),} #1\code{)}}}
 \newcommand{\NEG}[1]{{\key{UnaryOp(USub(),} #1\code{)}}}
 \newcommand{\ADD}[2]{{\key{BinOp}\LP #1\code{,} \key{Add()}\key{,}#2\code{)}}}
 \newcommand{\ADD}[2]{{\key{BinOp}\LP #1\code{,} \key{Add()}\key{,}#2\code{)}}}
+\newcommand{\ADDP}[2]{{\key{BinOp}\LP #1\code{,} \key{Add()}\key{,}#2\code{)}}}
 \newcommand{\SUB}[2]{{\key{BinOp}\LP \key{Sub()}\key{,}#1\code{,}#2\code{)}}}
 \newcommand{\SUB}[2]{{\key{BinOp}\LP \key{Sub()}\key{,}#1\code{,}#2\code{)}}}
 \newcommand{\PRINT}[1]{{\key{Expr}\LP\key{Call}\LP\key{Name}\LP\key{'print'}\RP\key{,}\LS#1\RS\RP\RP}}
 \newcommand{\PRINT}[1]{{\key{Expr}\LP\key{Call}\LP\key{Name}\LP\key{'print'}\RP\key{,}\LS#1\RS\RP\RP}}
 \newcommand{\CPRINT}[1]{\key{print}\LP #1\RP}
 \newcommand{\CPRINT}[1]{\key{print}\LP #1\RP}