第一章 first集的计算
现在我们开始自己做的YACC部分,首先我们要计算first集。在计算first集之前,我们要了解关于文法的一些基础知识,理解这部分内容,可能会涉及到离散数学中的关系一章。显然,对关系运算的理解有助于对编译原理的理解。
1 基础知识
1.1 文法定义
参见编译原理教材,可知一个文法定义为一个四元组(VN, VT, P, S)其中VN为非终结符号(或语法实体,或变量)集;VT为终结符号集;P为产生式(也称规则)的集合;VN, VT和P是非空有穷集。S称做识别符号或开始符号,它是一个非终结符,至少要在一条规则中作为左部出现。
VN和VT不含公共元素,即VN∩VT = Φ。通常V表示VN∪VT,V称为文法G的字母表或字汇表。
定义1
如α→β是文法G=( VN, VT, P, S)的规则(或说是P中第一个产生式),γ和δ是V*中的任意符号,若有符号串v,w满足:v=γαδ,w=γβδ,则说v(应用规则α→β)直接产生w,或说w是v的直接推导。
定义2
如果存在直接推导的序列:v=w0=>w1=>w2…=>wn=w,(n>0),则称v推导出(产生)w(推导长度为n)。记做v=>+w。
定义3
若有v=>+w,或v=w,则记做v=>*w。
定义4
设G[S]是一文法,如果符号串x是从识别符号推导出来的,即有S=>*x,则称x是文法G[S]的句型。若x只由终结符号组成,则称x为G[S]的句子。
定义5
文法G所产生的语言定义为集合{x | S=>*x,其中S为文法的开始符号,且x∈VT *}。可用L(G)表示该集合。
定义6
若L(G1) = L(G2),则称文法G1和G2是等价的。
1.1.1 文法的类型
设G=(VN, VT, P, S);乔姆斯基把文法分为四种类型:
l 0型文法:也叫做短语文法。0型文法的能力相当于图灵机(Turing)。或者说,任何0型语言都是递归可枚举的;反之也成立。
对于G的每个产生式,α→β,是这样一种结构:α∈(VN∪VT)+,且至少含有一个非终结符,而β∈(VN∪VT)*
l 1型文法:也叫做上下文有关文法G的任何产生式α→β,均满足| α |≤ | β |,仅仅S→ε除外。这就意味着对非终结符的替换必须要考虑上下文,并且一般不准替换为空串。
l 2型文法:G的任何产生式为A→β,A∈VN,β∈(VN∪VT)*。也叫做上下文无关文法
l 3型文法:也叫做正规文法。G的任何产生式为A→αB或者A→α,其中,α∈VT*,A、B∈VN。上述叫做右线性文法,另有左线性,二者等价。(注:| α |表示串的长度)
1.1.2 First 集
好了,有这些语言和文法的概念,我们就开始讨论First集。如果上面的概念不太懂,可以直接跳过去。WACC代码中的语言(Language类)的定义与上面的定义类似,等会儿就可以在代码中看到。呵呵。
定义:(来自《编译原理及实践》 Kenneth C. Louden 著)
令X为一个文法符号(一个终结符或非终结符)或 ε,则集合First(X)由终结符组成,此外可能还有ε,它的定义如下:
若X是终结符或ε,则First(X)= {X} 。
若X是非终结符,则对于每个产生式X –>X1X2…Xn ,First(X)都包含了First(X1)-{ε}。若对于某个i < n,所有的集合First(X1)…..First(Xi )都包括了ε,则First(X)也包含了 First(Xi+1)-{ε},若First(X)也包含了ε
现在为任意串α= X1X2…Xn (终结符和非终结符组成的串)定义First(α),如下所示:First(α),如下所示,First(α)包含First(X1)-{ε}。对于每个i = 2,……n, 如果对于所有的k = 1,…..,i-1, First(Xk)包含了ε,则First(α)也包含了ε。
1.1.3 算法
根据该定义,我们可以得到符号First集如下算法,无论手算还是机算都适用。
1) 若X∈VT,则FIRST(X)={X};
2) 若X∈VN,且有产生式X→a…,则把a加入到FIRST(X)中;若X→ε也是一条产生式,则把ε也加到FIRST(X)中。
3) 若X→Y…是一个产生式且Y∈VN,则把FIRST(Y)中的所有非ε元素都加到FIRST(X)中;若X→Y1Y2…Yk是产生式,Y1,…,Yi-1都是非终结符,而且对于任何的j,1≤j≤i-1,FIRST(Yj)都含有ε,则把FIRST(Yi)中的所有非ε元素都放到FIRST(X)中;特别的是,若所有的FIRST(Yj)均含有ε,j=1,2,…,k,则把ε加到FIRST(X)中
4) 重复上面的过程直到每个First集不再增大。
也许有人会疑问,要是First集无限增大怎么办?循环不就结束不了?其实大可放心,First集也好,包括后面的epsilon 闭包等,都是一种关系,可以用有序对<X,a>来表示,有限个元素产生的关系是有限的,你可以参考离散数学的教材就可以知道,其实你不懂离散数学,使用高中学的组合也可以知道这个结论。呵呵。
1.1.4 手算例子
给定文法
stmt_sequence->stmt stmt_seq
stmt_seq->; stmt_sequence
stmt_seq->
stmt->s
在文法中,我们不再给定哪些符号是终结符,哪些是非终结符。我们在这里认为,凡是在右部出现而没在左部出现的符号均为终结符,其它均为非终结符。在其它编译原理的教材中,右部为空使用A->ε表示右部为空,但我们在这里不采用这种表示方法。如stmt_seq-> 就表示stmt_seq右部为空。
文法first集计算
规则 | 第一遍 | 第二遍 |
stmt_sequence->stmt stmt_seq | First(stmt_sequence)={s} | |
stmt_seq->; stmt_sequence | First(stmt_seq)={;} | |
stmt_seq-> | First(stmt_seq)={;ε} | |
stmt->s | First(stmt)={s} |
图表 21
所以得出
First(stmt_sequence) = {s}
First(stmt_seq)={;ε}
First(stmt)={s}
First(s) = {s}
First(;) = {;}