OpenDSA 完整目录

Chapter 30 Interpreting the Functional Language SLang

| 关于   «  9. 递归函数   ::   目录   ::   2. 基于环境的求值模型  »

1. 定义 SLang 1

1.1. SLang 1 的语法

到目前为止,我们已经考察了如何从函数式编程的角度进行编程,以及 λ-演算如何为这一视角奠定理论基础。现在我们将转换焦点,考虑如何 真正为一种基于 λ-演算的语言开发一个小型解释器。我们把这种语言 称为 SLang 1 ,即“Simple Language version 1”(简单语言第 1 版)的缩写。

这个解释器的开发过程要求我们编写一个 Jison 文法来定义该语言的 语法,并把该语言中的程序转换成 抽象语法树 (abstract syntax tree,AST)。

具体语法 (concrete syntax)与 抽象语法 (abstract syntax)有何不同?换句话说,分析树与抽象语法树有何不同?

分析树 (parse tree)为每个词法单元(token)设置一个叶结点, 为每个非终结符设置一个内部结点。分析树适合用来表示源程序的结构 或语法。

然而,我们现在感兴趣的是程序的含义,而不仅仅是它的表面结构。 抽象语法树 (abstract syntax tree,AST)是把分析树中所有对 后续处理(对我们来说,就是执行或解释过程)并非必需的结点都去掉 之后得到的树。

在 AST 中:

  • 运算符出现在内部结点上,而不是叶结点上,其操作数成为它的子 结点。

  • 单位产生式链(即形如 <X> ::= <Y> 的产生式)会被折叠。

  • 列表会被展平。

  • 语法细节(分号、括号等)会被省略。

下面的例子说明了这一点。

   Parse Tree       Abstract Syntax Tree
   ==========       ====================

       exp                  *
        |                  / \
      term                3   +
       /|\                   / \
   term * factor            4   2
    /      /|\
   /      / | \
factor   ( exp )
  |        /|\
  3     exp + term
         |      |
       term   factor
         |      |
       factor   2
         |
         4

AST 通常只包含少量对应非终结符的结点。尽管如此,它包含了解释器 推导输入程序正确含义(即对程序求值并返回正确结果)所需的全部 信息。

     Input                                  Parse Tree
     =====                                  ==========

     {                                ____ methodBody _________
        x = 0;                       /       /            \    \
        while (x<10) {              {  declList        stmtList }
           x = x+1;                       |           /        \
        }                              epsilon   stmtList       stmt___
        y = x*2;                                /      \       /  | \  \
     }                                     stmtList   stmt    ID  = exp ;
                                          /      \       \   (y)   / | \
            AST                   stmtList      stmt     ...     exp * term
            ===                       |       / | |  \            |      |
                                   epsilon   ID = exp ;         term   factor
         methodBody                          (x)   |              |      |
        /          \                            INTLITERAL     factor   INT
declList            stmtList                      (0)             |     (2)
                   /   |    \                                    ID
             assign  while  assign                               (x)
             /     \  ...   /     \
            ID     INT     ID       *
            (x)    (0)     (y)     / \
                                 ID  INT
                                 (x) (2)

SLang 1 的具体语法由以下 EBNF 文法定义:

<program>  ::= <exp>
<exp>      ::= <var_exp> | <fn_exp> | <app_exp> | <papp_exp> | <int>
<fn_exp>   ::= fn '(' (<var_exp> (',' <var_exp>)*)? ')' => <exp>
<app_exp>  ::= '(' <exp> <exp>* ')'
<papp_exp> ::= <prim_op> '(' <args>? ')'
<args>     ::= <exp> (',' <exp>)*
<prim_op>  ::= + | * | add1

SLang 1 “程序” (fn (a,b) => b y 3) 会得到如下的分析树和 AST。

                       parse tree                          AST
                       ==========                          ===

                        program                          program
                           |                                |
                          exp                            app_exp
                           |                            /       \
                      _ app_exp ______            fn_exp         args
                     /   |   |    \   \           /    \        /    \
                    (  exp  exp   exp  )      [a,b]  var_exp var_exp int
              _________/      \     \                   |      |      |
             /              var_exp int                 b      y      3
    ______fn_exp___________     \     \
   / /    /  |    |  \  \  \     y     3               [ "Program",
  / /    /   |    |   \  \  \                            [ "AppExp",
fn ( var_exp , var_exp ) => exp                            [ "FnExp",
        |         |          |                               ["a","b"],
        a         b       var_exp                            ["VarExp","b"]],
                             |                             [ "args",
                             b                               ["VarExp","y"],
                                                             ["IntExp",3]]]]

上例右下角的表达式把抽象语法树表示为一个列表的列表。

1.2. SLang 1 的具体语法

下面的问题将帮助你掌握 SLang 1 的具体语法。要获得这道题的学分, 你必须连续三次正确完成这个随机化问题。

1.3. SLang 1 具体语法的更多练习

下面的问题通过提供更密集的练习来巩固你对 SLang 1 具体语法的掌握。 要获得这道题的学分,你必须连续三次正确完成这个随机化问题。

1.4. SLang 1 的抽象语法

下面的问题将帮助你掌握 SLang 1 的抽象语法。

1.5. SLang 1 中的 curry

下面的问题将展示 SLang 1 的语义,同时帮助你复习 curry 函数的 定义。

1.6. SLang 1 的语义

下面的问题着重考察 SLang 1 的语义。

   «  9. 递归函数   ::   目录   ::   2. 基于环境的求值模型  »

关闭窗口