欢迎访问宙启技术站
智能推送

使用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()函数构建了词法分析器对象。

上述代码是一个简单的四则运算计算器示例,可以实现基本的表达式解析和计算。你可以尝试输入不同的表达式进行测试。需要注意的是,这个示例代码并没有处理运算符的优先级和括号的作用,所以计算结果可能不太准确。如果想要实现更复杂的计算器功能,可以根据实际需求对代码进行扩展和修改。