LR0语法分析报告器.docx

上传人:b****6 文档编号:6229465 上传时间:2023-01-04 格式:DOCX 页数:12 大小:213.94KB
下载 相关 举报
LR0语法分析报告器.docx_第1页
第1页 / 共12页
LR0语法分析报告器.docx_第2页
第2页 / 共12页
LR0语法分析报告器.docx_第3页
第3页 / 共12页
LR0语法分析报告器.docx_第4页
第4页 / 共12页
LR0语法分析报告器.docx_第5页
第5页 / 共12页
点击查看更多>>
下载资源
资源描述

LR0语法分析报告器.docx

《LR0语法分析报告器.docx》由会员分享,可在线阅读,更多相关《LR0语法分析报告器.docx(12页珍藏版)》请在冰豆网上搜索。

LR0语法分析报告器.docx

LR0语法分析报告器

西安邮电大学

(计算机学院)

课内实验报告

实验名称:

LR(0)语法分析器

 

专业名称:

计算机科学与技术

班级:

计科1304

学生姓名:

裴世宇

学号(8位):

04131132(12)

指导教师:

陈燕

实验日期:

2016年05月15日

 

一、实验目的

.1.巩固对语法分析的基本功能和原理的认识。

2.通过对语法分析表的自动生成加深语法分析表的认识。

3.理解并处理语法分析中的异常和错误。

二、实验环境

VC++6.0

Windows7

三、实验内容

大多数用上下文无关文法描述的程序语言都可用LR分析器予以识别。

LR分析法比算符优先分析法或其他的“移进-规约”技术更加广泛,而且分析效率并不比他们差。

规范规约的关键问题是寻找句柄。

一个LR分析器实质上是一个带先进后出的存储器(栈)点确定有限状态自动机。

1.通过设计、编制、陶氏一个典型的语法分析程序,实现对词法分析程序所提供的单词序列进行语法检查和结构分析,进一步掌握常用的语法分析方法。

2.选择对各种常见程序语言都用的语法结构,如赋值语句(尤其是表达式)作为分析对象,并且与所选语法分析方法要比较贴切。

四、实验功能

LR分析器实质上是一个带先进后出存储器(栈)的确定有限状态自动机。

我们将把“历史”和“展望”材料综合地抽象成某些“状态”。

我们把栈的结构看成是:

LR分析器模型

LR分析器的核心部分是一张分析表。

这张分析表包括两部分,意识“动作”(ACTION)表,另一个是“状态转换”(GOTO)表。

他们都是二维数组。

ACTION[s,a]规定了当状态s面临符号a时应采取什么动作。

GOTO[s,X]规定了状态。

面对文法符号X(终结符或非终结符)时下一个状态是什么。

显然,GOTO[s,X]定义了一个以文法符号为字母表的DFA。

 对于任一文法G[S],若S’

αAω

αβω,若γ

是αβ的前缀,则称γ是G的一个活前缀。

    活前缀与句柄的关系:

①活前缀已含有句柄的全部符号,表明产生式A→β的右部β已出现在栈顶。

②活前缀只含句柄的一部分符号如β1表明A→β1β2的右部子串β1已出现在栈顶,当前期待从输入串中看到β2推出的符号。

③活前缀不含有句柄的任何符号,此时期望产生式A→β的右部所推出的符号串。

(1)ACTON表和GOTO表的构建

每一项ACTION[s,a]所规定的动作不外是下述四种可能之一:

①移进

    把Sj=GOTO[Si,a]移入到状态栈,把a移入到文法符号栈。

其中i,j表示状态号。

②归约

    当在栈顶形成句柄为β时,则用β归约为相应的非终结符A,即文法中有A→β的产生式,若β的长度为r(即|β|=r),则从状态栈和文法符号栈中自栈顶向下去掉r个符号,即栈指针SP减去r。

并把A移入文法符号栈内,Sj=GOTO[Si,A]移进状态栈,其中Si为修改指针后的栈顶状态。

③接受acc

    当归约到文法符号栈中只剩文法的开始符号S时,并且输入符号串已结束即当前输入符是'#',则为分析成功。

④报错

当遇到状态栈顶为某一状态下出现不该遇到的文法符号时,则报错,说明输入串不是该文法能接受的句子。

①若项目A→α·aβ属于Ik且转换函数GO(Ik,a)=Ij,当a为终结符时则置ACTION[k,a]为Sj,其动作含意为将终结符a移进符号栈,状态j进入状态栈,(相当状态k时遇a转向状态j)。

②若项目A→α·属于Ik,则对任何终结符a和'#'号置ACTION[k,a]和ACTION[k,#]为"rj",j为在文法G′中某产生式A→α的序号。

rj动作的含义是把当前文法符号栈顶的符号串α归约为A,并状态栈指针从栈顶向下移动|α|的长度,文法符号栈从栈顶弹出|α|个符号,非终结符A变为当前面临的符号。

③若GO(Ik,A)=Ij,则置GOTO[k,A]为"j",其中A为非终结符,表示当前状态为"k"时,遇文法符号A时状态应转向j,因此A移入文法符号栈,j移入状态栈。

④若项目S′→S·属于Ik,则置ACTION[k,#]为"acc",表示接受。

⑤凡不能用上述方法填入的分析表的元素,均应填上"报错标志"。

为了表的清晰我们仅用空白表示错误标志。

 

(2)LR(0)项目

    在文法G中每个产生式的右部适当位置添加一个圆点构成LR(0)项目。

我们也可以根据圆点所在的位置和圆点后是终结符还是非终结符把LR(0)项目分为以下几种:

①移进项目

    形如A→α·aβ,其中α,β∈V*,a∈VT,即圆点后面为终结符的项目为移进项目,对应状态为移进状态。

分析时把a移进符号栈。

②待约项目

    形如A→α·Bβ,其中α,β∈V*,B∈VN,即圆点后面为非终结符的项目称待约项目,它表明所对应的状态等待着分析完非终结符B所能推出的串归约成B,才能继续分析A右部的B后面部分。

③归约项目

    形如A→α·其中α∈V*,即圆点在最右端的项目,称归约项目,它表明一个产生式的右部已分析完,句柄已形成可以归约。

④接受项目

    形如S′→S·,其中S∈VN,S′→S为拓广文法的产生式,S′为左部的产生式只有一个,因而它是归约项目的特殊情况,对应状态称为接受状态,表明已分析成功。

我们规定S′→·S为初态。

(3)LR(0)项目集规范族的构造

    对于构成识别一个文法活前缀的DFA项目集(状态)的全体我们称之为这个文法的LR(0)项目集规范族。

为此,在这里须引入LR(0)项目集的闭包函数CLOSURE和状态转换函数GO两个概念。

①闭包函数CLOSURE(I)的定义如下:

a)I的项目均在CLOSURE(I)中。

b)若A→α·Bβ属于CLOSURE(I),则每一形如B→·γ的项目也属于CLOSURE(I)。

c)重复b)直到不出现新的项目为止。

即CLOSURE(I)不再扩大。

②转换函数GO(I,X)的定义:

    GO(I,X)=CLOSURE(J)

    其中:

I为包含某一项目集的状态,X为一文法符号,X∈(VN∪VT),J={任何形如  A→αX·β的项目|A→α·Xβ属于I}。

    这样就可以使用闭包函数和转换函数构造文法G′的LR(0)项目集规范族,其步骤如下:

a)置项目S′→·S为初态集的核,然后对核求闭包,CLOSURE({S′→·S})得到初态的项目集。

b)对初态集或其它所构造的项目集应用转换函数GO(I,X)=CLOSURE(J),求出新状态J的项目集。

c)重复b)直到不出现新的项目为止。

5、算法描述

核心算法为构建ACTION表和GOTO表,构造文法的所有项目。

全局变量的定义以及注释

charAnalyzedArray[MAXSIZE];//字符串

charVtArray[MAXSIZE];//终结符号数组

intNumVt;//终结符号个数

charVnArray[MAXSIZE];//非终结符号数组

intNumVn;//非终结符号个数

charGrammar[MAXARRAY][MAXARRAY];//文法数组

intNumGrammar;//文法条数

charGeneralization[MAXARRAY][MAXARRAY];

//拓广所有文法,egE->.aAE->a.AE->aA.

intNumGeneralization;//拓广文法条数

intACTION[MAXSIZE][MAXSIZE];//ACTION表正数=移进负数=规约100=接受0=报错

intGOTO[MAXSIZE][MAXSIZE];//GOTO表存放规约后的状态

intINum;//项目集规范族个数

利用二维数组Grammar[][]来存储所有的文法,利用二维数组Generalization[][]来存储拓广之后的所有文法。

voidgetDFAGeneralization()//获得文法的所有拓展即.在文法在文法终点所有位置

利用这个函数可以获得所有文法的拓广文法。

在实现这个函数的同时需要调用另一个函数:

voidInsert_ponitosP(intnum,char*s,char*G),将.插入到制定字符串的指定位置i并存储到扩展文法n位置

这样只需要进行下标的定位就可以实现.的加入。

之后,要进行项目规范族的划分,同一族的项目可以通过到达,所以利用递归算法可以很快实现项目集的划分,在同一族中被选中的项目原本的下标会出现靠后的情况,这时需要引入另一数组Used[]记录使用情况,如果被选中过,则不可以被再次选中,反之可以进入新的族。

voidCLOSURE_DFA(DFA*I,intnum,charc,intn,int*U),这个函数就是用来实现识别活前缀的DFA项目集规范族的构建。

并且它是递归的函数。

获得了每个独立的识别活前缀的DFA项目集规范族后,下一步,就是要将他们连接起来,连接的弧我们通过终结符号或非终结符号来实现。

通过函数voidLine_DFA(DFA*I)我们实现了连接项目集规范族。

在实现过程中我们调用了intArcX(char*pro1,char*pro2)函数,获得该字符串的弧c后的结果,比较pro1和pro2是否只是.的位置不同来确定两个字符串是否只是.的位置不同,因为每个项目都是不同的,当只有.的位置不同时可以确定他们是可以通过某个字符弧连接到的,也可以延伸到规范族可以连接到。

前期工作完成后接下来就是置表了。

首先完成ACTION表。

函数voidAction(DFA*I)置Action表纵坐标是规范族个数=INum,横坐标是终结符号=VtNum。

实现过程也如图上述实验功能所述,在此不再赘述。

值得一提的是,按实验功能所述,移进时应移进“si”表示状态i进栈,规约“rj”表示按照第j个文法进行规约,我在这里小小的动一下脑筋,因为存入“si”相当于字符串,存储和读取都非常的麻烦,所以我利用数字的“+”“-”区分存储和读取,“+”为移进,“-”为规约。

当然第一步是要初始化ACTION表全部赋值为“错误”的值,之后进行表的构建会将“错误”值替换。

GOTO表的构建如同ACTION表的过程,细心就好。

万事俱备,只欠分析。

最后一步也是最重要的一步就是分析函数voidAnalysis(seq*L,char*S,DFA*I),这是用来传入待分析串并且返回结果是否符合LR0文法。

函数的实现方法也如同实验功能所述,但是在结构体的创建时要想好需要什么标识符来标识需要用到的信息,比如该规范族通过某字符连接到下一规范族的下标需要存储等等。

6、运行结果

第一组正常数据

第二组正常数据

不正常数据

7、调试情况

初期设计思想比较迷茫,不知道LR0语法分析器的编写从何开始,无从下手。

所以只能从书上找到切入点。

按照书上的要求和提示,我进行了一步步的编写,偶尔出现要寻找下标的困难就要从存储方式上找捷径,就这样程序逐渐丰满起来。

我为了保证每一个模块的完整性,每次写完一个函数就要测试一下测试用例,对比着正确过程修改代码实现功能。

在写完所有功能,测试完功能过后就要进行优化。

优化包括界面的优化和算法优化。

8、实验总结及体会

开始对这次试验比较有兴趣,得知同学们都在写算符优先文法和LL1语法分析器后,我并没有后悔,只有LR0才能有挑战的快感,正因为如此我也找到了乐趣。

编写代码过程中确实有困扰的地方,包括为了实现一种功能想出了一条最容易想到的算法,但是时间复杂度很高,我会再想更先进的文法。

因为这样我编写的速度比较慢。

但是在程序全部完成的那一刻,我体会到了成就感。

九、源程序清单(电子版)

(另附文件。

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 表格模板 > 合同协议

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

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