一、 实验名称:语法分析——预测分析法
二、实验目的:根据文法判断是否为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
结果如下:





&spm=1001.2101.3001.5002&articleId=145003620&d=1&t=3&u=0a72e2c310cf4a7ab8dbf465e26fcbed)
5548

被折叠的 条评论
为什么被折叠?



