【编译原理】FIRST集合和FOLLOW集合

FIRST集合

定义:可从α推导得到的串的首符号的集合,其中α是任意的文法符号串。

规则:计算文法符号 X 的 FIRST(X),不断运用以下规则直到没有新终结符号或 ε可以被加入为止 :

(1)如果 X 是一个终结符号,那么 FIRST(X) = X。

(2)如果 X 是一个非终结符号,且 X ->Y1 Y2 … Yk是一个产生式,其中 k≥1,那么如果对于某个i,a在 FIRST(Y1)、FIRST(Y2)… FIRST(Yi-1)中,就把a加入到 FIRST(X) 中。

(3)如果 X ->ε是一个产生式,那么将ε加入到 FIRST(X)中。

上述为官方给出的计算FIRST集合的规则,不太好理解,接下来我将综合其他笔者总结的规则给出我理解的FIRST集合的规则。

(1)如果X是终结符,则FIRST(X) = { X } 。
(2)如果X是非终结符,且有产生式形如X → a…,则FIRST( X ) = { a }。
(3) 如果X是非终结符,且有产生式形如X → ABCdEF…(A、B、C均属于非终结符且包含 ε,d为终结符),需要把FIRST( A )、FIRST( B )、FIRST( C )、FIRST( d )加入到 FIRST( X ) 中。
(4)如果X经过一步或多步推导出空字符ε,将ε加入FIRST( X )。

下面给出文法示例并做讲解:

E -> T E'
E' -> + T E' | ε
T -> F T'
T' -> * F T' | ε
F -> ( E ) | id

FIRST(E) = FIRST(T) 根据规则3,很容易理解,这里要注意的由于T不含ε,所以遍历到T就停止了,E’不会加入进来
FIRST(E’) = FIRST(+) ∪ FIRST(ε)= { +, ε } 根据规则2和4,,很好理解
FIRST(T) = FIRST(F) 根据规则3,和第一条推导过程一样
FIRST(T’) = FIRST() ∪ FIRST(ε)= { , ε } 根据规则2和4,和第二条推导一样
FIRST(F) = FIRST( ( ) ∪ FIRST(id)= { ( , id } 根据规则2

结果:

FIRST(E) = FIRST(T) = FIRST(F) = { ( , id }

FIRST(E') = FIRST(+) ∪ FIRST(ε)= { + , ε }

FIRST(T') = FIRST(*) ∪ FIRST(ε)= { * , ε }

FOLLOW集合

定义:对于非终结符号X,FOLLOW(X) 被定义为可能在某些句型中紧跟在A右边的终结符号集合。

规则:计算文法符号 X 的 FOLLOW(X) ,不断运用以下规则直到没有新终结符号可以被加入任意FOLLOW集合为止 :

(1)将#加入到FOLLOW(X)中,其中S是开始符号,而#是输出右端的结束标记。

(2)如果存在一个产生式S->αXβ,那么将集合FIRST(β)中除ε外的所有元素加入到FOLLOW(X)当中。

(3)如果存在一个产生式 S->αX , 或者S->αXβ且FIRST(β)中包含ε , 那么将集合FOLLOW(S)中的所有元素加入到集合FOLLOW(X)中。

理解:FOLLOW集合对于非终结符而言,是非终结符的全部后跟符号的集合,

如果后跟终结符则加入,

如果后跟非终结符,则加入该非终结符的不含空符号串的FIRST集,

特别地,文法的识别符的FOLLOW集需要额外的加入‘#’。

下面给出简化后的规则:

首先:如果要找L的Follow,要从式子的右边找到L,然后来找L的Follow。

其次:将‘#’加入到 开始符 的 Follow中  ①

接着:如果L的右边是终结符,那么这个终结符加入L的Follow  ②

如果L的右边是非终结符, 那么把这个非终结符的First集合除去 ε后剩下的元素加到L的Follow中,同时将 '->' 符号左边的Follow加入L的Follow  ③

特别的,如果L处在末尾,那么,将 '->' 符号左边的Follow加入L的Follow  ④

练习:还是用之前的例子来做

1 |  E -> T E'
2 |  E' -> + T E' | ε
3 |  T -> F T'
4 |  T' -> * F T' | ε
5 |  F -> ( E ) | id

FOLLOW(E) ,运用 ① ,E是开始符,所以首先将 # 加入到 FOLLOW(E)中 ;接下来在上述文法的右边找到  E ,发现E在第5行文法的右边,E 后面是终结符 ) ,所以将 )加入到 FOLLOW(E)中 ;此处运用的是规则②,综上即 FOLLOW(E) = { ) , # }


FOLLOW(E’) ,先在上述文法的右边找到  E' ,发现E' 分别在第1行(在自己行不算),此时可以运用规则④,即将FOLLOW(E) 加入到FOLLOW(E')中,综上即 FOLLOW(E')= FOLLOW(E) = { ) , # } 


FOLLOW(T),先在上述文法的右边找到 T ,发现T在第一行,此时运用规则 ③,将E'的FIRST集合中除  ε外其他元素加入到FOLLOW(T)中,同时将FOLLOW(E) 加入到FOLLOW(T)中,综上即FOLLOW(T)= { + , ) , # } 


FOLLOW(T’) ,先在上述文法的右边找到 T ' ,发现T'在第三行,此时可以运用规则④,即将FOLLOW(T) 加入到FOLLOW(T')中,综上即 FOLLOW(T')= FOLLOW(T) = { + , ) , # } 


FOLLOW(F),先在上述文法的右边找到 ,发现F在第三行和第四行,此时运用规则 ③,对于第3行,将T'的FIRST集合中除  ε外其他元素加入到FOLLOW(F)中,同时将FOLLOW(T) 加入到FOLLOW(F)中,此时FOLLOW(F)= { * , + , ) , # } ;对于第4行,将将T'的FIRST集合中除  ε外其他元素加入到FOLLOW(F)中,同时将FOLLOW(T') 加入到FOLLOW(F)中,而 FOLLOW(T')= FOLLOW(T),所以FOLLOW(F)依旧= { * , + , ) , # } ,综上所述,FOLLOW(F)= { * , + , ) , # } 。

结果:

FOLLOW(E) = FOLLOW(E') = { ) , # }

FOLLOW(T) = FOLLOW(T') = { + , ) , # }

FOLLOW(F) = { * , + , ) ,# }

FIRST集合和FOLLOW集合在编译原理语法分析中是我觉得比较难理解的,以上是我看过很多csdn上面其他文章再加上我的理解总结出来的,尤其是FOLLOW集合,是我看了另一篇写的好的文章加上我的理解总结出来的,希望对你们有帮助。

评论 16
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值