编译原理求first和follow代码实现并打印预测分析表

编译原理求first和follow代码实现并打印预测分析表

filename=input("请输入要打开的文件名:")

with open(filename,'r',encoding='utf-8')as file:
    lines=file.readlines()

Predictions = [line.strip() for line in lines]
print(f'从文件中读取的规则:\n{Predictions}\n')


#找出终结符和非终结符
Vt=[]
Vn=[]

begin = Predictions[0]
BEGIN = begin[0]

for rule in Predictions:
    left,right = rule.split('->')
    #左边加入非终结符
    for lefts in left:
        if lefts.isupper() and lefts not in Vn:
            Vn.append(lefts)
    #右边加入终结符
    for rights in right:
        #if  rights.islower() and lefts != '->' and lefts !='ε' and rights not in Vt:
        if not rights.isupper() and rights != 'ε' and rights != '->' and rights not in Vt:
          Vt.append(rights)
print("非终结符列表:",Vn)
print("终结符列表",Vt)


def checkEmpty(v):
    global Predictions
    for i in Predictions:
        production=i.split('->')
       # print(production)  ['E', 'TA']
        if production[0] == v and production[1]=='ε':
            return  True
    return False

def addInsert(arr,v):
    flag=False
    if type(v)==str:
        if v not in arr:
            arr.append(v)
            flag = True
    else:
        for a in v:
            if a not in arr:
                flag=True
                arr.append(a)
    return flag

def getFirst():
    global Predictions, Vt, Vn
    first = {}
    for i in Predictions:
        first[i.split('->')[0]] = []#如first[S]=[]
    while True:
        flag = False
        for i in Predictions:
            key = i.split('->')[0]
            temp = i.split('->')
            # print(temp) ['S','bBZ']  temp[0]为左部,temp[1]为右部 ,
            r1 = temp[1][0]
            if r1 in Vt or r1 == 'ε':
                if addInsert(first[key], r1) == True:
                    flag = True
            if r1 in Vn:
                empty = 0
                for t in i.split('->')[1]:
                    if t in Vn:
                        if addInsert(first[key], [_ for _ in first[t] if _ != 'ε']):
                            flag = True
                        if checkEmpty(t) == False:
                            break
                        else:
                            empty += 1
                    else:
                        break
                if empty == len(i.split('->')[1]):
                    if addInsert(first[key], 'ε') == True:
                        flag = True
        if flag == False:
            break
    #print(first)
    return first

def getFollow(first):
    follow = {}
    global Predictions,begin
    for v in Vn:
        if v == BEGIN:
            follow[v]=set('#')
        else:
            follow[v]=set()
    while True:
        flag1=False
        for i in Predictions:#遍历所有的规则,然后对规则进行处理
            left = i.split('->')[0]
            right = i.split('->')[1]
            for index in range(len(right)):#遍历规则有部分的符号
                if right[index] in Vt or 'ε' in right[index]:
                    continue
                if index == (len(right) - 1):
                    for i in follow[left]:
                        lg = len(follow[right[index]])
                        follow[right[index]].add(i)
                        if lg < len(follow[right[index]]):
                            flag1 = True
                else:
                    if right[index + 1] in Vt: #如果有部分的符号为终结符
                        #将终结符添加到当前符号的FOLLOW集中
                        follow[right[index]].add(right[index + 1])
                        lg = len(follow[right[index]])
                        if lg < len(follow[right[index]]):
                            flag1 = True
                    else:
                    #如果右部的当前符号后面紧跟着一个非终结符,则将该非终结符的FIRST集中不包含空(ε)的符号添加到当前符号的FOLLOW集中
                    #遍历该非终结符的FIRST集中的每个符号,如果符号不是空(ε),则将其添加到当前符号的FOLLOW集中
                        for i in first[right[index + 1]]:
                            if i != 'ε':
                                follow[right[index]].add(i)
                                lg = len(follow[right[index]])
                                if lg < len(follow[right[index]]):
                                    flag1 = True
                    # 设置一个标志flag变量用于判断当前符号的后续符号是否都可以添加到FOLLOW集中
                    flag = False
                    #如果右部的当前符号后面的所有符号的FIRST集都包含空(ε)则将左部非终结符的FOLLOW集添加到当前符号的FOLLOW集中。
                    for _ in right[index + 1:]:
                        if (_ in Vt) or ('ε' not in first[_]):
                            flag = True
                    if flag == False:
                        for _ in follow[left]:
                            follow[right[index]].add(_)
                            lg = len(follow[right[index]])
                            if lg < len(follow[right[index]]):
                                flag1 = True
        if flag1 == False:
            break
    print(follow)
    return follow
def getSELECT(production, first, follow):
    select = set()
    left, right = production.split('->')
    #第一种情况如果右部包含空(ε),则将左部的 FOLLOW 集合中不包含空(ε)的符号添加到 SELECT 集合中。
    if 'ε' in right:
        select |= follow[left] - set(['ε'])

    for symbol in right:
        #第二种情况
        if symbol in first:
            select =select.union(set([_ for _ in first[symbol] if _ != 'ε']))
            if 'ε' not in first[symbol]:
                break
        else:
            #如果不在first中,就说明不能退出空
            select =select.union(set([symbol]))
            break
    select-=set('ε')
    return select

if __name__=='__main__':
    First=getFirst()
    Follow=getFollow(First)
    ru = Predictions[0]
    s = ru[0]
    print("FIRST集:")
    for k in Vn:
        print('     FIRST[', k, ']: ', First[k])
    print("FOLLOW集:")
    for k in Vn:
        print('     FOLLOW[', k, ']: ', Follow[k])
    print("SELECT集:")
    for production in Predictions:
        select = getSELECT(production, First, Follow)
        print('     SELECT[', production, ']: ', select)
        #print(select)


    # 将 '#' 添加到终结符列表 Vt 中
    Vt.append('#')

    # 构造预测分析表
    predict_table = {}
    for non_terminal in Vn:
        predict_table[non_terminal] = {}
        for terminal in Vt:
            predict_table[non_terminal][terminal] = set()#为每一个非终结符添加集合
            print('222',predict_table)
    for production in Predictions:
        left, right = production.split('->')
        select = getSELECT(production, First, Follow)
        for terminal in select:
            if terminal != 'ε':
                predict_table[left][terminal].add(production)
                #print('333',predict_table)
        if 'ε' in select:
            for terminal in Follow[left]:
                predict_table[left][terminal].add(production)
    # 打印预测分析表
    print("预测分析表:")
    print("  ", end="")
    for terminal in Vt:
        print(f"{terminal:^10}", end="")
    print()
    for non_terminal in Vn:
        print(f"{non_terminal:<2}", end="")
        for terminal in Vt:
            if predict_table[non_terminal][terminal]:
                print(f"{str(predict_table[non_terminal][terminal]):^10}", end="")
            else:
                print(f"{'':^10}", end="")
        print()

    #写入文件
    with open("follows.txt", "w+") as wp:
        for k in Follow:
            wp.write("follow(%s): \t" % k)
            wp.write("%s\n" % Follow[k])
    #写入文件
    with open("first.txt", "w+") as wp:
        for k in Follow:
            wp.write("follow(%s): \t" % k)
            wp.write("%s\n" % First[k])
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

不归路&

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值