《编译与反编译技术》—第3章3.1语 法 分 析

第3章 语 法 分 析
本章阐述编译器常用的语法分析方法,首先介绍描述语法结构的上下文无关文法的相关概念,然后介绍自上而下的语法分析方法,接下来介绍自下而上的语法分析方法,最后介绍语法分析器的自动生成工具YACC
软件。
3.1 上下文无关文法
要进行语法分析,必须对语言的语法结构进行描述。采用正规文法可以描述和识别语言的单词符号,而采用上下文无关文法则可以用来描述语法规则。
3.1.1 上下文无关文法的定义
在第2章用正规文法定义了一些简单的语言,比如C语言标识符组成的语言和无符号整数组成的语言,但是有很多相对复杂的语言是不能用正规文法来定义的,比如,由配对括号构成的串所组成的集合就不能用正规文法来描述。为了定义比正规文法描述能力更强的文法,这里介绍上下文无关文法。
定义3.1 (上下文无关文法) 一个上下文无关文法是一个四元式G=(VT,VN,P,S),其中:
1)VT为终结符组成的非空有限集。
2)VN为非终结符组成的非空有限集,VN和VT不含公共的元素,即VN ∩ VT = ?。
3)P为产生式组成的集合,每个产生式形如A→α,A∈VN,α∈ (VT ?∪? VN)*。
4)S称为文法的开始符号,它是一个非终结符,至少要在一条产生式中作为左部出现。
之所以称之为上下文无关文法,是因为其所定义的语法范畴(语法单元)是完全独立于这种范畴可能出现的环境的。由正规文法和上下文无关文法的定义可知,正规文法是一类特殊的上下文无关文法。以后如果不做特殊说明,我们所指的文法就是上下文无关文法。
例3.1 只含+、的简单算术表达式的文法可定义为G= ({i,+,,(,)},{E},E,P),其中,P由下列产生式组成:
E→i
E→E+E
E→E*E
E→(E)
同样可以只用开始符号和产生式来表示上下文无关文法,因此该文法还可表示为:
G(E):E→i | E+E | E*E | (E)(3.1)
3.1.2 语法树和推导
为了描述文法所定义的语言,需要使用推导的概念,所谓的推导就是把产生式看成重写规则,把符号串中的非终结符用其产生式右部的串来代替,其定义如下。
定义3.2 (直接推导和推导) 称αAβ直接推出αγβ当且仅当A→γ是一个产生式,且α、β∈(VT?∪?VN)* ,记作αAβ?αγβ。如果α1?α2?…?αn,则称这个序列是从α1到αn的一个推导。若存在一个从α1到αn的推导,则称α1可以推导出αn。
通常,用α1?+αn表示从α1出发,经过一步或若干步,可以推出αn。用α1?αn表示:从α1出发,经过0步或若干步,可以推出αn。所以,α?β即α=β或α?+β。
定义3.3 (文法的句型、句子、语言和上下文无关语言) 假定G是一个文法,S是它的开始符号。如果S?*α,则称α是该文法的一个句型。仅含终结符号的句型称为句子。文法G所产生的句子的全体是一个语言,将它记为L(G)。上下文无关文法所产生的语言称为上下文无关语言。
在以后的使用中,将对上下文无关文法G=(VT,VN,P,S)做如下限制:
1)不能含有形为A→A的产生式。它对描述语言显然是没有必要的,其只会引起文法的二义性。
2)每个非终结符A必须有用处,也即必须满足如下两个条件:
① A必须在某句型中出现。即有S?αAβ,其中α、β属于(VT?∪?VN)
② 必须能够从A推出终结符号串w来。即A?w,其中w∈VT
例3.2 证明(i*i+i)是式(3.1)文法的一个句子。
证明: 因为E ? (E) ? (E+E)? (EE+E) ? (iE+E)? (ii+E) ? (ii+i)
是从E到(ii+i)的一个推导。并且(ii+i)是只有终结符组成的字符串。所以,(i*i+i)是文法G(E)的一个句子。
例3.3 对于文法G(S),它有如下产生式:
S→(S) S | ε
试证明该文法所产生的语言L(G) ={配对的括号串}
证明:首先按推导步数进行归纳证明S所产生的每个句子都是配对的括号串。
归纳基础:S ? ε。S经过一步推导能推导出来的终结符串只有空串,它是配对的。
归纳假设:少于n步的推导都产生配对的括号串。
归纳步骤:n步的一个推导如下。
S ? (S)S ? (x) S ? (x) y
因为从S到x和y的推导都少于n步,所以由归纳假设,可得x和y都是配对的括号串,从而(x) y也是配对的括号串。
然后按串长进行归纳证明任何配对的括号串都可由S产生。
归纳基础:由S ? ε可知,空串可以从S推导出。
归纳假设:长度小于2n的配对括号串都可以从S推导出来。
归纳步骤:考虑长度为2n(n≥1)的括号串w = (x) y,其中x和y都是配对括号串,其长度都小于2n。由归纳假设可知,它们都可以从S推导出来,所以有如下推导
S ? (S)S ? (x) S ? (x) y
从而w = (x) y也可以从S推导出。
例3.4 对于文法G(S),它有两个产生式:
S→aSb
S→ab
试证明该文法所产生的语言L(G)={anbn∣n≥1}。
证明:考虑从S开始进行推导,若先用G中第二个产生式,则S?ab,就不能再往下推导了,此时相当于语言中n=1的情况。
若从S出发,先用n-1次第一个产生式,即S ? aSb ? aaSbb ? … ? an-1S bn-1,最后再使用第二个产生式一次,得到S ?*anbn,其中n>1。
再加上n=1的情况,即可得到L(G)={an bn∣n≥1}。
例3.5 构造一个文法,使其能产生语言L={wwR∣w∈{a,b}+ },其中wR是w的逆转。
解:wwR是由偶数个a、b组成且由中心开始左右对称的串,处于wwR中间的两个符号一定是同样的,不是aa就是bb,我们先用产生式来产生它们,然后再向左右两边扩充。由于要保持对称性,因此扩充的左右两边符号一定要相同(a或者b)。基于以上考虑,可以写出下面一组产生式。
1)S→aa
2)S→bb
3)S→aSa
4)S→bSb
下面证明由上面4个产生式组成的文法能够产生语言L。
如果要产生长度为2的句子,只用前两个产生式就行了。如果要产生所有长度为4的句子,则用后两个式子各一次,然后中间的S用前两个式子分别代入即可。也就是用以下的
推导:
S ? aSa ? aaaa,S ? aSa ? abba,
S ? bSb ? baab,S ? bsb ? bbbb。
一般地,设S已能推导出一切长度为2m(m≥2)的串,我们就可以从S推导出一切长度为2(m+1)的串。办法是用后两个产生式中的一个,在原来长度为2m的串上,左右两边都加上a(或b),就可以得到长度为2(m+1)的串。
例3.6 构造能产生全部十进制整数(每个整数前可有若干个0)的文法。
解:首先要有产生式能产生单个的十进制数字,然后再用递归的方法产生任意多位的十进制数。于是我们有文法G1(N)。
D→0∣1∣2∣3∣4∣5∣6∣7∣8∣9
N→D∣DN
还可以有如下的另一个文法G2(N):
N→0∣1∣2∣3∣4∣5∣6∣7∣8∣9
N→0N∣1N∣2N∣3N∣4N∣5N∣6N∣7N∣8N∣9N
G2(N)同样能产生全部十进制整数。可以看出,G2相当于在G1中将第一组产生式中D的各右部“代入”第二组产生式中而获得,它比G1少了一个变元D,但是产生式的个数由原来的12个扩充为20个。
定义3.4(文法的等价性) 对于两个不同的文法G1=(VT1,VN1,P1,S1),G2=(VT2,VN2,P2,S2),如果L(G1)=L(G2),则称文法G1与G2等价。
同一个语言可以由不同的文法产生。在例3.6中已经看到,一个很简单的十进制整数(每个整数前可有若干个0)所组成的语言就可由两个不同的文法产生。文法是用四元组定义的,在两个四元组的各对应部分中,只要有一点点的不同就应当看作不同的文法。如在一个已有的文法上随意加上一些变元、一些终结符,或一些不影响S推导结果的产生式等,都会变成新的文法。在这个意义下,任何一个语言都可以有无穷多个文法产生它。
从一个句型到另一个句型的推导往往不唯一。例如,对于式(3.1)文法,关于i+i就存在如下两个不同的推导:
E?E+E?i+E?i+i E?E+E?E+i?i+i
为了对句子结构进行确定性分析,我们往往只考虑最左推导或最右推导。
定义3.5(最左推导和最右推导) 所谓的最左推导是指任何一步α ? β都是对α中的最左非终结符进行替换。所谓的最右推导是指任何一步α ? β都是对α中的最右非终结符进行替换。最右推导又称为规范推导,由规范推导所得到的句型称为规范句型。
例3.7 式(3.1)文法关于i*i+i的最左推导为
E ?E+E?E*E+E
?iE+E?ii+E?i*i+i
最右推导为
E ?E+E?E+i
?EE+i?Ei+i?i*i+i
可以使用图形来表示推导,这种表示称为语法分析树,或简称语法树,其能更清楚、直观地表示句型或者句子的语法结构。
定义3.6(语法分析树) 给定上下文无关文法G=(VT,VN,P,S),满足下列要求的一棵树称为关于G的语法分析树:
1)树的每个结点带有一个标记,它是VT?∪?VN?∪?{ε}中的一个符号。
2)根结点的标记是S。
3)树的内部结点(非叶结点)只能以VN中的符号作为标记。
4)如果结点n带有标记A,结点n1,n2,…,nk 是结点n从左到右的儿子结点,并分别带有标记X1,X2,…,Xk、则A→X1X2…Xk必须是P中的一个产生式。
5)如果结点带有标记ε,则该结点是它父结点的唯一的儿子结点。
可以采用如下方法为文法的某一个句型构造语法分析树:
1)开始符号作为根结点。
2)如果非终结符被它的某个候选式所代替,则产生下一代新结点,并且候选式中自左向右每一个符号对应一个新结点,并用这些符号标记相应的新结点。
3)每个新结点与其父结点之间都有一条连线。
例3.8 式(3.1)文法关于句子i*i+i的语法分析树的生成过程如图3-1所示。

定义3.7(短语、直接短语和句柄) 对于一个给定的文法G(S),假定αβδ是它的一个句型,如果有
S?*αAδ且A?+β
则称β是句型αβδ相对于非终结符A的短语。特别是,如果有
A?β
则称β是句型αβδ相对于产生式A→β的直接短语。一个句型的最左直接短语称为该句型的句柄。
直观理解:短语就是某句型中的一个子串,这个子串是由某个非终结符通过至少一步推导得到,而直接短语是由某个非终结符通过一步推导得到的子串。基于上述理解,在一个句型对应的语法树中,以某非终结符为根的两代和两代以上的子树的所有末端结点从左到右排列所得到的子串,就是相对于该非终结符的一个短语;如果子树只有两代,则该短语就是直接短语。
例3.9 考虑文法G(E):
(1)E→E+T
(2)E→T
(3)T→T*F
(4)T→F
(5)F→(E)
(6)F→i(3.2)
和句型i1*i2+i3。因为
E ? E+T ? E+F ? E+i3 ? T+i3
? TF+i3 ? Ti2+i3 ? F*i2+i3
? i1*i2+i3
所以i1、i2、i3、i1i2和i1i2+i3是句型i1*i2+i3的所有短语,并且i1、i2和i3是直接短语,i1是句柄。
3.1.3 二义性
一棵语法分析树表示了一个句型的多种可能推导,包括最左推导和最右推导,如果坚持使用最左(最右)推导,那么,一棵语法分析树就完全等价于一个最左(最右)推导,这种等价包括树的步步成长和推导的步步展开之间的完全一致性。但是并不是每一个句型只对应一棵语法分析树,也就是说并不是每一个句型只有一个最左推导或者最右推导。
定义3.8 (文法的二义性) 如果一个文法存在某个句子对应两棵不同的语法分析树,也即两个不同的最左(右)推导,则称这个文法是二义的。
例3.10 证明式(3.1)文法是二义文法。
证明:在例3.2中已经证明(ii+i)是式(3.1)文法的一个句子。又因为式(3.1)文法关于(ii+i)存在如下两个不同的最左推导。
E?(E)?(E+E)?(EE+E)?(iE+E)?(ii+E)?(ii+i)
E?(E)?(EE)?(iE)?(iE+E)?(ii+E)?(i*i+i)
所以式(3.1)文法是二义文法。
一个文法是二义性的,并不能说明该文法所描述的语言也是二义性的。也即,对于一个二义性文法G(S),如果能找到一个非二义性文法G'(S),使得L(G')=L(G),则该二义性文法的二义性是可以消除的。如果找不到这样的G'(S),则该二义性文法所描述的语言为先天二义性。
定义3.9(语言二义性) 一个语言是二义性的,如果不存在产生该语言的无二义性文法。
例3.11 {aibicj | i, j≥1}?∪?{aibjcj | i, j≥1}就是一个二义性语言,对于n≥1,anbncn都是二义性句子。
已经证明二义性问题是不可判定问题,即不存在一个算法,它能在有限步骤内,确切地判定一个文法是否是二义的,但通常可以找到一组充分条件能够将一个二义文法等价地转化为无二义文法。
例3.12 消除式(3.1)文法的二义性。
解:造成式(3.1)文法二义性的原因是该文法中没有体现出运算符的结合律和优先级。要想体现做了乘、除运算之后才能做加、减运算,就必须将乘、除运算表示成另一种较高层次的语法单元,只有这个成分才有资格参加加、减运算。为此引入下面相关概念。
1)因子:因子是运算的最基本单位,通常包含常数、标识符、加括号的表达式等,用F表示。
2)项:一个因子是一个项,一个项乘以一个因子也是一个项,用T表示。
3)表达式:一个项是一个表达式,一个表达式加上一个项也是一个表达式,用E表示。
将上述内容用产生式的形式表示出来,就得到如式(3.2)文法所示的无二义文法。对于式(3.2)文法的句子(i*i+i),则有如下唯一的最左推导:
E ?T?F?(E)
?(E+T)?(T+T)
?(TF+T)?(FF+T)
?(iF+T)?(ii+T)
?(ii+F)?(ii+i)
例3.13 已知有如下文法G(stmt):
stmt→ if expr then stmt
| if expr then stmt else stmt
| other(3.3)
这里的other代表任何其他的语句。因为存在句子if expr then if expr then stmt else stmt 有两个不同的最左推导:
stmt ? if expr then stmt
? if expr then if expr then stmt else stmt
stmt ? if expr then stmt else stmt
? if expr then if expr then stmt else stmt
所以这是一个二义性文法。为了避免二义性,在所有允许这两种形式条件语句的程序设计语言中,都规定“else 必须匹配离它最近的那个未匹配的then”。根据这个原则,出现在then和else之间的语句必须是配对的,而所谓的配对语句是指那些不是条件语句的语句,还有那些只含配对语句的if-then-else语句。基于此,式(3.3)文法可改写为如下无二义文法:
stmt→matched_stmt | unmatched_stmt
matched_stmt→ if expr then matched_stmt else matched_stmt
| other
unmatched_stmt→ if expr then matched_stmt else unmatched_stmt
| if expr then stmt

时间: 2024-11-05 21:34:14

《编译与反编译技术》—第3章3.1语 法 分 析的相关文章

《编译与反编译技术》—第2章2.1节词法分析器的需求分析

本节书摘来自华章出版社<编译与反编译技术>一书中的第2章,第2.1节词法分析器的需求分析,作者庞建民,陶红伟,刘晓楠,岳峰,更多章节内容可以访问"华章计算机"公众号查看. 第2章 词法分析的理论与实践 词法分析是编译过程的第一步,也是编译过程必不可少的步骤.编译过程中执行词法分析的程序称为词法分析器.本章主要介绍词法分析器的手动构造和自动构造的原理. 2.1 词法分析器的需求分析 本节首先介绍词法分析器的功能及其输出的单词符号的表示方式,然后研究将词法分析独立出来的原因.

《编译与反编译技术》—第1章1.5节高级语言及其分类

本节书摘来自华章出版社<编译与反编译技术>一书中的第1章,第1.5节高级语言及其分类,作者庞建民,陶红伟,刘晓楠,岳峰,更多章节内容可以访问"华章计算机"公众号查看. 1.5 高级语言及其分类 根据应用类型的不同,涌现了多种多样的面向人类的高级语言,其中典型的有如下几类形式. 1.过程式语言 过程式语言也称为强制式语言(Imperative Language).这类语言的特点是面向语句,命令驱动.一个用过程式语言编写的程序由一系列语句组成,语句的执行会引起若干存储单元中的值

《编译与反编译技术》—第1章1.8节UNIX/Linux环境中的make和makefile

本节书摘来自华章出版社<编译与反编译技术>一书中的第1章,第1.8节UNIX/Linux环境中的make和makefile ,作者庞建民,陶红伟,刘晓楠,岳峰,更多章节内容可以访问"华章计算机"公众号查看. 1.8 UNIX/Linux环境中的make和makefile 在UNIX或Linux环境中,make是一个非常重要和经常使用的编译工具.无论是自己进行项目开发还是安装应用软件,都会经常用到make或make install.使用make工具,可以将大型的开发项目分解成

《编译与反编译技术》—第2章2.2词法分析器的设计

本节书摘来自华章出版社<编译与反编译技术>一书中的第2章,第2.2节词法分析器的设计,作者庞建民,陶红伟,刘晓楠,岳峰,更多章节内容可以访问"华章计算机"公众号查看. 2.2 词法分析器的设计 下面将词法分析器作为一个独立的子程序来考虑其设计.本节主要探讨实现词法分析器的关键技术和词法分析器的手工实现. 2.2.1 输入及其处理 词法分析器的结构如图2-3所示.词法分析器首先将源程序文本输入一个缓冲区中,该缓冲区称为输入缓冲区,单词符号的识别可以直接在输入缓冲区中进行.但在

《编译与反编译技术实战》——第1章 实践的环境与工具 1.1 实践环境概述

第1章 实践的环境与工具 本书致力于通过实践及案例,从正反向两个角度介绍编译系统的一般构造原理和基本实现技术,本章首先对书中内容涉及的环境与工具进行简单介绍,这些工具都是编译与反编译过程中常用的工具. 1.1 实践环境概述 在编译过程中所涉及的环境主要是编译环境及工具链,常用的工具有词法分析生成器.语法分析生成器.编译器.汇编器.链接器等.在反编译过程中主要涉及反汇编器.静态或动态的调试与分析工具.下面对近年来流行的编译与反编译工具逐一进行简单介绍.

《编译与反编译技术实战 》一 第1章 实践的环境与工具

第1章 实践的环境与工具 本书致力于通过实践及案例,从正反向两个角度介绍编译系统的一般构造原理和基本实现技术,本章首先对书中内容涉及的环境与工具进行简单介绍,这些工具都是编译与反编译过程中常用的工具. 1.1 实践环境概述 在编译过程中所涉及的环境主要是编译环境及工具链,常用的工具有词法分析生成器.语法分析生成器.编译器.汇编器.链接器等.在反编译过程中主要涉及反汇编器.静态或动态的调试与分析工具.下面对近年来流行的编译与反编译工具逐一进行简单介绍.

《编译与反编译技术》—第2章2.3节有穷自动机

本节书摘来自华章出版社<编译与反编译技术>一书中的第2章,第2.3节有穷自动机,作者庞建民,陶红伟,刘晓楠,岳峰,更多章节内容可以访问"华章计算机"公众号查看. 2.3 有穷自动机 前面在介绍词法分析程序的手工实现时引入了状态转换图,为了讨论词法分析器的自动生成,需要将上述状态图的概念形式化,即引入有穷自动机.有穷自动机分为确定的有穷自动机和非确定的有穷自动机. 2.3.1 确定的有穷自动机 定义2.9(确定的有穷自动机(Deterministic Finite Autom

《编译与反编译技术实战》——第1章实践的环境与工具

第1章实践的环境与工具本书致力于通过实践及案例,从正反向两个角度介绍编译系统的一般构造原理和基本实现技术,本章首先对书中内容涉及的环境与工具进行简单介绍,这些工具都是编译与反编译过程中常用的工具.

《编译与反编译技术》—第1章1.7节C语言程序的编译流程

本节书摘来自华章出版社<编译与反编译技术>一书中的第1章,第1.7节C语言程序的编译流程,作者庞建民,陶红伟,刘晓楠,岳峰,更多章节内容可以访问"华章计算机"公众号查看. 1.7 C语言程序的编译流程 本节以C语言程序的编译流程为例,介绍实际的C语言编译器是如何运作的.通常把整个代码的编译流程分为编译过程和链接过程. 1.编译过程 编译过程可分为编译预处理.编译与优化.汇编等阶段. (1)编译预处理 编译预处理即读取C源程序,对其中的伪指令(以#开头的指令)和特殊符号进行处