Jelajahi Sumber

python version sec. 2.1

Jeremy Siek 3 tahun lalu
induk
melakukan
96021f5137
1 mengubah file dengan 188 tambahan dan 57 penghapusan
  1. 188 57
      book.tex

+ 188 - 57
book.tex

@@ -1757,39 +1757,76 @@ the interpreter for \LangIf{} handle all of the new features in that
 language and then have a default case that dispatches to the
 language and then have a default case that dispatches to the
 interpreter for \LangVar{}. The following code sketches this idea.
 interpreter for \LangVar{}. The following code sketches this idea.
 \begin{center}
 \begin{center}
-  \begin{minipage}{0.45\textwidth}
+{\if\edition\racketEd\color{olive}  
+\begin{minipage}{0.45\textwidth}
 \begin{lstlisting}
 \begin{lstlisting}
-(define (interp-Rvar e)
+(define (interp_Rvar_exp e)
   (match e
   (match e
-    [(Prim '- (list e))
-     (fx- 0 (interp-Rvar e))]
+    [(Prim '- (list e1))
+     (fx- 0 (interp_Rvar_exp e1))]
     ...))
     ...))
 \end{lstlisting}
 \end{lstlisting}
 \end{minipage}
 \end{minipage}
 \begin{minipage}{0.45\textwidth}
 \begin{minipage}{0.45\textwidth}
   \begin{lstlisting}
   \begin{lstlisting}
-(define (interp-Rif e)
+(define (interp_Rif_exp e)
   (match e
   (match e
     [(If cnd thn els)
     [(If cnd thn els)
-     (match (interp-Rif cnd)
-       [#t (interp-Rif thn)]
-       [#f (interp-Rif els)])]
+     (match (interp_Rif_exp cnd)
+       [#t (interp_Rif_exp thn)]
+       [#f (interp_Rif_exp els)])]
+    ...
+    [else (interp_Rvar_exp e)]))    
+\end{lstlisting}
+\end{minipage}
+\fi}
+
+{\if\edition\pythonEd\color{purple}
+\begin{minipage}{0.45\textwidth}
+\begin{lstlisting}
+def interp_Rvar_exp(e):
+  match e:
+    case UnaryOp(USub(), e1):
+       return - interp_Rvar_exp(e1)
+    ...
+\end{lstlisting}
+\end{minipage}
+\begin{minipage}{0.45\textwidth}
+\begin{lstlisting}
+def interp_Rif_exp(e):
+  match e:
+    case IfExp(cnd, thn, els):
+      match interp_Rif_exp(cnd):
+        case True:
+          return interp_Rif_exp(thn)
+        case False:
+          return interp_Rif_exp(els)
     ...
     ...
-    [else (interp-Rvar e)]))    
+    case _:
+      return interp_Rvar_exp(e)
 \end{lstlisting}
 \end{lstlisting}
 \end{minipage}
 \end{minipage}
+\fi}
 \end{center}
 \end{center}
 The problem with this approach is that it does not handle situations
 The problem with this approach is that it does not handle situations
-in which an \LangIf{} feature, like \code{If}, is nested inside an \LangVar{}
-feature, like the \code{-} operator, as in the following program.
+in which an \LangIf{} feature, such as a conditional expression, is
+nested inside an \LangVar{} feature, like the \code{-} operator, as in
+the following program.
+{\if\edition\racketEd\color{olive}  
 \begin{lstlisting}
 \begin{lstlisting}
 (Prim '- (list (If (Bool #t) (Int 42) (Int 0))))
 (Prim '- (list (If (Bool #t) (Int 42) (Int 0))))
 \end{lstlisting}
 \end{lstlisting}
-If we invoke \code{interp-Rif} on this program, it dispatches to
-\code{interp-Rvar} to handle the \code{-} operator, but then it
-recurisvely calls \code{interp-Rvar} again on the argument of \code{-},
+\fi}
+{\if\edition\pythonEd\color{purple}
+\begin{lstlisting}
+print(-(42 if True else 0))
+\end{lstlisting}
+\fi}
+If we invoke \code{interp\_Rif\_exp} on this program, it dispatches to
+\code{interp\_Rvar\_exp} to handle the \code{-} operator, but then it
+recurisvely calls \code{interp\_Rvar\_exp} again on the argument of \code{-},
 which is an \code{If}.  But there is no case for \code{If} in
 which is an \code{If}.  But there is no case for \code{If} in
-\code{interp-Rvar}, so we get an error!
+\code{interp\_Rvar\_exp}, so we get an error!
 
 
 To make our interpreters extensible we need something called
 To make our interpreters extensible we need something called
 \emph{open recursion}\index{subject}{open recursion}, where the tying of the
 \emph{open recursion}\index{subject}{open recursion}, where the tying of the
@@ -1797,17 +1834,20 @@ recursive knot is delayed to when the functions are
 composed. Object-oriented languages provide open recursion with the
 composed. Object-oriented languages provide open recursion with the
 late-binding of overridden methods\index{subject}{method overriding}. The
 late-binding of overridden methods\index{subject}{method overriding}. The
 following code sketches this idea for interpreting \LangVar{} and
 following code sketches this idea for interpreting \LangVar{} and
-\LangIf{} using the
+\LangIf{} using
+\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.  We define one class for each
+\index{subject}{class} feature of Racket}
+\python{a Python \code{class} definition}.  We define one class for each
 language and define a method for interpreting expressions inside each
 language and define a method for interpreting expressions inside each
 class. The class for \LangIf{} inherits from the class for \LangVar{}
 class. The class for \LangIf{} inherits from the class for \LangVar{}
-and the method \code{interp-exp} in \LangIf{} overrides the
-\code{interp-exp} in \LangVar{}. Note that the default case of
-\code{interp-exp} in \LangIf{} uses \code{super} to invoke
-\code{interp-exp}, and because \LangIf{} inherits from \LangVar{},
-that dispatches to the \code{interp-exp} in \LangVar{}.
+and the method \code{interp\_exp} in \LangIf{} overrides the
+\code{interp\_exp} in \LangVar{}. Note that the default case of
+\code{interp\_exp} in \LangIf{} uses \code{super} to invoke
+\code{interp\_exp}, and because \LangIf{} inherits from \LangVar{},
+that dispatches to the \code{interp\_exp} in \LangVar{}.
 \begin{center}
 \begin{center}
+{\if\edition\racketEd\color{olive}  
 \begin{minipage}{0.45\textwidth}
 \begin{minipage}{0.45\textwidth}
 \begin{lstlisting}
 \begin{lstlisting}
 (define interp-Rvar-class
 (define interp-Rvar-class
@@ -1836,21 +1876,66 @@ that dispatches to the \code{interp-exp} in \LangVar{}.
   ))
   ))
 \end{lstlisting}
 \end{lstlisting}
 \end{minipage}
 \end{minipage}
+\fi}
+{\if\edition\pythonEd\color{purple}
+\begin{minipage}{0.45\textwidth}
+\begin{lstlisting}
+class InterpRvar:
+  def interp_exp(e):
+     match e:
+       case UnaryOp(USub(), e1):
+         return -self.interp_exp(e1)
+       ...
+  ...
+\end{lstlisting}
+\end{minipage}
+\begin{minipage}{0.45\textwidth}
+  \begin{lstlisting}
+def InterpRif(InterpRVar):
+  def interp_exp(e):
+    match e:
+      case IfExp(cnd, thn, els):
+        match self.interp_exp(cnd):
+          case True:
+            return self.interp_exp(thn)
+          case False:
+            return self.interp_exp(els)
+      ...
+      case _:
+        return super().interp_exp(e)
+  ...
+\end{lstlisting}
+\end{minipage}
+\fi}
 \end{center}
 \end{center}
 Getting back to the troublesome example, repeated here:
 Getting back to the troublesome example, repeated here:
+{\if\edition\racketEd\color{olive}  
 \begin{lstlisting}
 \begin{lstlisting}
 (define e0 (Prim '- (list (If (Bool #t) (Int 42) (Int 0)))))
 (define e0 (Prim '- (list (If (Bool #t) (Int 42) (Int 0)))))
 \end{lstlisting}
 \end{lstlisting}
-We can invoke the \code{interp-exp} method for \LangIf{} on this
-expression by creating an object of the \LangIf{} class and sending it the
-\code{interp-exp} method with the argument \code{e0}.
+\fi}
+{\if\edition\pythonEd\color{purple}
+\begin{lstlisting}
+-(42 if True else 0)
+\end{lstlisting}
+\fi}
+\noindent We can invoke the \code{interp\_exp} method for \LangIf{} on this
+expression, call it \code{e0}, by creating an object of the \LangIf{} class
+and calling the \code{interp\_exp} method.
+{\if\edition\racketEd\color{olive}
 \begin{lstlisting}
 \begin{lstlisting}
 (send (new interp-Rif-class) interp-exp e0)
 (send (new interp-Rif-class) interp-exp e0)
 \end{lstlisting}
 \end{lstlisting}
-The default case of \code{interp-exp} in \LangIf{} handles it by
-dispatching to the \code{interp-exp} method in \LangVar{}, which
+\fi}
+{\if\edition\pythonEd\color{purple}
+\begin{lstlisting}
+InterpRif().interp_exp(e0)
+\end{lstlisting}
+\fi}
+\noindent The default case of \code{interp\_exp} in \LangIf{} handles it by
+dispatching to the \code{interp\_exp} method in \LangVar{}, which
 handles the \code{-} operator. But then for the recursive method call,
 handles the \code{-} operator. But then for the recursive method call,
-it dispatches back to \code{interp-exp} in \LangIf{}, where the
+it dispatches back to \code{interp\_exp} in \LangIf{}, where the
 \code{If} is handled correctly. Thus, method overriding gives us the
 \code{If} is handled correctly. Thus, method overriding gives us the
 open recursion that we need to implement our interpreters in an
 open recursion that we need to implement our interpreters in an
 extensible way.
 extensible way.
@@ -1858,6 +1943,7 @@ extensible way.
 
 
 \subsection{Definitional Interpreter for \LangVar{}}
 \subsection{Definitional Interpreter for \LangVar{}}
 
 
+{\if\edition\racketEd\color{olive}
 \begin{figure}[tp]
 \begin{figure}[tp]
 %\begin{wrapfigure}[26]{r}[0.75in]{0.55\textwidth}
 %\begin{wrapfigure}[26]{r}[0.75in]{0.55\textwidth}
   \small
   \small
@@ -1894,60 +1980,105 @@ extensible way.
   \caption{Association lists implement the dictionary interface.}
   \caption{Association lists implement the dictionary interface.}
   \label{fig:alist}
   \label{fig:alist}
 \end{figure}
 \end{figure}
+\fi}
 
 
 Having justified the use of classes and methods to implement
 Having justified the use of classes and methods to implement
 interpreters, we turn to the definitional interpreter for \LangVar{}
 interpreters, we turn to the definitional interpreter for \LangVar{}
 in Figure~\ref{fig:interp-Rvar}. It is similar to the interpreter for
 in Figure~\ref{fig:interp-Rvar}. It is similar to the interpreter for
 \LangInt{} but adds two new \key{match} cases for variables and
 \LangInt{} but adds two new \key{match} cases for variables and
-\key{let}.  For \key{let} we need a way to communicate the value bound
-to a variable to all the uses of the variable. To accomplish this, we
-maintain a mapping from variables to values. Throughout the compiler
-we often need to map variables to information about them. We refer to
-these mappings as
-\emph{environments}\index{subject}{environment}.\footnote{Another common term
-  for environment in the compiler literature is \emph{symbol
-    table}\index{subject}{symbol table}.}
-%
-For simplicity, we use an association list (alist) to represent the
-environment. Figure~\ref{fig:alist} gives a brief introduction to
-alists and the \code{racket/dict} package.  The \code{interp-exp}
-function takes the current environment, \code{env}, as an extra
-parameter.  When the interpreter encounters a variable, it finds the
-corresponding value using the \code{dict-ref} function.  When the
-interpreter encounters a \key{Let}, it evaluates the initializing
-expression, extends the environment with the result value bound to the
-variable, using \code{dict-set}, then evaluates the body of the
-\key{Let}.
+\racket{\key{let}}\python{assignment}. For
+\racket{\key{let}}\python{assignment} we need a way to communicate the
+value bound to a variable to all the uses of the variable. To
+accomplish this, we maintain a mapping from variables to
+values. Throughout the compiler we often need to map variables to
+information about them. We refer to these mappings as
+\emph{environments}\index{subject}{environment}.\footnote{Another
+common term for environment in the compiler literature is \emph{symbol
+table}\index{subject}{symbol table}.}
+%
+For simplicity, we use \racket{an association list
+  (alist)}\python{dictionary} to represent the
+environment. \racket{Figure~\ref{fig:alist} gives a brief introduction
+  to alists and the \code{racket/dict} package.}  The
+\code{interp\_exp} function takes the current environment, \code{env},
+as an extra parameter.  When the interpreter encounters a variable, it
+looks up the corresponding value in the dictionary.
+%
+\racket{When the interpreter encounters a \key{Let}, it evaluates the
+  initializing expression, extends the environment with the result
+  value bound to the variable, using \code{dict-set}, then evaluates
+  the body of the \key{Let}.}
+%
+\python{When the interpreter encounters an assignment, it evaluates
+  the initializing expression and then associates the resulting value
+  with the variable in the environment.}
 
 
 \begin{figure}[tp]
 \begin{figure}[tp]
+{\if\edition\racketEd\color{olive}  
 \begin{lstlisting}
 \begin{lstlisting}
 (define interp-Rvar-class
 (define interp-Rvar-class
   (class object%
   (class object%
     (super-new)
     (super-new)
     
     
-    (define/public ((interp-exp env) e)
+    (define/public ((interp_exp env) e)
       (match e
       (match e
         [(Int n) n]
         [(Int n) n]
         [(Prim 'read '())
         [(Prim 'read '())
          (define r (read))
          (define r (read))
          (cond [(fixnum? r) r]
          (cond [(fixnum? r) r]
-               [else (error 'interp-exp "expected an integer" r)])]
-        [(Prim '- (list e)) (fx- 0 ((interp-exp env) e))]
+               [else (error 'interp_exp "expected an integer" r)])]
+        [(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))]
         [(Var x) (dict-ref env x)]
         [(Var x) (dict-ref env x)]
         [(Let x e body)
         [(Let x e body)
-         (define new-env (dict-set env x ((interp-exp env) e)))
-         ((interp-exp new-env) body)]))
+         (define new-env (dict-set env x ((interp_exp env) e)))
+         ((interp_exp new-env) body)]))
 
 
     (define/public (interp-program p)
     (define/public (interp-program p)
       (match p
       (match p
-        [(Program '() e) ((interp-exp '()) e)]))
+        [(Program '() e) ((interp_exp '()) e)]))
     ))
     ))
 
 
 (define (interp-Rvar p)
 (define (interp-Rvar p)
   (send (new interp-Rvar-class) interp-program p))
   (send (new interp-Rvar-class) interp-program p))
 \end{lstlisting}
 \end{lstlisting}
+\fi}
+{\if\edition\pythonEd\color{purple}
+\begin{lstlisting}
+class InterpPvar:
+  def interp_exp(self, e, env):
+    match e:
+      case BinOp(left, Add(), right):
+        l = self.interp_exp(left, env)
+        r = self.interp_exp(right, env)
+        return l + r
+      case UnaryOp(USub(), v):
+        return - self.interp_exp(v, env)
+      case Name(id):
+        return env[id]
+      case Constant(value):
+        return value
+      case Call(Name('input_int'), []):
+        return int(input())            
+
+  def interp_stmt(self, s, env):
+    match s:
+      case Assign([lhs], value):
+        env[lhs.id] = self.interp_exp(value, env)
+      case Expr(Call(Name('print'), [arg])):
+        print(self.interp_exp(arg, env))
+      case Expr(value):
+        self.interp_exp(value, env)
+
+  def interp_Pvar(self, p):
+    match p:
+      case Module(body):
+        env = {}
+        for s in body:
+          self.interp_stmt(s, env)
+\end{lstlisting}
+\fi}
 \caption{Interpreter for the \LangVar{} language.}
 \caption{Interpreter for the \LangVar{} language.}
 \label{fig:interp-Rvar}
 \label{fig:interp-Rvar}
 \end{figure}
 \end{figure}
@@ -1955,7 +2086,7 @@ variable, using \code{dict-set}, then evaluates the body of the
 The goal for this chapter is to implement a compiler that translates
 The goal for this chapter is to implement a compiler that translates
 any program $P_1$ written in the \LangVar{} language into an x86 assembly
 any program $P_1$ written in the \LangVar{} language into an x86 assembly
 program $P_2$ such that $P_2$ exhibits the same behavior when run on a
 program $P_2$ such that $P_2$ exhibits the same behavior when run on a
-computer as the $P_1$ program interpreted by \code{interp-Rvar}.  That
+computer as the $P_1$ program interpreted by \code{interp\_Rvar}.  That
 is, they output the same integer $n$. We depict this correctness
 is, they output the same integer $n$. We depict this correctness
 criteria in the following diagram.
 criteria in the following diagram.
 \[
 \[
@@ -1965,8 +2096,8 @@ criteria in the following diagram.
  \node (o)  at (4, -2) {$n$};
  \node (o)  at (4, -2) {$n$};
 
 
  \path[->] (p1) edge [above] node {\footnotesize compile} (p2);
  \path[->] (p1) edge [above] node {\footnotesize compile} (p2);
- \path[->] (p1) edge [left]  node {\footnotesize\code{interp-Rvar}} (o);
- \path[->] (p2) edge [right] node {\footnotesize\code{interp-x86int}} (o);
+ \path[->] (p1) edge [left]  node {\footnotesize\code{interp\_Rvar}} (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
 In the next section we introduce the \LangXInt{} subset of x86 that