|
@@ -1963,9 +1963,9 @@ following code uses method overriding to interpret \LangInt{} and
|
|
%
|
|
%
|
|
\racket{the
|
|
\racket{the
|
|
\href{https://docs.racket-lang.org/guide/classes.html}{\code{class}}
|
|
\href{https://docs.racket-lang.org/guide/classes.html}{\code{class}}
|
|
- \index{subject}{class} feature of Racket}
|
|
|
|
|
|
+ \index{subject}{class} feature of Racket.}
|
|
%
|
|
%
|
|
-\python{a Python \code{class} definition}.
|
|
|
|
|
|
+\python{a Python \code{class} definition.}
|
|
%
|
|
%
|
|
We define one class for each language and define a method for
|
|
We define one class for each language and define a method for
|
|
interpreting expressions inside each class. The class for \LangVar{}
|
|
interpreting expressions inside each class. The class for \LangVar{}
|
|
@@ -2125,11 +2125,11 @@ value bound to a variable to all the uses of the variable. To
|
|
accomplish this, we maintain a mapping from variables to values
|
|
accomplish this, we maintain a mapping from variables to values
|
|
called an \emph{environment}\index{subject}{environment}.
|
|
called an \emph{environment}\index{subject}{environment}.
|
|
%
|
|
%
|
|
-We use%
|
|
|
|
|
|
+We use
|
|
%
|
|
%
|
|
-\racket{an association list (alist)}
|
|
|
|
|
|
+\racket{an association list (alist) }%
|
|
%
|
|
%
|
|
-\python{a Python \href{https://docs.python.org/3.10/library/stdtypes.html\#mapping-types-dict}{dictionary}}
|
|
|
|
|
|
+\python{a Python \href{https://docs.python.org/3.10/library/stdtypes.html\#mapping-types-dict}{dictionary} }%
|
|
%
|
|
%
|
|
to represent the environment.
|
|
to represent the environment.
|
|
%
|
|
%
|
|
@@ -2165,7 +2165,9 @@ variable, it looks up the corresponding value in the dictionary.
|
|
[else (error 'interp_exp "expected an integer" r)])]
|
|
[else (error 'interp_exp "expected an integer" r)])]
|
|
[(Prim '- (list e)) (fx- 0 ((interp_exp env) e))]
|
|
[(Prim '- (list e)) (fx- 0 ((interp_exp env) e))]
|
|
[(Prim '+ (list e1 e2))
|
|
[(Prim '+ (list e1 e2))
|
|
- (fx+ ((interp_exp env) e1) ((interp_exp env) e2))]))
|
|
|
|
|
|
+ (fx+ ((interp_exp env) e1) ((interp_exp env) e2))]
|
|
|
|
+ [(Prim '- (list e1 e2))
|
|
|
|
+ (fx- ((interp_exp env) e1) ((interp_exp env) e2))]))
|
|
|
|
|
|
(define/public (interp_program p)
|
|
(define/public (interp_program p)
|
|
(match p
|
|
(match p
|
|
@@ -2180,6 +2182,8 @@ class InterpLint:
|
|
match e:
|
|
match e:
|
|
case BinOp(left, Add(), right):
|
|
case BinOp(left, Add(), right):
|
|
return self.interp_exp(left, env) + self.interp_exp(right, env)
|
|
return self.interp_exp(left, env) + self.interp_exp(right, env)
|
|
|
|
+ case BinOp(left, Sub(), right):
|
|
|
|
+ return self.interp_exp(left, env) - self.interp_exp(right, env)
|
|
case UnaryOp(USub(), v):
|
|
case UnaryOp(USub(), v):
|
|
return - self.interp_exp(v, env)
|
|
return - self.interp_exp(v, env)
|
|
case Constant(value):
|
|
case Constant(value):
|
|
@@ -2276,8 +2280,8 @@ criteria in the following diagram.
|
|
\path[->] (p2) edge [right] node {\footnotesize\code{interp\_x86int}} (o);
|
|
\path[->] (p2) edge [right] node {\footnotesize\code{interp\_x86int}} (o);
|
|
\end{tikzpicture}
|
|
\end{tikzpicture}
|
|
\]
|
|
\]
|
|
-In the next section we introduce the \LangXInt{} subset of x86 that
|
|
|
|
-suffices for compiling \LangVar{}.
|
|
|
|
|
|
+Next we introduce the \LangXInt{} subset of x86 that suffices for
|
|
|
|
+compiling \LangVar{}.
|
|
|
|
|
|
\section{The \LangXInt{} Assembly Language}
|
|
\section{The \LangXInt{} Assembly Language}
|
|
\label{sec:x86}
|
|
\label{sec:x86}
|
|
@@ -2398,7 +2402,7 @@ puts $10$ into register \key{rax} and then \lstinline{addq $32, %rax}
|
|
adds $32$ to the $10$ in \key{rax} and
|
|
adds $32$ to the $10$ in \key{rax} and
|
|
puts the result, $42$, back into \key{rax}.
|
|
puts the result, $42$, back into \key{rax}.
|
|
%
|
|
%
|
|
-The last instruction, \key{retq}, finishes the \key{main} function by
|
|
|
|
|
|
+The last instruction \key{retq} finishes the \key{main} function by
|
|
returning the integer in \key{rax} to the operating system. The
|
|
returning the integer in \key{rax} to the operating system. The
|
|
operating system interprets this integer as the program's exit
|
|
operating system interprets this integer as the program's exit
|
|
code. By convention, an exit code of 0 indicates that a program
|
|
code. By convention, an exit code of 0 indicates that a program
|
|
@@ -2436,13 +2440,13 @@ term \emph{pointer}\index{subject}{pointer} for something that
|
|
contains an address. The stack grows downward in memory, so we
|
|
contains an address. The stack grows downward in memory, so we
|
|
increase the size of the stack by subtracting from the stack pointer.
|
|
increase the size of the stack by subtracting from the stack pointer.
|
|
In the context of a procedure call, the \emph{return
|
|
In the context of a procedure call, the \emph{return
|
|
-address}\index{subject}{return address} is the instruction after the
|
|
|
|
|
|
+ address}\index{subject}{return address} is the instruction after the
|
|
call instruction on the caller side. The function call instruction,
|
|
call instruction on the caller side. The function call instruction,
|
|
\code{callq}, pushes the return address onto the stack prior to
|
|
\code{callq}, pushes the return address onto the stack prior to
|
|
jumping to the procedure. The register \key{rbp} is the \emph{base
|
|
jumping to the procedure. The register \key{rbp} is the \emph{base
|
|
-pointer}\index{subject}{base pointer} and is used to access variables
|
|
|
|
-that are stored in the frame of the current procedure call. The base
|
|
|
|
-pointer of the caller is store after the return address. In
|
|
|
|
|
|
+ pointer}\index{subject}{base pointer} and is used to access
|
|
|
|
+variables that are stored in the frame of the current procedure call.
|
|
|
|
+The base pointer of the caller is stored after the return address. In
|
|
Figure~\ref{fig:frame} we number the variables from $1$ to
|
|
Figure~\ref{fig:frame} we number the variables from $1$ to
|
|
$n$. Variable $1$ is stored at address $-8\key{(\%rbp)}$, variable $2$
|
|
$n$. Variable $1$ is stored at address $-8\key{(\%rbp)}$, variable $2$
|
|
at $-16\key{(\%rbp)}$, etc.
|
|
at $-16\key{(\%rbp)}$, etc.
|
|
@@ -2515,19 +2519,20 @@ which pushes its return address on the stack and then jumps to
|
|
by 16 bytes prior to the execution of any \code{callq} instruction, so
|
|
by 16 bytes prior to the execution of any \code{callq} instruction, so
|
|
when control arrives at \code{main}, the \code{rsp} is 8 bytes out of
|
|
when control arrives at \code{main}, the \code{rsp} is 8 bytes out of
|
|
alignment (because the \code{callq} pushed the return address). The
|
|
alignment (because the \code{callq} pushed the return address). The
|
|
-first three instructions are the typical \emph{prelude}\index{subject}{prelude}
|
|
|
|
-for a procedure. The instruction \code{pushq \%rbp} first subtracts $8$ from the stack
|
|
|
|
-pointer and then saves the base pointer of the caller at address
|
|
|
|
-\code{rsp} on the stack. The next instruction \code{movq \%rsp, \%rbp} sets the
|
|
|
|
-base pointer to the current stack pointer, which is pointing at the location
|
|
|
|
-of the old base pointer. The instruction \code{subq \$16, \%rsp} moves the stack
|
|
|
|
-pointer down to make enough room for storing variables. This program
|
|
|
|
-needs one variable ($8$ bytes) but we round up to 16 bytes so that
|
|
|
|
-\code{rsp} is 16-byte aligned and we're ready to make calls to other
|
|
|
|
-functions.
|
|
|
|
-\racket{The last instruction of the prelude is \code{jmp start},
|
|
|
|
-which transfers control to the instructions that were generated from
|
|
|
|
-the expression \racket{\code{(+ 52 (- 10))}}\python{52 + -10}.}
|
|
|
|
|
|
+first three instructions are the typical
|
|
|
|
+\emph{prelude}\index{subject}{prelude} for a procedure. The
|
|
|
|
+instruction \code{pushq \%rbp} first subtracts $8$ from the stack
|
|
|
|
+pointer \code{rsp} and then saves the base pointer of the caller at
|
|
|
|
+address \code{rsp} on the stack. The next instruction \code{movq
|
|
|
|
+ \%rsp, \%rbp} sets the base pointer to the current stack pointer,
|
|
|
|
+which is pointing at the location of the old base pointer. The
|
|
|
|
+instruction \code{subq \$16, \%rsp} moves the stack pointer down to
|
|
|
|
+make enough room for storing variables. This program needs one
|
|
|
|
+variable ($8$ bytes) but we round up to 16 bytes so that \code{rsp} is
|
|
|
|
+16-byte aligned and we're ready to make calls to other functions.
|
|
|
|
+\racket{The last instruction of the prelude is \code{jmp start}, which
|
|
|
|
+ transfers control to the instructions that were generated from the
|
|
|
|
+ expression \racket{\code{(+ 52 (- 10))}}\python{52 + -10}.}
|
|
|
|
|
|
\racket{The first instruction under the \code{start} label is}
|
|
\racket{The first instruction under the \code{start} label is}
|
|
%
|
|
%
|
|
@@ -2535,7 +2540,8 @@ the expression \racket{\code{(+ 52 (- 10))}}\python{52 + -10}.}
|
|
%
|
|
%
|
|
\code{movq \$10, -8(\%rbp)}, which stores $10$ in variable $1$.
|
|
\code{movq \$10, -8(\%rbp)}, which stores $10$ in variable $1$.
|
|
%
|
|
%
|
|
-The instruction \code{negq -8(\%rbp)} changes variable $1$ to $-10$.
|
|
|
|
|
|
+The instruction \code{negq -8(\%rbp)} changes the contents of variable
|
|
|
|
+$1$ to $-10$.
|
|
%
|
|
%
|
|
The next instruction moves the $-10$ from variable $1$ into the
|
|
The next instruction moves the $-10$ from variable $1$ into the
|
|
\code{rax} register. Finally, \code{addq \$52, \%rax} adds $52$ to
|
|
\code{rax} register. Finally, \code{addq \$52, \%rax} adds $52$ to
|
|
@@ -2550,7 +2556,7 @@ the value in \code{rax}, updating its contents to $42$.
|
|
The first two restore the \code{rsp} and \code{rbp} registers to the
|
|
The first two restore the \code{rsp} and \code{rbp} registers to the
|
|
state they were in at the beginning of the procedure. In particular,
|
|
state they were in at the beginning of the procedure. In particular,
|
|
\key{addq \$16, \%rsp} moves the stack pointer back to point at the
|
|
\key{addq \$16, \%rsp} moves the stack pointer back to point at the
|
|
-old base pointer. Then \key{popq \%rbp} returns the old base pointer
|
|
|
|
|
|
+old base pointer. Then \key{popq \%rbp} restores the old base pointer
|
|
to \key{rbp} and adds $8$ to the stack pointer. The last instruction,
|
|
to \key{rbp} and adds $8$ to the stack pointer. The last instruction,
|
|
\key{retq}, jumps back to the procedure that called this one and adds
|
|
\key{retq}, jumps back to the procedure that called this one and adds
|
|
$8$ to the stack pointer.
|
|
$8$ to the stack pointer.
|
|
@@ -2574,7 +2580,7 @@ label associated with every block, which is why the \key{X86Program}
|
|
struct includes an alist mapping labels to blocks. The reason for this
|
|
struct includes an alist mapping labels to blocks. The reason for this
|
|
organization becomes apparent in Chapter~\ref{ch:Lif} when we
|
|
organization becomes apparent in Chapter~\ref{ch:Lif} when we
|
|
introduce conditional branching. The \code{Block} structure includes
|
|
introduce conditional branching. The \code{Block} structure includes
|
|
-an $\itm{info}$ field that is not needed for this chapter, but becomes
|
|
|
|
|
|
+an $\itm{info}$ field that is not needed for this chapter but becomes
|
|
useful in Chapter~\ref{ch:register-allocation-Lvar}. For now, the
|
|
useful in Chapter~\ref{ch:register-allocation-Lvar}. For now, the
|
|
$\itm{info}$ field should contain an empty list.
|
|
$\itm{info}$ field should contain an empty list.
|
|
\fi}
|
|
\fi}
|
|
@@ -2676,8 +2682,8 @@ down the problem into several steps, dealing with the above
|
|
differences one at a time. Each of these steps is called a \emph{pass}
|
|
differences one at a time. Each of these steps is called a \emph{pass}
|
|
of the compiler.\index{subject}{pass}\index{subject}{compiler pass}
|
|
of the compiler.\index{subject}{pass}\index{subject}{compiler pass}
|
|
%
|
|
%
|
|
-This terminology comes from the way each step passes over, that is,
|
|
|
|
-traverses the AST of the program.
|
|
|
|
|
|
+This terminology comes from the way each step passes over, or
|
|
|
|
+traverses, the AST of the program.
|
|
%
|
|
%
|
|
Furthermore, we follow the nanopass approach, which means we strive
|
|
Furthermore, we follow the nanopass approach, which means we strive
|
|
for each pass to accomplish one clear objective (not two or three at
|
|
for each pass to accomplish one clear objective (not two or three at
|
|
@@ -2712,10 +2718,10 @@ Our compiler for \LangVar{} consists of the following passes.
|
|
|
|
|
|
{\if\edition\racketEd
|
|
{\if\edition\racketEd
|
|
\item[\key{explicate\_control}] makes the execution order of the
|
|
\item[\key{explicate\_control}] makes the execution order of the
|
|
- program explicit. It converts the abstract syntax tree representation
|
|
|
|
- into a control-flow graph in which each node contains a sequence of
|
|
|
|
- statements and the edges between nodes say which nodes contain jumps
|
|
|
|
- to other nodes.
|
|
|
|
|
|
+ program explicit. It converts the abstract syntax tree
|
|
|
|
+ representation into a graph in which each node contains a sequence
|
|
|
|
+ of statements and the edges between nodes say which nodes contain
|
|
|
|
+ jumps to other nodes.
|
|
\fi}
|
|
\fi}
|
|
|
|
|
|
\item[\key{select\_instructions}] handles the difference between
|
|
\item[\key{select\_instructions}] handles the difference between
|
|
@@ -2742,8 +2748,8 @@ The next question is: in what order should we apply these passes? This
|
|
question can be challenging because it is difficult to know ahead of
|
|
question can be challenging because it is difficult to know ahead of
|
|
time which orderings will be better (easier to implement, produce more
|
|
time which orderings will be better (easier to implement, produce more
|
|
efficient code, etc.) so oftentimes trial-and-error is
|
|
efficient code, etc.) so oftentimes trial-and-error is
|
|
-involved. Nevertheless, we can try to plan ahead and make educated
|
|
|
|
-choices regarding the ordering.
|
|
|
|
|
|
+involved. Nevertheless, we can plan ahead and make educated choices
|
|
|
|
+regarding the ordering.
|
|
|
|
|
|
\racket{What should be the ordering of \key{explicate\_control} with respect to
|
|
\racket{What should be the ordering of \key{explicate\_control} with respect to
|
|
\key{uniquify}? The \key{uniquify} pass should come first because
|
|
\key{uniquify}? The \key{uniquify} pass should come first because
|
|
@@ -2751,12 +2757,12 @@ choices regarding the ordering.
|
|
become local variables whose scope is the entire program, which would
|
|
become local variables whose scope is the entire program, which would
|
|
confuse variables with the same name.}
|
|
confuse variables with the same name.}
|
|
%
|
|
%
|
|
-\racket{We place \key{remove\_complex\_opera*} before \key{explicate\_control}
|
|
|
|
|
|
+\racket{We place \key{remove\_complex\_operands} before \key{explicate\_control}
|
|
because the later removes the \key{let} form, but it is convenient to
|
|
because the later removes the \key{let} form, but it is convenient to
|
|
-use \key{let} in the output of \key{remove\_complex\_opera*}.}
|
|
|
|
|
|
+use \key{let} in the output of \key{remove\_complex\_operands}.}
|
|
%
|
|
%
|
|
\racket{The ordering of \key{uniquify} with respect to
|
|
\racket{The ordering of \key{uniquify} with respect to
|
|
-\key{remove\_complex\_opera*} does not matter so we arbitrarily choose
|
|
|
|
|
|
+\key{remove\_complex\_operands} does not matter so we arbitrarily choose
|
|
\key{uniquify} to come first.}
|
|
\key{uniquify} to come first.}
|
|
|
|
|
|
The \key{select\_instructions} and \key{assign\_homes} passes are
|
|
The \key{select\_instructions} and \key{assign\_homes} passes are
|
|
@@ -2836,13 +2842,13 @@ The last pass, \key{prelude\_and\_conclusion}, places the program
|
|
instructions inside a \code{main} function with instructions for the
|
|
instructions inside a \code{main} function with instructions for the
|
|
prelude and conclusion.
|
|
prelude and conclusion.
|
|
%
|
|
%
|
|
-\racket{In the following section we discuss the \LangCVar{}
|
|
|
|
- intermediate language.}
|
|
|
|
|
|
+\racket{In the next section we discuss the \LangCVar{} intermediate
|
|
|
|
+ language that serves as the output of \code{explicate\_control}.}
|
|
%
|
|
%
|
|
The remainder of this chapter provides guidance on the implementation
|
|
The remainder of this chapter provides guidance on the implementation
|
|
of each of the compiler passes in Figure~\ref{fig:Lvar-passes}.
|
|
of each of the compiler passes in Figure~\ref{fig:Lvar-passes}.
|
|
|
|
|
|
-%% The output of \key{uniquify} and \key{remove-complex-opera*}
|
|
|
|
|
|
+%% The output of \key{uniquify} and \key{remove-complex-operands}
|
|
%% are programs that are still in the \LangVar{} language, though the
|
|
%% are programs that are still in the \LangVar{} language, though the
|
|
%% output of the later is a subset of \LangVar{} named \LangVarANF{}
|
|
%% output of the later is a subset of \LangVar{} named \LangVarANF{}
|
|
%% (Section~\ref{sec:remove-complex-opera-Lvar}).
|
|
%% (Section~\ref{sec:remove-complex-opera-Lvar}).
|
|
@@ -2882,8 +2888,8 @@ language~\citep{Kernighan:1988nx} in that it has separate syntactic
|
|
categories for expressions and statements, so we name it \LangCVar{}.
|
|
categories for expressions and statements, so we name it \LangCVar{}.
|
|
This style of intermediate language is also known as
|
|
This style of intermediate language is also known as
|
|
\emph{three-address code}, to emphasize that the typical form of a
|
|
\emph{three-address code}, to emphasize that the typical form of a
|
|
-statement is \CASSIGN{\key{x}}{\CADD{\key{y}}{\key{z}}} involves three
|
|
|
|
-addresses~\citep{Aho:2006wb}.
|
|
|
|
|
|
+statement such as \CASSIGN{\key{x}}{\CADD{\key{y}}{\key{z}}} involves three
|
|
|
|
+addresses: \code{x}, \code{y}, and \code{z}~\citep{Aho:2006wb}.
|
|
|
|
|
|
The concrete syntax for \LangCVar{} is defined in
|
|
The concrete syntax for \LangCVar{} is defined in
|
|
Figure~\ref{fig:c0-concrete-syntax} and the abstract syntax for
|
|
Figure~\ref{fig:c0-concrete-syntax} and the abstract syntax for
|
|
@@ -2897,7 +2903,8 @@ assignment statements which can be executed in sequence using the
|
|
\key{Return}, a guarantee that is baked into the grammar rules for
|
|
\key{Return}, a guarantee that is baked into the grammar rules for
|
|
\itm{tail}. The naming of this non-terminal comes from the term
|
|
\itm{tail}. The naming of this non-terminal comes from the term
|
|
\emph{tail position}\index{subject}{tail position}, which refers to an
|
|
\emph{tail position}\index{subject}{tail position}, which refers to an
|
|
-expression that is the last one to execute within a function.
|
|
|
|
|
|
+expression that is the last one to execute within a function or
|
|
|
|
+program.
|
|
|
|
|
|
A \LangCVar{} program consists of an alist mapping labels to
|
|
A \LangCVar{} program consists of an alist mapping labels to
|
|
tails. This is more general than necessary for the present chapter, as
|
|
tails. This is more general than necessary for the present chapter, as
|
|
@@ -2990,40 +2997,42 @@ with a \key{let} nested inside the initializing expression of another
|
|
\end{transformation}
|
|
\end{transformation}
|
|
|
|
|
|
We recommend implementing \code{uniquify} by creating a structurally
|
|
We recommend implementing \code{uniquify} by creating a structurally
|
|
-recursive function named \code{uniquify-exp} that mostly just copies
|
|
|
|
|
|
+recursive function named \code{uniquify\_exp} that mostly just copies
|
|
an expression. However, when encountering a \key{let}, it should
|
|
an expression. However, when encountering a \key{let}, it should
|
|
generate a unique name for the variable and associate the old name
|
|
generate a unique name for the variable and associate the old name
|
|
with the new name in an alist.\footnote{The Racket function
|
|
with the new name in an alist.\footnote{The Racket function
|
|
\code{gensym} is handy for generating unique variable names.} The
|
|
\code{gensym} is handy for generating unique variable names.} The
|
|
-\code{uniquify-exp} function needs to access this alist when it gets
|
|
|
|
-to a variable reference, so we add a parameter to \code{uniquify-exp}
|
|
|
|
|
|
+\code{uniquify\_exp} function needs to access this alist when it gets
|
|
|
|
+to a variable reference, so we add a parameter to \code{uniquify\_exp}
|
|
for the alist.
|
|
for the alist.
|
|
|
|
|
|
-The skeleton of the \code{uniquify-exp} function is shown in
|
|
|
|
-Figure~\ref{fig:uniquify-Lvar}. The function is curried so that it is
|
|
|
|
-convenient to partially apply it to an alist and then apply it to
|
|
|
|
-different expressions, as in the last case for primitive operations in
|
|
|
|
-Figure~\ref{fig:uniquify-Lvar}. The
|
|
|
|
|
|
+The skeleton of the \code{uniquify\_exp} function is shown in
|
|
|
|
+Figure~\ref{fig:uniquify-Lvar}.
|
|
|
|
+%% The function is curried so that it is
|
|
|
|
+%% convenient to partially apply it to an alist and then apply it to
|
|
|
|
+%% different expressions, as in the last case for primitive operations in
|
|
|
|
+%% Figure~\ref{fig:uniquify-Lvar}.
|
|
|
|
+The
|
|
%
|
|
%
|
|
\href{https://docs.racket-lang.org/reference/for.html#%28form._%28%28lib._racket%2Fprivate%2Fbase..rkt%29._for%2Flist%29%29}{\key{for/list}}
|
|
\href{https://docs.racket-lang.org/reference/for.html#%28form._%28%28lib._racket%2Fprivate%2Fbase..rkt%29._for%2Flist%29%29}{\key{for/list}}
|
|
%
|
|
%
|
|
-form of Racket is useful for transforming each element of a list to
|
|
|
|
|
|
+form of Racket is useful for transforming the element of a list to
|
|
produce a new list.\index{subject}{for/list}
|
|
produce a new list.\index{subject}{for/list}
|
|
|
|
|
|
\begin{figure}[tbp]
|
|
\begin{figure}[tbp]
|
|
\begin{lstlisting}
|
|
\begin{lstlisting}
|
|
-(define (uniquify-exp env)
|
|
|
|
|
|
+(define (uniquify_exp env)
|
|
(lambda (e)
|
|
(lambda (e)
|
|
(match e
|
|
(match e
|
|
[(Var x) ___]
|
|
[(Var x) ___]
|
|
[(Int n) (Int n)]
|
|
[(Int n) (Int n)]
|
|
[(Let x e body) ___]
|
|
[(Let x e body) ___]
|
|
[(Prim op es)
|
|
[(Prim op es)
|
|
- (Prim op (for/list ([e es]) ((uniquify-exp env) e)))])))
|
|
|
|
|
|
+ (Prim op (for/list ([e es]) ((uniquify_exp env) e)))])))
|
|
|
|
|
|
(define (uniquify p)
|
|
(define (uniquify p)
|
|
(match p
|
|
(match p
|
|
- [(Program '() e) (Program '() ((uniquify-exp '()) e))]))
|
|
|
|
|
|
+ [(Program '() e) (Program '() ((uniquify_exp '()) e))]))
|
|
\end{lstlisting}
|
|
\end{lstlisting}
|
|
\caption{Skeleton for the \key{uniquify} pass.}
|
|
\caption{Skeleton for the \key{uniquify} pass.}
|
|
\label{fig:uniquify-Lvar}
|
|
\label{fig:uniquify-Lvar}
|
|
@@ -3328,7 +3337,7 @@ regarding file names described in Exercise~\ref{ex:Lvar}.
|
|
In the \code{run-tests.rkt} script, add the following entry to the
|
|
In the \code{run-tests.rkt} script, add the following entry to the
|
|
list of \code{passes} and then run the script to test your compiler.
|
|
list of \code{passes} and then run the script to test your compiler.
|
|
\begin{lstlisting}
|
|
\begin{lstlisting}
|
|
-(list "remove-complex" remove-complex-opera* interp_Lvar type-check-Lvar)
|
|
|
|
|
|
+(list "remove-complex" remove-complex-operands interp_Lvar type-check-Lvar)
|
|
\end{lstlisting}
|
|
\end{lstlisting}
|
|
While debugging your compiler, it is often useful to see the
|
|
While debugging your compiler, it is often useful to see the
|
|
intermediate programs that are output from each pass. To print the
|
|
intermediate programs that are output from each pass. To print the
|
|
@@ -6529,7 +6538,6 @@ respectively. The \LangIf{} language includes all of
|
|
\FALSE{},\racket{ and} the \code{if} expression\python{, and the
|
|
\FALSE{},\racket{ and} the \code{if} expression\python{, and the
|
|
\code{if} statement}. We expand the set of operators to include
|
|
\code{if} statement}. We expand the set of operators to include
|
|
\begin{enumerate}
|
|
\begin{enumerate}
|
|
-\item subtraction on integers,
|
|
|
|
\item the logical operators \key{and}, \key{or}, and \key{not},
|
|
\item the logical operators \key{and}, \key{or}, and \key{not},
|
|
\item the \racket{\key{eq?} operation}\python{\key{==} and \key{!=} operations}
|
|
\item the \racket{\key{eq?} operation}\python{\key{==} and \key{!=} operations}
|
|
for comparing integers or Booleans for equality, and
|
|
for comparing integers or Booleans for equality, and
|
|
@@ -6550,7 +6558,7 @@ respectively. The \LangIf{} language includes all of
|
|
\Type &::=& \key{Boolean} \\
|
|
\Type &::=& \key{Boolean} \\
|
|
\itm{bool} &::=& \TRUE \MID \FALSE \\
|
|
\itm{bool} &::=& \TRUE \MID \FALSE \\
|
|
\itm{cmp} &::= & \key{eq?} \MID \key{<} \MID \key{<=} \MID \key{>} \MID \key{>=} \\
|
|
\itm{cmp} &::= & \key{eq?} \MID \key{<} \MID \key{<=} \MID \key{>} \MID \key{>=} \\
|
|
- \Exp &::=& \CSUB{\Exp}{\Exp} \MID \itm{bool}
|
|
|
|
|
|
+ \Exp &::=& \itm{bool}
|
|
\MID (\key{and}\;\Exp\;\Exp) \MID (\key{or}\;\Exp\;\Exp)
|
|
\MID (\key{and}\;\Exp\;\Exp) \MID (\key{or}\;\Exp\;\Exp)
|
|
\MID (\key{not}\;\Exp) \\
|
|
\MID (\key{not}\;\Exp) \\
|
|
&\MID& (\itm{cmp}\;\Exp\;\Exp) \MID \CIF{\Exp}{\Exp}{\Exp}
|
|
&\MID& (\itm{cmp}\;\Exp\;\Exp) \MID \CIF{\Exp}{\Exp}{\Exp}
|
|
@@ -6736,8 +6744,6 @@ class InterpLif(InterpLvar):
|
|
return self.interp_exp(body, env)
|
|
return self.interp_exp(body, env)
|
|
else:
|
|
else:
|
|
return self.interp_exp(orelse, env)
|
|
return self.interp_exp(orelse, env)
|
|
- case BinOp(left, Sub(), right):
|
|
|
|
- return self.interp_exp(left, env) - self.interp_exp(right, env)
|
|
|
|
case UnaryOp(Not(), v):
|
|
case UnaryOp(Not(), v):
|
|
return not self.interp_exp(v, env)
|
|
return not self.interp_exp(v, env)
|
|
case BoolOp(And(), values):
|
|
case BoolOp(And(), values):
|
|
@@ -7623,7 +7629,7 @@ Run the script to test your compiler on all the test programs.
|
|
\section{Uniquify Variables}
|
|
\section{Uniquify Variables}
|
|
\label{sec:uniquify-Lif}
|
|
\label{sec:uniquify-Lif}
|
|
|
|
|
|
-Add cases to \code{uniquify-exp} to handle Boolean constants and
|
|
|
|
|
|
+Add cases to \code{uniquify\_exp} to handle Boolean constants and
|
|
\code{if} expressions.
|
|
\code{if} expressions.
|
|
|
|
|
|
\begin{exercise}\normalfont
|
|
\begin{exercise}\normalfont
|
|
@@ -7728,7 +7734,7 @@ code in this pass.
|
|
In the \code{run-tests.rkt} script, add the following entry to the
|
|
In the \code{run-tests.rkt} script, add the following entry to the
|
|
list of \code{passes} and then run the script to test your compiler.
|
|
list of \code{passes} and then run the script to test your compiler.
|
|
\begin{lstlisting}
|
|
\begin{lstlisting}
|
|
-(list "remove-complex" remove-complex-opera* interp-Lif type-check-Lif)
|
|
|
|
|
|
+(list "remove-complex" remove-complex-operands interp-Lif type-check-Lif)
|
|
\end{lstlisting}
|
|
\end{lstlisting}
|
|
\fi}
|
|
\fi}
|
|
\end{exercise}
|
|
\end{exercise}
|