2007年1月23日、编译原理第五课

    由于昨天写的博客可能没有保存,所以对第四课的学习日志暂时先空着,进行第二边学习的时候再详细记载。
    昨天在看完书之后看了看网上的消息,说国内翻译的编译原理著作基本上都是简单的翻译了龙书、虎书和鲸书的内容,我在google上查了下载了一本虎书,不过是java版本的不是希望下的c语言版本的,不过原理性的东西应该不会有太大的差距,所以打算将编译原理及实践看完之后把虎书好好细读一遍。

     今天学习编译原理的第五课----自底向上分析,首先自底向上分析程序使用了显式栈来完成,这与非递归的自顶向下分析程序类似。

    自底向上分析的分析栈包括记号和非终结符,它包括了两种可能的动作:
    1,将终结符从输入的开头移进到栈的顶部
    2,假设有BNF的选择A-->a,将栈顶部的串a归约为非终结符A。
   有一特征是:出于后面要讲的技术原因,总是将文法与一个新的开始符号一同扩充。就是意味着若S是开始符号,那么将新的开始符号S’增加到文法中,同时还添加一个单元产生式到前面的开始符号中:S’-->S,其实自底向上的分析程序可将输入符号移进到栈里直到它判断出要执行的是何种动作为止。同样的情景如E在堆栈中,而在某时候使用文法一,却在另一时候使用E’-->E归约,所以任何执行分析的酸法必须使用下一个输入记号(先行)来判断出适当的动作,如下一记号是+。则移进,而下一记号是空时候,则使用E’-->E归约,判断分析中的下一个句柄是移进-归约分析程序的主要任务,如在右句子格式n+n中,它的句柄是由最左边的单个记号n与用来归约它以产生新的右句型E+n的产生式E-->n组成的串。句柄串总是为它的产生式构成一个完整的右部,而且当归约发生时,句柄串最右边的位置将与栈的顶部相对应。

    LR(0)项
    上下文无关文法的LR(0)项是在其右边带有区分位置的产生式选择。用一个句点来指出这个区分的位置。也就是说,如果A-->abc,那么A-->.abc   A-->a.bc  A-->ab.c  A-->abc.分别是LR(0)项。项目概念的思想就是指项目记录了特定文法规则右边识别中的中间步。也就是说在识别文法右边规则的每一步就针对着一个项。项目A-->.a意味着将要利用文法规则选择A-->a来识别A ,项目A-->a.意味着a现在已经位于分析栈的顶部,而且若A-->a在下一个归约中使用的话,它有可能是句柄(称完整项)
    LR(0)项可作为一个保持有关分析栈和移进-归约分析过程的信息的有穷自动机的状态来使用。这将从作为非确定性的有穷自动机开始。第二课的内容知道该项的NFA可利用子集构造来构建出项集合的DFA,LR(0)项的NFA转换是什么呢?下面详细说明一下: 
    若有项目A-->a.y假设y是以符号X开始,其中X可以是记号或非终结符,所以项目可以写成A-->aX.n,那么在符号X上就有一个从该项目代表的状态到由项目A-->aX.n代表的状态转换,则:
1,若X是一记号,那么该转换与X的一个在分析中输入到栈顶部的移进相对应。 
    A-->a.Xn====X===>A-->aX.n
2,另一方面,若X是一非终结符,因为X永远不会作为输入符号出现,则该转换就多了一层意思,首先这样的转换仍在分析时将X入栈相对应,但是只发生在由产生式X-->B形成的归约时,那么在对每个项目A-->a.Xn,必须为X的每个产生式X-->B,添加一个空形式,它指示通过识别它的产生式的右边的任意匹配来产生X。
     A-->a.Xn===空====>X-->.B

    这仅仅是NFA的转换,下来是初始状态和接受状态,NFA的初始状态应与分析程序的初始状态相对应:栈是空,而且将要识别一个S,其中S是文法的开始符号。但是这样带出一个问题,S可能有多个产生式,怎么选择用哪一个?无法做到这一点,解决的方法就是通过产生式S'-->S扩充文法,那么S'成为扩充文法的开始状态。(这就是为什么扩充文法的原因)。
    那么在NFA中那些状态将成为接受状态?其实NFA的任务是用于了解分析的状态,分析状态本身决定何时接受,而NFA则无需包含这一信息,所以NFA实际上没有接受状态。这样LR(0)项的NFA的描述就完整了。

LR(0)分析算法取决于要了解项目集合的DFA 当前状态,所以要修改分析栈不但能够存储符号还能存储状态数,即入栈一个符号后再将新的状态数入栈。实际上状态本身包含了有关符号的信息,所以可以完全将符号省略而只保存状态数。下来就是对该分析算法的定义描述:令s为当前的状态,即位于分析栈的顶部,则动作定义如下:
1,若状态包含了格式A-->a.Xn的任何项目,其中X是一终结符,则动作就是将当前的输入符号入栈,若这个记号是X,则状态s包含了项目A-->a.Xn,则入栈的新状态包含了项目A-->aX.n的状态,若记号不是X,那么就是一个错误。
2,若状态s包含了任何完整项目格式A-->a.,则动的规则是用规则A-->a归约。假设输入为空,用规则S'-->S归约与接受相等价;若输入不为空,则出现错误。
    若一个状态包含了完整项目A-->a.,那么就有两中形式的二义性出现,首先如果这样的状态还包括一个移进的项目A-->a.Xn,(X为终结符)那么就出现了到底是执行动作1,还是动作2的二义性,称为移进-归约冲突,第二 ,如果这个状态包括了两一个完整项目B-->b.那么就出现了归约哪个产生式的二义性,称为归约-归约冲突。所以当仅当每个状态都是移进状态或包含了单个完整项目的归约时,文法才是LR(0)文法。该文法不包括先行的显式引用。SLR(1)或LR(1)文法与LR(0)一样使用了项目集合的DFA,但是通过使用输入串的下一个记号来指导它的动作,这样大大提高了LR(0)的分析能力,通过两种方法实现的:首先在一个移进之前先考虑输入记号以确保存在着一个适当的DFA。其次使用非终结符的FOLLOW集合来决定是否执行一个归约。对它定义如下:
令s为当前状态即位于分析栈的顶部,则动作可定义如下:
1,若状态包含了格式A-->a.Xn的任何项目,其中X是一终结符,且X是输入串中的下一个记号,则动作将当前输入记号移进到栈中,且被压入到栈中的新状态是包含了项目A-->aX.n的状态
2,若状态s包含了完整项目A-->y.,则输入串中下一个记号是在FOLLOW(A)中,所以动作是用规则A-->y归约。用规则S'-->S归约与接受等价,其中S是开始状态;只有当下一个输入记号是$时候,才会发生。在所有的其他情况中,新状态都是这样计算的:删除串a和所有它的来自分析栈中的对应状态。相对应地,DFA回到a开始构造的状态。通过构造,这个状态必须包括格式B-->y.Ab的一个项目。将A压入栈中,并将包含了项目B-->aA.b的状态压入。
3,若下一个输入记号都不是上面良种情况,则错误。

    当仅当对于任何状态s对于:
1,对于在s中的任何项目A-->a.Xn,当X是一个终结符,且X在FOLLOW(B)中时,s中没有完整的项目B-->Y.
2,对于s中任何两个完整项目,A-->a.  B-->b.都有Folow(A)交Follow(B)为空
    满足时,文法为SLR(1)

SLR(1)文法是对LR(0)分析的一个简单而有效扩展,而LR(0)分析的能力足以处理几乎所有实际的语言结构。但是在有些情况SLR(1)分析能力不太强。所以还需要学习LR(1)和LALR(1)分析。SLR(1)最困难在于它在LR(0)项的DFA的构造之后提供先行,而构造却又忽略了先行,一般的LR(1)方法的功能在于使用了一个开始时就将先行构建在它的构造中的新DFA。这DFA使用了LR(0)项的扩展的项目。由于它们包含了每个项目中的一个先行记号,所以就叫LR(1)项,准确的说LR(1)项应是由LR(0)项和一个先行记号组成的对,[A-->a.b n]其中A-->a.b是LR(0)项,而n是一个记号。

    为了完成一般LR(1)分析所用的自动机定义,需要定义LR(1)之间的转换,定义如下:假设有LR(1)项目[A-->a.Xy,n]其中X是任意符号(终结符或非终结符),那么X就有一个到项目[A-->aX.y,n]的转换。注意:在两个项目出现了相同的先行n,所以这些转换不会引起新的先行出现,只有空-转换才“创建”新的先行。如下:
假设有LR(1)项目[A-->a.Xy,n],其中X 是一个非终结符,那么对于每个产生式X-->b和在First(ua)中的每个记号c都有到项目[B-->.b,c]的空-转换。

    LR(1)分析算法:令s为当前状态,则动作定义如下:
1,若状态s包含了格式[A-->a.Xb,n] 的任意LR(1)项目,其中X是一个终结符且是输入串中下一个记号,则动作就是将输入记号移进栈中,且入栈新状态是包含了[A-->aX.b,n]的状态
2,若状态s包含了完整的LR(1)项目[A-->a.,n],且输入串中的下一个记号是m,动作就是规则A-->a归约。
3,若下一个输入记号不是上面所述的任何情况,则错误。

同样需要满足两个条件才能是一个LR(1)文法,即
1,对于s中任何项目[A-->a.Xb,n],且X是一个终结符,则在s中没有格式[B-->b.,X]的项目,否则就移进-归约冲突
2,在s中没有两个[A-->a.,n]和[B-->b.,n],否则就归约-归约冲突

    对三个不同的分析算法的学习,从LR(0)到SLR(1)再到 LR(1),可以说是一步一步的去理解,SLR(1)与LR(1)都是建立在LR(0)的概念基础上的。而SLR(1)与LR(1)都是在LR(0)的基础上引入了先行的概念去提高分析的能力,正如上所定义的。而这两个先行算法的不同之处正好显示出了两种不同算法的区别所在。即SLR(1)文法是对LR(0)分析的一个简单而有效扩展,SLR(1)最困难在于它在LR(0)项的DFA的构造之后提供先行,而构造却又忽略了先行,一般的LR(1)方法的功能在于使用了一个开始时就将先行构建在它的构造中的新DFA。

  

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值