【问题标题】:Recursive descent parsing - from LL(1) up递归下降解析 - 从 LL(1) 向上
【发布时间】:2010-09-12 19:36:26
【问题描述】:

以下简单的“计算器表达式”文法 (BNF) 可以使用简单的递归下降解析器轻松解析,该解析器具有预测性 LL(1):

<expr>      :=  <term> + <term>
            |   <term> - <term>
            |   <term>
<term>      :=  <factor> * <factor>
                <factor> / <factor>
                <factor>
<factor>    :=  <number>
            |   <id>
            |   ( <expr> )
<number>    :=  \d+
<id>        :=  [a-zA-Z_]\w+

因为看到下一个标记总是足以知道要选择的规则。但是,假设我添加了以下规则:

<command>   :=  <expr>
            |   <id> = <expr>

为了在命令行上与计算器进行交互,使用变量,如下所示:

calc> 5+5
=> 10
calc> x = 8
calc> 6 * x + 1
=> 49

我真的不能使用简单的 LL(1) 预测解析器来解析 &lt;command&gt; 规则吗?我试图为它编写解析器,但似乎我需要知道更多的令牌。是使用回溯的解决方案,还是我可以只实现 LL(2) 并始终向前看两个令牌?

RD 解析器生成器如何处理这个问题(例如 ANTLR)?

【问题讨论】:

  • 语法是 LL(2),但这并不意味着您总是必须向前看两个标记。您通常只会向前看一个标记,并且仅在需要时才看两个(例如您必须在 之间进行选择的情况)。例如,ANTLR 为每个语法规则计算出所需的前瞻。

标签: parsing compilation recursive-descent


【解决方案1】:

问题

<command>   :=  <expr>
            |   <id> = <expr>

当您“看到”&lt;id&gt; 时,您无法判断它是分配的开始(第二条规则)还是“&lt;factor&gt;”。您只会知道何时阅读下一个令牌。

AFAIK ANTLR 是 LL(*)(如果我没记错的话,它也能够生成 rat-pack 解析器)所以它可能会同时考虑两个标记来处理这个语法。

如果您可以使用语法,我建议您为作业添加一个关键字(例如let x = 8):

<command>   :=  <expr>
            |   "let" <id> "=" <expr>

或使用= 表示评估:

<command>   :=  "=" <expr>
            |   <id> "=" <expr>

【讨论】:

    【解决方案2】:

    我认为使用递归下降解析器有两种方法可以解决这个问题:使用(更多)前瞻或回溯。

    前瞻

    command() {
        if (currentToken() == id && lookaheadToken() == '=') {
            return assignment();
        } else {
            return expr();
        }
    }
    

    回溯

    command() {
        savedLocation = scanLocation();
        if (accept( id )) {
             identifier = acceptedTokenValue();
             if (!accept( '=' )) {
                 setScanLocation( savedLocation );
                 return expr();
             }
             return new assignment( identifier, expr() );
        } else {
             return expr();
        }
    }
    

    【讨论】:

      【解决方案3】:

      问题在于语法:

      <command> := <expr> | <id> = <expr>

      不是一个相互递归的过程。对于递归体面的解析器,您需要确定一个非递归等价物。

      rdentato 帖子展示了如何解决这个问题,假设您可以使用语法。这个 powerpoint 更详细地说明了这个问题,并展示了如何纠正它: http://www.google.com/url?sa=t&source=web&ct=res&cd=7&url=http%3A%2F%2Fxml.cs.nccu.edu.tw%2Fcourses%2Fcompiler%2Fcp2006%2Fslides%2Flec3-Parsing%26TopDownParsing.ppt&ei=-YLaSPrWGaPwhAK5ydCqBQ&usg=AFQjCNGAFrODJxoxkgJEwDMQ8A8594vn0Q&sig2=nlYKQVfakmqy_57137XzrQ

      【讨论】:

      • 你能详细说明一下吗?我不记得有任何相互递归的限制,龙书也没有提到。
      【解决方案4】:

      ANTLR 3 使用“LL(*)”解析器而不是 LL(k) 解析器,因此如果需要,它将向前看直到到达输入的末尾,而无需回溯,使用特别优化的确定性有限自动机 (DFA)。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-08-07
        • 1970-01-01
        • 2012-05-21
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多