1、编译原理大作业论文学号:1083710614姓名:杨文华哈尔滨工业大学软件学院2010 年 12 月摘要- I -摘要语法分析是编译程序的核心部分,其任务是检查词法分析器输出的单词序列是否构成源语言中的句子,亦即是否符合源语言的语法规则。本文从自上而下和自下而上两种角度论述了几种语法分析方法的优劣和各自试用的文法。关键词 编译;语法分析;文法;Abstract- II -AbstractSyntax analysis is the core of the compiler, the task is to check the output of the lexerconstitute the s
2、ource language word sequence in the sentence, that is, whether the source language syntax rules. From the top down and bottom-up perspective of bothanalysis methods are discussed the advantages and disadvantages of several syntaxand grammar of their trial.Keywords Compile , grammatical analysis, gra
3、mmar第一章 综述- I -目录摘要 .IAbstract II第 1 章 综述 11.1 语法分析概述 .11.2 分析方法 .1第 2 章 四种文法的比较 22.1 LL(1).22.2 SLR(1) 32.3 LR(1).42.4 LALR(1) .42.5 小结 .5参考文献 6第 1 章 综述- 1 -第 1 章 综述1.1 语法分析概述语法分析的任务是检查词法分析器输出的单词序列是否构成源语言中的句子,亦即是否符合源语言的语法规则。1.2 分析方法进行语法分析主要有两种:自顶向下的分析方法和自底向上的分析方法。本文讨论基于以上两种分析方式的五种文法:LL(1),LR(1),SLR
4、(1),LALR(1)以及算符优先文法。这五种文法各有其特点与适用范围,很难确切的说孰优孰劣。第 2 章 五种文法的比较- 2 -第 2 章 五种文法的比较2.1 LL(1)文法2.1.1 概述LL(1)语法分析属于自顶向下的语法分析。所谓自顶向下的语法分析,就是对给定的输入单词序列 w,试图自顶向下的为其建立一棵语法分析树。或者说从文法德开始符号出发,试图寻找 w 的一种最左推导。这种分析过程实质上是一种试探过程,而且对文法的限制比较多,可能会导致分析效率极低甚至失败。具体的有预测分析法和递归下降分析法。2.1.2 对文法的限制但是无论哪种方法,在分析过程中都可能会遇到一些共同的问题:1 二
5、义性问题;2 回溯问题;3 左递归引起的无穷推导问题。所以说,自顶向下的语法分析方法并不能处理所有的文法,有时为了适应所选择的分析方法,常常需要对原始文法进行改造,包括如下 3 步:1 消除二义性。这一步只能是人工手动的修改文法。2 消除左递归。这一步可以由程序来处理。假设有 n 个语法变量,那么这一步的时间复杂度是 O( ) 。23 提取左公因子。这一步也主要有人工手动处理。经过这三步处理后的文法,便可以使用预测分析法或者递归下降分析法来进行语法分析了。2.1.3 处理过程在接下来的处理中,两种方法都需要进行三步预处理,即:1 求出单个文法符号 X 和文法符号串 的 FIRST 集;2 求
6、FOLLOW 集;3 求 LL(1)分析表。第 2 章 五种文法的比较- 3 -对于求单个文法符号 X 的时间复杂度,假设文法符号的个数为 n,非终结符个数为 m,由于循环的次数与嵌套的层数和计算的顺序有极大的关联,最坏情况要循环 O(n)次,为方便计算,再根据实际情况假设每个产生式右部的文法符号个数为 10,所以,求单个文法符号 X 的时间复杂度为 O(10*n*m)= O(mn),而对于符号串 ,假设它包含 k 个符号,则计算它的时间复杂度为O(mnk) ,求出了 FIRST 集采能求 FOLLOW 集,易知求 FOLLOW 集的时间复杂度也为 O(mn) 。接下来,还需要求出 LL(1)
7、分析表,分析表是一个二维数组 MA,a,A 是语法变量,a 是输入符号或#。也可以在 O(mn)的时间内求出,两种方法其实都用到了预测 LL(1)分析表,只不过使用的方法不太一样。2.1.4 预测分析法对于预测分析法,它采用表驱动的方式来实现,它具有一个输入缓冲区、一个分析栈、一张 LL(1)分析表和一个输出流。输入缓冲区中包含待分析的串和结束符#。分析栈用来存放文法符号序列,栈底符号是#。初始时,栈中只有文法开始符号及其下的#。整个分析过程在于从文法开始符号开始,试图构造输入缓冲区中待分析串的最左推导。假设某程序共有符号 s 个,整个控制程序的时间复杂度为 O(s) 。2.1.5 递归下降分
8、析法而对于递归下降分析法,是指根据各个候选式的结构,为文法的每个语法变量编写一个处理子程序,用来识别该语法变量所代表的语法成分。设有产生式 AX1X2X3XkXn,则与 A 对应的处理子程序遇到的 Xk 是终结符时直接进行匹配,而遇到 Xk 是语法变量时就调用与 Xk 对应的处理子程序。由于产生式中的语法变量可能是递归定义的,所以这种实现方法要求处理子程序可以递归调用。另外,这种分析方法也是寻求输入串的一个推导过程,所以称为递归下降分析法。实际上,上面所说的预测分析法是一种特殊的递归下降分析法,它是通过显示地维护一个状态栈而不是通过隐式的递归来实现的。如果编译程序的实现语言允许进行过程的递归调
9、用,则可以采用一般形式的递归下降分析法。这种方法的主要优点是易于实现。此外,由于分析器和文法的紧密对应性,这种方法还易于保证语法分析器的正确性。其缺点是频繁的递归调用会降低分析器的效率,而且与预测分析法相比,这种分析器的代码规模非常大。尽管如此,第 2 章 五种文法的比较- 4 -递归子程序法仍然是一种有效的语法分析方法,因为在实际应用中,递归的层次往往不会太深,许多高级程序设计语言的编译系统都采用这种分析方法。2.1.6 综述总之,自顶向下分析法只能处理上下文无关文法的一些子类,对于文法的限制也比较多,而且其中许多部分必须人工手动完成,比较难以实现自动化,与之相反的是自底向上的 LR 分析法
10、,基于 LR 分析法的良好形式和理论基础,人们可以寻求这种方法的进一步自动化,于是就有了 Yacc 之类的语法分析程序自动生成工具。2.2 SLR(1)文法SLR(1)语法分析属于自底向上的语法分析。自底向上的语法分析的思想就是从输入串出发,反复利用产生式进行归约,如果最后能得到文法的开始符号,则输入串是句子,否则输入串有语法错误。核心是寻找句型中的当前归约对象“句柄”进行归约,用不同的方法寻找句柄,就可获得不同的分析方法。和自顶向下文法类似,每种自底向上文法也是有局限性的。比如 LR(0)文法。上下文无关文法不是都能用 LR(0)方法进行分析的,也就是说,CFG 不总是 LR(0)文法。当文
11、法分析过程中会出现归约 归约冲突和移进- 规约冲突时,此文法就不是 LR(0)文法。下面写一下对几种自底向上文法的比较。LR(1)总体来说,就是从左到右扫描输入符号。最右推导对应的最左归约,超前读入 1 个符号,以便确定归约用的产生式。为解决 LR(0)中的冲突,SLR 分析法引入了每个符号的 FOLLOW 集,SLR(1)分析方法描述能力强于 LL(1) ,SLR(1)还考虑 FOLLOW 集中的符号,LL(1) 仅考虑产生式的首符号。SLR(1) 文法是在 LR(0)分析表的基础上增加了 FOLLOW 集,可以解决一部分冲突,但是,SLR 文法依然有解决不了的问题。SLR(1)只孤立地考察
12、输入符号是否属于归约项目 A.相关联的集合 FOLLOW(A ) ,而没有考察符号串 所在规范句型的“上下文” 。即未考虑规约的有效性,即只考虑了FOLLOW 集是否符合规约条件,而没有考虑输入串中后面的字符。第 2 章 五种文法的比较- 5 -2.3 LR(1)文法LR(1)语法分析属于自底向上的语法分析。LR(1) 文法可以说比 SLR 又强大了一些。因为 LR(1)在构造状态时就考虑 follow 集,而不是在规约时考虑。与 LR(0)文法类似,识别文法全部活前缀的 DFA 的每一状态也是用一个LR(1)项目集来表示,为保证分析时,每一步都在栈中得到规范句型的活前缀,应使每一个 LR(1
13、)项目集仅由若干个对相应活前缀有效的项目组成。但是文法的强大也会带来一些代价,LR(1)分析表相比起 LR(0)和SLR(1)庞大许多,相对来说也会有比较大的运行开销。2.4 LALR(1) 文法LALR(1)语法分析属于自底向上的语法分析。 LALR(1)是对 LR(1)状态的简化,不同的 LR(1)项目闭包可能有相同的 LR(0)项目,但后继符可能不同,我们称这种情况为两个闭包同心,将两个同心闭包合并,即是LALR( 1)文法。它的显著好处就是减少了状态的数量,缩减了分析表,但是合并后可能带来归约归约冲突。合并那些不会带来冲突的同心的 LR(1)闭包/状态,可以得到 LALR(1)分析表,
14、反之,如果合并会出现规约 -规约冲突,那么不能使用 LALR(1)分析法,换句话说,存在合并后规约规约冲突的文法不是 LALR(1)文法。分析能力 LALR(1)强于 SLR(1) ,因为合并后的后继符仍然是 FOLLOW 集的子集,弱于 LR(1) ,因为有上述局限性。2.5 算符优先文法2.5.1 概述算符优先分析法是一种简单适用的方法,用这种方法分析程序设计语言中的各类表达式尤为有效。由于这种方法简单直观,它还特别适用于手工方式来实现。所谓算符优先分析就是将句型中的终结符当做算符,然后定义算符之间的某种优先关系,利用这种优先关系来寻找句柄并进行规约,也是一种自下而上的分析方法。第 2 章
15、 五种文法的比较- 6 -2.5.2 过程首先要构造 FIRSTOP 集合和 LASTOP 集合,构造过程中分别使用了一个|V|*|T|大小的二维布尔数组来表示某个终结符 b 是否在 B 的 FIRSTOP 集合或LASTOP 集合中,又使用了一个栈来帮助计算其他非终结符的这两个集合。算法的时间复杂度主要主产生式的个数有关,设产生式个数为 p,则该算法时间复杂度为 O()第 3 章 小结- 7 -第 3 章 小结 综上,各种分析文法其实无所谓孰优孰劣,就看适用在那些场合,就分析能力来说,LR(1)LALR(1) SLR(1)LL(1)LR(0),但是相对来说就可能带来更大的实现复杂度和开销。我们在决定使用哪种分析方法时,主要是看定义的文法,一般的文法只要稍加修改,SLR(1)和 LALR(1)的要求是很容易满足的,可以适用于大部分分析程序,比如 yacc 语法分析器内部就是使用SLR(1)分析法。参考文献- 8 -参考文献1蒋宗礼,姜守旭, 编译原理北京:高等教育出版社, 2010.2.2张伟, 编译原理学习辅导北京:清华大学出版社, 2005.2.3(美) 阿霍 等著,赵建华 等译.编译原理(第二版)机械工业出版社,2009.1