我在某个地方看到了一个问题,询问LL(0)和LR(0)解析器之间的区别。是否有LL(0)解析器这样的东西?如果是这样,他们如何在不查看任何令牌的情况下进行解析?
答案 0 :(得分:21)
LL(0)解析器会查看标记,但它们不会决定要对它们应用哪些生成。他们只是确定序列是否属于该语言。这意味着每个非终端符号必须有一个右侧,并且可能没有递归。
G == ID name lastname
name == STRING
lastname == STRING
# lexer rules
# -----------
ID == [0-9]+
STRING == <unicode>+
请注意,如@ 280Z28所述,需要单独的词法分析器来处理可变长度部分(ID
和STRING
),或者语法不是LL(0)
。
应用于解析具有该语法的输入的作品序列需要零预测。
当解析部分给定输入序列后可以应用多个生成时,确定性需要前瞻。
理论上,语法生成一种语言,并且,其中,歧义(具有多种方式来推导给定短语)很好。在解析中,只有一种方式是语义(意义),这就是我们想要的。
在解析编程语言时,前瞻是了解下一步要使用哪种语法生成所需的信息。
在LL(0)语言中,没有选择,因此输入序列被接受并解析或拒绝。
答案 1 :(得分:2)
当我接受编译器时,我们从未谈过它们,尽管我们谈过LL(1)。在Wikipedia上没有提及它们。
LL(0)解析器意味着解析器可以在不知道流中的下一个令牌的情况下做出决定。我希望如果存在具有该属性的语言,则它们非常罕见。
答案 2 :(得分:2)
LR(k)中的k指的是 lookahead 标记的数量。您始终使用至少一个令牌来确定要执行的操作。 Wikipedia page页面提供了更多相关信息。
直观地说,额外的先行符号可以让您通过更多信息进行缩减选择,因此它们允许表达更大类的语法而不会发生冲突。
答案 3 :(得分:0)
由于其他答案中给出的原因,您通常不会听到LL(0)解析:非平凡的解析需要看到一些输入。但是,LL(1)解析器的某些部分确实可以作为LL(0)解析器运行。
例如,这是一个简单的BNF语法,只需要在一个产品中先行阅读即可:
S -> A
A -> B
B -> 'a' | 'b'
B产生式有两个右侧,分别对应输入中的两个单独的字符串“ a”和“ b”。因此,解析器必须查看输入以选择适当的RHS。
但是,S和A生产都没有任何选择。因此,尽管它们实际上具有关联的FIRST集(包含“ a”和“ b”),但不需要FIRST集来做出解析决定,这意味着S-> A和A-> B乘积是一个LL(0)子语法。因此,一种优化方法是忽略这两个非终结点的FIRST集。
为清楚起见,假设输入为字符串“ b”。然后,解析器甚至可以在不看输入的情况下自动自动生成自顶向下的推导S-> A a和A-> B(这称为自动机)。然后,对于B的最内层推导,它必须查看输入以确定使用哪个B生成来完成解析树。
这种优化的一个优点是可以在检查输入的那一刻而不是在解析时进行错误检测(找不到输入,或者输入“ a”或“ b”以外的其他输入)其他一些产品。如果需要,错误消息不仅可以引用B生成,还可以引用A和S生成,因为它们已经生成。如果在没有优化的情况下检查了第一组S,那么当所有已知的尝试是S-> A时,都将必须报告错误,这对于用户来说是少得多的上下文信息。