一. 实验三: LR(1)分析法
二. 实验目的及要求
实现目的:
构造LR(1)分析程序,利用它进行语法分析,判断给出的符号串是否为该文
法识别的句子,了解LR(K)分析方法是严格的从左向右扫描,和自底向上的
语法分析方法。
实验要求:
1、编程时注意编程风格:空行的使用、注释的使用、缩进的使用等。
2、如果遇到错误的表达式,应输出错误提示信息。
3、程序输入/输出实例:
输入一以#结束的符号串(包括+*()i#):在此位置输入符号串
输出过程如下:
三. 实验内容
对下列文法,用LR(1)分析法对任意输入的符号串进行分析:
(1)E->E+T
(2)E->T
(3)T->T*F
(4)T->F
(5)F->(E)
(6)F->i
四. 核心算法流程
五.核心代码
def CLOSURE(mystr, num): # 用于项目集内容的补充(找等价项目)
my_dicts[num].append(mystr) # 先加上它本身
zhanwang = getSymbol(mystr) # 再计算展望符
# 遍历mystr 记录点后面那个字符
for i in range(0, len(mystr)):
if (mystr[i] == '.'):
ch = mystr[i + 1]
# 后面那个字符是非终结符
if (ch in VNT):
# 遍历非终结符ch的每个产生式
for j in range(0, len(my_dict[ch])):
# 取得非终结符ch的一个产生式的右部ch2
ch2 = my_dict[ch][j]
# 遍历展望符的每个元素
for k in range(0, len(zhanwang)):
mystr = ch + "->." + ch2 + "," + zhanwang[k]
# 如果新的项目不在项目集中
if (my_dicts[num].count(mystr) == 0):
my_dicts[num].append(mystr) # 添加
# 如果ch2是一个非终结符 继续向下
if (ch2[0] in VNT):
for ss in my_dict[ch2[0]]:
zhanwangs = getSymbol(mystr)
for kk in range(0, len(zhanwangs)):
mystr2 = ch2[0] + "->." + ss + "," + zhanwangs[kk]
if (my_dicts[num].count(mystr2) == 0):
CLOSURE(mystr2, num)
else:
return
def deleteI(delnum): # 删除重复状态
for i in delnum:
del my_dicts[i]
# 往出指的过程
def DFA(mynum):
# 用于存储新的状态集。
newstr = []
# 用于存储字符到状态集序号的映射。
command = dict()
global Inum
# 遍历第mynum个项目集
for fs in my_dicts[mynum]: # 用字典存储 目标字符和状态集序号
# 遍历一个项目(fs) 这个循环的目的是将左部填入
for i in range(0, len(fs)):
if (fs[i] == '.'): #规约项目
if (fs[i + 1] == ','):
break
else: # 产生式右部
# 如果新的项目集还没有存储这个点后面的元素
if (newstr.count(fs[i + 1]) == 0):
newstr.append(fs[i + 1])
# 增加项目集序号
Inum += 1
# 将字符映射到新的状态集序号
command[fs[i + 1]] = Inum
# 再遍历一次
for fs in my_dicts[mynum]:
for i in range(0, len(fs)):
if (fs[i] == '.'):
if (fs[i + 1] == ','):
break
else: #遇到点后面的元素
# 获取这个项目在新的项目集的编号
mynums = command[fs[i + 1]]
# s1是当前项目
s1 = list(fs)
# 交换位置(点和点后元素)
s1[i] = s1[i + 1]
# 在右部的开头加点
s1[i + 1] = '.'
# 转化为字符串
sq = ''.join(s1) # 巧妙实现字符串的替换
CLOSURE(sq, mynums) # 找等价项目
delnum = []
for key, value in command.items():
for j in range(0, value):
if (set(my_dicts[j]) == set(my_dicts[value])): # 如果两个状态集合相同
command[key] = j # 修改状态序号
delnum.append(value)
# 删除多余的集合
deleteI(delnum)
for key, value in command.items():
end.append([mynum, key, value])
numset.append(mynum)
numset.append(value) # 利用集合特性,修订状态数
六. 具体代码
github仓库链接:https://github.com/1StephenCurry1/Compiler-Design.git