ImageVerifierCode 换一换
格式:DOCX , 页数:23 ,大小:24.94KB ,
资源ID:9516689      下载积分:3 金币
快捷下载
登录下载
邮箱/手机:
温馨提示:
快捷下载时,用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)。 如填写123,账号就是123,密码也是123。
特别说明:
请自助下载,系统不会自动发送文件的哦; 如果您已付费,想二次下载,请登录后访问:我的下载记录
支付方式: 支付宝    微信支付   
验证码:   换一换

加入VIP,免费下载
 

温馨提示:由于个人手机设置不同,如果发现不能下载,请复制以下地址【https://www.bdocx.com/down/9516689.html】到电脑端继续下载(重复下载不扣费)。

已注册用户请登录:
账号:
密码:
验证码:   换一换
  忘记密码?
三方登录: 微信登录   QQ登录  

下载须知

1: 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。
2: 试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓。
3: 文件的所有权益归上传用户所有。
4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
5. 本站仅提供交流平台,并不能对任何下载内容负责。
6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

版权提示 | 免责声明

本文(LR文法分析报告.docx)为本站会员(b****8)主动上传,冰豆网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知冰豆网(发送邮件至service@bdocx.com或直接QQ联系客服),我们立即给予删除!

LR文法分析报告.docx

1、LR文法分析报告实验名称: LR(0)文法分析一、 实验目的 :输入:任意的压缩了的上下文无关文法。输出:相应的 LR(0)分析表。二、 实验原理:对于 LR文法,我们可以自动构造相应的 LR 分析表。为了构造 LR分析表, 我们需要定义一个重要概念文法的规范句型“活前缀” 。这种句柄之后不含任何符号的前缀称为活前缀。在 LR 分析工作过程中的任何时候,栈里的文法符号(自栈底而上) X1X2 Xm 应该构成活前缀, 把输入串的剩余部分配上之后即应成为规范句型 (如果整个输 入串确实构成一个句子) 。因此,只要输入串的已扫描部分保持可归约成一个活 前缀,那就意味着所扫描过的部分没有错误。对于一个

2、文法 G,我们可以构造一个有限自动机, 它能识别 G的所有活前缀, 然后把这个自动机转变成 LR 分析表,按照该 LR 分析表进行 LR 分析,就能保证 在分析的过程中,如果分析的句子是正确的,栈里的文法符号(自栈底而上)始 终构成活前缀。假若一个文法 G的拓广文法 G 的活前缀识别自动机中的每个状态(项目集) 不存在下述情况:(1)既含移进项目又含归约项目; (2)含有多个归约项目,则 称 G 是一个 LR( 0)文法。该自动机的状态集合即为该文法的 LR( 0)项目集规 范族。构造识别文法活前缀 DFA有 3 种方法:(1)根据形式定义求出活前缀的正则表达式,然后由此正则表达式构造 NFA

3、 再确定为 DFA;(2)求出文法的所有项目,按一定规则构造识别活前缀的 NFA再确定化为 DFA;(3)使用闭包函数( CLOSUR)E和转向函数 (GO(I,X) 构造文法 G的 LR(0) 的项目集规范族,再由转换函数建立状态之间的连接关系来得到识别活前缀的 DFA。符号串的前缀是指该符号串的任意首部, 包括空串。例如,对于符号串 abc, 其前缀有, a,ab,abc。如果输入串没有错误的话,一个规范句型的活前缀是 该句型的一个前缀, 但它不含句柄之后的任何符号。 之所以称为活前缀, 是因为 在该前缀后联接尚未输入的符号串可以构成一个规范句型。活前缀与句柄的关系如下:(1)活前缀已含有

4、句柄的全部符号, 表明产生式 A的右部已出现在栈 顶。(2)活前缀只含句柄的一部分符号,表明 A 12的右部子串 1已出现在 栈顶,期待从输入串中看到 2推出的符号。(3)活前缀不含有句柄的任何符号, 此时期望 A的右部所推出的符号串。 在文法 G的每个产生式的右部(候选式)的任何位置上添加一个圆点,所构 成的每个产生式称为 LR(0 )项目。如产生式 A xyz 有如下项目: A .xyz , A x.yz , A xy.z ,A xyz. 。为刻划分析过程中的文法的每一个产生式的右部 符号已有多大一部分被识别 (出现在栈顶) ,可以用这种标有圆点的产生式来确 定。(1)A . 刻划产生式

5、A的右部已出现在栈顶。(2)A 1. 2 刻划 A 1 2的右部子串 1已出现在栈顶,期待从输入串中 看到 2推出的符号。(3)A. 刻划没有句柄的任何符号在栈顶,此时期望 A的右部所推出 的符号串。(4)对于A的LR(0)项目只有 A。 设文法G=(VT,VN,S,P)是一个上下文无关文法,若存在一个规范推导 S * rm 错误!未找到引用源。 Aw 错误!未找到引用源。错误! 未找到引用源。 1错误! 未找到引用源。 2w(其中 A错误!未找到引用源。错误!未找到引用源。 1错误! 未找到引用源。 2错误!未找到引用源。 P),则称项目 A错误!未找到引用源。错 误!未找到引用源。 1?

6、错误!未找到引用源。 2对活前缀 错误!未找到引用源。 =错误!未找到引用源。错误!未找到引用源。 1是有效的,即 LR(0) 有效项目。从直观意义上讲,一个 LR(0) 项目指明了在分析过程中的某一步我们看到产 生式的多大部分被识别, LR(0) 项目中的圆点可看成是分析栈栈顶与输入串的分 界线,圆点左边为已进入分析栈的部分,右边是当前输入或继续扫描的符号串。不同的 LR(0) 项目,反映了分析栈顶的不同情况。我们根据 LR(0) 项目的作 用不同,将其分为四类:(1)归约项目:表现形式: A a.这类 LR(0)项目表示句柄 a 恰好包含在栈中,即当前栈顶的部分内容构成了 所期望的句柄,应

7、按 A a 进行归约。(2)接受项目:表现形式: S a.其中 S 是文法惟一的开始符号。这类 LR(0)项目实际是特殊的归约项目,表 示分析栈中内容恰好为 a,用 S a进行归约,则整个分析成功。(3)移进项目:表现形式: Aa. b ( b VT)这类 LR(0) 项目表示分析栈中是不完全包含句柄的活前缀,为构成恰好有句 柄的活前级,需将 b 移进分析栈。(4)待约项目:表现形式: A.B (B VN)这类 LR(0) 项目表示分析栈中是不完全包含句柄的活前缀,为构成恰好有句 柄的活前缀,应把当前输入字符串中的相应内容先归约到 B。在给出 LR(0) 项目的定义和分类之后,我们从这些 LR

8、(0)项目出发,来构造 能识别文法所有前缀的有限自动机。 其步骤是:首先构造能识别文法所有活前缀 的非确定的有限自动机, 再将其确定化和最小化, 最终得到所需的确定的有限自 动机。由文法 G的 LR(0) 项目构造识别文法 G的所有活前缀的非确定有限自动机的 方法:(1)规定含有文法开始符号的产生式(设 S A)的第一个 LR(0) 项目(即 S .A )为 NFA的惟一初态。(2)令所有 LR(0) 项目分别对应 NFA的一个状态且 LR(0) 项目为归约项目的 对应状态为终态。(3)若状态 i 和状态 j 出自同一文法 G的产生式且两个状态 LR(0) 项目的 圆点只相差一个位置,即:若

9、i 为 XX1X2Xi-1XiXn, j 为 XX1X2XiXi+1Xn,则从状态 i 引 一条标记为 Xi 的弧到状态 j 。(4)若状态 i 为待约项目(设 X A),则从状态 i 引弧到所有 A r 的状态。为了使“接受”状态易于识别,我们通常将文法 G 进行拓广。假定文法 G是一个以 S 为开始符号的文法,我们构造一个 G ,它包含了整 个 G,但它引进了一个不出现在 G中的非终结符 S ,并加进一个新产生式 S S, 以 S SG 为开始符号。那么,我们称 G 是 G的拓广文法。这样,便会有一个仅含项目 S S 的状态,这就是惟一的“接受”态。 如果I是文法G的一个项目集,定义和构造

10、 I 的闭包CLOSURE(I如) 下:(1) I 的项目都在 CLOSURE(I中) 。(2) 若A .B 属于 CLOSURE(I,) 则每一形如 B. 的项目也属于 CLOSURE(I。)(3) 重复( 2)直到 CLOSURE(I不) 再扩大。定义转换函数如下:GO(I,X)= CLOSUR(E J)其中: I为包含某一项目集的状态, X为一文法符号, J= A X . | A .X I 。圆点不在产生式右部最左边的项目称为核,惟一的例外是 S .S,因此用 GOTO(I ,X)状态转换函数得到的 J为转向后状态闭包项目集的核。使用闭包函数(CLOSUR)E和转换函数 (GO(I,X)

11、 构造文法G的LR(0)的项目 集规范族,步骤如下:(1) 置项目S .S为初态集的核,然后对核求闭包 CLOSUR(ES .S ) 得到初态的闭包项目集。(2) 对初态集或其他所构造的项目集应用转换函数 GO(I,X)= CLOSURE(J) 求出新状态 J的闭包项目集。(3) 重复( 2)直到不出现新的项目集为止。 计算LR(0)项目集规范族 C=I 0,I 1 , . In 的算法伪代码如下:Procedure itemsets(G );Begin C := CLOSURE (S .S)RepeatFor C 中每一项目集 I 和每一文法符号 XDo if GO(I,X) 非空且不属于

12、CThen 把 GO(I,X) 放入 C中 Until C 不再增大End;一个项目集可能包含多种项目,若移进和归约项目同时存在,则称移进 - 归约冲突,若归约和归约项目同时存在,则称归约 - 归约冲突。下面看一个具体的例子: 我们希望能根据识别文法的活前缀的 DFA建立 LR分析器,因此,需要研究 这个 DFA的每个项目集(状态)中的项目的不同作用。我们说项目 A1. 2对活前缀 1是有效的,其条件是存在规范推导 S A 1 2 。一般而言,同一项目可能对几个活前缀都是有效的(当一个 项目出现在几个不同的集合中时便是这种情形) 。若归约项目 A1. 对活前缀 1是有效的,则它告诉我们应把符号

13、串 1归约为 A,即把活前缀 1变成 A。 若移进项目 A1. 2对活前缀 1是有效的,则它告诉我们,句柄尚未形成, 因此,下一步动作应是移进。但是,可能存在这样的情形,对同一活前缀,存在 若干项目对它都是有效的。而且它们告诉我们应做的事情各不相同,互相冲突。 这种冲突通过向前多看几个输入符号,或许能够获得解决。对于每个活前缀, 我们可以构造它的有效项目集。 实际上, 一个活前缀的 有效项目集正是从上述的 DFA的初态出发, 经读出后而到达的那个项目集 (状 态)。换言之,在任何时候,分析栈中的活前缀 X1X2Xm 的有效项目集正是栈顶状态 Sm所代表的那个集合。这是 LR 分析理论的一条基本

14、定理。实际上,栈顶的 项目集(状态)体现了栈里的一切有用信息历史。前面我们已经对 LR(0)文法进行了定义 , 下面我们来看一下 LR(0)分析表 是如何构造的。对于 LR(0)文法,我们可以直接从它的项目集规范族 C 和活前缀识别自动 机的状态转换函数 GO构造出 LR 分析表。下面是构造 LR(0)分析表的算法。假定C=I 0, I 1, , In ,令每个项目集 I k的下标k为分析器的一个状态,因 此, G的LR(0)分析表含有状态 0,1, n。令那个含有项目 S S的I k的下 标k为初态。 ACTION子表和 GOTO子表可按如下方法构造:(1)若项目 A .a 属于 Ik且GO

15、( I k, a)= Ij, a为终结符,则置 ACTIONk, a为“把状态 j 和符号 a移进栈”,简记为“ sj”;(2)若项目A属于 I k,那么,对任何终结符 a,置ACTIONk,a为“用 产生式A进行规约”,简记为“ r j ”;其中,假定 A为文法 G的第j个产 生式;(3)若项目S S属于I k, 则置ACTIONk, #为“接受”,简记为“acc”;(4)若GO (Ik, A)= I j, A 为非终结符,则置 GOTOk, A=j;(5)分析表中凡不能用上述 1至4填入信息的空白格均置上“出错标志”。 按上述算法构造的含有 ACTION和GOTO两部分的分析表, 如果每个

16、入口不含多 重定义,则称它为文法 G的一张LR(0)分析表。具有 LR(0)表的文法 G称为一个 LR (0)文法, LR(0) 文法是无二义的。例如,文法 G(E)的拓广文法如下:(0)S E(1)E aA(2)E bB(3)A cA(4)A d(5)B cB三、实验内容及其代码如下所示:#include#include#include#includeusing namespace std;#define OK 1#define ERROR 0#define N 50#define Y 20 int vtnum,vnnum,pronum;/ 依次是终结符个数,非终结符个数,产生式个数 cha

17、r vtN;/ 终结符集 char vnN;/ 非终结符集char oldNN=/0;/ 用于存储文法char oldzNN=/0;/ 用于存储增广文法int ACTIONNN=0;/ 动作表int GOTONN=0;/ 状态转换表typedef struct SqEint t;/ 状态编号 char c1;SqE;/ 堆栈元素typedef struct itemint f;/ 项目前部,表示产生式编号int l;/ 项目后部,表示停顿点在产生式的位置item;/ 定义项目typedef struct linkint f;/ 连接前部,表示所用符号的编号,非终结符编号 =在 vn 中的下标

18、+100int l;/ 连接后部,即状态编号link;/ 定义状态之间的连接typedef struct cdint item_num;/ 状态中的项目数int link_num;/ 状态的连接数item wN;/ 项目集 link uN;/ 连接集cd;/ 定义状态typedef struct DFAint cd_num;/ 状态个数cd sN+1;/ 状态集DFA;/ 定义规范 LR(0)项目族 ,D.sN 用作状态转换函数 go_switch() 的存储空 间DFA D;void dfa();/ 求规范 LR(0)项目族 void closure(int);/ 求闭包void go_sw

19、itch(int,int);/ int test_go_switch();void add_go_switch();/ void del_go_switch();/求转换增加新状态清空状态转换函数的存储空间void action();/ 构造 ACTION表 void go_answer();/ 构造 GOTO表int control();/ int length(int);/ int test(char); void printf_ag();/总控程序返回增广文法产生式右部的长度输出 ACTION表和 GOTO表 bool test_link(int i,int num);void main

20、()int i,j;ifstream in(input1.txt,ios_base:in);/ 读 文 件 , 从 文 件 中 读 入 pronum,vtnum,vnnum 以及产生式inpronumvnnumvtnum;invn;invt;for(i=1;ioldi;/ 将产生式存入 old,old1 为第一个产生式 for(i=1;iS,将原文法扩充,使其变为增广文法vtvtnum=$;/ 把结束符 $ 加入终结符集D.cd_num=0;for(i=0;i=N;i+)D.si.item_num=0;D.si.link_num=0;/ 初始化状态个数、连接个数、项目个数dfa(); acti

21、on(); go_answer(); printf_ag(); control();/ 求一个状态的闭包 void closure(int i) int j,k,m,x,flag;do j=D.si.item_num;/j 是本轮循环开始前的项目数 for(k=0;kD.si.item_num;k+) for(m=0;ma.Ab 应找到 A-. flag=0;/ 判断该项是否在当前状态 i 中 , 即检查 (m,1) 是 否存在于状态 i 中, 保证求闭包时加入的新项目和原项目集不重合 for(x=0;xD.si.item_num;x+) if(D.si.wx.f=m&D.si.wx.l=1)

22、 flag=1; break; if(flag=0)/ 如果该项不在当前状态 i 中,将其加入状 态i D.si.wD.si.item_num.f=m; D.si.wD.si.item_num.l=1; D.si.item_num+; while(j!=D.si.item_num);/ 当一轮没有新的项目加入 i 时,结束循环 / 状态转换函数, i 是状态编号,num是符号编号,状态转换函数的结果存于 sN void go_switch(int i,int num) int j; for(j=0;jD.si.item_num;j+) if(test(oldzD.si.wj.fD.si.wj.

23、l)=num) D.sN.wD.sN.item_num.f=D.si.wj.f; D.sN.wD.sN.item_num.l=D.si.wj.l+1; D.sN.item_num+;closure(N); / 返回终结符和非终结符的标号 , 判断符号的类型 ,0=终结符返回值 100,100= 非终结符返回值 200, 错误符号返回值 =200int test(char c) int i,j;for(i=0;ivtnum;i+) if(vti=c)break;if(ivtnum)return i;elsefor(j=0;jvnnum;j+)if(vnj=c)break;if(jvtnum) r

24、eturn (100+j);else return 200;/ 检验状态转换函数的结果int test_go_switch() int i,j,k,flag;if(D.sN.item_num=0)/ 判断状态转换的结果是否为空, 即当前状态可否 接收该字符return 0; else for(i=0;iD.cd_num;i+)/ 选定一状态,对 sN 中的每个项目进行循 环,如果存在一个项目在当前状态中未找到,即 flag=0 ,立即跳至下一状态flag=1;/ 判断状态转换函数的结果是否已经完全包含于某一现有状 态中,例如 go_switch( 状态 4, 符号 a) 依然存在于状态 4 中

25、,go_switch( 状态 4, 符号 c) 已经存在于状态 5 中for(j=0;jD.sN.item_num;j+)/ 如果在当前状态 i 中找不到 sN 的当前项目 j, 就跳至下一状态for(k=0;k=D.si.item_num) flag=0; break; if(flag=1) return 1000+i;return 1;/ 状态转换函数的结果未被任何现有状态完全包含,完全满 足建立新状态的条件/ 把状态转换函数的结果加入 DFA,即当建立新状态的条件符合时,建立新的状 态 sD.cd_num void add_go_switch()int i;for(i=0;iS 加入初状

26、态,并求其闭包do i=D.cd_num;/ 本轮循环开始时状态数for(j=0;jD.cd_num;j+)/对每个状态进行循环for(k=0;k=1000)/ 含于某一现有状态D.sj.uD.sj.link_num.f=k+100;/ 状态和该现有状态的连接如果状态转换的结果包建立当前D.sj.uD.sj.link_num.l=test_go_switch()-1000;D.sj.link_num+;del_go_switch();/ 清空for(k=0;kvtnum;k+)/ 对当前状态,每个终结符if(!test_link(j,k)go_switch(j,k);if(test_go_switch()=1)add_go_switch();D.sj.u

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1