乐趣区

关于程序员:LL1文法的判断及转换

一、试验名称

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

 

 

 


退出移动版