一、试验名称
LL(1)文法的判断及转换
二、试验目标
输出:任意一个文法
输入:(1)是否为LL(1)文法
(2)若是,给出每条产生式的select集
(3)若不是,看看是否含有左公共因子或者含有左递归,并用相应的办法将非 LL(1)文法变成LL(1)文法,并输入新文法中每条产生式的select集。
三、试验原理
1、First集定义
令X为一个文法符号(终止符或非终止符)或,则汇合First(X)有终止符组成,此外可能还有,它的定义如下:
\1. 若X是终止符或,则First(X)= {X}。
\2. 若X是非终结符,则对于每个产生式X—>X1X2…Xn,First(X)蕴含了First(X1)-{}。 若对于某个i < n,所有的汇合First(X1),... ,First(Xi)都蕴含了,则First(X)也包 括了First(Xi+1)- {}。若所有汇合First(X1),...,First(Xn)都包含了,则First(X)也包含了。
2、Follow集定义
给出一个非终结符A,那么汇合Follow(A)则是由终结符组成,此外可能还含有#(#是题目约定的字符串结束符)。汇合Follow(A)的定义如下:
\1. 若A是开始符号,则#在Follow(A)中。
\2. 若存在产生式B—>A,则First()- {}在Follow(A)中。
\3. 若存在产生式B—>A,且在First()中,则Follow(A)包含Follow(B)。
3、Select集定义
对于产生式A—>。汇合select(A—>)定义如下:
\1. 若不能推出,则select(A—>) = first()。
\2. 若能推出,则select(A—>)= first()∪ follow(A)。
4、含左递归文法
一个文法G,若存在P通过一次或屡次推导失去Pa(即能推导出以P结尾的式子), 则称G是左递归的。
左递归分为间接左递归和间接左递归。
间接左递归通过一次推导就能够看出文法存在左递归,如P→Pa|b。
间接左递归侧需屡次推导才能够看出文法存在左递归,如文法:S→Qc|c,Q→Rb|b,R→Sa|a有S =>Qc =>Rbc =>Sabc
四、试验思路
本次试验采纳python实现。
1、求非终结符是否能导出空
a. 第一轮扫描。以后的产生式还没被删除,非终结符lp能够导出空,将以该非终结符为左部的产生式标记为要删除的。产生式右局部解,若该产生式右部蕴含终结符,删除该产生式因为由它不会导出空。判断没有被删除的产生式中是否还有以该非终结符为左部的产生式。
b. 第二轮扫描。逐个扫描每一条产生右部的每一个符号,循化直至每个非终结符的状态都确定下来。
2、求First集算法
存储每一个非终结符对应的First集,扫描每一条产生式,记录每一轮扫描是每个非终结符First集是否增大过。全副初始化为没有增大的状态,对于课本的五种类型顺次求解,每次将后果退出对应的汇合中,若一次扫描First集没有增大,则阐明循环完结。
3、求Follow集算法
存储每一个非终结符对应的Follow集,将'#'退出文法的开始符号的Follow汇合中,记录每一轮扫描是每个非终结符Follow汇合是否增大过,全副初始化为没有增大的状态,扫描每一条产生式的右部,扫描到非终结符,判断在该非终结符之后的子串是否推导空,若该符号串能够推导出空,还要将Follow(lp)退出到外面。
4、求Select集算法
初始化每条产生式对应的Select汇合为空,若产生式右部不能推导出空,则将右部的First集退出Select集,如果能够推出空,则须要同时将左部的Follow汇合右部的First集去掉空的局部退出Select集。
五、试验小结
通过本次试验,晓得了如何判断一个文法是不是LL(1)文法,同时对于First、Follow以及Select集的求解原理变得更加相熟,并且晓得了如何用计算机语言求解First,Follow以及Select集。不足之处是,没有实现判断文法是否为左递归文法以及左递归文法的转换局部。
六、附件
1、源代码
class Gw: def __init__(self): with open('D:\\test\\Gw.txt') as f: content = f.readlines() content = [line.strip() for line in content] self.Vn = content[0].split(' ') self.Vt = content[1].split(' ') self.start = content[2] self.produce = [] self.left = [] self.right = [] for i in range(3,len(content)): self.produce.append(content[i]) self.left.append(content[i].split('->')[0]) self.right.append(content[i].split('->')[1]) def showGw(self): print('非终结符:',self.Vn) print('终 结 符:',self.Vt) print('开始符号:',self.start) print('产生式如下:') for l,r in zip(self.left,self.right): print(l+'->'+r) def canEmpty(self): self.isEmpty = dict() for i in range(len(self.Vn)): self.isEmpty[self.Vn[i]] = -1 print(self.isEmpty) temp = self.produce[::] deleteIndex=[] pointer = 0 while pointer<len(temp): if pointer not in deleteIndex: lp = temp[pointer].split('->')[0] rp = temp[pointer].split('->')[1] if rp=='!': self.isEmpty[lp] = 1 for i in range(len(temp)): if temp[i].split('->')[0]==lp and i not in deleteIndex: deleteIndex.append(i) l = list(rp) isContainVt = [i in self.Vt for i in l] if True in isContainVt: deleteIndex.append(pointer) for k in range(len(temp)): if k not in deleteIndex: if temp[k].split('->')[0]==lp: break else: self.isEmpty[lp] = 0 pointer = pointer+1 while -1 in self.isEmpty.values(): for i in range(len(temp)): if i not in deleteIndex: lp = temp[i].split('->')[0] rp = temp[i].split('->')[1] rlsit = list(rp) for j in range(len(rlsit)): if self.isEmpty[rlsit[j]]==1: if j==len(rlsit)-1: self.isEmpty[lp]=1 elif self.isEmpty[rlsit[j]]==0: deleteIndex.append(i) for k in range(len(temp)): if k not in deleteIndex: if temp[k].split('->')[0]==lp: break else: self.isEmpty[lp] = 0 else: continue def show(self): print('非终结符是否推导出空的信息:') for v in self.Vn: if self.isEmpty[v]==1: yon = '是' else: yon = '否' print('%s:%s'%(v,yon)) def getFirst(self): self.First = dict() for i in self.Vn: self.First[i] = list() isChange = dict() while True: for k in self.Vn: isChange[k] = 0 for i in range(len(self.produce)): lp = self.produce[i].split('->')[0] rp = self.produce[i].split('->')[1] rlist = list(rp) if rlist[0]=='!' or rlist[0] in self.Vt: if rlist[0] not in self.First[lp]: self.First[lp].append(rlist[0]) isChange[lp]=1 else: for j in rlist: if j in self.Vn: if self.isEmpty[j]==1: oldsize = len(self.First[lp]) templist = self.First[j][::] if '!' in templist: templist.remove('!') for x in templist: if x not in self.First[lp]: self.First[lp].append(x) if rp.endswith(j) and '!' not in self.First[lp]: self.First[lp].append('!') newsize = len(self.First[lp]) if oldsize!=newsize: isChange[lp]=1 else: oldsize = len(self.First[lp]) if j in self.Vn: templist = self.First[j][::] for x in templist: if x not in self.First[lp]: self.First[lp].append(x) else: if j not in self.First[lp]: self.First[lp].append(x) newsize = len(self.First[lp]) if oldsize!=newsize: isChange[lp]=1 break if 1 not in isChange.values(): print('First汇合不再增大!') break else: print('First汇合有增大!') pass def showFirst(self): print('First汇合信息:') for v in self.Vn: print(v,self.First[v]) def canCauseEmpty(self,plist): first = list() if len(plist)==0: first.append('!') else: for i in plist: if i in self.Vn: if self.isEmpty[i]==1: t = self.First[i][::] if '!' in t: t.remove('!') for k in t: if k not in first: first.append(k) if ''.join(plist).endswith(i) and '!' not in first: first.append('!') else: for k in self.First[i]: if k not in first: first.append(k) break else: if i not in first: first.append(i) break return first def getFollow(self): self.Follow = dict() for i in self.Vn: self.Follow[i] = list() self.Follow[self.start].append('#') isChange = dict() while True: for k in self.Vn: isChange[k] = 0 for i in range(len(self.produce)): lp = self.produce[i].split('->')[0] rp = self.produce[i].split('->')[1] rlist = list(rp) for j in range(len(rlist)): if rlist[j] in self.Vn: reslist = self.canCauseEmpty(rlist[j+1::]) if '!' in reslist: oldsize = len(self.Follow[rlist[j]]) for y in self.Follow[lp]: if y not in self.Follow[rlist[j]]: self.Follow[rlist[j]].append(y) newsize = len(self.Follow[rlist[j]]) if oldsize!=newsize: isChange[rlist[j]] = 1 else: pass oldsize = len(self.Follow[rlist[j]]) for x in reslist: if x!='!' and x not in self.Follow[rlist[j]]: self.Follow[rlist[j]].append(x) newsize = len(self.Follow[rlist[j]]) if oldsize!=newsize: isChange[rlist[j]] = 1 if 1 not in isChange.values(): break def showFollow(self): print('Follow汇合信息:') for key in self.Vn: print(key,self.Follow[key]) def getSelect(self): self.Select = dict() for i in self.produce: self.Select[i] = list() for i in range(len(self.produce)): lp = self.produce[i].split('->')[0] rp = self.produce[i].split('->')[1] rlist = list(rp) if rlist[0]=='!': for v in self.Follow[lp]: if v not in self.Select[self.produce[i]]: self.Select[self.produce[i]].append(v) elif rlist[0] in self.Vt: self.Select[self.produce[i]].append(rlist[0]) else: res = self.canCauseEmpty(rlist) if '!' not in res: for v in res: if v not in self.Select[self.produce[i]]: self.Select[self.produce[i]].append(v) else: for v in res: if v not in self.Select[self.produce[i]] and v!='!': self.Select[self.produce[i]].append(v) for v in self.Follow[lp]: if v not in self.Select[self.produce[i]]: self.Select[self.produce[i]].append(v) def showSelect(self): print('Select汇合信息:') for key in self.produce: print(key,self.Select[key]) def isLLone(self): isright = [] for k in self.Vn: tset = set() tset.add('#') tset = tset | set(self.Vt) for l,r in zip(self.left,self.right): if k==l: p = l+'->'+r tset = tset & set(self.Select[p]) if len(tset)==0: isright.append(1) else: isright.append(0) if 0 in isright: print('不是LL(1)文法!') self.isll1 = False else: print('是LL(1)文法!') self.isll1 = True print(isright)if __name__=='__main__': w = Gw() #w.showGw() #文件中读到的内容 w.canEmpty() w.show() w.getFirst() w.showFirst() w.getFollow() #res = w.canCauseEmpty(['A','D']) #print('res=',res) w.showFollow() w.getSelect() w.showSelect() w.isLLone()
2、运行后果截图
输出:
文法的判断及转换/2.png)
输入:
文法的判断及转换/1.png)