Python 对于文法的预测分析表进行预测分析
已知文法G(E):
E→TE’
E’→+TE’ |ε
T→FT’
T’→*FT’ |ε
F→(E) | i
先计算FIRST、FOLLOW、SELECT集合
计算方法见 链接: link.
检查是否能是LL(1)文法
通过SELECT集合
如:
select(A->bc)={a,b}
select(A->bd)={a,d}
因为select(A->bc) 并 select(A->bd) !=空
所以该文法不是LL(1)文法
非LL(1)文法到LL(1)文法的转换
如果存在左递归:
S->Sa|ε
那么消除左递归见 链接:[link](https://www.cnblogs.com/nano94/p/4020775.html)
如果存在左公共因子
S->aB
S-aC
那么消除左公共因子见 链接 [link]:(https://blog.csdn.net/chen_dsir/article/details/72801574)
.
通过SELECT集和来构建预测分析表
预测分析表的构建见 连接:link.
基于已有的预测分析表进行预测分析
本文代码是基于已计算完毕的预测分析表进行预测分析,而不是对于文法直接进行预测文法
class G():
# 初始化函数
# 参数 Vn 非终结符集合
# 参数 Vt 终结符集合 (集合的元素为字符串,存在E'这样的终结符)
# 参数 dict_FAT 以二重字典形式存在的预测分析表
# 字典的第一重的键值为非终结符 元素为字典
# 字典的第二重的键值为终结符和# 元素为元组 元组中的每个字符串元素表示一个Vn或Vt
# 例:dict={'P':{'a':['b','Q'], 'b':['a','P'], '#':['ε']},
# 'Q':{'a':['c','E'], 'b':['a','Q'],'#':['a']}
# }
def __init__(self, Vn, Vt, dict_FAT):
self.Vn = Vn
self.Vt = Vt
self.dict = dict()
for key in dict_FAT.keys():
if key not in self.Vn:
print('ketError! key:{:} not in Vn'.format(key))
for key2 in dict_FAT[key].keys():
if key2 not in self.Vt and key2 !='#':
print('ketError! key:{:} not in Vn'.format(key))
self.dict = dict_FAT
# 打印Vn Vt 和预测分析表
def print(self):
print('vn:{:}'.format(str(self.Vn)))
print('vt:{:}'.format(str(self.Vt)))
for key in self.dict.keys():
print(key)
for key2 in self.dict[key].keys():
print('{:} {:}'.format(key2,self.dict[key][key2]),end=';')
print()
# 判断输入的字符串是否能通过预测分析
def isAccept(self,string):
stack_Ansy = [] # 分析栈
stack_Ansy.append("#")
stack_Ansy.append('E') # 默认开始符为E
list_str = list(string) # 输入栈
while(stack_Ansy[len(stack_Ansy)-1] != '#' or list_str[0] != '#'): # 如果分析栈和输入栈的最后一个元素都为# 时 表示分析通过
#print('{:50}'.format(" ".join(stack_Ansy)),end=' | ')
#print('{:50}'.format(" ".join(list_str)),end=' | ')
ansy = stack_Ansy.pop() # 分析栈出栈
s = list_str[0] # 取输入字符
if ansy == s: # 如果分析栈弹出的元素等于当前读取的字符
list_str = list_str[1:] # 将字符串去掉第一个元素 切片操作
# print('{:}=={:}'.format(ansy,s))
continue
try: # 如果出现字典的keyError 那么表示出现了取空操作 那么存在不再分析表的的A a
#print('{:5} {:5} '.format(ansy,s),end=' | ')
ss = self.dict[ansy][s] # 查询分析表 如果没用相应的A a那么抛出KeyError异常结束
# print(ss)
if ss != ['ε']: # 如果取出的产生式的右部不为空
ss.reverse() # 将产生式逆置
stack_Ansy.extend(ss) # 将产生式压入分析栈
ss.reverse() # 恢复产生式的顺序0
except BaseException as ke:
#print(repr(ke))
return False
return True
if __name__ == '__main__':
dict_FAT = { # 预测分析表
'E':{'i': ['T','E`'], '(':['T','E`']},
'E`':{'+': ['+','T','E`'], ')':['ε'], '#':['ε']},
'T':{'i': ['F','T`'], '(':['F','T`']},
'T`':{'+': ['ε'], '*':['*','F','T`'], ')':['ε'], '#':['ε']},
'F':{'i': ['i'], '(':['(','E',')'] },
}
vn = ['E','E`','T','T`','F'] # 非终结符集合
vt = ['i','+','*','(',')'] # 终结符集合
g = G(vn, vt, dict_FAT) # 创建文法对象
accept = 'syntax correct'
not_accpet = 'syntax error'
strs = [] # 定义一个元组 存储即将输入的数据
try: # 循环输入 输入EOF时抛出异常结束输入
string = input()
while(string is not None): # 当输入的字符串不是空时
strs.append(string) # 将输入的字符串加入到元组中
string = input() # 输入下一个字符串
except BaseException: # 在Python 中如果输入Ctrl Z(EOF)那么input()将会抛出异常
pass
for s in strs: # 遍历输入的句子 检查是否能通过预测分析
if g.isAccept(s): # 进行预测分析
print(accept)
else:
print(not_accpet)
注释部分将输出分析过程