第九章语言和有限状态机
§9.1语言和语法
英语的单词可以用很多方法排列起来,英语的语法告诉我们是否一个单词的排列是一个有效的句子。例如,the frog writes neatly 是一个有效的句子,因为它是由一个名词组 the frog (由定冠词 the 和 名词 frog 组成),后跟一个动词词组 writes neatly (由动词 writes 和副词neatly组成)。我们不在意这个句子没有实际意义,因为我们只关心句法或者说句子的形式,而不是它的语义或者说含义。我们也注意到下面单词的排列 swims quickly mathematics 是无效的句子,因为它不符合英语的语法。
自然语言的句法是非常复杂的,事实上,不太可能把它的所有句法规则写出来,再把一个语言自动转换成另一个语言的研究中使用了形式语言的概念,它不像自然语言,它被一个封闭的句法规则集所确定。句法规则不但在自然语言的研究中重要,在程序语言中也很重要。我们将描述使用一个语法的形式语言的句子。在程序语言的应用中经常遇到两类问题:(1)怎么决定一个单词的排列是否是一个形式语言中的有效句子?(2)如何产生一个形式语言中的有效的句子?语法的使用可以帮助我们解决这些问题。
在给出语法的定义之前,我们先来看一个产生英语语言的子集的语法的例子。这个英语语言的子集用一个规则来产生一个有效的句子,规则如下:
1.一个句子由一个名词词组后跟一个动词词组组成;
2.一个名词词组由一个定冠词后跟一个形容词再后跟一个名词组成,或者
3.一个名词词组由一个定冠词后跟一个名词组成;
4.一个动词词组由一个动词后跟一个副词,或者
5.一个动词词组由一个动词组成;
6.一个定冠词是a,或者
7.一个定冠词是the;
8.一个形容词是large或者
9.一个形容词是hungry;
10.一个名词是rabbit,或者
11.一个名词是mathematician;
12.一个动词是eats,或者
13.一个动词是hops;
14.一个副词是quickly,或者
15.一个副词是wildly.
通过这些规则我们就可以使用一系列的替换直到没有规则可用为止,这样就可以得到有效的句子。例如,
sentence
noun phrase verb phrase
article adjective noun verb phrase
article adjective noun verb adverb
the adjective noun verb adverb
the large noun verb adverb
the large rabbit verb adverb
the large rabbit hops adverb
the large rabbit hops quickly
这样就得到一个有效的句子,我们也可以得到其它的有效的句子,如:a hungry
mathematician eats wildly; a large mathematician hops; the rabbit eats quickly等。我们也可以看到 the quickly eats mathematician 不是一个有效的句子。
9.1.1语法结构
在定义语法之前,我们先给出一个术语。
定义9.1.1.一个字母表V是一个非空有限的集合,这个集合中的元素称为符号。由V的符号组成的有限序列的字符串称为V上的词(或者句子)。空串记入λ,它是不包含任何符号的字符串。V上所有词的集合记为V ∗ 。V ∗ 的任何子集称为语言。需要注意的是空串λ,它没有任何符号,它和空集ϕ不同。{λ}是包含一个串的集合,这个串是空串。
语言可以用很多方法给出来,一种方法是把语言中的所有词都列举出来,另一种方法是给出语言中的词所必须满足的一些标准。这一节我们将讨论另外一种给定语言的重要方法,即利用语法,如象我们前面说过的那样包含若干规则的集合,一个语法给出了一个各种符号的集合和一个产生词的规则集合。精确地说,一个语法有一个字母表V,它是用来产生语言的符号集合,字母表中的一些符号不能被其它符号代替,称为终止符,另外一些符号能被其它符号所代替,称为非终止符。终止符集合非终止符的集合分别记为T和N。
在前面给的例子中,终止符集合是
{a,the,rabbit,mathematician,hops,eats,quickly,wildly}
,非终止符集合是
{sentence,nounphrase,verbphrase,adjective,article,noun,verb,adverb}
。字母表中有一个特殊的元素称为初始符,记为S,我们通常都是从这个符号S开始的。在前面的例子中,初始符是sentence。那些决定我们什么时候可以替换
V ∗
中的符号串的规则称为语法的产生式。产生式记为
w 0 →w 1
,它表示
w 0
可以被
w 1
替换。
定义9.1.2.一个语法结构是一个四元组G=(V,T,S,P),其中V是字母表,T是V的一个子集,它的元素都是终止符,S是V的一个元素,它是初始符。P是产生式的集合。集合V−T记为N,N中的元素称为非终止符。P中的每一个产生式的左端至少有一个非终止符。
例9.1.1.设G=(V,T,S,P),其中V={a,b,A,B,S},T={a,b},S是初始符,P={S→ABa,A→BB,B→ab,AB→b},则G是一个语法结构。
我们对语法结构的产生式所产生的词感兴趣。
定义9.1.3.设G=(V,T,S,P)是一个语法结构。设w 0 =lz 0 r(符号l,z 0 亦即r的连接),w 1 =lz 1 r是V上的符号串,如果z 0 →z 1 是G的一个产生式,我们称w 1 是由w 0 直接演绎出来,记为w 0 ⇒w 1 。如果w 0 ,w 1 ,⋯,w n ,n≥0,是V上的字符串,其中w 0 ⇒w 1 ,w 1 ⇒w 2 ,⋯,w n−1 ⇒w n 。则称w n 是由w 0 演绎出来,记为w 0 ⇒∗w n 。从w 0 得到w n 的序列称为一个演绎。
例9.1.2.在例9.1.1.中字符串Aaba是由ABa直接演绎出来,因为B→ab是这个语言的一个产生式。符号串abababa是由ABa演绎出来的,因为连续使用产生式B→ab,A→BB,B→ab,B→ab而得到ABa⇒Aaba⇒BBaba⇒Bababa⇒abababa.
定义9.1.4.设G=(V,T,S,P)是一个语法结构,由G产生的语言(或者说G的语言)是由初始状态S演绎出来的所有终止符的集合,记为L(G)={w∈T ∗ |S⇒∗w}。
例9.1.3.设G是一个语法结构,字母表为V={S,A,a,b},终止符集合T={a,b},初始符号为S,产生式P={S→aA,S→b,A→aa},这个语法的语言L(G)是什么?
解:用产生是S→b可以演绎出b,用产生式A→aa从aA可以演绎出aaa,没有任何其它的词可以被演绎出来了,所以L(G)={b,aaa}。
例9.1.4.设G是一个语法结构,字母表为V={S,0,1},终止符集合T={0,1},初始符号为S,产生式P={S→11S,S→0},这个语法的语言L(G)式什么?
解:用产生式S→0可以从初始状态S演绎出0,用产生式S→11S可以演绎出11S,从11S可以演绎出110或者1111S,从1111S可以演绎出11110和111111S。在演绎的过程中,我们或者在S前加两个1,或者把S替换成0而结束演绎。所以L(G)={0,110,11110,1111110,⋯},这个集合中的符号串是以偶数个1开头,然后由一个0结束。
例9.1.5.给出一个语法结构,可以产生集合{0 n 1 n |n=0,1,2,⋯}。
解:这个集合中的符号串的特点是若干个0后跟同样多个1,其中包括空串。要想产生这个集合,我们需要用两个产生式,第一个是连续分别在符号前面和后面同时加0和1来得到更长的串,第二个是把S替换成空串。所以此语法是G=(V,T,S,P),其中,V={0,1,S},T={0,1},S是初始符,产生式为S→0S1;S→λ。这个例子的符号串是若干个0后跟若干个1,0的个数和1的个数相同,下面的例子也是考虑若干个0后跟若干个1,但0的个数与1的个数可以不同。
例9.1.6.给出一个语法结构,可以产生集合{0 m 1 n |m和n是非负整数}.
解:我们将给出两个产生这个集合的语法G 1 ,G 2 ,这说明两个不同的语法可以产生同一个语言。语法G 1 的字母表是V={S,0,1},终止符集合T={0,1},产生式为S→0S,S→S1,和S→λ。这个语法就能产生我们要求的集合,因为用第一个产生式m次就可以把m个0放在串的前面,用第二个产生式n次就可以把n个1放在串后面。语法G 2 的字母表是V={S,A,0,1},终止符集合T={0,1},产生式为S→0S,S→1A,S→1,A→1A,A→1和S→λ。这个语法也能产生我们要求的集合。
例9.1.7.产生集合{0 n 1 n 2 n |n=0,1,2,⋯}的语法是G=(V,T,S,P),其中V={0,1,2,S,A,B},T={0,1,2},初始状态是S,产生式是S→0SAB,S→λ, BA→AB,0A→01,1A→11,1B→12,2B→22。这个语法是能产生这个集合的最简单的语法。
9.1.2语法结构的类型
根据所使用的产生式可以对语法结构进行分类:0型语法对产生式没有任何限制;1型语法的产生式都形如w 1 →w 2 ,其中w 2 的长度大于 等于w 1 的长度或者w 1 →λ的形式;2型语法只有形如w 1 →w 2 这样的产生式,其中w 1 是单个的非终止符;3型语法只有形如w 1 →w 2 这样的产生式,其中w 1 =A并且w 2 =aB或者w 2 =a,其中A和B是非终止符号,a是终止符号,也可以是w 1 →λ的形式。
据此我们可以看出,任何一个3型语法都是一个2型语法,任意一个2型语法都是一个1型语法,任何一个1型语法都是一个0型语法。2型语法也称为上下文无关语法,因为任何一个非终止符出现时,都可以用它在左面的产生式替换它而不用考虑符号串中其它的字符。由2型语法产生的语言称为上下文无关语言。当有一个形如lw 1 r→lw 2 r这样的产生式时(而不是w 1 →w 2 )这个语法称为1型或者上下文有关语法,因为w 1 只有前后有l和r时,才能被w 2 替换。3型语法也称为正则语法,由正则语法产生的语言称为正则语言。
例9.1.8.例9.1.6中集合{0 m 1 n |m和n是非负整数}是一个正则语言,因为它可以由一个正则语法G 2 所产生。其中S→0S,S→1A,S→1,A→1A,A→1和S→λ。
例9.1.9.例9.1.5中集合{0 n 1 n |n=0,1,2,⋯}是一个上下文无关语法,因为这个语法的产生式为S→0S1和S→λ。在§9.4我们将说明它不是一个正则的语言。
例9.1.10.集合{0 n 1 n 2 n |n=0,1,2,⋯}是一个上下文有关语言,因为它是一个1型语言而不是2型语言。其中产生式是S→0SAB,S→λ,BA→AB,0A→01,1A→11,1B→12,2B→22.
表9.1.1 语法的类型
类型 | 对于产生式的限制 w 1 →w 2 |
---|---|
0 | 没有任何限制 |
1 | w 1 的长度小于等于 w 2 的长度,或者 w 2 =λ |
2 | w 1 =A,A 是非终止符。 |
3 | S→λ,或者w 1 =A并且w 2 =aB或者w 2 =a,其中A,B是非终止符。 |
9.1.3演绎树
一个由上下文无关的语法产生语言的演绎可以用一个有序的树来表示,称为演绎树。这个树的根代表初始符。树的分支结点代表演绎中出现的非终止符,树的叶节点代表演绎中出现的终止符。如果在演绎过程中使用了产生 A→w,w 是一个词,那么代表A的节点把代表 w 的每个符号的结点做为儿子结点,顺序是从左到右。
例9.1.11.给出的例子中关于the hungry rabbit eats quickly的演绎的演绎树。
判断一个符号串是否在一个由上下文无关语法产生的语言中,这是一个在应用中经常遇见的问题,如构造编译器等。在下面的例子中我们有两种解决办法。
例9.1.12.判断词caab是否属于由语法G=(V,T,S,P)产生的语言,其中V={a,b,c,A,B,C,S},T={a,b,c},S是初始符号,产生式为S→AB,A→Ca,B→Ba,B→Cb,B→b,C→cb,C→b
解:第一种方法是,从S开始,试图使用一系列的产生式来演绎出cbab.因为只有一个产生式的左端是S,所以必须从S⇒AB开始,接着使用唯一的一个左端是A的产生式,即A→Ca,得到S⇒AB⇒CaB,因为cbab以字符cb开头,所以我们要使用产生式C→cb。这样我们就得到S⇒AB⇒CaB⇒cbaB,最后使用产生式B→b,得到S⇒AB⇒CaB⇒cbaB⇒cbab。上面这种方法我们称为自顶向下分析,因为它是从初始符号开始通过不断使用产生式进行的。第二种方法称为自底向上的分析,在这种方法中,过程正好相反,因为cbab是要被演绎的符号串,我们可以用产生式C→cb,有Cab⇒cbab,然后我们使用产生式A→Ca,有Ab⇒Cab⇒cbab,使用产生式B→b,有AB⇒Ab⇒Cab⇒cbab,最后,使用S→AB得到了关于cbab的演绎:S⇒AB⇒Ab⇒Cab⇒cbab.
9.1.4Backus−Naurform
有另外一个概念有时用来描述2型语法,称为Backus−Naur form,它是由JohnBackus发明的,后来由PeterNaur改进用来描述程序语言ALGOL.Backus−Naur form用来描述很多计算机语言的规则,包括java。在2型语法的产生式中右边都有单个的一个非终止符。我们不把所有的产生式都分别列举出来,而是把左边有同样的非终止符的产生式结合成一个短语,在产生式中不再使用符号→,而是使用::=,把所有的非终止符放在括弧<>里,并且把产生式的所有右端都放在一个短语里,用一个竖线隔开。例如产生式A→Aa,A→a,和A→AB可以结合成
<A><A>a|a|<A><B>
。
例9.1.13.本节最前面的关于英语的一个子集的例子中的语法的Backus−Naur form是什么?
解:这个语法的Backups−Naur form是:
<sentence>
::=<noun phrase><verb phrase><noun phrase>
::=<article><adjective><noun>|<article><noun>
<verb phrase>::=<verb><adverb>|<verb>
<article>::=a | the
<adjective>::= large | hungry
<noun>::=rabbit | mathematician
<verb>::=eats | hops
<adverb>::=quickly | wildly
例9.1.14.给出十进制整数的产生式的Backus−Naur form.
解:Backus−Naur form如下:
<十进制整数>::=<符号><非负整数>
<符号>::=+|-
<非负整数>::=<数字>|<数字><非负整数>
<数字>::=0|1|2|3|4|5|6|7|8|9