浏览代码

chap 8 updates

Jeremy Siek 6 年之前
父节点
当前提交
599e2f5ad1
共有 1 个文件被更改,包括 113 次插入120 次删除
  1. 113 120
      book.tex

+ 113 - 120
book.tex

@@ -6870,8 +6870,12 @@ needed for compiling untyped Racket. The type predicates,
 $(\key{boolean?}\,e)$ etc., expect a tagged value and return \key{\#t}
 $(\key{boolean?}\,e)$ etc., expect a tagged value and return \key{\#t}
 if the tag corresponds to the predicate, and return \key{\#t}
 if the tag corresponds to the predicate, and return \key{\#t}
 otherwise.
 otherwise.
-%
-The type checker for $R_6$ is given in Figure~\ref{fig:typecheck-R6}.
+
+
+The type checker for $R_6$ is given in Figure~\ref{fig:typecheck-R6}
+and the definitional interpreter for $R_6$ is in
+Figure~\ref{fig:interp-R6}
+
 
 
 \begin{figure}[tbp]
 \begin{figure}[tbp]
 \begin{lstlisting}[basicstyle=\ttfamily\footnotesize]
 \begin{lstlisting}[basicstyle=\ttfamily\footnotesize]
@@ -6935,8 +6939,6 @@ The type checker for $R_6$ is given in Figure~\ref{fig:typecheck-R6}.
 
 
 %Also, \key{eq?} is extended to operate on values of type \key{Any}.
 %Also, \key{eq?} is extended to operate on values of type \key{Any}.
 
 
-Figure~\ref{fig:interp-R6} shows the definitional interpreter
-for $R_6$.
 
 
 \begin{figure}[tbp]
 \begin{figure}[tbp]
 \begin{lstlisting}
 \begin{lstlisting}
@@ -7012,59 +7014,59 @@ Figure~\ref{fig:interp-R7}.
 
 
 \begin{figure}[tbp]
 \begin{figure}[tbp]
 \begin{lstlisting}[basicstyle=\ttfamily\footnotesize]
 \begin{lstlisting}[basicstyle=\ttfamily\footnotesize]
-(define (get-tagged-type v) (match v [`(tagged ,v1 ,ty) ty]))
+(define (tag-of-any e)
+  (match e
+    [`(tagged ,v ,ty) ty]
+    [else (error 'tag-of-any "expected a tagged value, not ~a" e)]
+    ))
+
+(define (value-of-any e)
+  (match e
+    [`(tagged ,v ,ty) v]
+    [else (error 'value-of-any "expected a tagged value, not ~a" e)]))
 
 
-(define (valid-op? op) (member op '(+ - and or not)))
+(define (tag-value v)
+  (cond [(boolean? v) `(tagged ,v Boolean)]
+        [(fixnum? v) `(tagged ,v Integer)]
+        [(procedure? v)
+         (define n (procedure-arity v))
+         `(tagged ,v (,@(for/list ([_ (range 0 n)]) 'Any) -> Any))]
+        ...))
 
 
-(define (interp-r7 env)
+(define (interp-R7-exp env)
   (lambda (ast)
   (lambda (ast)
-    (define recur (interp-r7 env))
+    (vomit "interp-R7-exp" ast env)
+    (define recur (interp-R7-exp env))
     (match ast
     (match ast
-      [(? symbol?) (lookup ast env)]
-      [(? integer?) `(inject ,ast Integer)]
-      [#t `(inject #t Boolean)]
-      [#f `(inject #f Boolean)]
-      [`(read) `(inject ,(read-fixnum) Integer)]
+      ...
+      [(? integer?) `(tagged ,ast Integer)]
+      [#t `(tagged #t Boolean)]
       [`(lambda (,xs ...) ,body)
       [`(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 (for/list ([d ds]) ((interp-r7 '()) d))])
-         (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 ,(app recur elts) ...)
-       (define tys (map get-tagged-type elts))
-       `(inject ,(apply vector elts) (Vector ,@tys))]
-      [`(vector-set! ,(app recur v1) ,n ,(app recur v2))
-         (match v1
-           [`(inject ,vec ,ty)
-             (vector-set! vec n v2)
-            `(inject (void) Void)])]
-      [`(vector-ref ,(app recur v) ,n)
-       (match v [`(inject ,vec ,ty) (vector-ref vec n)])]
-      [`(let ([,x ,(app recur v)]) ,body)
-       ((interp-r7 (cons (cons x v) env)) body)]
-      [`(,op ,es ...) #:when (valid-op? op)
-       (interp-r7-op op (for/list ([e es]) (recur e)))]
-      [`(eq? ,(app recur l) ,(app recur r))
-       `(inject ,(equal? l r) Boolean)]
-      [`(if ,(app recur q) ,t ,f)
-       (match q
-         [`(inject #f Boolean) (recur f)]
+       `(tagged (lambda ,xs ,body ,env) (,@(for/list ([x xs]) 'Any) -> Any))]
+      [`(vector-ref ,e1 ,n)
+       (define vec (value-of-any (recur e1)))
+       (define i (value-of-any (recur n)))
+       (vector-ref vec i)]
+      [`(if ,q ,t ,f)
+       (match (value-of-any (recur q))
+         [#f (recur f)]
          [else (recur t)])]
          [else (recur t)])]
-      [`(,(app recur f-val) ,(app recur vs) ...)
-       (match f-val
-         [`(inject (lambda (,xs ...) ,body ,lam-env) ,ty)
-          (define new-env (append (map cons xs vs) 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. UPDATE ME -Jeremy}
+      [`(,op ,es ...)
+       #:when (set-member? primitives op)
+       (tag-value
+        (apply (interp-op op) (for/list ([e es]) (value-of-any (recur e)))))]
+      [(or `(app ,f ,es ...) `(,f ,es ...))
+       (define new-args (map recur es))
+       (let ([f-val (value-of-any (recur f))])
+         (match f-val 
+           [`(lambda (,xs ...) ,body ,lam-env)
+            (define new-env (append (map cons xs new-args) lam-env))
+            ((interp-R7-exp new-env) body)]
+           [else (error "interp-R7-exp, expected function, not" f-val)]))]
+      )))
+...
+\end{lstlisting}
+\caption{Selections from the interpreter for the $R_7$ language.}
 \label{fig:interp-R7}
 \label{fig:interp-R7}
 \end{figure}
 \end{figure}
 
 
@@ -7119,10 +7121,10 @@ Similarly, we recommend translating the type predicates
 
 
 We recommend compiling an \key{inject} as follows if the type is
 We recommend compiling an \key{inject} as follows if the type is
 \key{Integer} or \key{Boolean}.  The \key{salq} instruction shifts the
 \key{Integer} or \key{Boolean}.  The \key{salq} instruction shifts the
-destination to the left by the number of bits specified by the source
-($2$) and it preserves the sign of the integer. We use the \key{orq}
-instruction to combine the tag and the value to form the tagged value.
-\\
+destination to the left by the number of bits specified its source
+argument (in this case $3$, the length of the tag) and it preserves
+the sign of the integer. We use the \key{orq} instruction to combine
+the tag and the value to form the tagged value.  \\
 \begin{tabular}{lll}
 \begin{tabular}{lll}
 \begin{minipage}{0.4\textwidth}
 \begin{minipage}{0.4\textwidth}
 \begin{lstlisting}
 \begin{lstlisting}
@@ -7135,16 +7137,15 @@ $\Rightarrow$
 \begin{minipage}{0.5\textwidth}
 \begin{minipage}{0.5\textwidth}
 \begin{lstlisting}
 \begin{lstlisting}
 (movq |$e'$| |\itm{lhs}'|)
 (movq |$e'$| |\itm{lhs}'|)
-(salq (int 2) |\itm{lhs}'|)
+(salq (int 3) |\itm{lhs}'|)
 (orq (int |$\itm{tagof}(T)$|) |\itm{lhs}'|)
 (orq (int |$\itm{tagof}(T)$|) |\itm{lhs}'|)
 \end{lstlisting}
 \end{lstlisting}
 \end{minipage}
 \end{minipage}
 \end{tabular}  \\
 \end{tabular}  \\
 The instruction selection for vectors and procedures is different
 The instruction selection for vectors and procedures is different
 because their is no need to shift them to the left. The rightmost 3
 because their is no need to shift them to the left. The rightmost 3
-bits are already zeros as described above. So we combine the value and
-the tag using
-\key{orq}.  \\
+bits are already zeros as described above. So we just combine the
+value and the tag using \key{orq}.  \\
 \begin{tabular}{lll}
 \begin{tabular}{lll}
 \begin{minipage}{0.4\textwidth}
 \begin{minipage}{0.4\textwidth}
 \begin{lstlisting}
 \begin{lstlisting}
@@ -7160,19 +7161,39 @@ $\Rightarrow$
 (orq (int |$\itm{tagof}(T)$|) |\itm{lhs}'|)
 (orq (int |$\itm{tagof}(T)$|) |\itm{lhs}'|)
 \end{lstlisting}
 \end{lstlisting}
 \end{minipage}
 \end{minipage}
-\end{tabular}  \\
+\end{tabular} 
 
 
-\paragraph{Project}
+\paragraph{Tag of Any}
 
 
+Recall that the \code{tag-of-any} operation extracts the type tag from
+a value of type \code{Any}. The type tag is the bottom three bits, so
+we obtain the tag by taking the bitwise-and of the value with $111$
+($7$ in decimal).
 
 
-The instruction selection for \key{project} is a bit more involved.
-Like \key{inject}, the instructions are different depending on whether
-the type $T$ is a pointer (vector or procedure) or not (Integer or
-Boolean). The following shows the instruction selection for Integer
-and Boolean.  We first check to see if the tag on the tagged value
-matches the tag of the target type $T$. If not, we halt the program by
-calling the \code{exit} function. If we have a match, we need to
-produce an untagged value by shifting it to the right by 2 bits.
+\begin{tabular}{lll}
+\begin{minipage}{0.4\textwidth}
+\begin{lstlisting}
+(assign |\itm{lhs}| (tag-of-any |$e$|))
+\end{lstlisting}
+\end{minipage}
+&
+$\Rightarrow$
+&
+\begin{minipage}{0.5\textwidth}
+\begin{lstlisting}
+(movq |$e'$| |\itm{lhs}'|)
+(andq (int 7) |\itm{lhs}'|)
+\end{lstlisting}
+\end{minipage}
+\end{tabular}  
+
+\paragraph{Value of Any}
+
+Like \key{inject}, the instructions for \key{value-of-any} are
+different depending on whether the type $T$ is a pointer (vector or
+procedure) or not (Integer or Boolean). The following shows the
+instruction selection for Integer and Boolean.  We produce an untagged
+value by shifting it to the right by 3 bits.
 %
 %
 \\
 \\
 \begin{tabular}{lll}
 \begin{tabular}{lll}
@@ -7187,23 +7208,17 @@ $\Rightarrow$
 \begin{minipage}{0.5\textwidth}
 \begin{minipage}{0.5\textwidth}
 \begin{lstlisting}
 \begin{lstlisting}
 (movq |$e'$| |\itm{lhs}'|)
 (movq |$e'$| |\itm{lhs}'|)
-(andq (int 3) |\itm{lhs}'|)
-(if (eq? |\itm{lhs}'| (int |$\itm{tagof}(T)$|))
-    ((movq |$e'$| |\itm{lhs}'|)
-     (sarq (int 2) |\itm{lhs}'|))
-    ((callq exit)))
+(sarq (int 3) |\itm{lhs}'|)
 \end{lstlisting}
 \end{lstlisting}
 \end{minipage}
 \end{minipage}
 \end{tabular}  \\
 \end{tabular}  \\
 %
 %
-The case for vectors and procedures begins in a similar way, checking
-that the runtime tag matches the target type $T$ and exiting if there
-is a mismatch. However, the way in which we convert the tagged value
-to a value is different, as there is no need to shift. Instead we need
-to zero-out the rightmost 2 bits. We accomplish this by creating the
-bit pattern $\ldots 0011$, applying \code{notq} to obtain $\ldots
-1100$, and then applying \code{andq} with the tagged value get the
-desired result. \\
+In the case for vectors and procedures, there is no need to
+shift. Instead we just need to zero-out the rightmost 3 bits. We
+accomplish this by creating the bit pattern $\ldots 0111$ ($7$ in
+decimal) and apply \code{bitwise-not} to obtain $\ldots 1000$ which we
+\code{movq} into the destination $\itm{lhs}$.  We then generate
+\code{andq} with the tagged value to get the desired result. \\
 %
 %
 \begin{tabular}{lll}
 \begin{tabular}{lll}
 \begin{minipage}{0.4\textwidth}
 \begin{minipage}{0.4\textwidth}
@@ -7216,20 +7231,15 @@ $\Rightarrow$
 &
 &
 \begin{minipage}{0.5\textwidth}
 \begin{minipage}{0.5\textwidth}
 \begin{lstlisting}
 \begin{lstlisting}
-(movq |$e'$| |\itm{lhs}'|)
-(andq (int 3) |\itm{lhs}'|)
-(if (eq? |\itm{lhs}'| (int |$\itm{tagof}(T)$|))
-    ((movq (int 3) |\itm{lhs}'|)
-     (notq |\itm{lhs}'|)
-     (andq |$e'$| |\itm{lhs}'|))
-    ((callq exit)))
+(movq (int |$\ldots 1000$|) |\itm{lhs}'|)
+(andq |$e'$| |\itm{lhs}'|)
 \end{lstlisting}
 \end{lstlisting}
 \end{minipage}
 \end{minipage}
-\end{tabular}  \\
+\end{tabular}  
 
 
-\paragraph{Type Predicates} We leave it to the reader to
-devise a sequence of instructions to implement the type predicates
-\key{boolean?}, \key{integer?}, \key{vector?}, and \key{procedure?}.
+%% \paragraph{Type Predicates} We leave it to the reader to
+%% devise a sequence of instructions to implement the type predicates
+%% \key{boolean?}, \key{integer?}, \key{vector?}, and \key{procedure?}.
 
 
 \section{Compiling $R_7$ to $R_6$}
 \section{Compiling $R_7$ to $R_6$}
 \label{sec:compile-r7}
 \label{sec:compile-r7}
@@ -7249,18 +7259,17 @@ before the addition can be performed.
 %
 %
 The compilation of \key{lambda} (third row of
 The compilation of \key{lambda} (third row of
 Figure~\ref{fig:compile-r7-r6}) shows what happens when we need to
 Figure~\ref{fig:compile-r7-r6}) shows what happens when we need to
-produce type annotations, we simply use \key{Any}.
+produce type annotations: we simply use \key{Any}.
 %
 %
-The compilation of \code{if}, \code{eq?}, and \code{and} all
-demonstrate how this pass has to account for some differences in
-behavior between $R_7$ and $R_6$. The $R_7$ language is more
-permissive than $R_6$ regarding what kind of values can be used in
-various places. For example, the condition of an \key{if} does not
-have to be a Boolean. Similarly, the arguments of \key{and} do not
-need to be Boolean. For \key{eq?}, the arguments need not be of the
-same type.
+The compilation of \code{if} and \code{eq?}  demonstrate how this pass
+has to account for some differences in behavior between $R_7$ and
+$R_6$. The $R_7$ language is more permissive than $R_6$ regarding what
+kind of values can be used in various places. For example, the
+condition of an \key{if} does not have to be a Boolean. For \key{eq?},
+the arguments need not be of the same type (but in that case, the
+result will be \code{#f}).
 
 
-\begin{figure}[tbp]
+\begin{figure}[btp]
 \centering
 \centering
 \begin{tabular}{|lll|} \hline
 \begin{tabular}{|lll|} \hline
 \begin{minipage}{0.25\textwidth}
 \begin{minipage}{0.25\textwidth}
@@ -7370,23 +7379,7 @@ $\Rightarrow$
 \end{lstlisting}
 \end{lstlisting}
 \end{minipage}
 \end{minipage}
 \\[2ex]\hline
 \\[2ex]\hline
-\begin{minipage}{0.25\textwidth}
-\begin{lstlisting}
-(and |$e_1$| |$e_2$|)
-\end{lstlisting}
-\end{minipage}
-&
-$\Rightarrow$
-&
-\begin{minipage}{0.6\textwidth}
-\begin{lstlisting}
-(let ([tmp |$e'_1$|])
-   (if (eq? tmp (inject #f Boolean))
-      tmp
-      |$e'_2$|))
-\end{lstlisting}
-\end{minipage} \\\hline
-\end{tabular}  \\
+\end{tabular} 
 
 
 \caption{Compiling $R_7$ to $R_6$.}
 \caption{Compiling $R_7$ to $R_6$.}
 \label{fig:compile-r7-r6}
 \label{fig:compile-r7-r6}