用python通过编写一个语义分析器,实现用LR分析法对文法G1: L→E E→E=T|T E→E+T|T T→T-F|F F→(E)|id 的文法分析,并输出过程
时间: 2023-07-19 18:27:12 浏览: 198
python实现LR_0分析器(带ui界面)
以下是一个简单的Python程序,实现对文法G1的LR分析:
```
# 定义文法规则
rules = {
'L': ['E'],
'E': ['E', '+', 'T'],
['E', '-', 'T'],
['T'],
'T': ['T', '*', 'F'],
['T', '/', 'F'],
['F'],
'F': ['(', 'E', ')'],
['id'],
}
# 定义Action表和Goto表
action = {
0: {'id': ('s', 5), '(': ('s', 4)},
1: {'+': ('s', 6), '-': ('s', 7), '$': ('acc', None)},
2: {'+': ('r', 2), '-': ('r', 2), '*': ('s', 8), '/': ('s', 9), ')': ('r', 2), '$': ('r', 2)},
3: {'+': ('r', 4), '-': ('r', 4), '*': ('r', 4), '/': ('r', 4), ')': ('r', 4), '$': ('r', 4)},
4: {'id': ('s', 5), '(': ('s', 4)},
5: {'+': ('r', 6), '-': ('r', 6), '*': ('r', 6), '/': ('r', 6), ')': ('r', 6), '$': ('r', 6)},
6: {'id': ('s', 5), '(': ('s', 4)},
7: {'id': ('s', 5), '(': ('s', 4)},
8: {'id': ('s', 5), '(': ('s', 4)},
9: {'id': ('s', 5), '(': ('s', 4)},
}
goto = {
0: {'E': 1, 'T': 2, 'F': 3},
4: {'E': 10, 'T': 2, 'F': 3},
6: {'T': 11, 'F': 3},
7: {'T': 12, 'F': 3},
8: {'F': 13},
9: {'F': 14},
}
# 定义LR分析器
class LRParser:
def __init__(self, rules, action, goto):
self.rules = rules
self.action = action
self.goto = goto
def parse(self, input_tokens):
stack = [0]
input_index = 0
output = ''
while True:
state = stack[-1]
token = input_tokens[input_index][0]
if token in self.action[state]:
action_type, action_value = self.action[state][token]
if action_type == 's':
stack.append(token)
stack.append(action_value)
input_index += 1
elif action_type == 'r':
rule_index = action_value
rule = self.rules[rule_index]
for _ in range(len(rule)):
stack.pop()
stack.pop()
state = stack[-1]
stack.append(rule[0])
stack.append(self.goto[state][rule[0]])
output += 'Reduce using rule ' + str(rule_index) + ': ' + str(rule) + '\n'
elif action_type == 'acc':
output += 'Accept\n'
break
else:
output += 'Error\n'
break
return output
# 定义语义分析器
class SemanticAnalyzer:
def __init__(self):
self.variables = {}
self.temp_count = 0
def generate_temp(self):
self.temp_count += 1
return 't' + str(self.temp_count)
def analyze(self, parse_tree):
if parse_tree.label == 'L':
self.analyze(parse_tree.children[0])
elif parse_tree.label == 'E':
if len(parse_tree.children) == 1:
self.analyze(parse_tree.children[0])
elif parse_tree.children[1].label == 'T':
self.analyze(parse_tree.children[0])
self.analyze(parse_tree.children[2])
else:
temp = self.generate_temp()
self.analyze(parse_tree.children[0])
self.variables[temp] = self.analyze(parse_tree.children[2])
self.variables[parse_tree.children[0].value] = temp
elif parse_tree.label == 'T':
if len(parse_tree.children) == 1:
return self.analyze(parse_tree.children[0])
else:
temp = self.generate_temp()
self.variables[temp] = self.analyze(parse_tree.children[0])
self.variables[temp] -= self.analyze(parse_tree.children[2])
return temp
elif parse_tree.label == 'F':
if parse_tree.children[0].label == '(':
return self.analyze(parse_tree.children[1])
else:
return self.variables[parse_tree.children[0].value]
# 定义输入字符串
input_str = 'id + id * id - id / id'
# 将输入字符串转换为token序列
tokens = input_str.split()
input_tokens = [(token, None) for token in tokens] + [('$', None)]
# 创建LR分析器和语义分析器
lr_parser = LRParser(rules, action, goto)
semantic_analyzer = SemanticAnalyzer()
# 执行语法分析和语义分析
parse_tree = lr_parser.parse(input_tokens)
output = semantic_analyzer.analyze(parse_tree)
# 输出分析结果
print('Parse Tree:\n' + parse_tree)
print('Variables:\n' + str(semantic_analyzer.variables))
```
解释:
这段程序首先定义了文法规则、Action表和Goto表。其中,文法规则使用字典类型表示,Action表和Goto表使用嵌套字典类型表示。接下来,定义了一个名为LRParser的类,该类包含三个属性:rules、action和goto。类方法parse实现了LR分析算法。它使用一个栈来模拟分析过程,同时按照Action表和Goto表中的规则进行分析。如果分析成功,则返回一个表示语法分析树的字符串。如果分析失败,则返回一个错误信息。
接下来,定义了一个名为SemanticAnalyzer的类,该类包含两个属性:variables和temp_count。variables是一个字典,用于存储变量和它们的值。temp_count是一个计数器,用于生成临时变量。类方法generate_temp用于生成一个新的临时变量。类方法analyze执行语义分析。它根据语法树的节点类型执行不同的操作。如果节点类型是L,则递归地执行其子节点。如果节点类型是E,则检查子节点数目,如果只有一个子节点,则递归地执行该子节点;否则,根据子节点类型执行不同的操作。如果子节点类型是T,则递归地执行第1和第3个子节点。如果子节点类型是E,则生成一个新的临时变量,将第1个子节点的值和第3个子节点的值相加,并将结果存储在新的临时变量中。最后,将新的临时变量的名称存储在第1个子节点的值中。如果节点类型是T,则检查子节点数目,如果只有一个子节点,则递归地执行该子节点;否则,生成一个新的临时变量,将第1个子节点的值减去第3个子节点的值,并将结果存储在新的临时变量中。最后,返回新的临时变量的名称。如果节点类型是F,则检查第1个子节点的类型。如果第1个子节点是左括号,则递归地执行第2个子节点;否则,返回存储在variables中与第1个子节点的值相对应的变量的值。
最后,使用输入字符串创建token序列,然后使用LR分析器和语义分析器执行语法分析和语义分析。最终输出分析结果,包括语法分析树和变量的值。
阅读全文