编译原理实验自动生成LR0分析表Word文档格式.docx
- 文档编号:17914640
- 上传时间:2022-12-12
- 格式:DOCX
- 页数:11
- 大小:79.54KB
编译原理实验自动生成LR0分析表Word文档格式.docx
《编译原理实验自动生成LR0分析表Word文档格式.docx》由会员分享,可在线阅读,更多相关《编译原理实验自动生成LR0分析表Word文档格式.docx(11页珍藏版)》请在冰豆网上搜索。
其中,假定A→α为文法G'
的第j个产生式
c.若项目S'
→S.属于Ik,则置ACTION[k,#]为“接受”,简记为“acc”;
d.若GO(Ik,A)=Ij,A为非终结符,则置GOTO[k,A]=j;
e.分析表中凡不能用上述1至4填入信息的空白格均置上“出错标志”。
按上述算法构造的含有ACTION和GOTO两部分的分析表,如果每个入口不含多重定义,则称它为文法G的一张LR(0)分析表。
具有LR(0)表的文法G称为一个LR(0)文法,LR(0)文法是无二义的。
四、实验思路
本次实验采用python完成。
1、输入
构造一个LR类,输入非终结符,终结符,开始符以及产生式分别存于LR类的成员:
Vn,Vt,start,production。
2、建立项目
构造函数Project,根据产生式建立项目,对每一条产生式的右部进行处理,依次在右部的每个终结符和非终结符前添加原点,并在最后添加原点。
3、closure算法
构造函数closure,求一个项目的闭包closure。
分三种情况讨论,对于S->
·
和E->
a这两种情况,返回自身。
对于E->
b·
B这种情况,对项目的右部进行处理,继续求B->
r闭包,因此这是一个递归函数。
最终函数以列表的形式返回每个项目集。
4、转向函数GO(I,X)的算法
构造函数GO,求一个项目集的GO(I,X)。
建立字典go存放最终结果,对不是S->
a·
形式的项目进行讨论,对项目的右部进行处理,将原点后移一位,利用closure函数得到圆点后移得到的项目的项目集,加入go中。
直到处理完该项目集的所有项目。
5、建立状态及对应的项目集
构造函数createDFA,建立状态及对应的项目集。
首先,从拓广文法的第一个项目开始,建立初态,定义number存放状态编号,初始值为0。
设立字典status存放状态编号及对应的项目集。
将初态加入一个队列qu中。
每次从qu中取出一个状态,求该状态的项目集的Go(I,x),再对得到的项目集进行判断,若该项目集是已知的状态,则不做处理,若该项目集是新的状态,则将其加入队列qu中,number加1。
每次从qu中取出一个状态重复上述操作,直到队列为空,说明已求得所有状态。
6、ACTION子表的构造
分两种情况讨论:
项目集只有一个项目和项目集不止一个项目。
对于第一种情况,再分两种情况,看该项目是否对应了初态,若是,则将#对应为acc,其余终结符对应为error,若不是,则求得该项目去掉圆点之后的产生式的编号i,终结符合#对应为ri。
对于项目集不止一个项目的情况,依次对终结符和#寻找在该状态的的GO(I,X)下是否有所对应,有则求得编号对应为Si,没有则对于error。
7、GOTO子表的构造
对于每个状态的GO(I,X)函数进行遍历,寻找是否有对应的终结符,若有则返回对应的项目集的编号,若没有则返回error。
五、实验小结
通过本次实验,了解了LR(0)分析表的构造,对于构造过程所需要的一些算法有了深入的了解,通过实际的编写程序代码完成LR(0)分析表的构造,对于程序的编写能力有了一定的提升。
在实验过程中,主要对于closure闭包函数的构造以及状态的设置有问题。
Closure闭包函数用了递归的结构,因此对于递归的结束条件需要标注清楚。
对于状态的建立,需要注意每次通过GO(I,X)得到的新的项目集是否是已经存在的状态,若是则不做处理。
对于状态的遍历使用队列来完成,每次新的状态都加入队列中,队列为空说明状态遍历完毕。
有一点问题值得注意,由于状态编号的项目集的存储结构使用了字典,字典是无序的结构,因此每次遍历得到的状态编号都不同,程序的每次运行得到的最终LR(0)分析表不唯一。
六、附件
1、源代码
importcopy
importqueue
classLR:
def__init__(self):
self.Vn=[]
self.Vt=[]
self.start=None#开始符号
self.production=[]#产生式
self.project=[]#项目
self.status={}#存放状态编号及对应的项目集
self.goto={}#存放goto表{0:
{E:
'
1'
A:
error'
B:
}}
self.action={}#存放action表{0:
{a:
S2'
b:
S3'
defsetVn(self):
Vn=input('
输入非终结符(以空格区分,回车结束):
)
self.Vn=Vn.split('
'
defsetVt(self):
Vt=input('
输入终结符(以空格区分,回车结束):
self.Vt=Vt.split('
defsetS(self):
S=input('
输入开始符号(以回车结束):
self.start=S
defsetf(self):
#生成产生式
n=int(input('
输入产生式数目:
))
print('
输入产生式(以回车区分):
foriinrange(n):
f=input()
self.production.append(f)
defProject(self):
#建立项目
forfinself.production:
temporary=copy.deepcopy(f)#temporary与f相同
temporary=temporary.split('
->
l=temporary[0]#产生式左部
r=list(temporary[1])#产生式右部
foriinrange(len(r)+1):
#对产生式右部处理
temporary1=copy.deepcopy(r)
temporary1.insert(i,'
newf=l+'
+'
.join(temporary1)
self.project.append(newf)
defclosure(self,pro):
#求一个项目pro的闭包E->
E->
bE->
B返回列表
temporary=[]#最终返回的结果
temporary.append(pro)#将pro自身加入
l1=pro.split('
)[0]#左部
r1=pro.split('
)[1]#右部
x=list(r1)#存放右部的列表
index=x.index('
)#得到圆点位置
iflen(x)==1:
#S->
returntemporary
else:
ifindex==len(r1)-1orx[index+1]inself.Vt:
#E->
a
#E->
B
foreleminrange(len(self.project)):
l=self.project[elem].split('
r=self.project[elem].split('
ifl==x[index+1]andr.startswith('
):
#继续求B->
r闭包
conlist=self.closure(self.project[elem])
iflen(conlist)==0:
pass
temporary.extend(conlist)
defGO(self,project):
#计算一个项目集的GO(I,x),返回字典形式
go={}#存放Go(I,x)结果,形式为{a:
[],b:
[]}
foreleminproject:
l=elem.split('
)[0]#项目左部
r=elem.split('
)[1]#项目右部
index=list(r).index('
)#返回·
的位置
ifnotr.endswith('
#不是S->
形式
ifgo.get(list(r)[index+1])==None:
#说明x所对应的go中没有项目
temporary=list(r)
temporary.insert(index+2,'
temporary.remove('
)#将·
后移一位
x=l+'
.join(temporary)#产生一个完整的项目
go[list(r)[index+1]]=self.closure(x)#将该项目对应的项目集加入x的go中
#说明x所对应的go中已有项目
temporary.insert(index+2,'
go[list(r)[index+1]].extend(self.closure(x))
returngo
defcreateDFA(self):
#建立识别活前缀的DFA
number=0#初始状态编号为0
first='
S->
+self.start#初态
x=self.closure(first)#初态闭包
self.status[number]=x
qu=queue.Queue()#构造队列,用于存放得到的状态
qu.put({number:
self.status[number]})#把初始状态加入队列中
number=number+1
whilenotqu.empty():
#队列不为空,说明状态没有遍历完毕
temporary=qu.get()#队列中取出一个状态
fork,vintemporary.items():
y=self.GO(v)#求项目集的Go(I,x)
forkey,valueiny.items():
flag=-1#标志位,判断value是否是新的状态
forke,vainself.status.items():
ifset(va)==set(value):
flag=ke#状态已存在,返回状态编号
break
ifflag==-1:
#新的状态,加入状态集中
self.status[number]=value
self.status[number]})
#已有状态
pass#不作处理
defGOTO(self):
#goto表
foriinrange(len(self.status)):
self.goto[i]={}
temp=self.GO(self.status[i])#每个状态的GO
forvninself.Vn:
#对非终结符遍历
ifvnintemp.keys():
#非终结符存在于状态的Go中
forkey,valueinself.status.items():
ifset(value)==set(temp[vn]):
number=key#记录编号
self.goto[i][vn]=number
self.goto[i][vn]='
defACTION(self):
vtx=copy.deepcopy(self.Vt)
vtx.append('
#'
)#终结符加‘#’
self.action[i]={}
iflen(self.status[i])==1:
#项目集只有一个项目
ifself.status[i][0].startswith('
S'
E·
forvtinself.Vt:
self.action[i][vt]='
self.action[i]['
]='
acc'
#填写rj的项目E->
aA·
temp=self.status[i][0].rstrip('
)#删去项目的·
aA
forninrange(len(self.production)):
ifself.production[n]==temp:
m=n+1#产生式在G'
中下标从1开始
forvtinvtx:
r'
+str(m)
#填写Sj的项目
temp=self.GO(self.status[i])#字典形式{a:
ifvtintemp.keys():
#确定到哪一个状态
ifset(value)==set(temp[vt]):
number=key#返回状态编号
+str(number)
defoutput(self):
#输出LR(0)分析表表格形式
LR(0)分析表'
.center(85))
状态'
.center(5),'
ACTION'
.center(50),'
GOTO'
.center(30))
.center(10),end='
#action
print(vt.center(10),end='
#goto
print(vn.center(10),end='
print()#换行
#输出每一行
print(str(i).center(10),end='
forkeyinself.action[i]:
#{0:
{'
b'
:
S1'
ifvt==key:
print(self.action[i][key].center(10),end='
forkeyinself.goto[i]:
ifvn==key:
print(str(self.goto[i][key]).center(10),end='
defshow(self):
#显示各个状态及对应的项目集
所有状态及对应的项目集:
print(key,value)
if__name__=='
__main__'
E21414020陈国柱'
a=LR()
a.setVn()
a.setVt()
a.setS()
a.setf()
a.Project()
a.createDFA()
a.ACTION()
a.GOTO()
a.show()
a.output()
2、运行结果截图
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 编译 原理 实验 自动 生成 LR0 分析
![提示](https://static.bdocx.com/images/bang_tan.gif)