Parsing 递归下降解析-从LL(1)开始

Parsing 递归下降解析-从LL(1)开始,parsing,compilation,recursive-descent,Parsing,Compilation,Recursive Descent,以下简单的“计算器表达式”语法(BNF)可以用一个简单的递归下降解析器(即预测LL(1))轻松解析: 我真的不能使用简单的LL(1)预测解析器来解析规则吗?我试图为它编写解析器,但似乎我需要了解更多的令牌。解决方案是使用回溯,还是我可以实现LL(2)并始终向前看两个令牌 RD解析器生成器如何处理这个问题(例如ANTLR)?问题在于语法: <command> := <expr> | <id> = <expr> := | =

以下简单的“计算器表达式”语法(BNF)可以用一个简单的递归下降解析器(即预测LL(1))轻松解析:

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


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

问题在于语法:


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

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

rdentato post展示了如何解决这个问题,假设您可以使用语法。此powerpoint更详细地阐述了问题,并展示了如何纠正它:

问题在于

<command>   :=  <expr>
            |   <id> = <expr>
或者使用
=
表示评估:

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

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

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

先行 回溯
你能详细说明一下吗?我不记得交互递归的任何限制,龙之书也没有提到它。语法是LL(2),但这并不意味着你总是要向前看两个标记。您通常只在前面查看一个令牌,并且只在需要时查看两个令牌(就像在您必须在和之间进行选择的情况下)。例如,ANTLR为语法的每一条规则计算出所需的先行检查。

<command>   :=  <expr>
            |   <id> = <expr>
<command>   :=  <expr>
            |   <id> = <expr>
<command>   :=  <expr>
            |   "let" <id> "=" <expr>
<command>   :=  "=" <expr>
            |   <id> "=" <expr>
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();
    }
}