Parsing 如何确定语言是否为LL(1)LR(0)SLR(1)

Parsing 如何确定语言是否为LL(1)LR(0)SLR(1),parsing,compiler-construction,theory,grammar,bnf,Parsing,Compiler Construction,Theory,Grammar,Bnf,有没有一种简单的方法来确定语法是LL(1)、LR(0)、SLR(1)。。。仅仅从语法上看而不做任何复杂的分析 例如:要确定BNF语法是否为LL(1),必须先计算集合,然后再计算集合——在某些情况下,这可能很耗时 有人知道如何更快地做到这一点吗? 任何帮助都将不胜感激 首先,有点迂腐。您无法通过检查语法来确定语言是否为LL(1),您只能对语法本身进行陈述。完全可以为存在LL(1)语法的语言编写非LL(1)语法 这样一来: 您可以为语法编写一个解析器,让一个程序先计算,然后跟踪集合和其他属性。毕竟

有没有一种简单的方法来确定语法是LL(1)、LR(0)、SLR(1)。。。仅仅从语法上看而不做任何复杂的分析

例如:要确定BNF语法是否为LL(1),必须先计算集合,然后再计算集合——在某些情况下,这可能很耗时

有人知道如何更快地做到这一点吗?
任何帮助都将不胜感激

首先,有点迂腐。您无法通过检查语法来确定语言是否为LL(1),您只能对语法本身进行陈述。完全可以为存在LL(1)语法的语言编写非LL(1)语法

这样一来:

  • 您可以为语法编写一个解析器,让一个程序先计算,然后跟踪集合和其他属性。毕竟,这是BNF语法的最大优势,它们是机器可理解的

  • 检查语法并查找各种语法类型约束的违反情况。例如:LL(1)允许右递归,但不允许左递归,因此,包含左递归的语法不是LL(1)。(对于其他语法属性,您将不得不花一些时间来研究这些定义,因为我现在记不起任何其他内容:)


一个方面,“语言/语法是否不明确”类似于和问题。

回答您的主要问题:对于一个非常简单的语法,可以确定它是否为LL(1),而无需构造第一个和第二个集合,例如

A→ A+A | A

不是LL(1),而是

A→ a | b

但当你变得更复杂时,你需要做一些分析

A→ B|a
B→ A+A

这不是LL(1),但它可能不是很明显

算术的语法规则很快变得非常复杂:

expr→ 术语{'+'术语}
学期→ 因子{'*'因子}
因素→ 编号|'('expr')'

这个语法只处理乘法和加法,现在还不清楚该语法是否为LL(1)。仍然可以通过查看语法来评估它,但随着语法的发展,它变得越来越不可行。如果我们要为整个编程语言定义语法,几乎肯定需要进行一些复杂的分析

这就是说,有几个明显的迹象表明,语法不是LL(1)-像a→ 上面的A+A-如果你能在语法中找到其中任何一个,你就会知道如果你在写递归下降解析器,它需要重写。但是没有快捷方式来验证语法是否为LL(1)

  • 构造LR(0)DFA、E的跟随集和SLR动作/转到表
  • 这是LR(0)语法吗?证明你的答案
  • 使用SLR表格,显示LR解析器解析的步骤(移位、缩减、接受):
    id(id+id)

ya ll(1)语法有捷径

1) 如果A->B1 | B2 |.| Bn 然后第一个(B1)交叉点第一个(B2)交叉点。第一个(Bn)=空集,然后是ll(1)语法

2) 如果A->B1 |ε 那么B1交叉点跟随(A)是空集

3) 如果G是任何语法,使得每个非终结符只派生一个结果,那么该语法就是LL(1)

直接来自Aho等人的《编译器:原理、技术和工具》一书

第223页:

语法G是LL(1)当且仅当A->alpha | beta是G的两个不同产物时,以下条件成立:

  • 对于无端子“a”,是否同时派生以“a”开头的alpha和beta字符串
  • alpha和beta中最多有一个可以派生空字符串
  • 如果beta可以通过零个或多个转换到达空转换,那么alpha不会派生任何以FOLLOW(a)中的终端开头的字符串。同样,如果alpha可以通过零个或多个转换到达空转换,那么beta不会派生任何以FOLLOW(a)中的终端开头的字符串

  • 本质上,这是一个验证语法是否通过成对不相交测试的问题,也不涉及左递归。或者更简洁地说,左递归或不明确的语法G不能是LL(1)。

    检查语法是否不明确。如果是,那么语法就不是LL(1),因为没有不明确的语法是LL(1)。

    关于语言和语法之间的区别,这是一个很好的观点。如果语法不是LL(1),那么仍然可以为该语言构造LL(1)语法。这是一个关键的区别,而它通常被掩盖的事实是理解的一个障碍。@JasonOrendorff:Ditto.BTW,您不需要为LL(1)计算FOLLOW,因为它只根据FIRST定义。@jpalecek:如果非终结符为空,您实际上需要为LL(1)计算FOLLOW集。这样,您就可以“越过”非终结符查看要使用的产品。
    p0 S' → E
    p1 E → id
    p2 E → id ( E )
    p3 E → E + id