Parsing 递归下降分析语法

Parsing 递归下降分析语法,parsing,grammar,context-free-grammar,Parsing,Grammar,Context Free Grammar,有没有一种简单的方法来判断一个简单的语法是否适合递归下降?消除左递归和左分解语法是否足以实现这一点?不一定 要构建递归下降解析器(无回溯),需要消除或解决所有预测冲突。所以一个决定性的测试是看语法是否为LL(1);根据定义,LL(1)语法没有预测冲突。此任务需要左因子分解和左递归消除,但它们可能不够,因为预测冲突可能隐藏在两个相互竞争的非终端后面: list ::= item list' list' ::= ε | ';' item list' item ::= e

有没有一种简单的方法来判断一个简单的语法是否适合递归下降?消除左递归和左分解语法是否足以实现这一点?

不一定

要构建递归下降解析器(无回溯),需要消除或解决所有预测冲突。所以一个决定性的测试是看语法是否为LL(1);根据定义,LL(1)语法没有预测冲突。此任务需要左因子分解和左递归消除,但它们可能不够,因为预测冲突可能隐藏在两个相互竞争的非终端后面:

 list  ::= item list'
 list' ::= ε 
         | ';' item list'
 item  ::= expr1
         | expr2
 expr1 ::= ID '+' ID
 expr2 ::= ID '(' list ')
上述问题(或者至少有一个问题)是,当解析器需要一个
并看到一个
ID
时,它无法知道要尝试
expr1
expr2
中的哪一个。(这是一个预测冲突:两个非终端都可以预测。)在这种特殊情况下,很容易看出如何消除冲突,但它不是真正的左因子分解,因为它是从组合两个非终端开始的。(在完整语法中,这可能是摘录自,将两个非终结符组合起来可能要困难得多。)

在一般情况下,没有任何算法可以将任意语法转换为LL(1)语法,甚至无法确定该语法所识别的语言是否也具有LL(1)语法。(然而,很容易判断语法本身是否为LL(1)。)因此总是会涉及一些艺术和/或实验

我认为值得补充的是,在实际的递归下降解析器中不需要消除左递归,因为通常可以将其转换为while循环而不是递归。例如,撇开上面两种
expr
类型的问题不谈,带有重复运算符的扩展BNF中的原始语法可能类似于

list ::= item (';' item)*
也就是说:

def parse_list():
    parse_item()
    while peek(';'):
        match(';')
        parse_item()
(错误检查和AST构建省略。)

在这种特殊情况下,很容易看出如何消除冲突,但它不是真正的左因子分解,因为它是从组合两个非终端开始的。很高兴知道重构被称为什么(“item:ID'+'ID | ID'('list')”=>“item:ID('+'ID |'('list'))”)。我还没有找到一个名称,所以我称之为“分组”,因为它将alts与EBNF组相结合。