使用PLY.YACC构建一个简单的计算器
发布时间:2023-12-23 20:47:35
PLY (Python Lex-Yacc) 是Python的一个工具库,用于快速解析和分析文本。它包含了PLY.Lex和PLY.Yacc两个模块,分别用于词法分析和语法分析。
下面是一个使用PLY.Yacc构建一个简单的四则运算计算器的示例代码:
import ply.yacc as yacc
from calculator_lexer import tokens
# 定义语法规则
start = 'expression'
def p_expression_plus(p):
'expression : expression PLUS term'
p[0] = p[1] + p[3]
def p_expression_minus(p):
'expression : expression MINUS term'
p[0] = p[1] - p[3]
def p_expression_term(p):
'expression : term'
p[0] = p[1]
def p_term_times(p):
'term : term TIMES factor'
p[0] = p[1] * p[3]
def p_term_div(p):
'term : term DIVIDE factor'
if p[3] != 0:
p[0] = p[1] / p[3]
else:
raise ZeroDivisionError("division by zero")
def p_term_factor(p):
'term : factor'
p[0] = p[1]
def p_factor_num(p):
'factor : NUMBER'
p[0] = p[1]
def p_factor_expr(p):
'factor : LPAREN expression RPAREN'
p[0] = p[2]
def p_error(p):
raise ValueError("Syntax error in input!")
# 构建解析器
parser = yacc.yacc()
# 测试计算器
while True:
try:
s = input("请输入表达式:")
except EOFError:
break
result = parser.parse(s)
print("计算结果:", result)
上述代码中,我们首先定义了语法规则,其中包括了加法、减法、乘法、除法和括号的运算规则。每条语法规则的定义都是一个函数,函数名以p_开头,后面跟着规则的名称。
在每个规则定义中,我们使用了特殊的p_参数来访问规则中的符号,例如p[1]表示规则中的 个符号。
然后,我们定义了一个p_error函数,用于处理语法错误时抛出异常。
最后,我们使用yacc.yacc()函数构建解析器对象,并在循环中输入表达式进行测试。
需要注意的是,上面的代码中使用了一个名为calculator_lexer的模块,它是自定义的词法分析器。我们需要在同一个目录下创建该模块,并定义相应的词法规则,例如:
import ply.lex as lex
# 定义词法规则
tokens = (
'NUMBER',
'PLUS',
'MINUS',
'TIMES',
'DIVIDE',
'LPAREN',
'RPAREN'
)
t_PLUS = r'\+'
t_MINUS = r'-'
t_TIMES = r'\*'
t_DIVIDE = r'/'
t_LPAREN = r'\('
t_RPAREN = r'\)'
def t_NUMBER(t):
r'\d+'
t.value = int(t.value)
return t
# 忽略空白字符
t_ignore = ' \t'
def t_error(t):
raise ValueError("Illegal character!")
# 构建词法分析器
lexer = lex.lex()
在这个模块中,我们先定义了词法规则,包括数字和运算符。每个运算符使用正则表达式进行匹配。然后,我们定义了一个t_NUMBER函数,用于将数字字符串转换为整数。最后,我们使用lex.lex()函数构建了词法分析器对象。
上述代码是一个简单的四则运算计算器示例,可以实现基本的表达式解析和计算。你可以尝试输入不同的表达式进行测试。需要注意的是,这个示例代码并没有处理运算符的优先级和括号的作用,所以计算结果可能不太准确。如果想要实现更复杂的计算器功能,可以根据实际需求对代码进行扩展和修改。
