问题描述
我正在尝试找出如何从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
我将如何进行转换以删除O
和var original = "2020-09-01T12:14:05.663-01:23";
var time = original.split('T')[1].split('.')[0];
中的递归?
解决方法
我认为这里的问题不是间接递归,而是模棱两可。
如果只是间接递归,则可以简单地替换N
,A
和O
的右侧,从而消除间接递归:
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的情况下才有意义。
该表指示AND
和OR
是具有相同优先级的左关联运算符(略有不同的决策),而NOT
是具有较高优先级的一元运算符。反过来,这意味着BNF应该这样写:
N → n N
| t
E → A
| O
| N
A → E a N
O → E o N
N → n N
| t
如优先级表所示,与OP中语法的唯一区别是消除了歧义。
同样,第一步是替换非终结符A
和O
,以使左递归直接进行:
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
的多重产生,看起来O
和E
的因式分解最终变得相当复杂。