編譯原理實驗:實現算符優先分析程序,依舊使用python實現,由於注釋很詳細就不單獨寫編程思路啦
功能如下:
求出文法中每一個非終結符的FIRSTVT集和LASTVT集
打印算符優先關系表
進行算符優先分析並打印分析結果
源代碼:
import sys
import operator
import copy
#終結符
terSymbol = ['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',
'+','-','*','/','(',')','^','#']
#非終結符
non_ter = ['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']
firstVT = [[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[]]
lastVT = [[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[]]
#求firstVT集
def first(gra_line):
#開頭的非終結符,所以求的是x的firstVT
x = gra_line[0]
ind = non_ter.index(x)
indexSET = []
# 找到所有產生式右部的第一個字符,下標值返回列表indexSET
i = 0
while i < len(gra_line):
if gra_line[i] == '>' or gra_line[i] == '|':
indexSET.append(i + 1)
i += 1
#判斷符合P->a...或P->Qa...,以及P->Q...那個情況,注意gra_line[i]是當前遍歷的字符
for i in indexSET:
if gra_line[i] in terSymbol and gra_line[i] not in firstVT[ind]:
firstVT[ind].append(gra_line[i])
elif gra_line[i] in non_ter:
for f in firstVT[non_ter.index(gra_line[i])]:
if f not in firstVT[ind]:
firstVT[ind].append(f)
if gra_line[i + 1] in terSymbol and gra_line[i + 1] not in firstVT[ind]:
firstVT[ind].append(gra_line[i + 1])
return firstVT
#求lastVT集
def last(gra_line):
# 開頭的非終結符,所以求的是x的lastVT
x = gra_line[0]
ind = non_ter.index(x)
indexSET = []
# 找到所有產生式右部的最后一個字符,下標值返回列表indexSET
i = 0
while i < len(gra_line):
if gra_line[i] == '|' or gra_line[i] == '\n':
indexSET.append(i - 1)
i += 1
# 判斷符合P->...a或P->...aQ,以及P->...Q那個情況,注意gra_line[i]是當前遍歷的字符
for i in indexSET:
if gra_line[i] in terSymbol and gra_line[i] not in lastVT[ind]:
lastVT[ind].append(gra_line[i])
elif gra_line[i] in non_ter:
for f in lastVT[non_ter.index(gra_line[i])]:
if f not in lastVT[ind]:
lastVT[ind].append(f)
if gra_line[i - 1] in terSymbol and gra_line[i - 1] not in lastVT[ind]:
lastVT[ind].append(gra_line[i - 1])
return lastVT
#求每一個產生式的右部單獨的產生式
def prostr(grammer):
pro_str = []
for gra_line in grammer:
#先看每一行有幾個產生式,把每一個產生式的開始索引加入pro_index
pro_index = []
i = 0
while i < len(gra_line):
if gra_line[i] == '>' or gra_line[i] == '|':
pro_index.append(i + 1)
i += 1
for p in pro_index:
str = ''
for s in gra_line[p:]:
if s == '|' or s == '\n':
break
else:
str = str + s
pro_str.append(str)
return pro_str
#構造優先關系表
def table(grammer, num):
#表頭
n = len(num) + 1
#創建一個n行n列的空表
gra = [[' ' for col in range(n)] for row in range(n)]
#填充表頭
i = 1
for c in num:
gra[0][i] = c
i += 1
j = 1
for r in num:
gra[j][0] = r
j += 1
#填充表體
pro_str = prostr(grammer)
for str in pro_str:
if str == '@':
continue
else:
j = -1
for i in str[:-1]:
#i是當前元素,j是當前索引
j += 1
if i in terSymbol and str[j + 1] in terSymbol:
r = num.index(i) + 1
c = num.index(str[j + 1]) + 1
if gra[r][c] == '·>' or gra[r][c] == '<·':
print("該文法不是算符優先文法,請檢查輸入")
return False
else:
gra[r][c] = '=·'
if j < (len(str) - 2) and i in terSymbol and str[j + 2] in terSymbol and str[j + 1] in non_ter:
r = num.index(i) + 1
c = num.index(str[j + 2]) + 1
if gra[r][c] == '·>' or gra[r][c] == '<·':
print("該文法不是算符優先文法,請檢查輸入")
return False
else:
gra[r][c] = '=·'
if i in terSymbol and str[j + 1] in non_ter:
for a in firstVT[non_ter.index(str[j + 1])]:
r = num.index(i) + 1
c = num.index(a) + 1
if gra[r][c] == '·>' or gra[r][c] == '=·':
print("該文法不是算符優先文法,請檢查輸入")
return False
else:
gra[r][c] = '<·'
if i in non_ter and str[j + 1] in terSymbol:
for a in lastVT[non_ter.index(i)]:
r = num.index(a) + 1
c = num.index(str[j + 1]) + 1
if gra[r][c] == '=·' or gra[r][c] == '<·':
print("該文法不是算符優先文法,請檢查輸入")
return False
else:
gra[r][c] = '·>'
#添加#的行和列元素
for a in firstVT[non_ter.index(grammer[0][0])]:
r = num.index('#') + 1
c = num.index(a) + 1
gra[r][c] = '<·'
for a in lastVT[non_ter.index(grammer[0][0])]:
r = num.index(a) + 1
c = num.index('#') + 1
gra[r][c] = '·>'
r = num.index('#') + 1
c = num.index('#') + 1
gra[r][c] = '=·'
return gra
#歸約函數
def reduce(str):
#str是傳進來的最左素短語
p_s = prostr(grammer)
for s in p_s:
if len(s) != len(str):
continue
else:
j = 0
for i in s:
#如果是最后一個字符相比較了
if j + 1 == len(str):
if i in terSymbol and str[j] in terSymbol and i == str[j]:
return True
elif i in non_ter and str[j] in non_ter:
return True
else:
if i in terSymbol and str[j] in terSymbol and i == str[j]:
j += 1
elif i in non_ter and str[j] in non_ter:
j += 1
else:
break
return False
#總控程序
def master(ana_str, num):
stack = ['#']
ana_str += '#'
print("當前棧中元素為:")
print(stack)
print("當前字符串為:")
print(ana_str)
while stack != ['#','N','#']:
if ana_str == '#':
stack.append('#')
print("移進#")
print()
print("當前棧中元素為:")
print(stack)
continue
#字符串第一個字符是非終結符,則加入棧
if ana_str[0] in non_ter:
stack.append(ana_str[0])
print("移進" + ana_str[0])
print()
print("當前棧中元素為:")
print(stack)
ana_str = ana_str[1:]
print("當前字符串為:")
print(ana_str)
#j是stack中最上面終結符的下標
if stack[-1] in terSymbol:
j = len(stack) - 1
else:
j = len(stack) - 2
#stack[j]是棧最上面的終結符,a是當前輸入串的第一個字符(終結符
a = ana_str[0]
if stack[j] not in num or a not in num:
print("ERROR")
return False
else:
#棧頂終結符優先級低於等於字符串第一個終結符
if gra[num.index(stack[j]) + 1][num.index(a) + 1] == '<·' or gra[num.index(stack[j]) + 1][num.index(a) + 1] == '=·':
stack.append(a)
print("移進" + a)
print()
print("當前棧中元素為:")
print(stack)
ana_str = ana_str[1:]
print("當前字符串為:")
print(ana_str)
if ana_str[0] in non_ter:
stack.append(ana_str[0])
print("移進" + ana_str[0])
print()
print("當前棧中元素為:")
print(stack)
ana_str = ana_str[1:]
print("當前字符串為:")
print(ana_str)
j += 1
if stack[j] in non_ter:
j += 1
a = ana_str[0]
if stack[j] not in num or a not in num:
print("ERROR")
return False
else:
#如果棧頂終結符優先級高於字符串第一個終結符
while gra[num.index(stack[j]) + 1][num.index(a) + 1] == '·>':
#尋找最左素短語
str = ''
if ana_str[0] in non_ter:
str += ana_str[0]
ana_str = ana_str[1:]
#如果棧頂是非終結符
if stack[-1] in non_ter:
str += stack[-1]
while j >= 1:
#j是往下遍歷的指針,b是減小之前的
#b記錄當前棧頂非終結符,並將b加入最左素短語
b = stack[j]
str += b
#如果當前終結符的下一個是終結符,指向下一個,否則指向下下一個
if stack[j - 1] in terSymbol:
j -= 1
else:
str += stack[j - 1]
j -= 2
#如果下一個終結符優先級小於當前終結符
if gra[num.index(stack[j]) + 1][num.index(b) + 1] == '<·':
break
str = str[::-1]
#歸約,str是最左素短語
if reduce(str) == True:
print("將" + str + "歸約為N")
print()
del stack[len(stack) - len(str):]
stack.append('N') #反正模糊歸約,這個非終結符隨便寫個就行了8
print("當前棧中元素為:")
print(stack)
print("當前字符串為:")
print(ana_str)
else:
print("歸約失敗")
break
if gra[num.index(stack[j]) + 1][num.index(a) + 1] != '·>'\
and gra[num.index(stack[j]) + 1][num.index(a) + 1] != '=·'\
and gra[num.index(stack[j]) + 1][num.index(a) + 1] != '<·':
print("ERROR")
return False
#j已經指向棧頂第一個終結符
return True
#比較兩個嵌套列表是否相等
def cmp(SET1, SET2):
i = 0
while i < 26:
if (operator.eq(SET1[i], SET2[i])) == False:
return False
else:
i += 1
return True
if __name__ == '__main__':
ana_str = input("請輸入一個待分析的串:")
print("請輸入一個文法:")
grammer = sys.stdin.readlines()
#循環求最終firstVT集
first1 = copy.deepcopy(firstVT)
for gr in grammer:
first(gr)
first2 = copy.deepcopy(firstVT)
while not cmp(first1, first2):
first1 = copy.deepcopy(firstVT)
for gr in grammer:
first(gr)
first2 = copy.deepcopy(firstVT)
print("該文法的非終結符的firstVT集為:")
i = 0
for f in firstVT:
if len(f) != 0:
print('firstVT(' + non_ter[i] + '):', f)
i += 1
print()
# 循環求最終lastVT集
last1 = copy.deepcopy(lastVT)
for gr in grammer:
last(gr)
last2 = copy.deepcopy(lastVT)
while not cmp(last1, last2):
last1 = copy.deepcopy(lastVT)
for gr in grammer:
last(gr)
last2 = copy.deepcopy(lastVT)
print("該文法的非終結符的lastVT集為:")
j = 0
for f in lastVT:
if len(f) != 0:
print('lastVT(' + non_ter[j] + '):', f)
j += 1
print()
num = []
for gra_line in grammer:
for gr in gra_line:
if gr == '-' and gra_line.index(gr) == 1:
continue
elif gr in terSymbol and gr not in num:
num.append(gr)
num.append('#')
if table(grammer,num) != False:
print("該文法的優先關系表為:")
gra = table(grammer, num)
for i in range(len(gra)): # 控制行
for j in range(len(gra[i])): # 控制列
print(gra[i][j], end='\t')
print()
print()
print("分析過程如下:")
print()
if master(ana_str, num) == True:
print("接受")