LL(1)文法的判断及转换

一、实验名称

​ 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')[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)

 

 

 


你可能感兴趣的:(程序员)