实验介绍
LR(0)分析表是LR(0)分析器的重要组成部分,它是总控程序分析动作的依据。对于不同的文法,LR(0)分析表不同,它可以用一个二维数组表示,行标为状态号,列标为文法符号和’#’号,分析表的内容可由两部分组成,一部分为动作(ACTION)表,它表示当前状态下所面临输入符应做的动作是移进、归约、接受或出错,动作表的行标只包含终结符和’#’,另一部分为转换表(GOTO),它表示在当前状态下面临文法符号时应转向的下一个状态,相当于识别活前缀的有限自动机DFA的状态转换矩阵。因此构造一个文法的LR(0)分析表时,首先应构造识别活前缀的自动机DFA,这样可以很方便地利用DFA的项目集和状态转换函数构造它的LR(0)分析表,在实际应用中为了节省存储空间,通常把关于终结符部分的GOTO表和ACTION表重叠,也就是把当前状态下面临终结符应作的移进-归约动作和转向动作用同一数组元素表示。
实验代码
source.txt 保存了文法
Y->S
S->BB
B->aB
B->b
main.py 保存了程序源码
VN = [] # 非终结符
VT = [] # 终结符
NFA = [] # NFA表
DFA = [] # DFA表
grammar = [] # 读入的文法
doted_grammar = [] # 加点后的文法
VN2Int = {} # 非终结符映射
VT2Int = {} # 终结符映射
action = [] # action表
goto = [] # goto表
DFA_node = [] # DFA节点表
status_stack = [] # 状态栈
symbol_stack = [] # 符号栈
now_state = '' # 栈顶状态
input_ch = '' # 栈顶字符
input_str = '' # 输入串
location = 0 # 输入位置
now_step = 0 # 当前步骤
# 读取文法
def read_grammar(file_name):
global grammar
with open(file_name, 'r') as file:
for line in file:
line = line.replace('\n', "")
grammar.append(line)
file.close()
# 找到终结符和非终结符
def find_term_non():
global grammar
n = int(len(grammar))
temp_vt = []
l = 0
for i in range(n):
X, Y = grammar[i].split('->')
if X not in VN:
VN.append(X)
VN2Int.update({X: l})
l += 1
for Yi in Y:
temp_vt.append(Yi)
m = 0
for i in temp_vt:
if i not in VN and i not in VT:
VT.append(i)
VT2Int.update({i: m})
m += 1
VT.append('#')
VT2Int.update({
'#': m})
# 在字符串某个位置加点
def add_char2str(grammar_i, i):
grammar_i = grammar_i[0:i] + '.' + grammar_i[i:len(grammar_i)]
return grammar_i
# 给文法加点
def add_dot():
global doted_grammar
j = 0
n = 0
for i in grammar:
for k in range(len(i) - 2):
doted_grammar.append([])
doted_grammar[n].append(add_char2str(i, k + 3))
doted_grammar[n].append('false')
n += 1
j += 1
# 显示加点后的文法
def print_doted_grammar():
print('----加点后的文法----')
j = 1
for i in doted_grammar:
print('%d.%s' % (j, i[0]))
j += 1
# 显示读入文法</