【编译原理】一篇搞定First集、Follow集与select集(超详细)

🌈 个人主页:十二月的猫-CSDN博客
🔥 系列专栏: 🏀编译原理_十二月的猫的博客-CSDN博客

💪🏻 十二月的寒冬阻挡不了春天的脚步,十二点的黑夜遮蔽不住黎明的曙光 

目录

1. 预测分析技术与LL(1)文法

1.1 FIRST集求法

1.2 求FOLLOW集

1.3 求SELECT集

2. 求First集与Follow集例题

3. 总结


1. 预测分析技术与LL(1)文法

思考回溯算法的问题——随意选择文法产生式作为操作。

想要不是随便选择,而是有目的性的选择就需要 考察后面输入的值是什么

这也就是为什么这类算法叫做预测分析考察下一位是什么,然后预测哪个产生式可能性高)~~


基本思想:采用深度优先策略构建解析树,每次为非终结符号选择适当的产生式,以避免回溯。具体实现上通过向前查看输入中的一个或多个尚未被匹配的终结符来选定产生式

对于非左递归文法,因不再回溯所以速度更快;但是仍存在无法处理的文法(例如左递归文法)。

考虑通过向前查看一个输入符号就能用预测分析算法解析的文法:人们将这类文法定义为LL(1)文法。

一个文法是LL(1)文法的充要条件是L:每个非终结符A的两个不同产生式A→α,A→β满足SELECT(A→α)∩SELECT(A→β)=∅。

其中第一个“L”表示从左向右扫描输入,第二个“L”表示最左推导,“1”表示只需要看一个输入符号。这个命名规则在后面同样适用。

要进行这样的预测就需要语法分析表,构建语法分析表的过程需要FIRST和FOLLOW两个函数的辅助,二者都可以辅助选择合适的生成式:

  • FIRST(α):可以出现在α导出的句型的开头的终结符的集合;如果α⇒ϵ∗,那么ϵ也包含在FIRST(α)中。
  • FOLLOW(α):可能在某些句型中紧跟在α右边的终结符的集合

FOLLOW(α):是针对于非终结符而言的,这意味着α只能是非终结符。

FIRST(α):是针对非终结符和终结符而言的,这意味着α可以是终结符也可以是非终结符。


小提示:后面的很多算法求解过程都会用到 不动点思想(While直到集合没变化停止)🤗! 


1.1 FIRST集求法

规则如下: 

  • 如果X是一个终结符,那么FIRST(X)=X
  • 如果X是一个非终结符,且X→Y1Y2...Yk∈P(k≥1),那么如果对于某个i,a在FIRST(Yi)中且ε在所有的FIRST(Y1),FIRST(Y2)...FIRST(Yi−1)中,那么把a加入FIRST(X)中
  • 如果X→ε,那么把ε放入FIRST(X)中

求串的first:

  • 向FIRST(X1X2...Xn)中加入FIRST(X1)中的所有非ε符号

  • 如果ε在FIRST(X1)中,那么把FIRST(X2)中所有非ε符号加入FIRST(X1X2...Xn)......以此类推

  • 最后,如果对于所有的i,ε在FIRST(Xi)中,那么把ε加入FIRST(X1​X2​...Xn​)

上面的代码希望大家好好体会一下,非常有助于理解!!😊😊 

1.2 求FOLLOW集

不断应用以下规则,知道没有新的终结符可以加到任何FOLLOW集合。

  • 将$放入FOLLOW(S)中,其中S是开始符号,$是输入右端的结束标记
  • 如果存在一个产生式A→αBβ,那么FIRST(β)中所有非ε符号都在FOLLOW(B)中
  • 如果存在一个产生式A→αB,或存在A→αBβ且FIRST(β)包含ε,那么FOLLOW(A)中的所有元素都在FOLLOW(B)中这里说明了一种FOLLOW(B)对于FOLLOW(A)的依赖关系

求FOLLOW的过程是不断更新的过程,FOLLOW集直接有依赖关系,如果后面一个FOLLOW集更新了,那么所有依赖他的FOLLOW集都需要更新。可以在他们之间建一条边,说明这种依赖关系。

上面的代码希望大家好好体会一下,非常有助于理解!!😊😊  

小tip:用其他元素的first和follow集来求解自己的时一定加入的都是非ε符号

1.3 求SELECT集

SELECT集针对的是产生式

FOLLOW集和FIRST集针对的是符号(终结符、非终结符)

SELECT(A→α):要选择A→α的预测符集合

对于一个产生式A→αA→α,求SELECT(A→α)SELECT(A→α)

  • 若ε∉FIRST(α),那么SELECT(A→α)=FIRST(α)
  • 若ε∈FIRST(α),那么SELECT(A→α)=FIRST(α)∪FOLLOW(A)

2. 求First集与Follow集例题

强烈建议去看下面这个博客:如何求First集与Follow集(超详细)_first集合和follow集合的求法-CSDN博客

这个博客求解方法使用的是:不动点算法,也是前面提到的伪代码流程 

可能有的人喜欢按照规则去求解First集与Follow集,可以去看下面这篇文章:[编译原理]FIRST集和FOLLOW集的介绍和求解_文法first集follow集的计算-CSDN博客

我并不喜欢~~~

例1:写出下面文法中所有非终结符的FIRST集。

	E → TE’
	E’ → +E|ε
	T → FT’
	T’ → T|ε
	F → PF’
	F’ → *F’|ε
	P  → (E)|a|b|^

 解答:

	FIRST(E’) = {+ , ε}  			
	FIRST(F’) = {* , ε}    		 	
	FIRST(P)  = {( , a , b , ^}		
	FIRST(F)  = FIRST(PF’) = FIRST(P)\{ε}= {( , a , b , ^}	
	FIRST(T)  = FIRST(FT’) = FIRST(F)\{ε}= {( , a , b , ^}	
	FIRST(E)  = FIRST(TE’) = FIRST(T)\{ε}= {( , a , b , ^}	
	FIRST(T’) = {FIRST(T)\{ε}} ∪ {ε} = {( , a , b , ^ ,ε}	

 例2:写出下面文法中求FIRST(S),FIRST(A),FIRST(B)。

	G: S → BA
	   A → BS|d
	   B → aA|bS|c

解答:

	FIRST(A) = {FIRST(B)\{ε}}∪{d} = {a, b, c, d} 
	FIRST(S) = {FIRST(B)\{ε}} = {a, b, c}
	FIRST(B)={a, b, c}

例3:写出下面文法中所有非终结符的FOLLOW集。

  	G:  E  → TE’
		E’ → +TE’|ε 
		T  → FT’ 
		T’ → *FT’|ε 
		F  → (E)|i

已知: 

	FIRST(E)  = FIRST(T) = FIRST(F) = {(, i}
	FIRST(E’) = {+, ε}
	FIRST(T’) = {*, ε}

解答:

 

例4:写出下面文法中所有非终结符的LL(1)分析表。

G'[E]: E  → TE'
	   E' → +TE'|ε
	   T  → FT'
	   T' → *FT'|ε
	   F  → (E)|i

这个文法就是前面给出的文法,前面已经求出first和follow集,只要求出select集就可以写出LL(1)分析表了。

已知: 

FIRST(E) = {(,i}
FIRST(E') = {+,ε}
FIRST(T) = {(,i}
FIRST(T') = {*,ε}
FIRST(F) = {(,i}

FOLLOW(E) = {#,)}
FOLLOW(E') = {#,)}
FOLLOW(T) = {+,#,)}
FOLLOW(T') = {+,#,)}
FOLLOW(F) = {*,+,#,)}

解答: 

SELECT(E → T E') = {(,i}
SELECT(E' → + T E') = {+}
SELECT(E' → ε) = {#,)}
SELECT(T → F T') = {(,i}
SELECT(T' → * F T') = {*}
SELECT(T' → ε) = {+,#,)}
SELECT(F → ( E )) = {(}
SELECT(F → i) = {i}

于是有分析表如下:

到这里,我们也就能理解为什么 SELECT(A→α)∩SELECT(A→β)=∅是LL(1)算法的一个条件了

3. 总结

 本文到这里就结束啦~~

本系列专栏将专注于【编译原理】知识。

内容包括:知识点讲解、习题练习、重点知识带练等~~目前已完成:

【编译原理】编译原理知识点汇总·概论与文法-CSDN博客

【编译原理】编译原理知识点汇总·词法分析器(正则式到NFA、NFA到DFA、DFA最小化)-CSDN博客

【编译原理】词法分析器设计(山东大学实验一)_山东大学编译原理实验-CSDN博客

【编译原理】语法、语义分析器设计(山东大学实验二)_语法分析实验-实现一个简单语法分析器(自上而下方法)实验小结-CSDN博客

【编译原理】代码生成器的构建与测试(山东大学实验三)_编译原理实验语义分析代码-CSDN博客 【编译原理】一篇搞定正规式到NFA、NFA到DFA、DFA最小化-CSDN博客

【编译原理】一篇搞定语法分析器对文法的要求(上下文无法文法、消除二义性文法、消除左递归)-CSDN博客期待您的关注~~🥰🥰

猫猫陪你永远在路上💪💪

如果觉得对你有帮助,友友们可以点个赞,收个藏呀~

首先,我们需要先了解一下什么是FIRST。对于一个文法符号串,它的FIRST就是由所有可能的最左终结符组成的合。具体来说,对于一个文法符号串X,它的FIRST包含以下内容: 1. 如果X是一个终结符,则FIRST(X)={X}。 2. 如果X可以推导出ε,则ε∈FIRST(X)。 3. 如果X可以推导出Y1Y2...Yk,则将ε加入FIRST(X)中,当且仅当Y1,Y2,...,Yk都可以推导出ε,或者Y1,Y2,...,Yk-1都可以推导出ε并且Yk可以推导出一个不含ε的终结符。 接下来,我们分别解G[A]的每一个非终结符的FIRST: 1. FIRST(A)={g,c,d},因为A可以推导出gDB、BCcε,其中g、cd分别是它们的最左终结符。 2. FIRST(B)={b,ε},因为B可以推导出bCDEε,其中b是它的最左终结符。 3. FIRST(C)={c,d,a},因为C可以推导出DaBca,其中d、ac分别是它们的最左终结符。 4. FIRST(D)={d,ε},因为D可以推导出dDε,其中d是它的最左终结符。 5. FIRST(E)={g,c},因为E可以推导出gAf,其中gc分别是它们的最左终结符。 (2)、FOLLOW解: 接下来,我们需要解每一个非终结符的FOLLOW。对于一个非终结符X,它的FOLLOW就是由所有可能的紧跟在X后面的终结符组成的合。具体来说,对于一个非终结符X,它的FOLLOW包含以下内容: 1. 如果X是文法的开始符号,则将$加入FOLLOW(X)中。 2. 对于每个产生式A→αBβ,将FIRST(β)中除ε以外的所有终结符加入FOLLOW(B)中。 3. 如果存在一个产生式A→αB或者A→αBβ且ε∈FIRST(β),则将FOLLOW(A)加入FOLLOW(B)中。 接下来,我们分别解G[A]的每一个非终结符的FOLLOW: 1. FOLLOW(A)={$},因为A是开始符号,所以$紧跟在A后面。 2. FOLLOW(B)={c},因为存在产生式A→BCc,所以c紧跟在B后面。 3. FOLLOW(C)={b,c},因为存在产生式B→bCDEC→DaB,所以bc都可能紧跟在C后面。 4. FOLLOW(D)={b,c},因为存在产生式C→DaB,所以bc都可能紧跟在D后面。 5. FOLLOW(E)={c},因为存在产生式B→bCDEE→gAf,所以c可能紧跟在E后面。
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

十二月的猫

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值