当前位置:文档之家› 上下文无关文法

上下文无关文法

第三部分上下文无关语言和下推自动机前面介绍的有限自动机是计算的初级模型,它所接受的正规语言不太关心字符串自身的结构。

上下文无关文法(CFL)是一种简单的描述语法规则的递归方法,语言中的字符串由这些规则产生。

所有的正规语言都能用上下文无关文法描述,它也可以描述非正规语言。

上下文无关文法描述的语法规则更复杂多变,可以在相当大的程度上,描述高级程序设计语言的语法和其他一些形式语言。

类似正则语言对应的抽象机模型是有限自动机,CFL也有对应的抽象机模型。

CFL对应的计算模型是在有限自动机的基础上增加存储空间得到,并被设想成无限空间(对应有限自动机的有限空间),采用了一种简单的管理模式,栈(stack),这种新的计算模型(或抽象机)称为下推自动机(pushdown automata),下推是栈最典型的操作。

有必要在下推自动机中保留非确定性,确定型下推自动机不能接受所有的CFL,但给定一个CFG,容易构造一个相应的非确定型下推自动机,它在识别字符串过程中的移动模拟了文法的推导过程,这个过程称为分析(parse)。

分析不是一定需要下推自动机来完成。

CFL仍然不够通用,不能包括所有有意义的、或有用的形式语言。

采用类似第五章的技术,我们将给出一些不是CFL的简单例子,这些技术也用于解决与CFL相关的判定问题。

6 上下文无关文法6.1 上下文无关文法的定义为了描述我们在第二部分考察的各种语言,包括一些非正则语言,我们引入一种语言的递归定义方法,称为文法。

文法与我们熟悉的语言的语法描述相近,是描述语言和分析语言的有力工具。

问题:文法的形式化定义似乎可以模仿有限自动机,比如5元组或6元组之类。

例子6.1 正如我们在例子2.16中所见,字母表{a, b}上的回文语言pal可以用下面的递归方法描述:1.Λ, a, b∈pal2.对每个S∈pal,aSa和bSb也属于pal3.pal中不包含其他字符串如果将上面的符号S看成一个变量,代表了所有我们希望计算(比如某种递归算法)的pal 的元素,那么上面的规则1和规则2可以非正式地重新表述如下:1.S的值可以是Λ, a, b2.每个S可以写成aSa或bSb的形式如果我们用→表示“可以取值为”,则可以写出下面的式子:S→aSa→abSba→abΛba=abba上面的产生过程可以总结成下面的两组产生式(或称规则):S→a | b | ΛS→aSa | bSb符号“|”表示“或”的含义。

上式的含义是aSa或bSb,而不是a或b,即连接运算的优先级高于“|”。

我们使用的这套术语中,小写字母a和b表示终结符,大写字母S表示非终结符,或称变量。

总共有5条规则,或产生式(production)。

符号S是非终结符,也是起始终结符,即我们生成字符串的起始符号是S,然后不断利用规则替换符号串中的非终结符,直到最终得到一个不含非终结符的符号串,就生成了规则所定义的语言的一个字符串。

例子2中的产生式具有除起始符S外的多个非终结符,我们设想S表示了语言中任意的字符串,其他非终结符表示了其他辅助性的字符串类型,他们可用来方便地生成S表示的字符串。

例子6.2 我们要构造一个生成所有在字母表{a, b}上的非回文字符串的文法,那样的字符串可以描述如下:从字符串的两端开始比较,也许能够发现一些相同的字符对,但最终能够发现一对不同的字符。

对于前一种情况,我们可以借用回文语言的产生式:S→aSa | bSb如果加入产生式S→a | b | Λ则这种左右匹配的形式将体现在整个字符串上,为了中断这种左右匹配的情况,即体现上面提到的第二种情况,我们引入新的非终结符,比如D,表示那些左右两个端点上的字符不同的字符串。

且所有符合D的字符串也符合S,因此有S→D。

非终结符的定义比较简单,它唯一的条件是左右两个端点的字符不相同,中间的字符串可以是任意的,我们用非终结符A表示任意的字符串,则有D→aAb | bAa。

A表示任意的字符串,因此A的产生式更简单了,不用添加新的非终结符来简化问题,它的产生式是,A→Λ | aA | bA。

我们把上面三个非终结符的产生式写在一起,就得到了描述所规定语言的产生式集:S→aSa | bSb | DD→aAb | bAaA→Λ | aA | bA因此一个完整的非回文字符串“abbaaba”的产生过程是,S→aSa→abSba→abDba→abbAaba→abbaAaba→abbaΛaba→abbaaba定义6.1 上下文无关文法(context-free grammar, CFG)是一个4元组G=(V, ∑, S, P),其中,V和∑是不相交的有限集,S∈V,P是一组有限的产生式规则,形如A→α,其中A∈V,且α∈(V⋃∑)*。

V的元素称为非终结符(或变量),∑的元素称为终结符,S是一个特殊的非终结符,称为起始符,P的元素称为语法规则,或产生式。

设G=(V, ∑, S, P)是一个CFG,我们将符号→保留给P的产生式专用,符号⇒G用于表示字符串的产生过程的每一步,如α⇒Gβ表示字符串β能够通过替换α中的某些变量(根据P定义的产生式来替换)得到,即如果有α=α1Aα2且A→γ∈P,则β=α1γα2。

这里能够看到,我们命名为上下文无关(context-free)的含义,即我们在利用产生式规则,用一组符号替换某个非终结符时,与非终结符的上下文无关(此处,A的替换与α1和α2无关),替换是无限制的。

在没有多个文法出现,很清楚用到文法G是什么的情况下,推导符号⇒G可以简写成⇒。

多步的推导可以写成⇒*G,即如果存在一组符号串,α=α0、α1、…、αk=β,每个后者都是前者的直接推导,则称为α可以多步推导出β,记为α⇒*Gβ,简写成α⇒*β。

定义6.2 G=(V, ∑, S, P)是一个CFG,则G产生的语言是所有可由G产生的字符串组成的集合,即L(G)={x∈∑* | S⇒*G x}。

一个语言L是上下文无关语言(context-free language, CFL),当且仅当存在一个CFG G,使得L=L(G)。

此处可以把文法设想成类似自动机的抽象模型,则一个语言L是CFL当且仅当存在一个CFG G接受它(或识别它),类似前面正则语言与有限自动机的关系,接受(或识别)的含义是两方面的,一方面凡是L中的字符串都能由G产生,另一方面,凡是不属于L的字符串都不能由G产生。

前面的例子,能够比较容易地说明这两方面的限制,下面的例子则不是很明显。

例子6.3 考虑语言L={x∈{0, 1}* | n0(x)=n1(x)},其中n i(x)表示数字i在x中的出现次数(即含有相同数目0和1的语言)。

写出生成L的CFG。

分析:既然CFG的本质是一个递归定义,那么类似例子6.1,我们可以先发现归纳基础,然后找到归纳推理。

显然Λ∈L,另外如果存在一个字符串x∈L,那么得到更长的属于L的字符串的两个方法是,0x1和1x0,即分别在两端添加相同数量的0和1。

(当然,还有很多生成方法,比如x01,x10,或在x中插入相同数量的0和1),这样得到三个产生式:S→Λ | 0S1 | 1S0显然,还遗漏了一些字符串,如0110。

我们注意到L中任意两个元素的连接仍然属于L,因此可以增加一个产生式,S→SS。

与前面的三个产生式合并,我们得到一个CFG G如下,S→Λ | 0S1 | 1S0 | SS显然G产生的字符串都满足0和1数目相等这个条件,即L(G)⊆L,现在只要证明L⊆L(G)。

令d(x)=n0(x)-n1(x)。

则字符串x∈L,当且仅当d(x)=0。

因此只需证明每个满足d(x)=0的x,都有x∈L(G)。

我们用数学归纳法来证明L⊆L(G)。

归纳对象是字符串的长度|x|。

1.归纳基础,|x|=0且d(x)=0,则x∈L(G),这是显然的,因为此时x=Λ,而Λ可以由产生式S→Λ得到。

2.归纳推理,设k>=0,每个满足|y|<=k,d(y)=0的字符串y都属于L(G)。

要证明每个长度等于k+1且d(x)=0的字符串x也属于L(G)。

分情况讨论如下:a)如果x以0开始,以1结尾,则可以写成x=0y1,且d(y)=0,根据归纳假设y∈L(G),即存在一组推导,S⇒*G y。

因此对于x,存在推导,S⇒0S1⇒*0y1⇒x。

b)如果x以1开始,以0结尾,类似a)的处理,能够得到从S到x的推导。

c)如果x以0开始,且以0结尾。

则x的长度至少为2,设x=0y0。

现在考察x的所有前缀z的d(z),其中d(0)=1,d(0y)=d(0y0)-d(0)=-1,而d(z)随着z的长度增1,至多增加1或减少1,而当前缀从0变化到0y时,d(z)从1变化到-1,因此存在某个长于0短于0y的前缀z,使得d(z)=0,则x=zw,显然d(w)=0,由于z、w的长度都<=k,因此z、w都属于L(G),分别存在从S出发到z和w的推导。

为了得到从S出发到x的推导,首先用产生式S→SS。

d)如果x以1开始,且以1结尾,类似c)的处理。

例子6.4 考查语言L={x∈{0, 1}* | n0(x)≠n1(x)},写出它的CFG。

分析:例子6.3看起来与本例关系很大,但实际上没有什么帮助,我们在第8章,将详细解释为什么一个语言的CFG并不能帮助发现它的补集语言的CFG。

L中的字符串可以分为两大类,一类含有的0的个数多于1,另一类含有1的个数多于0,前者组成集合L0,后者组成L1。

如果能够发现L0和L1的CFG,由于L= L0⋃L1,就能够很容易找到L的CFG。

类似以前的做法,我们尽力找到语言L0的递归特征。

显然0∈L0,且如果x∈L0,则0x和x0也属于L0,由此得到三个产生式:S→0 | S0 | 0S我们无法保证L0中的字符串连接1仍然属于L0,但是如果两个L0中的字符串连接后再连接一个1能够保证新字符串仍然属于L0,因此得到另外三个产生式:S→1SS | SS1 | S1S合并这两组产生式就得到了生成L0的CFG G0如下,S→0 | S0 | 0S | 1SS | SS1 | S1S类似前面,我们只要证明L0⊆L(G0)。

令d(x)=n0(x)-n1(x),要证明凡是d(x)>0的x都能由G0产生,对x的长度应用数学归纳法。

1.归纳基础,显然|x|=1且d(x)>0时,即x=0,x可由S→0推导,属于L(G0)。

2.归纳推理,设k>=0,对每个|x|<=k且d(x)>0的x都属于L(G0),要证明每个|x|<=k且d(x)>0的x也属于L(G0)。

分情况讨论,此处仅讨论x=0y0的情况(即以0开始和结尾的情况),a)x仅由0组成,易证。

b)x至少含有一个1。

则x=w1z,现在证明d(w)>0且d(z)>0。

相关主题