编译原理课程上的一次实验
程序中手动建立了ACTION表和GOTO表(为什么不用项目集的方法?答:因为本小白能力不足没能搞出来。咳咳,重点是体会分析过程)。
实现对指定txt文件中文法的分析,并对输入的字符串(这里不需要手动输入,输入串**‘i+i*i#’**已在程序内)进行过程分析。
有问题可留言或私聊讨论哈~
txt文件内容:
S->E
E->E+T
E->T
T->T*F
T->F
F->(E)
F->i
源代码:
NN=[]
#自然树集合:
for i in range(100):
NN.append(str(i))
#定义终结符:
VT=['a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z','+','_','*',"/",'(',')','#']
#定义非终结符:
VN=["A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z" ]
#终结符匹配函数:
def VT_matching(p):
for word in VT:
if p==word:
return 1
#非终结符匹配函数:
def VN_matching(p):
for word in VN:
if p==word:
return 1
#从文件提取文法:
with open(r'D:\PC\txt\SLR(1).txt') as f:
predictions = [] #使用predictions来记录所有文法,以列表的形式
while True:
line=f.readline().split() #按行读取并去掉空格
predictions=predictions+line
if not line:break
print("文法(predictions)为:",predictions)
#扫描非终结符:
Vn=[] #Vn是非终结符列表
Vn_copy=[]
for prediction in predictions:
p=prediction #p是一个字符串
if (VN_matching(p[0])==1):
Vn.append(p[0])
for i in Vn:
if(i not in Vn_copy):
Vn_copy.append(i)
Vn=Vn_copy
print("文法中的非终结符(Vn)为:",Vn)
#扫描终结符:
Vt=["#"] #Vt是终结符列表,初始化时就有#
for prediction in predictions: #prediction是一个字符串
for t in prediction:
if (VT_matching(t)==1 ):
Vt.append(t)
set(Vt) #set语句去除Vt中的重复元素
print("文法中的终结符(Vt)为:",Vt)
#建立文法字典Prediction_dic{}:
Prediction_dic={}
def PREDICTION_DIC():
global Prediction_dic
c=0
d=0
rn=""
R=[]
while (d<len(predictions)):
rn="r"+str(d)
R.append(rn)
d+=1
P={} #函数内的文法字典,便于建立后直接赋予Prediction_dic
while (c<len(predictions)):
P[R[c]]=predictions[c]
c+=1
Prediction_dic=P.copy()
PREDICTION_DIC()
print("文法序号字典(Prediction_dic)为:",Prediction_dic)
Action_col={
'i':0,
'+':1,
'*':2,
'(':3,
')':4,
'#':5
}
print("终结符字典(Action_col)为:",Action_col)
Goto_col={
'E':0,
'T':1,
'F':2
}
print("非终结符字典(Goto_col)为",Goto_col)
#初始化ACTION
ACTION=[["None"]*6 for i in range(12)]
ACTION[0][0]='5'
ACTION[0][3]='4'
ACTION[1][1]='6'
ACTION[1][5]='acc'
ACTION[2][1]='r2'
ACTION[2][2]='7'
ACTION[2][4]='r2'
ACTION[2][5]='r2'
ACTION[3][1]='r4'
ACTION[3][2]='r4'
ACTION[3][4]='r4'
ACTION[3][5]='r4'
ACTION[4][0]='5'
ACTION[4][3]='4'
ACTION[5][1]='r6'
ACTION[5][2]='r6'
ACTION[5][4]='r6'
ACTION[5][5]='r6'
ACTION[6][0]='5'
ACTION[6][3]='4'
ACTION[7][0]='5'
ACTION[7][3]='4'
ACTION[8][1]='6'
ACTION[8][4]='11'
ACTION[9][1]='r1'
ACTION[9][2]='7'
ACTION[9][4]='r1'
ACTION[9][5]='r1'
ACTION[10][1]='r3'
ACTION[10][2]='r3'
ACTION[10][4]='r3'
ACTION[10][5]='r3'
ACTION[11][1]='r5'
ACTION[11][2]='r5'
ACTION[11][4]='r5'
ACTION[11][5]='r5'
print("ACTION:",ACTION)
#初始化GOTO
GOTO=[["None"]*3 for i in range(12)]
GOTO[0][0]='1'
GOTO[0][1]='2'
GOTO[0][2]='3'
GOTO[4][0]='8'
GOTO[4][1]='2'
GOTO[4][2]='3'
GOTO[6][1]='9'
GOTO[6][2]='3'
GOTO[7][2]='10'
print("GOTO",GOTO)
def DeleteLF(s):
temp=''
d=1
while (d<len(s)):
temp=temp+s[d]
d=d+1
s=temp
return s
#string=['i','+','i','*','i','#'] #输入字符串
string='i+i*i#'
SStack=[0] #初始化状态栈
CStack=['#'] #初始化符号栈
action='' #记录ACTION
goto='' #单字符记录GOTO
def PROCESS():
global string
global action
global goto
#步骤一的初始化
char=string[0] #记录输入的第一个字符
print("分析开始:")
print("步骤 1 : ")
print("状态栈:",SStack)
print("符号栈:",CStack)
print("输入串:",string)
action=ACTION[SStack[len(SStack)-1]][Action_col.get(char)] # 状态栈末位和输入串首位匹配,结果输入action
print("action:", action)
print("goto:", goto)
step=2
#while (SStack != ['#', 'E'] or CStack!= ['#']): #结束循环条件
while (1):
print("步骤",step,":")
if (action in NN): #若上一步骤action是一个状态(自然数):
SStack.append(action) # 结束后action进入状态栈末尾
CStack.append(string[0]) #输入串周字符进入符号栈
string=DeleteLF(string) #删除输入的首字符
char=string[0]
action=ACTION[int(SStack[len(SStack)-1])][int(Action_col.get(char))] #状态栈末位和输入串首位匹配,结果输入action
if action[0]=='r': #若本步骤action已经是r.编写goto
pre=Prediction_dic.get(action) #调出文法
left=pre.split('->')[0] #文法左部
right=pre.split('->')[1] #文法右部
l=len(right) #l记录文法右部长度
goto=int(GOTO[int(SStack[len(SStack)-l-1])][Goto_col.get(left)]) #计算出goto,got这里为整型
else : #剩下的,若上一步骤的action为文法序号r
#goto入栈
#char=string[0]
pre=Prediction_dic.get(action) #调出文法
left=pre.split('->')[0] #文法左部
right=pre.split('->')[1] #文法右部
l=len(right) #l记录文法右部长度
#以下为符号栈的出栈:
d=0
while (d<l): #l有多少位
CStack.pop() #删除符号栈最后一个元素
d=d+1
#以下为符号栈的入栈:
CStack.append(left)
#以下为状态栈的出栈:
c=0
while (c<l):
SStack.pop()
c=c+1
#以下为状态栈的入栈:
SStack.append(goto)
action=action=ACTION[SStack[int(len(SStack)-1)]][Action_col.get(char)]
if (action in NN): #若本步骤的action值是一个数字
goto='' #goto值设置为空
elif (action!='acc'): #若action不为接受
pre=Prediction_dic.get(action) #调出文法
left=pre.split('->')[0] # 文法左部
right=pre.split('->')[1] # 文法右部
l=len(right) # l记录文法右部长度
goto=int(GOTO[int(SStack[len(SStack)-l-1])][Goto_col.get(left)]) #计算出goto,这里为整型
else: #action='acc'
print("状态栈:", SStack)
print("符号栈:", CStack)
print("输入串:", string)
print("action:", action)
break
step+=1
print("状态栈:", SStack)
print("符号栈:", CStack)
print("输入串:", string)
print("action:",action)
print("goto:",goto)
print("分析结束!")
PROCESS()