Python-求First、Follow、select集合以及预测分析表和表驱动程序;

VT代表终结符集合
VN代表非终结符集合

一、求First集合:

求first集很简单

求解FIRST(X)
1)若X ∈ VT,则FIRST(X) = {X}。【终结符自己就是自己的FIRST集合】
2)若X ∈ VN,且有产生式X → a……, a ∈ VT,则a ∈ FIRST(X) 【非终结符,选第一个终结符加入】
3)若X ∈ VN,X → ε,则 ε ∈ FIRST(X) 【能直接推出ε,ε加入FIRST】
4)若X,Y1,Y2,……,Yn ∈ VN,而有产生式X → Y1,Y2,……,Yn。
当Y1,Y2,……,Y(i-1) 直接推出ε时,则FIRST(Y1) - ε, FIRST(Y2) - ε, …… , FIRST(Y(i-1) - ε) ,FIRST(Yi) 都包含在FIRST(X)中【中间的ε是不会加入进去的】
5)当4)中所有Yi 都推出 ε时,则最后的FIRST(X) = FIRST(Y1) ∪ FIRST(Y2) ∪ …… ∪ FIRST(Yn) ∪ {ε}

二、求Follow集合:

求follo集合比较麻烦,遇到很多坑点。
奈何老师东哥很严,再麻烦也得弄…

1)S是文法开始符号,初始化follow(S)= {  #  }
2)	D --+--> BAC        follow(A)+=first(C)/ @
3)如果上述产生式D--+-->BAC 中,存在C->@,即  D--+-->BA  ,那么还要进行follow(A)+=  follow(B)
坑点1:注意S --+-->BAC ,如果C能为空,那么要将其看成S --+-->BA ,S --+-->BAC两种情况
坑点2:
如果出现循环引用:follow(A)=follow(B) +…  而follow(B) = follow(A)这种情况:
原则上是要继续使用上述规则,直到每个Vn的follow集合不再变化为止,
然后让循环调用的follow集赋值为空,但具体很难办,就直接用下面的的做法:
如果遇到:S ---> BA,且S是开始符 ,
那么follow(A)={ # } 而不是 follow(A)=follow(S)

三、求Select集合:

A->B,A属于Vn,
若B不能推导出空,那么select(A->B) = first(B)
如果B经过有限次推导能推出空,那么那么select(A->B) = first(B) - 空  ∪ Follow(A)

四、预测分析表:

根据select集合来求

五、表驱动分析程序:

整体代码:

input.txt文件内容
E -> TA
A -> +TA
A -> @
T -> FB
B -> *FB
B -> @
F -> i
F -> (E)

```python
# !/usr/bin/env python
# -*- coding: utf-8 -*-
# @Author : WangRay
# @Software: PyCharm
def getOriginData():
    tranformFunctionData = {}
    Vn = []
    Vt = []
    with open("input.txt", 'r+', encoding="utf-8") as f:
        temp = f.readlines()
    for ind,i  in enumerate(temp):
        t = i[:-1].split(" ") #去掉换行 E -> TA
        if ind == 0: # 默认第一个Vn是开始符
            S =  i[0]
        x = tranformFunctionData.get(t[0],None)
        if x :
            x.append(t[2])
            tranformFunctionData.update( { t[0] : x } )
        else:
            tranformFunctionData[ t[0] ] = [ t[2] ]  #加入 {E : [TA,]}
        if( 'A'<=t[0] <='Z'):
            Vn.append(t[0])
        else:
            Vt.append(t[0])
        for tx in t[2]:
            if( 'A'<= tx <='Z'):
                Vn.append(tx)
            else:
                Vt.append(tx)
    Vn = getOnly(Vn)
    Vt = getOnly(Vt)
    return (Vn,Vt,tranformFunctionData,S)
def getOnly(l):
    n = []
    for x in l:
        if x not in n :
            n.append(x)
    return n
class MyChart():
    def __init__(self, mystr):
        self.mstr = mystr  # 输入的句子
        self.Vn = []  # 非终结符
        self.Vt = []  # 终结符
        tranformFunctionData = {}
        self.S = None  # 开始符
        self.first = {}  # first集合,是一个map对象,元素是"V":{ }
        self.follow = {}  # follow集合,也是一个map对象
        self.select = {}  # select集合,也是一个map对象,每个对象key是Vn;Value是一个map={"产生式","Vt集合"},{ F : { "->i" : "i" , "->(E)":"(" }  }
        self.analysisTable = []
        self.initFirstAndFollow()
        self.getFollow(self.S)
        self.getselect()
        self.row = []
        self.column = []
        self.initAnalysisTableData()
        print("预测分析表:")
        for i in self.analysisTable:
            print(i)
        print()

    def doAnaysis(self):
        myStack = ["#", self.S]
        X = myStack[-1]
        ind = 0
        a = self.mstr[ind]
        ind += 1
        while myStack:
            if X in self.Vt:
                if X == a:
                    a = self.mstr[ind]
                    ind += 1
                    myStack.pop()
                    X = myStack[-1]
                else:
                    return "error,经判断" + self.mstr + "不是符合该文法的句子"
            else:
                if X == "#":
                    if X == a:
                        return "success,经判断" + self.mstr + "是符合该文法的句子"
                    else:
                        return "error,经判断" + self.mstr + "不是符合该文法的句子"
                else:
                    prod = self.getProd(X, a)
                    if prod == "#":  # 没有对应产生式
                        return "error,经判断" + self.mstr + "不是符合该文法的句子"
                    else:  # 存在对应产生式
                        myStack.pop()
                        temp = prod[:1:-1]
                        if temp != "@":
                            myStack.extend(temp)  #
                        X = myStack[-1]

    def getselect(self):
        for k in self.tranformFunctionData.keys():  # k是Vn,E A T B F
            for prod in self.tranformFunctionData.get(k):  # prod 是Vn k=F 对应的产生式["i","(E)"]
                # 对于一个k->prod,检查prod的组成元素Vn集合,能不能同时都变成@,
                if self.checkIfTranfToKong(prod) == 1:  # 等于1表示全都能变成@
                    # 若能:tempS = prod[0]的first集合除去空∪follow(k)
                    temps = self.first.get(prod[0]).replace("@", "") + self.follow.get(k)
                else:
                    # 否则:tempS = prod[0]的first集合
                    temps = self.first.get(prod[0])
                prodToTemps = self.select.get(k, None)
                if prodToTemps is None:
                    self.select.update({k: {"->" + prod: temps}})
                else:
                    self.select.get(k).update({"->" + prod: temps})

    def checkIfTranfToKong(self, prod):
        for i in prod:  # 遍历 (E) 的每一个Vn/Vt,但凡有一个是Vt(不是空)或者有一个Vn的first不包含@,那么返回-1
            if i == "@":
                continue
            if i in self.Vt:
                return -1
            elif "@" not in self.first.get(i):
                return -1
        return 1

    def initAnalysisTableData(self):
        self.row = self.Vn.copy()
        self.column = self.Vt.copy()
        self.column.remove("@")
        self.column.append("#")
        for tempVn in self.row:  # 拿到行标
            T = self.getRowColumnPrdo(tempVn)
            self.analysisTable.append(T)

    def getRowColumnPrdo(self, tempVn):
        T = []
        for tempVt in self.column:
            mp = self.select.get(tempVn)  # {'->+TA': '+', '->@': '#)'}
            flag = 0
            for tk in mp.keys():
                if tempVt in mp.get(tk):
                    T.append(tk)
                    flag = 1
            if flag == 0:
                T.append("#")
        return T

    def getProd(self, X, a):
        x = self.row.index(X)
        y = self.column.index(a)
        return self.analysisTable[x][y]

    def initFirstAndFollow(self):
        (self.Vn, self.Vt, self.tranformFunctionData, self.S) = getOriginData()
        for t in self.Vn + self.Vt:
            if t in self.Vt:
                self.first.update({t: t})
            else:
                self.first.update({t: None})
                self.follow.update({t: ""})
        for t in self.Vn + self.Vt:
            self.getFisrt(t)
        for t in self.Vn:
            self.follow.update({t: self.getFollow(t)})

    def getFollow(self, T):
        x = self.follow.get(T)
        if x != "": return x
        if T == self.S:
            tempFollow = "#"
        else:
            tempFollow = ""
        for prodFromLeft in self.tranformFunctionData.keys():  # 遍历所有的左部 "A","P"  。 tranformFunctionData为  { "A":["+E" , "@"]  ,"P": [ "(E)","a","b","^" ]  }
            for prodFromRight in self.tranformFunctionData.get(
                    prodFromLeft):  # 遍历每个左部能够产生的右部"aTCA","TE","ABT","a","@"   ===>>> ["+E" , "@"]  [ "(E)","a","b","^" ]
                ind = prodFromRight.find(T)
                mylen = len(prodFromRight)
                if ind != -1 and mylen >= 2:  # 产生式右部满足T -> ABC的形式
                    if (ind == mylen - 1):
                        tempFollow = self.restart(tempFollow, prodFromLeft, T)
                    else:
                        tempFollow += self.first.get(prodFromRight[ind + 1]).replace("@", "")  # 除去 @ 符号

                        if (ind == mylen - 2 and prodFromRight[mylen - 1] in self.Vn and "@" in
                                self.tranformFunctionData[prodFromRight[mylen - 1]]):
                            tempFollow = self.restart(tempFollow, prodFromLeft, T)  # 进行反复传送
        return "".join(sorted(list(set(tempFollow))))

    # 求follow的反复传送函数
    def restart(self, tempFollow, prodFromLeft, T):
        if T == prodFromLeft: return tempFollow  # 有些产生式可能是 T -> aT ,这个时候不要再follow(T) = follow(T)了,会死循环
        if self.follow.get(prodFromLeft) == "" and prodFromLeft == self.S:
            tempFollow += "#"
        else:
            tempFollow += self.getFollow(prodFromLeft)
        return tempFollow

    # 求first集合
    def getFisrt(self, T):
        '''
        # 注意如果 T -> AB , A如果能产生@,那么firstB也属于First(T)
        :param T: 终结符或者非终结符
        :return String :  T的first集,
        '''
        x = self.first.get(T, None)
        if x:
            return x
        else:  # 为空,求了First,更新了self.first,再返回其first集
            tempFirst = ""
            for prodForm in self.tranformFunctionData[T]:  # 遍历所有它的产生式右部 T -> ["F" , "Ta" , "(E)" , "a" , @ ]
                tempFirst += self.getFisrt(prodForm[0])
                if len(prodForm) >= 2 and prodForm[1] in self.Vn and prodForm[0] in self.Vn and '@' in \
                        self.tranformFunctionData[prodForm[0]]:
                    tempFirst += self.getFisrt(prodForm[1])
            self.first.update({T: tempFirst})
            return tempFirst


if __name__ == "__main__":
    mstr = "i+i*i#"
    print("待判断的句子为:", mstr)
    mc = MyChart(mstr)
    print(mc.doAnaysis())


  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值