从此语法中删除间接左递归

问题描述

我正在尝试找出如何从Ruby解析器(https://github.com/kenaniah/ruby-parser/blob/master/ruby-parser/src/parsers/expression/logical.rs)的Rust端口中的逻辑关键字表达式中删除间接左递归。语法如下:

E = expression
A = keyword_and_expression
O = keyword_or_expression
N = keyword_not_expression
A

我将如何进行转换以删除Ovar original = "2020-09-01T12:14:05.663-01:23"; var time = original.split('T')[1].split('.')[0]; 中的递归?

解决方法

我认为这里的问题不是间接递归,而是模棱两可。

如果只是间接递归,则可以简单地替换NAO的右侧,从而消除间接递归:

E → n E
  | E a E
  | E o E
  | t

为了摆脱直接的左递归,您可以使用left-factor:

E → n E
  | E A'
  | t
A'→ a E
  | o E

,然后删除其余的左递归:

E → n E E'
  | t E'
E'→ ε
  | A' E'
A'→ a E
  | o E

没有直接或间接的左递归,并且每个规则都以唯一的终端开头。但是,它不是LL(1),因为存在先/后冲突。

这真的不足为奇,因为原始语法非常含糊,并且左递归消除并不能消除歧义。原始语法只有在带有operator precedence table的情况下才有意义。

该表指示ANDOR是具有相同优先级的左关联运算符(略有不同的决策),而NOT是具有较高优先级的一元运算符。反过来,这意味着BNF应该这样写:

N → n N
  | t
E → A
  | O
  | N
A → E a N
O → E o N
N → n N
  | t

如优先级表所示,与OP中语法的唯一区别是消除了歧义。

同样,第一步是替换非终结符AO,以使左递归直接进行:

E → E a N
  | E o N
  | N
N → n N
  | t

这基本上与算术表达式的语法相同(忽略乘法,因为只有一个优先级),并且可以直接消除左递归:

E  → N E'
E' → a E
   | o E
   | ε
N  → n N
   | t
,

根据此factorization tool,结果语法为:

E  -> N
    | A
    | O
    | t
N  -> n E
A  -> n E a E A'
    | O a E A'
    | t a E A'
O  -> n E o E O'
    | n E a E A' o E O'
    | t a E A' o E O'
    | t o E O'
A' -> a E A'
    | ϵ
O' -> a E A' o E O'
    | o E O'
    | ϵ

由于A的多重产生,看起来OE的因式分解最终变得相当复杂。