编译原理实验作业(语法分析预测分析法python实现)

Python3.8

Python3.8

Conda
Python

Python 是一种高级、解释型、通用的编程语言,以其简洁易读的语法而闻名,适用于广泛的应用,包括Web开发、数据分析、人工智能和自动化脚本

一、 实验名称:语法分析——预测分析法

二、实验目的:根据文法判断是否为LL(1)文法,是的话,构造预测分析表,再进行输入串的匹配。

三、实验步骤:

1.文法输入框内输入待判断的文法产生式,每个产生式一行,再进行数据入串的匹配。

2.分离终结符和非终结符,求First、Follow、Select集合。

3.判断Select集合相交是否为空。

4.构造预测分析表。

5.输入符号串进行匹配分析判断。

详细代码已给出:

from pandas import DataFrame
from copy import deepcopy
import sys ; sys.setrecursionlimit(sys.getrecursionlimit() * 5)
#打包:
#pyinstaller -F 编译原理.py
#pyinstaller 编译原理.spec
#codegex

strings = []
print("每个产生式一行,回车键换行,连按两次回车执行。例:S->aB,请依次输入:")
while True:
    line = input()
    if line == "":
        break
    strings.append(line)


#strings=["S->AB","S->bC","A->ε","A->b","B->ε","B->aD","C->AD","C->b","D->aS","D->c"]
#strings= ["S->AB","S->bC","A->ε","A->b","B->ε","B->aD","C->AD","C->b","D->aS","D->c"]
#strings= ["E->TE'","E'->+TE'","E'->ε","T->FT'","T'->*FT'","T'->ε","F->i","F->(E)"]
#strings = ["S->aH","H->aMd","H->d","M->Ab","M->ε","A->aM","A->e"]
#strings = ["E->TE'","E'->+E","E'->ε","T->FT'","T'->T","T'->ε","F->PF'","F'->*F'","F'->ε","P->(E)","P->a","P->b","P->^"]
#strings=["S->MH","S->a","H->LSo","H->ε","K->dML","K->ε","L->eHf","M->K","M->bLM"]

前=[]
后=[]
for i in strings:
    左侧,右侧 = i.split("->")
    前.append(左侧)
    后.append(右侧)
print("前:",前)
print("后:",后)

##空值表
非终结符 = [x for i, x in enumerate(前) if i == 前.index(x)]
终结符 = set()
A=""
f = False
for 产生式 in 后:
    for 字符 in 产生式[::-1]:
        if 字符 == "'":
            f = True
        if 字符 in 非终结符:
            if f == True:
                A = 字符 + "'"
                f = False
            else:
                A = 字符
        elif f == False:
            A = 字符
        if A not in 非终结符 and A!="":
            终结符.add(A)
print("非终结符:",非终结符)
print("终结符:",终结符)

#(1)
空值表 = {}

#(2)
# 1)
# 创建一个标记列表
删除标记 = [False] * len(后)
# 遍历并标记需要删除的元素
for i, 产生式 in enumerate(后):
    for 字符 in 产生式:
        if 字符 not in 非终结符 and 字符 != 'ε':
            删除标记[i] = True
            break
# 根据标记删除元素
前2 = [产生式 for i, 产生式 in enumerate(前) if not 删除标记[i]]
后2 = [产生式 for i, 产生式 in enumerate(后) if not 删除标记[i]]
for i in 非终结符:
    if i not in 前2:
        空值表[i]='否'

#2)
# 创建一个标记列表
删除标记 = [False] * len(后2)
删除值 = []
# 遍历并标记需要删除的元素
for i, 产生式 in enumerate(后2):
    for 字符 in 产生式:
        if 字符 == 'ε':
            删除标记[i] = True
            删除值.append(前2[i])
            空值表[前2[i]]='是'
            break
for i, 产生式 in enumerate(前2):
    if 产生式 in 删除值:
        删除标记[i] = True

# 根据标记删除元素
前2 = [产生式 for i, 产生式 in enumerate(前2) if not 删除标记[i]]
后2 = [产生式 for i, 产生式 in enumerate(后2) if not 删除标记[i]]


#(3)
删除标记 = [False] * len(后2)
while set(非终结符) != set(空值表.keys()):
    for i,产生式 in enumerate(后2):
        for 字符 in 产生式:
            if(字符 in 空值表):
                if 空值表[字符]=='是': #1)
                    后2[i] = 产生式.replace(字符, '')
                    if len(后2[i]) == 0:
                        空值表[前2[i]] = '是'
                        删除标记[i] = True
                elif 空值表[字符]=='否': #2)
                    空值表[前2[i]] = '否'
                    删除标记[i] = True
前2=[产生式 for i, 产生式 in enumerate(前2) if not 删除标记[i]]
后2=[产生式 for i, 产生式 in enumerate(后2) if not 删除标记[i]]

print("空值表",空值表)


# 初始化First集合并为每个非终结符赋空集合
First = {非终结符: set() for 非终结符 in 非终结符}
for i in list(终结符):
    First[i] = {i}
First后部={i: set() for i in 后}

# 遍历所有产生式
while True:
    temp = ""
    First2 = deepcopy(First)
    #print("First",First)
    #print("First2",First2)
    for i, 产生式 in enumerate(后):
        左部 = 前[i]
        右部 = 后[i]
        # 如果右部第一个字符是终结符,直接加入First集合
        if 右部[0] not in 非终结符:
            First[左部].add(右部[0])
            #print("右部第一个字符是终结符",左部,First[左部])
        else:
            # 遍历右部的每个字符
            for 字符 in 右部:
                # 如果字符是终结符,加入First集合并停止
                if 字符 not in 非终结符:
                    First[左部].add(字符)
                    #print("字符是终结符",左部,First[左部])
                    break
                # 如果字符是非终结符且能推导空字符串,继续检查下一个字符
                elif 空值表[字符] == '是':
                    First[左部].update(First[字符]-{'ε'})
                    #print("字符是非终结符且能推导空字符串",左部,First[左部],字符)
                # 如果字符是非终结符且不能推导空字符串,停止
                else:
                    First[左部].update(First[字符]-{'ε'})
                    #print("字符是非终结符且不能推导空字符串",左部,First[左部])
                    break
            # 如果所有字符都能推导空字符串,First集合中加入空字符串
            else:
                First[左部].add('ε')
    if First==First2:break
print("First  ")
for i in First:
    print(First[i])

后3 = []
for j, 产生式 in enumerate(后):
    i = 0
    后4 = []
    while i < len(产生式):
        if 产生式[i:i + 2] in 非终结符 and "'" in 产生式[i:i + 2]:
            A = 产生式[i:i + 2]
            i += 2  # 跳过下一个字符,因为我们已经处理了长度为2的非终结符
            # print(f";{A}", i)
        else:
            A = 产生式[i]
            i += 1
        后4.append(A)
    后3.append(后4)
#print(后3)
for k,产生式 in enumerate(后3):
    if 产生式[0] in 非终结符 and 空值表[产生式[0]]=='否':
        First后部[后[k]].update(First[产生式[0]])
        continue
    if 产生式[0] in 终结符 and 'ε' not in First[产生式[0]]:
        First后部[后[k]].update(First[产生式[0]])
        continue
    i=1
    j=0
    while i<=len(产生式)-1:
        #print(f"{产生式[i]}")
        while j<=i-1:
            if (产生式[i] in 非终结符 and 空值表[产生式[i]]=='否') or (产生式[i] in 终结符 and 'ε' not in First[产生式[i]]):
                if(产生式[j] in 非终结符 and 空值表[产生式[j]]=='是') or (产生式[j] in 终结符 and 'ε' in First[产生式[j]]):
                    First后部[后[k]].update(First[产生式[j]]-{'ε'})
                    #print(f"First后部[后[k]]={First后部[后[k]]}")
                First后部[后[k]].update(First[产生式[i]])
                #print(f"First后部[后[k]]={First后部[后[k]]}")
            j+=1
        i+=1
    if all(产生式[j] in 非终结符 and 空值表[产生式[j]]=='是' or 产生式[j] in 终结符 and 'ε' in First[产生式[j]] for j in range(0,len(产生式))):
        for j in range(0, len(产生式)):
            First后部[后[k]].update(First[产生式[j]])
            First后部[后[k]].update({'ε'})
print("First后部",First后部)
First.update(First后部)
#Follow
# 初始化Follow集合并为每个非终结符赋空集合
Follow = {非终结符: set() for 非终结符 in 非终结符}
Follow[前[0]].add('#')
A = ""
f = False

pattern='.?'+'['+''.join(非终结符) +']'+".+"
pattern2 = '.?'+'['+''.join(非终结符) +']'+".?"

while True:
    temp = ""
    Follow2 = deepcopy(Follow)
    for j,产生式 in enumerate(后):
        i = 0
        while i < len(产生式):
            if 产生式[i:i + 2] in 非终结符 and "'" in 产生式[i:i + 2]:
                A = 产生式[i:i + 2]
                i += 2  # 跳过下一个字符,因为我们已经处理了长度为2的非终结符
                #print(f";{A}", i)
            else:
                A = 产生式[i]
                i += 1

            if A in 非终结符:
                #print(f";;{A}", i)
                # 如果A是非终结符,且A后面有终结符,则将该符号的First非空集合添加到FOLLOW(A)中
                if i < len(产生式) and 产生式[i] in 终结符:
                    if('ε' in First[产生式[i]]):
                        F1 = First[产生式[i]].copy()
                        F1.discard('ε')
                        Follow[A].update(F1)
                    else:
                        Follow[A].update(First[产生式[i]])
                    #print(f"{产生式[i]}")
                # 如果A是非终结符,且A后面是非终结符,则将FOLLOW(B)的非空元素添加到FOLLOW(A)中
                elif i < len(产生式):
                    if 产生式[i:i + 2] in 非终结符 and "'" in 产生式[i:i + 2]:
                        B = 产生式[i:i + 2]
                    elif  产生式[i] in 非终结符:
                        B = 产生式[i]
                    #print(f"{A}$$${B}")
                    if (空值表[B] == '是'):
                        F2 = First[B].copy()
                        #print(f"F2={F2}   {B}")
                        F2.discard('ε')
                        Follow[A].update(F2)
                        #print(f"pppppppp{A}",First[B],F2)
                        #print(f"i={i}")
                        if i == len(产生式)-len(B):
                            # 如果A是非终结符,且A在产生式的末尾,则将FOLLOW(产生式的左部)添加到FOLLOW(A)中
                            Follow[A].update(Follow[前[j]])
                            #print(f"{A}在产生式的末尾{产生式[i:i + 2]}", A, Follow)
                    else:
                        Follow[A].update(First[B])
                        #print("@@@", Follow)

                # 如果A是非终结符,且A在产生式的末尾,则将FOLLOW(产生式的左部)添加到FOLLOW(A)中
                if i == len(产生式) and A in 非终结符:
                    #print("<<>>",A,前[j])
                    Follow[A].update(Follow[前[j]])
                    #print(f"{A}在产生式的末尾", Follow)
    if Follow == Follow2: break
print("Follow  ")
for i in Follow:
    print(Follow[i])
Select={i+"->"+j : set() for i,j in zip(前,后)}
'''
后3=[]
for j,产生式 in enumerate(后):
    i = 0
    后4=[]
    while i < len(产生式):
        if 产生式[i:i + 2] in 非终结符 and "'" in 产生式[i:i + 2]:
            A = 产生式[i:i + 2]
            i += 2  # 跳过下一个字符,因为我们已经处理了长度为2的非终结符
            # print(f";{A}", i)
        else:
            A = 产生式[i]
            i += 1
        后4.append(A)
    后3.append(后4)
'''
#print("First",First)
for i,产生式 in enumerate(后3):
    能否推空 = True
    for j,产生式2 in enumerate(产生式):
        if 产生式2 in 终结符 and 'ε' not in 产生式2:
            能否推空=False
            break
        elif 产生式2 in 非终结符 and 空值表[产生式2]=='否':
            能否推空=False
            break

    if 能否推空:
        F3=First[后[i]]
        F3.discard('ε')
        #print(后[i],F3)
        Select[前[i] + "->" + 后[i]].update(F3)
        Select[前[i] + "->" + 后[i]].update(Follow[前[i]])
        #print(Select[前[i] + "->" + 后[i]])
    else:
        Select[前[i] + "->" + 后[i]].update(First[后[i]])
#print(后3)

print("SELECT ")
for i in Select:
    print(Select[i])
第一列=[]
第二列=[]
第三列=[]
for i,式子 in enumerate(Select):
    #print(i,式子)
    第一列.append(式子.split("->")[0])
    第二列.append(式子.split("->")[1])
    第三列.append(Select[式子])
#print("第一列",第一列)
#print("第二列",第二列)
#print("第三列",第三列)
flag=True
for i in range(len(第一列)):
    for j in range(len(第一列)):
        if i!=j and 第一列[i]==第一列[j]:
            if 第三列[i]==第三列[j]:
                flag=False
if flag:
    print("没有交集,是LL(1)文法")
else:
    print("有交集,不是LL(1)文法")

# 初始化预测分析表
预测分析表 = {i: {} for i in 第一列}
if flag==True:
    # 遍历所有产生式
    for i, 产生式 in enumerate(第三列):
        for j,字符 in enumerate(产生式):
            预测分析表[第一列[i]][字符] = "->"+第二列[i]
    # 打印预测分析表
    df = DataFrame(预测分析表)
    df = df.fillna('')  # 将缺失值设置为空字符串
    df = df.transpose()  # 转换行和列
    print(df)

    分析栈 = ['#',前[0]]
    剩余输入串 = input("请输入要分析的字符串:")
    #剩余输入串 ='i+i*i#'
    步骤 = 0
    print(f"{"步骤":<4}\t\t{"分析栈":<20}\t\t{"剩余输入串":>20}\t\t{"推导所用产生式或匹配":<20}")
    #print(f"{步骤}\t{分析栈}\t{剩余输入串}\t{推到所用产生式或匹配}")
    while True:
        a = 剩余输入串[0]#当前终结符送a
        A = ""
        i = 0
        组合 = []
        步骤 += 1
        while i < len(分析栈):
            if 分析栈[i:i + 2] in 非终结符:
                A = 分析栈[i:i + 2]
                i += 2  # 跳过下一个字符,因为我们已经处理了长度为2的非终结符
            else:
                A = 分析栈[i]
                i += 1
            #print("A", A)
            组合.append(A)
        #print("组合",组合)
        X=组合[-1]#当前栈顶元素
        #print("X",X,"a",a)

        if X in 终结符:
            if X == 'ε':
                分析栈.pop()
                步骤-=1
                continue
            if X == a:
                print(f"{步骤:<4}\t\t{''.join(分析栈):<20}\t\t{剩余输入串:>20}\t\t{a+"匹配":<20}")
                分析栈.pop()
                剩余输入串 = 剩余输入串[1:]  # 剩余输入串去掉第一个
                continue
            else:
                print("出现非法符号,不适配,出错!!!")
                break
        else:
            if X == '#':
                if X == a:
                    #print(f"{步骤}\t\t{', '.join(分析栈)}\t\t{剩余输入串}\t\t{推导所用产生式或匹配}")
                    print(f"{步骤:<4}\t\t{''.join(分析栈):<20}\t\t{剩余输入串:>20}\t\t{"接收":<20}")
                    break
            else:
                #print(预测分析表[X].keys())
                #print("a",a)
                if a in 预测分析表[X].keys():
                    推导所用产生式或匹配 = X+预测分析表[X][a]
                    print(f"{步骤:<4}\t\t{''.join(分析栈):<20}\t\t{剩余输入串:>20}\t\t{推导所用产生式或匹配:<20}")
                    分析栈.pop()
                    A=""
                    i=0
                    组合=[]
                    temp=预测分析表[X][a][2:]
                    #print("temp",temp)
                    while i < len(temp):
                        if temp[i:i + 2] in 非终结符 and "'" in temp[i:i + 2]:
                            A = temp[i:i + 2]
                            i += 2  # 跳过下一个字符,因为我们已经处理了长度为2的非终结符
                        else:
                            A = temp[i]
                            i += 1
                        #print("A",A)
                        组合.append(A)
                    #print(组合)
                    分析栈 += 组合[::-1]
                    continue
                else:
                    print("非法产生式,出错!!!")
                    break
        print(f"{步骤:<4}\t\t{''.join(分析栈):<20}\t\t{剩余输入串:>20}\t\t{推导所用产生式或匹配:<20}")

c=input("请输入任意字符退出")

测试用例如下:

#测试用例1
S->AB
S->bC
A->ε
A->b
B->ε
B->aD
C->AD
C->b
D->aS
D->c

#测试用例2
S->AB
S->bC
A->ε
A->b
B->ε
B->aD
C->AD
C->b
D->aS
D->c

#测试用例3
E->TE'
E'->+TE'
E'->ε
T->FT'
T'->*FT'
T'->ε
F->i
F->(E)

#测试用例4
S->aH
H->aMd
H->d
M->Ab
M->ε
A->aM
A->e

#测试用例5
E->TE'
E'->+E
E'->ε
T->FT'
T'->T
T'->ε
F->PF'
F'->*F'
F'->ε
P->(E)
P->a
P->b
P->^

#测试用例6
S->MH
S->a
H->LSo
H->ε
K->dML
K->ε
L->eHf
M->K
M->bLM

#测试用例7
S->aS'
S'->aZ
S'->b
Z->A'b
Z->ε
A->aA'
A'->A
A'->ε
B->a

结果如下:

 

您可能感兴趣的与本文相关的镜像

Python3.8

Python3.8

Conda
Python

Python 是一种高级、解释型、通用的编程语言,以其简洁易读的语法而闻名,适用于广泛的应用,包括Web开发、数据分析、人工智能和自动化脚本

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值