浏览代码

more python

Jeremy Siek 3 年之前
父节点
当前提交
000bc69e2e
共有 3 个文件被更改,包括 224 次插入50 次删除
  1. 16 0
      book.bib
  2. 207 49
      book.tex
  3. 1 1
      defs.tex

+ 16 - 0
book.bib

@@ -1,3 +1,19 @@
+
+
+@Misc{PSF21:cpython,
+  title = 	 {CPython github repository},
+  organization = {Python Software Foundation},
+  howpublished = {\url{https://github.com/python/cpython}},
+  year = 	 2021}
+
+@Manual{PSF21:python_ref,
+  title = 	 {The Python Language Reference},
+  organization = {Python Software Foundation},
+  month = 	 {June},
+  year = 	 2021,
+  howpublished = {\url{https://docs.python.org/3/reference/}},
+}
+
 @book{Lutz:2013vp,
 @book{Lutz:2013vp,
 	author = {Mark Lutz},
 	author = {Mark Lutz},
 	date-added = {2021-06-10 10:29:47 -0400},
 	date-added = {2021-06-10 10:29:47 -0400},

+ 207 - 49
book.tex

@@ -532,7 +532,7 @@ node it is the child of). If a node has no children, it is a
 %% S-expression.
 %% S-expression.
 %% \begin{lstlisting}
 %% \begin{lstlisting}
 %% (define ast1.4 `(- 8))
 %% (define ast1.4 `(- 8))
-%% (define ast1.1 `(+ (read) ,ast1.4))
+%% (define ast1_1 `(+ (read) ,ast1.4))
 %% \end{lstlisting}
 %% \end{lstlisting}
 %% In general, the Racket expression that follows the comma (splice)
 %% In general, the Racket expression that follows the comma (splice)
 %% can be any expression that produces an S-expression.
 %% can be any expression that produces an S-expression.
@@ -571,7 +571,7 @@ operator has zero children:
 \end{lstlisting}
 \end{lstlisting}
 whereas the addition operator has two children:
 whereas 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}
 
 
 We have made a design choice regarding the \code{Prim} structure.
 We have made a design choice regarding the \code{Prim} structure.
@@ -906,7 +906,7 @@ Consider the following example. \index{subject}{match} \index{subject}{pattern m
 \begin{minipage}{0.5\textwidth}
 \begin{minipage}{0.5\textwidth}
 {\if\edition\racketEd\color{olive}
 {\if\edition\racketEd\color{olive}
 \begin{lstlisting}
 \begin{lstlisting}
-(match ast1.1
+(match ast1_1
   [(Prim op (list child1 child2))
   [(Prim op (list child1 child2))
     (print op)])
     (print op)])
 \end{lstlisting}
 \end{lstlisting}
@@ -997,6 +997,8 @@ def leaf(arith):
             return False
             return False
         case BinOp(e1, Add(), e2):
         case BinOp(e1, Add(), e2):
             return False
             return False
+        case _:
+            return False
 
 
 print(leaf(Call(Name('input_int'), [])))
 print(leaf(Call(Name('input_int'), [])))
 print(leaf(UnaryOp(USub(), eight)))
 print(leaf(UnaryOp(USub(), eight)))
@@ -1028,6 +1030,11 @@ print(leaf(Constant(8)))
 
 
 
 
 
 
+
+    
+
+
+
     
     
    True
    True
    False
    False
@@ -1056,11 +1063,12 @@ of your choice (e.g. \code{e1} and \code{e2}).
 \label{sec:recursion}
 \label{sec:recursion}
 \index{subject}{recursive function}
 \index{subject}{recursive function}
 
 
-Programs are inherently recursive. For example, an \LangInt{} expression is
-often made of smaller expressions. Thus, the natural way to process an
-entire program is with a recursive function.  As a first example of
-such a recursive function, we define \texttt{exp} below, which takes
-an arbitrary value and determines whether or not it is an \LangInt{}
+Programs are inherently recursive. For example, an \LangInt{}
+expression is often made of smaller expressions. Thus, the natural way
+to process an entire program is with a recursive function.  As a first
+example of such a recursive function, we define the function
+\code{exp} in Figure~\ref{fig:exp-predicate}, which takes an
+arbitrary value and determines whether or not it is an \LangInt{}
 expression.
 expression.
 %
 %
 We say that a function is defined by \emph{structural recursion} when
 We say that a function is defined by \emph{structural recursion} when
@@ -1070,12 +1078,16 @@ makes a recursive call on each
 child node.\footnote{This principle of structuring code according to
 child node.\footnote{This principle of structuring code according to
   the data definition is advocated in the book \emph{How to Design
   the data definition is advocated in the book \emph{How to Design
     Programs} \url{https://htdp.org/2020-8-1/Book/index.html}.}.
     Programs} \url{https://htdp.org/2020-8-1/Book/index.html}.}.
-Below we also define a second function, named \code{Rint}, that
-determines whether an AST is an \LangInt{} program.  In general we can
+\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{Rint}, 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
 expect to write one recursive function to handle each non-terminal in
 a grammar.\index{subject}{structural recursion}
 a grammar.\index{subject}{structural recursion}
-%
-\begin{center}
+
+\begin{figure}[tp]
+{\if\edition\racketEd\color{olive}
 \begin{minipage}{0.7\textwidth}
 \begin{minipage}{0.7\textwidth}
 \begin{lstlisting}
 \begin{lstlisting}
 (define (exp ast)
 (define (exp ast)
@@ -1092,7 +1104,7 @@ a grammar.\index{subject}{structural recursion}
     [(Program '() e) (exp e)]
     [(Program '() e) (exp e)]
     [else #f]))
     [else #f]))
 
 
-(Rint (Program '() ast1.1)
+(Rint (Program '() ast1_1)
 (Rint (Program '()
 (Rint (Program '()
        (Prim '- (list (Prim 'read '())
        (Prim '- (list (Prim 'read '())
                       (Prim '+ (list (Num 8)))))))
                       (Prim '+ (list (Num 8)))))))
@@ -1118,7 +1130,83 @@ a grammar.\index{subject}{structural recursion}
    #f
    #f
 \end{lstlisting}
 \end{lstlisting}
 \end{minipage}
 \end{minipage}
-\end{center}
+\fi}
+{\if\edition\pythonEd\color{purple}
+\begin{minipage}{0.7\textwidth}
+\begin{lstlisting}
+def exp(e):
+  match e:
+    case Constant(n):
+      return True
+    case Call(Name('input_int'), []):
+      return True
+    case UnaryOp(USub(), e1):
+      return exp(e1)
+    case BinOp(e1, Add(), e2):
+      return exp(e1) and exp(e2)
+    case _:
+      return False
+
+def stmt(s):
+  match s:
+    case Call(Name('print'), [e]):
+      return exp(e)
+    case Expr(e):
+      return exp(e)
+    case _:
+      return False
+  
+def Rint(p):
+  match p:
+    case Module(body):
+      return all([stmt(s) for s in body])
+    case _:
+      return False
+
+print(Rint(Module([Expr(ast1_1)])))
+print(Rint(Module([Expr(BinOp(read, Sub(),
+                  UnaryOp(Add(), Constant(8))))])))
+\end{lstlisting}
+\end{minipage}
+\vrule
+\begin{minipage}{0.25\textwidth}
+\begin{lstlisting}
+
+
+
+
+
+
+  
+
+
+
+
+
+
+
+
+  
+
+
+
+
+
+
+
+
+
+
+   True
+   False
+\end{lstlisting}
+\end{minipage}
+\fi}
+
+\caption{Example of recursive functions for \LangInt{}. These functions
+  recognize whether an AST is in \LangInt{}.}
+\label{fig:exp-predicate}
+\end{figure}
 
 
 
 
 %% You may be tempted to merge the two functions into one, like this:
 %% You may be tempted to merge the two functions into one, like this:
@@ -1147,71 +1235,131 @@ a grammar.\index{subject}{structural recursion}
 
 
 
 
 \section{Interpreters}
 \section{Interpreters}
-\label{sec:interp-Rint}
+\label{sec:interp_Rint}
 \index{subject}{interpreter}
 \index{subject}{interpreter}
 
 
-In general, the intended behavior of a program is defined by the
-specification of the language. For example, the Scheme language is
-defined in the report by \cite{SPERBER:2009aa}. The Racket language is
-defined in its reference manual~\citep{plt-tr}. 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
+The behavior of a program is defined by the specification of the
+programming language.
+%
+\racket{For example, the Scheme language is defined in the report by
+  \cite{SPERBER:2009aa}. The Racket language is defined in its
+  reference manual~\citep{plt-tr}.}
+%
+\python{For example, the Python language is defined in the Python
+  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}.
 \emph{definitional interpreter}~\citep{reynolds72:_def_interp}.
-\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 \texttt{interp-Rint} function is defined in
-Figure~\ref{fig:interp-Rint}. The body of the function is a match on the
-input program followed by a call to the \lstinline{interp-exp} helper
-function, which in turn has one match clause per grammar rule for
-\LangInt{} expressions.
+\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 \texttt{interp\_Rint}
+function is defined in Figure~\ref{fig:interp_Rint}. The body of the
+function is a match on the input program followed by a call to the
+\lstinline{interp_exp} helper function, which in turn has one match
+clause per grammar rule for \LangInt{} expressions.
 
 
 \begin{figure}[tp]
 \begin{figure}[tp]
+{\if\edition\racketEd\color{olive}
 \begin{lstlisting}
 \begin{lstlisting}
-(define (interp-exp e)
+(define (interp_exp 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 "read expected an integer" r)])]
+           [else (error 'interp_exp "read expected an integer" r)])]
     [(Prim '- (list e))
     [(Prim '- (list e))
-     (define v (interp-exp e))
+     (define v (interp_exp e))
      (fx- 0 v)]
      (fx- 0 v)]
     [(Prim '+ (list e1 e2))
     [(Prim '+ (list e1 e2))
-     (define v1 (interp-exp e1))
-     (define v2 (interp-exp e2))
+     (define v1 (interp_exp e1))
+     (define v2 (interp_exp e2))
      (fx+ v1 v2)]))
      (fx+ v1 v2)]))
 
 
-(define (interp-Rint p)
+(define (interp_Rint p)
   (match p
   (match p
-    [(Program '() e) (interp-exp e)]))
+    [(Program '() e) (interp_exp e)]))
+\end{lstlisting}
+\fi}
+{\if\edition\pythonEd\color{purple}
+\begin{lstlisting}
+def interp_exp(e):
+    match e:
+        case BinOp(left, Add(), right):
+            l = interp_exp(left)
+            r = interp_exp(right)
+            return l + r
+        case UnaryOp(USub(), v):
+            return - interp_exp(v)
+        case Constant(value):
+            return value
+        case Call(Name('input_int'), []):
+            return int(input())            
+
+def interp_stmt(s):
+    match s:
+        case Expr(Call(Name('print'), [arg])):
+            print(interp_exp(arg))
+        case Expr(value):
+            interp_exp(value)
+
+def interp_Pint(p):
+    match p:
+        case Module(body):
+            for s in body:
+                interp_stmt(s)
 \end{lstlisting}
 \end{lstlisting}
+\fi}
 \caption{Interpreter for the \LangInt{} language.}
 \caption{Interpreter for the \LangInt{} language.}
-\label{fig:interp-Rint}
+\label{fig:interp_Rint}
 \end{figure}
 \end{figure}
 
 
 Let us consider the result of interpreting a few \LangInt{} programs. The
 Let us consider the result of interpreting a few \LangInt{} programs. The
 following program adds two integers.
 following program adds two integers.
+{\if\edition\racketEd\color{olive}
 \begin{lstlisting}
 \begin{lstlisting}
 (+ 10 32)
 (+ 10 32)
 \end{lstlisting}
 \end{lstlisting}
+\fi}
+{\if\edition\pythonEd\color{purple}
+\begin{lstlisting}
+print(10 + 32)
+\end{lstlisting}
+\fi}
 The result is \key{42}, the answer to life, the universe, and
 The result is \key{42}, the answer to life, the universe, and
 everything: \code{42}!\footnote{\emph{The Hitchhiker's Guide to the
 everything: \code{42}!\footnote{\emph{The Hitchhiker's Guide to the
     Galaxy} by Douglas Adams.}.
     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:
+{\if\edition\racketEd\color{olive}
 \begin{lstlisting}
 \begin{lstlisting}
 (Program '() (Prim '+ (list (Int 10) (Int 32))))
 (Program '() (Prim '+ (list (Int 10) (Int 32))))
 \end{lstlisting}
 \end{lstlisting}
-
+\fi}
+{\if\edition\pythonEd\color{purple}
+\begin{lstlisting}
+Module([Expr(Call(Name('print'), [BinOp(Constant(10), Add(), Constant(32))]))])    
+\end{lstlisting}
+\fi}
 The next example demonstrates that expressions may be nested within
 The next example demonstrates that expressions may be nested within
 each other, in this case nesting several additions and negations.
 each other, in this case nesting several additions and negations.
+{\if\edition\racketEd\color{olive}
 \begin{lstlisting}
 \begin{lstlisting}
 (+ 10 (- (+ 12 20)))
 (+ 10 (- (+ 12 20)))
 \end{lstlisting}
 \end{lstlisting}
+\fi}
+{\if\edition\pythonEd\color{purple}
+\begin{lstlisting}
+print(10 + -(12 + 20))
+\end{lstlisting}
+\fi}
+
 What is the result of the above program?
 What is the result of the above program?
 
 
+{\if\edition\racketEd\color{olive}
 As mentioned previously, the \LangInt{} language does not support
 As mentioned previously, the \LangInt{} language does not support
 arbitrarily-large integers, but only $63$-bit integers, so we
 arbitrarily-large integers, but only $63$-bit integers, so we
 interpret the arithmetic operations of \LangInt{} using fixnum arithmetic
 interpret the arithmetic operations of \LangInt{} using fixnum arithmetic
@@ -1241,26 +1389,36 @@ it is required to report that an error occurred. To signal an error,
 exit with a return code of \code{255}.  The interpreters in chapters
 exit with a return code of \code{255}.  The interpreters in chapters
 \ref{ch:Rdyn} and \ref{ch:Rgrad} use
 \ref{ch:Rdyn} and \ref{ch:Rgrad} use
 \code{trapped-error}.
 \code{trapped-error}.
+\fi}
+
+% TODO: how to deal with too-large integers in the Python interpreter?
 
 
 %% This convention applies to the languages defined in this
 %% This convention applies to the languages defined in this
 %% book, as a way to simplify the student's task of implementing them,
 %% book, as a way to simplify the student's task of implementing them,
 %% but this convention is not applicable to all programming languages.
 %% but this convention is not applicable to all programming languages.
 %% 
 %% 
 
 
-Moving on to the last feature of the \LangInt{} language, the \key{read}
-operation prompts the user of the program for an integer.  Recall that
-program \eqref{eq:arith-prog} performs a \key{read} and then subtracts
-\code{8}. So if we run
+Moving on to the last feature of the \LangInt{} language, the
+\READOP{} operation prompts the user of the program for an integer.
+Recall that program \eqref{eq:arith-prog} requests an integer input
+and then subtracts \code{8}. So if we run
+{\if\edition\racketEd\color{olive}
+\begin{lstlisting}
+(interp_Rint (Program '() ast1_1))
+\end{lstlisting}
+\fi}
+{\if\edition\pythonEd\color{purple}
 \begin{lstlisting}
 \begin{lstlisting}
-(interp-Rint (Program '() ast1.1))
+interp_Pint(Module([Expr(Call(Name('print'), [ast1_1]))]))
 \end{lstlisting}
 \end{lstlisting}
-and if the input is \code{50}, the result is \code{42}.
+\fi}
+\noindent and if the input is \code{50}, the result is \code{42}.
 
 
-We include the \key{read} operation in \LangInt{} so a clever student
+We include the \READOP{} operation in \LangInt{} so a clever student
 cannot implement a compiler for \LangInt{} that simply runs the interpreter
 cannot implement a compiler for \LangInt{} that simply runs the interpreter
 during compilation to obtain the output and then generates the trivial
 during compilation to obtain the output and then generates the trivial
-code to produce the output. (Yes, a clever student did this in the
-first instance of this course.)
+code to produce the output.\footnote{Yes, a clever student did this in the
+first instance of this course!}
 
 
 The job of a compiler is to translate a program in one language into a
 The job of a compiler is to translate a program in one language into a
 program in another language so that the output program behaves the
 program in another language so that the output program behaves the
@@ -1356,7 +1514,7 @@ Appendix~\ref{appendix:utilities}.\\
 \begin{lstlisting}
 \begin{lstlisting}
 (define (test-pe p)
 (define (test-pe p)
   (assert "testing pe-Rint"
   (assert "testing pe-Rint"
-     (equal? (interp-Rint p) (interp-Rint (pe-Rint p)))))
+     (equal? (interp_Rint p) (interp_Rint (pe-Rint p)))))
 
 
 (test-pe (parse-program `(program () (+ 10 (- (+ 5 3))))))
 (test-pe (parse-program `(program () (+ 10 (- (+ 5 3))))))
 (test-pe (parse-program `(program () (+ 1 (+ 3 1)))))
 (test-pe (parse-program `(program () (+ 1 (+ 3 1)))))
@@ -9744,7 +9902,7 @@ Next consider the match case for \code{vector-ref}.  The
 \code{check-tag} auxiliary function (Figure~\ref{fig:interp-Rdyn-aux})
 \code{check-tag} auxiliary function (Figure~\ref{fig:interp-Rdyn-aux})
 is used to ensure that the first argument is a vector and the second
 is used to ensure that the first argument is a vector and the second
 is an integer. If they are not, a \code{trapped-error} is raised.
 is an integer. If they are not, a \code{trapped-error} is raised.
-Recall from Section~\ref{sec:interp-Rint} that when a definition
+Recall from Section~\ref{sec:interp_Rint} that when a definition
 interpreter raises a \code{trapped-error} error, the compiled code
 interpreter raises a \code{trapped-error} error, the compiled code
 must also signal an error by exiting with return code \code{255}.  A
 must also signal an error by exiting with return code \code{255}.  A
 \code{trapped-error} is also raised if the index is not less than
 \code{trapped-error} is also raised if the index is not less than
@@ -13750,7 +13908,7 @@ for the compilation of \LangPoly{}.
 \index{subject}{interpreter}
 \index{subject}{interpreter}
 
 
 We provide interpreters for each of the source languages \LangInt{},
 We provide interpreters for each of the source languages \LangInt{},
-\LangVar{}, $\ldots$ in the files \code{interp-Rint.rkt},
+\LangVar{}, $\ldots$ in the files \code{interp\_Rint.rkt},
 \code{interp-Rvar.rkt}, etc.  The interpreters for the intermediate
 \code{interp-Rvar.rkt}, etc.  The interpreters for the intermediate
 languages \LangCVar{} and \LangCIf{} are in \code{interp-Cvar.rkt} and
 languages \LangCVar{} and \LangCIf{} are in \code{interp-Cvar.rkt} and
 \code{interp-C1.rkt}.  The interpreters for \LangCVec{}, \LangCFun{}, pseudo-x86,
 \code{interp-C1.rkt}.  The interpreters for \LangCVec{}, \LangCFun{}, pseudo-x86,

+ 1 - 1
defs.tex

@@ -124,7 +124,7 @@
 \newcommand{\READ}{{\color{purple}\key{Call(Name('input\_int'),[])}}}
 \newcommand{\READ}{{\color{purple}\key{Call(Name('input\_int'),[])}}}
 \newcommand{\NEG}[1]{{\color{purple}\key{UnaryOp(USub(),} #1\code{)}}}
 \newcommand{\NEG}[1]{{\color{purple}\key{UnaryOp(USub(),} #1\code{)}}}
 \newcommand{\ADD}[2]{{\color{purple}\key{BinOp(Add()}\key{,}#1\code{,}#2\code{)}}}
 \newcommand{\ADD}[2]{{\color{purple}\key{BinOp(Add()}\key{,}#1\code{,}#2\code{)}}}
-\newcommand{\PRINT}[1]{{\color{purple}\key{Call}\LP\key{Name}\LP\key{print}\RP\key{,}\LS#1\RS\RP}}
+\newcommand{\PRINT}[1]{{\color{purple}\key{Expr}\LP\key{Call}\LP\key{Name}\LP\key{'print'}\RP\key{,}\LS#1\RS\RP\RP}}
 \newcommand{\EXPR}[1]{{\color{purple}\key{Expr}\LP #1\RP}}
 \newcommand{\EXPR}[1]{{\color{purple}\key{Expr}\LP #1\RP}}
 \newcommand{\PROGRAM}[2]{\code{Module}\LP #2\RP}
 \newcommand{\PROGRAM}[2]{\code{Module}\LP #2\RP}
 \fi
 \fi