Compiler construction 如何找到递归语法的第一组和第二组?

Compiler construction 如何找到递归语法的第一组和第二组?,compiler-construction,context-free-grammar,Compiler Construction,Context Free Grammar,假设我有下面的CFG A -> B | Cx | EPSILON B -> C | yA C -> B | w | z 现在如果我想找到 FIRST(C) = FIRST(B) U FIRST(w) U FIRST(z) = FIRST(C) U FIRST(yA) U {w, z} 也就是说,我要做一个循环。 因此,我假设我必须将它转换成一种具有立即左递归的形式,我可以这样做 A -> B | Cx | EPSILON B -> C | yA

假设我有下面的CFG

A -> B | Cx | EPSILON
B -> C | yA
C -> B | w | z
现在如果我想找到

FIRST(C) = FIRST(B) U FIRST(w) U FIRST(z)
         = FIRST(C) U FIRST(yA) U {w, z}
也就是说,我要做一个循环。 因此,我假设我必须将它转换成一种具有立即左递归的形式,我可以这样做

A -> B | Cx | EPSILON
B -> C | yA
C -> C | yA | w | z
FIRST(C) = FIRST(C) U FIRST(yA) U FIRST(w) U FIRST(z)
         = { y, w, z } // I ignore FIRST(C)
FIRST(B) = FIRST(C) U FIRST(yA)
         = { y, w, z }
FIRST(A) = FIRST(B) U FIRST(Cx) U FIRST(EPSILON)
         = { y, w, z, EPSILON }
现在,如果我试着计算第一组,我想我可以得到如下结果

A -> B | Cx | EPSILON
B -> C | yA
C -> C | yA | w | z
FIRST(C) = FIRST(C) U FIRST(yA) U FIRST(w) U FIRST(z)
         = { y, w, z } // I ignore FIRST(C)
FIRST(B) = FIRST(C) U FIRST(yA)
         = { y, w, z }
FIRST(A) = FIRST(B) U FIRST(Cx) U FIRST(EPSILON)
         = { y, w, z, EPSILON }
我说的对吗

但即使我是对的,当我试图从这个语法计算跟随集时,我仍然遇到了一个问题

FOLLOW(A) = { $ } U FOLLOW(B) U FOLLOW(C)
我从第二条规则中得到FOLLOW(B),从第三条规则中得到FOLLOW(C)。但现在要计算FOLLOW(B),我需要FOLLOW(A)(来自第一条语法规则),所以我又陷入了一个循环

有什么帮助吗?
提前谢谢

因为FIRST和FOLLOW(通常)是递归的,所以把它们看作是要求解的方程组是很有用的;可以使用一个简单的增量算法来实现该解决方案,该算法包括重复应用所有右侧,直到在一个循环中没有任何集合发生更改

因此,让我们对给定语法采用以下关系:

A → B | Cx | ε
B → C | yA
C → B | w | z
我们可以直接推导方程:

FOLLOW(A) = FOLLOW(B) ∪ {$}
FOLLOW(B) = FOLLOW(A) ∪ FOLLOW(C)
FOLLOW(C) = FOLLOW(B) ∪ {x}
因此,我们首先将下面的所有集合设置为{},然后继续

第一轮:

FOLLOW(A) = {} ∪ {$} = {$}
FOLLOW(B) = {$} ∪ {} = {$}
FOLLOW(C) = {$} U {x} = {$,x}
第二轮:

FOLLOW(A) = {$} ∪ {$} = {$}
FOLLOW(B) = {$} ∪ {$,x} = {$,x}
FOLLOW(C) = {$,x} U {x} = {$,x}
第三轮:

FOLLOW(A) = {$,x} ∪ {$} = {$,x}
FOLLOW(B) = {$} ∪ {$,x} = {$,x}
FOLLOW(C) = {$,x} U {x} = {$,x}
第四轮:

FOLLOW(A) = {$,x} ∪ {$} = {$,x}
FOLLOW(B) = {$,x} ∪ {$,x} = {$,x}
FOLLOW(C) = {$,x} U {x} = {$,x}
我们在这里停下来,因为上一轮没有任何变化


此算法必须终止,因为符号数量有限,并且每一轮只能将符号添加到步骤中。这不是最有效的技巧,尽管它在实践中通常已经足够好了。

谢谢兄弟,这对我帮助很大!谢谢。真的帮助了我!首先计算的“最有效技术”是什么?我认为应该从目标符号开始,递归地跟随每个RHS,传播第一个设置树。不过,循环检测会变得很棘手。@david:最有效的技术是使用Tarjan算法的一些变体来计算传递闭包的图像(有关优化此算法的一些技术,请参阅,尽管我相信最近也有研究)(传递闭包的映像采用关系R和函数F并计算R*F;正如Nuutila指出的,如果您找到映像集的并集,而不是找到节点集的并集,然后计算映像,则TC算法可以更快。)