上下文无关文法与语言

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

第 5 章上下文无关文法及语言

现在我们把注意力从正则语言转移到另外一大类语言上来,它们叫做“上下文无关语言”。这个语言类有着自然、递归的表示方法,这种表示方法叫做“上下文无关文法”。从1960年以来,上下文无关文法一直在编译技术中扮演着重要的角色。它们能够把分析器(一类用来在编译过程中发掘源程序结构的程序)的实现从一种费时的、不通用方式的设计工作转变成为一种能够很快完成的工作。近年来,上下文无关文法也被用来描述文档格式:XML(eXtensible Markup Language 可扩展标记语言)中使用的DTD(Document-Type Definition 文档类型定义)就是用来描述Web上的信息交换格式的。

在本章中,我们将首先介绍上下文无关文法的表示方法,然后将介绍怎样用文法来定义语言。我们将会讨论到“语法分析树”──对一个文法处在它所表示的语言的字符串中结构的图形描述。语法分析树是对一个编程语言的语法分析器的产物,也是通常用来获得程序结构的途径。

上下文无关语言还有另外一种等价的自动机表示叫做“下推自动机”。我们将在第6章介绍下推自动机。虽然它不如有穷自动机重要,但仍然要介绍它,原因是作为一种语言的定义机制来说,它跟上下文无关文法具有等价性,后面在第7章研究如何判定上下文无关语言以及研究上下文无关语言的封闭性时,这种等价性是非常有用的。

5.1 上下文无关文法

这一章的内容将从非形式化地介绍上下文无关文法的表示法开始。形式化的定义会在读者了解到这些文法的一些重要的能力之后给出。届时我们将会说明怎样形式地定义一个文法,并将介绍一种叫作“推导”的过程:它能够决定在一个文法的语言中到底有哪些串。

5.1.1一个非形式化的例子

下面来考虑一个“回文(palindrome)”的语言。“回文”是指正向和反向读起来都一样的串,比如otto或者madamimadam(“Madam, I’m Adam,”引自Eve在Eden的花园里听到的第一句话)。换句话说,串w是一个回文当且仅当w = w R。考虑简单些的情况——只需要描述字母表{0, 1}上的回文,这个语言包括像0110,11011这样的串,也包括空串ε,但不包括像011或0101这样的串。

很容易验证这个0,1上的回文语言L pal不是正则语言,要做到这点只需要使用泵引理即可:假设L pal是一个正则语言,令n是与其相关的常数,考虑回文串w = 0n10n,如果L pal 是正则的,那么我们就能够把w写为w = xyz,其中y由第一组0中的若干个(但至少一个)构成。接下来,如果L pal是正则的话那么xz也应该在L pal里。然而由于xz的两端的0的个数不同,进而可知它不可能是回文串,由此得出的矛盾可以推翻前面关于L pal是正则语言的假设。

对于什么样的0,1串在L pal里,有一个自然的、递归的定义,它从一个最基本的显然属于L pal中的串开始,接着利用一个最直观的思想:如果一个串在L pal里,那么它开头和结尾

的字母一定相同,进一步得出:当把它开头和结尾的字母都去掉以后,剩下的串一定也是回文。具体写出来就是:

基础:ε,0和1都是回文。

归纳:如果w是回文,那么0w0和1w1也都是回文。另外,除了由上面的基础和归纳定义出来的串之外就再没有回文了。

上下文无关文法就是一个形式化的表示法,它可用来表达这种递归形式定义的语言。一个文法是由一个以上用来代表字符串类(也就是语言)的变元构成的,在这个例子里,我们只需要使用一个变元P,它用来代表回文串的集合(也就是组成语言L pal的字符串类)。另外还有一些用来说明每个类中的串是怎样构造的规则,构造既可以使用字母表上的符号,也可以使用类中已经有的串,还可以两者都用。

图5.1:回文的上下文无关文法

例5.1:图5.1给出了用上下文无关文法定义回文的规则。这些规则的含义将在第5.1.2节中阐明。

前三条规则定义了基础,它们表示回文的字符串类中包括串ε,0和1。这三条规则的右端(箭头指向的那边)都没有变元,这也是说它们定义了基础的原因。

后两条规则是定义的归纳部分。比如,规则4是说如果串w在P这个类中的话,那么串0w0也在P这个类中。类似的,规则5告诉我们1w1也在P中。□

5.1.2上下文无关文法的定义

语言的文法性描述包括四个重要部分:

1.一个符号的有穷集合,它定义了语言的字符串中可能出现的符号。在上面回文

的例中该集合为{0, 1},这些符号叫做终结符号。

2.一个变元的有穷集合,变元有时也叫做非终结符或语法范畴。每个变元代表一

个语言,也就是说,一个字符串的集合。在上面的例中只有一个变元P并且它

就是用来代表以{0, 1}为字母表的回文串类(回文串的语言)的。

3.有一个变元叫做开始符号,它代表语言开始被定义的地方。其它变元用来代表

其它辅助的字符串类,这些变元是用来帮助开始符号定义该语言的。在上面的

例中,唯一的变元P同时也是开始符号。

4.一个产生式(或者也叫规则)的有穷集合,它用来表示语言的递归定义,每个

产生式包括:

(a)一个变元,它被该产生式定义或者部分定义,这个变元通常叫做产生式的

头。

(b)一个表示产生式的符号 。

(c)一个包含零个或多个终结符号或变元的串,它叫做产生式的体,它用来表示

一种构成产生式头变元所代表语言的方法。具体的构造过程是:保持终结符

号不动,把任何已知属于该语言的串里出现的产生式的头用产生式的体替

换。

图5.1是一个产生式的例子。

上面给出的四个部分构成了一个上下文无关文法(Context-Free Grammar),简称文法,或者CFG。一个CFG G可以用组成它的四部分表示,记做G = (V, T, P, S),其中V是变元(Variable)的集合,T是终结符号(Terminal)的集合,P是产生式(Production)的集合,S代表开始符号(Start Symbol)。

例5.2:回文的文法G pal可以表示为

G pal = ({P}, {0, 1}, A, P)

其中A表示图5.1中五个产生式的集合。

例5.3:这次来考虑一个复杂一些的CFG,它可简化地表示典型的编程语言中的表达式。首先,运算符限制为只有+和*,分别用来表示加法和乘法。其次,表达式中允许有标识符,但不是一般编程语言中的那种(字母开头,后面有零个或多个字母或数字),而是字母仅限为a和b、数字仅限为0和1。也就是说每个标识符必须由a或b打头,后面可以跟着任何{a, b, 0, 1}*中的串。

这个文法中需要两个变元。一个记做E,代表表达式(Expression),同时它也是开始符号,用来表示我们所要定义的语言。另一个变元记做I,代表标识符(Identifier),它所代表的语言其实是正则的,也就是下面的正则表达式所表示的语言:

(a + b)(a + b + 0 + 1)*

然而,在文法中不应该出现正则表达式。不过我们可以用一系列的产生式来表示和这个正则表达式所表示的实质上一样的东西。

图5.2:简单表达式的上下文无关文法

这个描述表达式的文法可以形式化的记为G = ({E, I}, T, P, E),其中T是终结符号的集合{+, *, (, ), a, b, 0, 1},P是图5.2中产生式的集合,下面是这些产生式的解释

规则(1)定义了表达式类的基础部分,说的是一个表达式可以是一个标识符。规则(2)到(4)给出了表达式类定义的归纳部分:规则(2)说一个表达式可以由两个表达式中间用加号连接组成;规则(3)和(2)类似,不过把加号换成了乘号;规则(4)则说任何由一对括号括起来的一个表达式本身也是表达式。

相关文档
最新文档