文法分析器.docx

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

文法分析器.docx

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

文法分析器.docx

文法分析器

 

仲恺农业工程学院

编译原理课程设计

课程设计题目:

LR(0)文法分析器

 

姓名:

陈瑞鑫

院(系):

计算机科学与工程学院

专业班级:

计算机科学与技术071班

学号:

200710214111

指导教师:

陈勇

设计日期:

2009年12月23日

目录

1.需求分析1

1.1.总述1

1.2.程序功能要求2

2.概要设计2

2.1.开发环境2

2.2.总体设计3

2.3.模块设计4

2.3.1.模块结构图4

2.3.2.模块说明5

2.3.3.功能设计5

2.3.4.界面设计6

3.详细设计8

3.1.文法输入及识别模块8

3.1.1.类说明9

3.1.2.文法的合法性判断9

3.2.分析表构造模块12

3.2.1.类图12

3.2.2.算法分析与设计12

3.2.3.分析表构造基本流程15

3.3.句子分析模块15

3.3.1.类图15

3.3.2.句子分析过程16

3.4.语法树构造模块18

3.4.1.类图18

3.4.2.语法树构造函数18

4.测试分析19

4.1.功能测试19

4.2.程序问题分析21

4.2.1.LR(0)分析程序工作的正确性21

4.2.2.LR(0)语法分析器的错误恢复策略21

4.3.程序的扩展性22

5.用户手册23

5.1.运行环境23

5.2.功能说明24

6.课程总结25

7.参考文献26

LR(0)文法分析器(LR(0)grammarparser)

1.需求分析

1.1.总述

《编译原理》是计算机专业的一门重要专业课,旨在介绍编译程序构造的一般原理和基本方法。

内容包括语言和文法、词法分析、语法分析、语法制导翻译、中间代码生成、存储管理、代码优化和目标代码生成。

虽然只有少数人从事编译方面的工作,但是这门课在理论、技术、方法上都对学生提供了系统而有效的训练,有利于提高软件人员的素质和能力。

语法分析是编译过程的一个逻辑阶段。

语法分析的任务是在词法分析的基础上将单词序列组合成各类语法短语,如“程序”,“语句”,“表达式”等等。

语法分析程序判断源程序在结构上是否正确。

源程序的结构由上下文无关文法描述。

语法分析程序可以用YACC等工具自动生成。

语法分析器是对单词符号串进行语法分析得出相应的语法单位,在编译过程中占有很重要的地位。

如图1-1所示。

图1-1语法分析器在编译器中的位置

其中LR分析法是一种自下而上进行规范归约的语法分析法,L指从左到右扫描输入符号串,R是指构造最右推导的逆过程。

对大多数无二义性上下文无关文法描述的语言都可用它进行有效的分析。

主要分析器有LR(0),SLR

(1),LR

(1),LALR

(1)。

LR(0):

在分析的每一步,只需根据当前栈顶状态而不必向前查看输入符号就能确定应采取的分析动作。

所能分析的LR(0)文法要求文法的每一个LR(0)项目集中都不含冲突项目。

示例文法:

0S’->E

1E->aA

2E->bB

3A->cA

4A->d

5B->cB

6B->d

详见电子版根目录下的“1.txt”文本文件。

另外还给出了额外的文法测试实例,详见该目录下的“2.txt”、“3.txt”、“4.txt”、“5.txt”;当然,用户可以自己通过建立文本文件给出测试实例,也可以在主界面通过直接输入给出文法。

1.2.程序功能要求

通过本学期对《编译原理》这门课程的学习,以及在编译原理的实验课上学到的理论知识和实践进行了这次《编译原理》的课程设计,这次课程设计主要完成对LR(0)文法分析器的构造,该程序具有如下功能:

(1)对文法的识别输入或采用txt文件导入方式。

(2)程序根据已具备的算法能力构造相应的文法分析表。

(3)对输入句子进行分析和判断是否合法。

(4)产生句子的移进—归约步骤。

(5)生成语法分析树。

(6)其他人性化操作功能如:

非终结符或终结符的输入和删除功能、对产生式集合的操作、实现对文法的导入、保存和分析功能,以及对分析结果的保存等。

本程序主要采用窗口类和控件组装成整个界面,内部对象和类均使用MFC基类所派生和构造,使整个设计过程更易于实现和操作。

2.概要设计

2.1.开发环境

开发平台:

WindowsXP+VisualC++6.0

开发使用框架:

MFCAppWizard(exe)-Dialogbased

开发语言:

C++

建立MFC界面过程如图2-1所示。

图2-1MFCAppWizard

2.2.总体设计

程序基于VisualC++6.0开发。

程序通过MFC向导建立后,VisualC++自动产生说明文件,即电子版根目录下的“ReadMe.txt”文本文件。

然后通过一步步建立程序控件、类以及相关对象实现整个程序的完成,采用面向对象方法进行控制和完善,实现起来简单明了,并在这一个过程中给出了各个类的说明,可以参见“ReadMe.txt”文本文件,也可以详见模块设计的类说明和构造过程以及实现的具体功能。

本程序的总体设计框架如图2-2所示。

 

 

图2-2系统总体设计框架

系统最终效果界面如图2-3所示。

图2-3系统效果图

2.3.模块设计

2.3.1.模块结构图

图2-4各个模块间的传递关系

2.3.2.模块说明

本程序主要分为四个模块:

文法输入及识别模块、分析表构造模块、句子分析模块、语法树构造模块。

文法输入及识别模块:

由于在进行拓广文法是要用到各个非终结符和终结符,所以对这两者进行封装成为集合形式,界面提供给用户输入文法,用户除了要输入产生式集合外,还需填写文法开始符号、非终结符的集合以及终结符集合,如果采用“导入文法”方式输入文法则需要在txt文本文件中设置四个集合形式如图2-5所示。

否则在导入过程将会出错。

图2-5文本文件格式

分析表构造模块:

首先列出你输入的文法,然后进行文法拓广,用算法进一步构造该文法的项目,以及LR(0)项目集规范族,最后构造文法的LR(0)分析表。

句子分析模块:

当用户给定一个句子时,该模块可以进行分析,分析过程包括步骤、状态栈、符号栈、输入串、action和goto,即句子的规约过程,当最终能够规约到文法的开始符号时,输出“分析完成,输入的字符串是预定文法的句子”。

如果不能规约到文法开始符号则输出“分析失败,输入的字符串是不符合预定文法的!

语法树构造模块:

根据输入的句子进行语法树构造,语法树包括字符的规约过程,当句子不合法时语法树为空,否则按规约步骤显示树节点,本模块采用MFC树形类进行显示,直观明了。

2.3.3.功能设计

(7)各个集合的元素的添加和删除。

(8)导入文法、清除文法和保存文法。

(9)保存分析句子的过程到用户选择的目录下的txt文本文件。

(10)窗口采用文本识别,可以进行全选和复制等操作。

(11)识别结果都在分析后进行提示。

(12)各个窗口的部分按钮实现快捷键按钮方式,操作起来方便快捷。

2.3.4.界面设计

图2-6文法导入和识别

图2-7句子分析

对输入的文法进行分析表构造如图2-8所示。

图2-8分析表构造

对输入的句子进行语法树构造如图2-9所示。

图2-9语法树构造

3.详细设计

3.1.文法输入及识别模块

文法输入及识别模块主要使用的类有Grammar类、Pair类、Set类,与之关联的还有CtableDlg类,它们之间的关系如类图3-1所示。

图3-1文法类和其他类的关系

3.1.1.类说明

表3-1Grammar类部分说明表

名称

属性

说明

cStart

数据成员

文法开始符号

P

数据成员

存放可变长度的产生式容器

C

数据成员

存放可变长度的项目集容器

GoSet

数据成员

存放可变长度的goto集合容器

Vt

数据成员

终结符的set对象(集合式)

Vn

数据成员

非终结符的set对象(集合式)

nVt

数据成员

终结符

nVn

数据成员

非终结符

nP

数据成员

产生式

nC

数据成员

开始符号

GetGoTo

成员方法

产生goto集合(状态转换)

GetAction

成员方法

产生action集合(移入或归约)

GetPrecept

成员方法

获取产生式集合

operator=

成员方法

文法类的相等,等号重载函数

SetVt

成员方法

保存终结符

SetVn

成员方法

保存非终结符

SetStart

成员方法

保存开始符号

GenerateLR0Table

成员方法

产生lr0分析表函数

OutputHTML

成员方法

列出产生分析表的步骤

AddPrecept

成员方法

增加产生式

IsLegalLR0Grammar

成员方法

判断文法是否合法

CopyGrammar

成员方法

文法复制

GetProject

成员方法

返回项目

GetClosure

成员方法

返回闭包

3.1.2.文法的合法性判断

文法合法性的判断包括多方面的判断,下面先通过各个步骤的分析然后构造流程图,最后完成C++程序的函数构造和编写。

首先:

文法中必须含有开始符号,而且开始符号为非终结符,所以必须在非终结符集合中能够找到开始符号。

其次:

终结符和非终结符集合为两个互斥集合,里面的元素不能重叠,即元素a不可能既为终结符也为非终极符。

再者:

产生式的左右部符号必须是终结符集合或者非终结符集合里的元素,所以在遍历两个集合时能够做出对文法合法性的判断。

最后:

再具体到产生式的格式,这方面可以通过一个函数进行产生式左右部符号的获取,使得产生式能够被正确识别和判断。

流程图如图3-2所示。

 

图3-2文法识别(合法性判断)

根据流程图和前面的分析所描述,进一步构造并实现从逻辑算法到代码的转化,即算法代码化的过程。

文法合法性判断:

C++程序的函数构造和编写如下。

boolGrammar:

:

IsGrammarLegal()//判断文法是否合法

{

boolflag=false;//初始化标记为FALSE

if(!

Vn.Find(cStart))//判断是否在非终结符中找到开始符号

returnfalse;//如果没有则返回错误

if(P.empty())//判断产生式集合是否为空

returnfalse;//是则返回FALSE

for(inti=0;i

{

if(Vt.Find(Vn.GetAt(i)))

returnfalse;//有则返回FALSE

}

for(i=0;i

{

if(Vn.Find(Vt.GetAt(i)))

returnfalse;//有则返回FALSE

}

for(i=0;i

{

stringstrTest;

strTest=P[i].GetLeft();//产生式左部

for(unsignedintj=0;j

{//观察左部符号是否在终结符或者非终结符集合中

if((!

Vn.Find(strTest[j]))&&(!

Vt.Find(strTest[j])))

returnfalse;

if((j==0)&&(strTest[j]==cStart))//第一个左部符号必须为开始符号

flag=true;

}

strTest=P[i].GetRight();//产生式右部

for(j=0;j

{//观察右部符号是否在终结符或者非终结符集合中

if((!

Vn.Find(strTest[j]))&&(!

Vt.Find(strTest[j])))

returnfalse;

}

}

returnflag;//返回最终判断结果

}

程序中的P[i].GetLeft()和P[i].GetRight()两个函数的定义是关于取产生式左部符号和右部符号的算法实现,具体见源程序关于“classPrecept”的定义。

3.2.分析表构造模块

分析表构造过程主要采用CExplorer1类来完成,包括整个窗口的设计实现和分析表的具体构造过程,算法过程在类成员函数完成和调用其他类共同实现。

3.2.1.类图

图3-3Cexplorer1类图

3.2.2.算法分析与设计

自底向上语法分析思想:

自底向上语法分析也称移动归约分析法。

移动归约分析法为输入串构造分析树时从叶结点(底端)开始,向根结点(顶端)前进。

LR(0)分析法是一种非常有效的自底向上分析方法,LR(0)分析法给出一种能够根据当前分析栈中的符号串(通常以状态表示)和向右顺序查看输入串1个符号就可唯一地确定分析器的动作是移进还是归约以及用哪个产生式进行归约,归约过程是规范推导的逆过程,所以LR(0)分析过程是一种规范归约过程,每一步归约的都是真正的句柄,因而也就能唯一地确定句柄。

LR(0)分析法具有萌发前缀性,即当它一旦发现一个输入字符串的前缀不是该语言任何字符串的前缀时就能检查出错误。

LR(0)分析器模型如图3-4所示。

图3-4LR(0)分析器模型

驱动程序:

每次从输入缓冲区读一个符号,它使用栈存储形式为S0X1S1X2S2…XmSm的串,Sm在栈顶。

Xi是文法符号,Si是状态,状态符号概括了栈中它下面部分所含的信息。

栈顶的状态符号和当前的输入符号用来检索分析表,以决定移进归约分析的动作。

LR(0)分析表:

包括动作表(action)和状态转换表(goto)两个部分。

LR(0)分析驱动程序的行为是:

它根据栈顶当前的状态sm和当前的输入符号ai,访问action[sm,ai],它可能的四个值如下:

(1)移进s,其中s是一个状态。

(2)按文法产生式A->b归约。

(3)接受。

(4)出错。

分析栈:

包括文法符号栈和状态栈。

(一)拓广文法。

由于最后的归约状态必须归约为开始符号,因此为了归约的唯一性,开始符号的产生式必须智能有一个候选式,因此对于开始符号有两个或以上候选式的情况(例如本例),需要对文法进行拓广,加入一条产生式S->E,且把S作为开始符号。

(二)计算LR项目集族。

由于LR分析法是模拟规范归约,因此每次归约后的符号串都应称为一个规范句型,那么,已扫描过的字符串就是规范句型的一个前缀,且不含句柄之后的任何符号,称之为活前缀。

造表的基本思想就是构造一个识别所有活前缀的有限自动机,再转换成分析表。

此有限自动机的状态就是每一个产生式后面加一个圆点后形成的项目。

识别文法活前缀的DFA的项目集的全体称为LR项目集规范族。

计算方法为:

1、从S一>开始符号产生式开始,求产生式的CLOSURE闭包。

设I为任意项目集:

①I的任何项目集都属于CLOSURE(I);②如A->α·Bβ在CLOSURE(I)中,那么,对任何关于B的产生式B->γ,项目B->·γ也属于CLOSURE(I)。

③重复执行上述两步骤直至CLOSURE(I)不再增大为止。

2、计算项目集中的所有项目的GO函数:

GO(I,X)=CLOSURE(J)其中,J={任何形如A->αX·β的项目|A->α·Xβ属于I}。

按上述规则,计算出本例的项目集族为I0-I11,分别为:

I0={S’->·E,E->·aA,E->·bB}

I1=GO(I0,E)={S’->E·}

I2=GO(I0,a)={E->a·A,A->·cA,A->·d}

I3=GO(I0,B)={E->b·B,B->·cB,B->·d}

I4=GO(I2,c)={A->c·A,A->·cA,A->·d}=Go(I4,c)

I5=GO(I3,c)={E->c·B,B->·cB,B->·d}

I6=GO(I2,A)={E->aA·}

I7=GO(I3,B)={E->bB·}

I8=GO(I4,A)={A->cA·}

I9=GO(I5,B)={B->cB·}

I10=GO(I4,d)=GO(I2,d)={A->d·}

I11=GO(I3,d)=GO(I5,d)={B->d·}

(三)构造LR分析表。

对于LR(0)文法,可以直接从它的项目集规范族c和识别活前缀的自动机的状态转换函数GO构造出LR分析表。

LR分析器的分析表可以抽象为分析动作表Action和状态转移表GOTO。

构造方法如下:

1、若项目A->α·aβ属于Ik且GO(Ik,a)=Ij,a为终结符,则置ACTION[k,a]为“把(j,a)移近栈”,简记为Sj。

2、若项目A->α·属于Ik,那么,对任何终结符a(或终结符#),置ACTION[k,a]为用产生式A->α(设为第j个产生式)进行归约,简记为rj。

3、若项目S’->S·属于Ik,则置ACTION[k,#]为接受,简介为Acc。

4、若GO(Ik,A)=Ij,A为非终结符号,则置GOTO[k,A]=j。

5、分析表中凡不能用以上规则添入信息的空白均置“报错”。

综上,按照以上规则,本例的LR(0)分析表如表3-2所示。

表3-2LR(0)分析表

状态

ACTION表

GOTO表

a

b

c

d

#

E

A

B

0

S2

S3

 

 

 

1

 

 

1

 

 

 

 

ACC

 

 

 

2

 

 

S4

S10

 

 

6

 

3

 

 

S5

S11

 

 

 

7

4

 

 

S4

S10

 

 

8

 

5

 

 

S5

S11

 

 

 

9

6

r1

r1

r1

r1

r1

 

 

 

7

r2

r2

r2

r2

r2

 

 

 

8

r3

r3

r3

r3

r3

 

 

 

9

r5

r5

r5

r5

r5

 

 

 

10

r4

r4

r4

r4

r4

 

 

 

11

r6

r6

r6

r6

r6

 

 

 

3.2.3.分析表构造基本流程

根据3.2.2节对LR(0)分析表构造算法的设计和分析,可以抽象并简化为流程图如图3-5所示。

图3-5LR(0)分析表构造流程图

3.3.句子分析模块

3.3.1.类图

对用户输入的句子进行分析,判断是否符合文法的规则,这一过程主要有类CAnalyzeDlg,它的类图,以及与基类CResizingDialog的关系如图3-5所示。

图3-5CAnalyzeDlg和基类CResizingDialog类图

3.3.2.句子分析过程

(一)逻辑结构。

输出

Action

Goto

LR总控程序

分析表

SmXm

··

··

··

S1X1

S0#

状态栈

输入串a0a1······an# 

(二)分析器的工作流程。

LR分析器的分析表可以抽象为分析动作表Action和状态转移表GOTO。

对于Action表中的动作Action[S,a]有如下四种情况(其中a为终结符号∪#):

1、Action[S,a]=“移入”,表示为S

2、 Action[S,a]=“归约”,表示为rj,即用第j个表达式进行归约;

3、 Action[S,a]=“接受”表示为Acc,即为接受状态;

4、Action[S,a]=“出错”。

Goto[S,X]=Si表示S移入X后进入的状态为Si,在表中填数字i即可。

LR分析器的工作流程为:

(1)初始格局:

S0a1a2……an#

#

(2)一般格局:

S0S1……Smaiai+1……an#

#X1……Xm

 对于一般格局情况,应查分析表[Sm,ai],按表中的规定分为3种情况:

①Action[Sm,ai]=S,表示移入,即符号ai进入符号栈,再查Goto[Sm,ai]=Sm+1,形成新的格局:

 S0S1……SmSm+1ai+1……an#

#X1……Xmai

 ②Action[Sm,ai]=rj,且第j个产生式为A->Xm-r+1……Xm,表示归约,即符号栈中的n项符号Xm-r+1……Xm归约为A,形成格局:

S0S1……Sm-rai+1……an#

#X1……Xmai

 查Goto表,Goto[Sm-r,A]=Sk,把Sk状态添入状态栈,形成格局:

S0S1……Sm-rSkai+1……an#

#X1……Xm-rai

(3)接受格局:

S0Sz#

#Z

对于一般格局情况,应查分析表Action[Sz,#]=Acc,表示接受状态,分析结束。

(三)LR总控程序算法。

将初始状态S0置于语法分析器的栈顶,输入串ω#放入缓冲区,S是栈顶状态,a为指针p指向的符号。

总控算法如下:

指针p指向第一个符号

While

(1)

{

If(Action[s,a]=S移入)

{

查goto表goto[s,a]=s’

把a入符号栈,s’入状态栈

P指向下一个输入符号

}

elseif(action[s,a]=rj归约)//rj为A->β

{

栈顶退掉β个字符,

符号栈A入栈

查Goto表Goto[Sm,A]=Sm+1;

Sm+1入栈;

}

elseif(action[S,a]=accept)

return

else

error();

}

3.4.语法树构造模块

3.4.1.类图

CTreeDlg类是由基类CresizingDialog所派生,它是一颗句子归约的语法树,根据具体的文法和句子而定。

CTreeDlg类图如图3-6所示。

图3-6CTreeDlg类图

3.4.2.语法树构造函数

voidCLR0ForWinDlg:

:

DoDataExchange(CDataExchange*pDX)

{

CDialog:

:

DoDataExchange(pDX);

//{{AFX_DATA_MAP(CLR0ForWinDlg)

DDX_Control(pDX,IDC_VTLIST,m_vtlist);

DDX_Control(pDX,IDC_VTEDIT,m_vtedit);

DDX_Control(pDX,IDC_VNLIST,m_vnlist);

DDX_Control(pDX,IDC_VNEDI

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

当前位置:首页 > 高等教育 > 军事

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

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