是否可以为此语法编写递归下降解析器?

时间:2016-03-19 09:13:32

标签: parsing grammar context-free-grammar ll lr

来自this question,涉及二进制运算符(+ - * /)的表达式的语法,它不允许使用外括号:

top_level   : expression PLUS term
            | expression MINUS term
            | term TIMES factor
            | term DIVIDE factor
            | NUMBER
expression  : expression PLUS term
            | expression MINUS term
            | term
term        : term TIMES factor
            | term DIVIDE factor
            | factor
factor      : NUMBER
            | LPAREN expression RPAREN

这个语法是LALR(1)。因此,我能够使用PLYyacc的Python实现)来为语法创建自下而上的解析器。

为了进行比较,我现在想尝试为同一种语言构建一个自上而下的递归下降解析器。我已经改变了语法,删除了左递归并应用了左因子:

top_level   : expression top_level1
            | term top_level2
            | NUMBER
top_level1  : PLUS term
            | MINUS term
top_level2  : TIMES factor
            | DIVIDE factor
expression  : term expression1
expression1 : PLUS term expression1
            | MINUS term expression1
            | empty
term        : factor term1
term1       : TIMES factor term1
            | DIVIDE factor term1
            | empty
factor      : NUMBER
            | LPAREN expression RPAREN

如果没有top_level规则,这个语法就是LL(1),所以写一个递归下降的解析器会相当简单。不幸的是,包括top_level,语法不是LL(1)。

  1. 是否有" LL"该语法的分类(例如LL(k),LL(*))?
  2. 是否可以为此语法编写递归下降解析器?怎么办? (需要回溯吗?)
  3. 是否可以简化此语法以简化递归下降方法?

2 个答案:

答案 0 :(得分:5)

语法不是具有有限前瞻的LL,但语言是LL(1),因为LL(1)语法存在。实际上,即使不修改语法,递归下降解析器也很容易编写。

  
      
  1. 此语法是否有“LL”分类(例如LL(k),LL(*))?
  2.   

如果α是expression的推导,term的β和factor的γ,那么top_level可以推导出句子 α + β和句子α * γ(但它不能导出句子α。)然而,α是两者{{}的可能推导1}}和expression,因此在遇到 之后的符号之前,无法确定要使用哪个term生成。由于α可以是任意长度,因此没有 k k 的前瞻足以区分这两个产品。有些人可能称之为LL(∞),但这对我来说似乎不是一个非常有用的语法范畴。 (LL(*)是afaik,由Terence Parr发明的解析策略的名称,而不是一类语法的公认名称。)我只想说语法不是LL( k )任何 k

  
      
  1. 是否可以为此语法编写递归下降解析器?怎么办? (需要回溯吗?)
  2.   

不确定。这甚至都不困难。

第一个符号必须是top_level。如果是NUMBER,我们预测(调用)NUMBER。如果是,我们使用它,调用expression,使用以下(或声明错误,如果下一个符号不是一个紧密的括号),然后取决于下一个符号是什么,请调用expressionexpression1然后调用term1。再次,如果下一个符号与expression1的第一组或expression1,我们声明语法错误。请注意,上述策略根本不需要term1制作。

由于这显然无需回溯,因此可以作为编写LL(1)语法的基础。

  
      
  1. 是否可以简化此语法以简化递归下降方法?
  2.   

我不确定以下语法是否更简单,但它确实对应于上面描述的递归下降解析器。

top_level*

我留下了两个观察结果,你可以完全自由地忽略它们(特别是第二个100%意见)。

首先,我禁止top_level : NUMBER optional_expression_or_term_1 | LPAREN expression RPAREN expression_or_term_1 optional_expression_or_term_1: empty | expression_or_term_1 expression_or_term_1 : PLUS term expression1 | MINUS term expression1 | TIMES factor term1 expression1 | DIVIDE factor term1 expression1 expression : term expression1 expression1 : PLUS term expression1 | MINUS term expression1 | empty term : factor term1 term1 : TIMES factor term1 | DIVIDE factor term1 | empty factor : NUMBER | LPAREN expression RPAREN 但允许(1+2)(((1)))+2似乎很奇怪。但毫无疑问,你有理由。 (当然,您可以通过在((1+2))+3的第二个作品中将expression替换为top_level来轻松禁止多余的双括号。

其次,在我看来,在第三部分中涉及LL(1)语法的箍跳是另一个理由,为什么有任何理由使用LL语法。 LR(1)语法更容易阅读,它与语言的句法结构的对应关系更加清晰。生成的递归下降解析器的逻辑可能更容易理解,但对我来说似乎是次要的。

答案 1 :(得分:2)

要制作语法LL(1),您需要完成左因子top_level。 你停在了:

top_level   : expression top_level1
            | term top_level2
            | NUMBER

expressionterm在其FIRST集合中都有NUMBER,因此必须先将它们替换为左因子:

top_level   : NUMBER term1 expression1 top_level1
            | NUMBER term1 top_level2
            | NUMBER
            | LPAREN expression RPAREN term1 expression1 top_level1
            | LPAREN expression RPAREN term1 top_level2

然后你可以将因子留给

top_level   : NUMBER term1 top_level3
            | LPAREN expression RPAREN term1 top_level4

top_level3  : expression1 top_level1
            | top_level2
            | empty

top_level4  : expression1 top_level1
            | top_level2

请注意,这仍然不是LL(1),因为存在重叠的FIRST和FOLLOW集的epsilon规则(term1,expression1)。所以你需要将它们考虑在内以使它成为LL(1)