python - Yacc - 具有函数支持的方程解析器

标签 python function grammar yacc lex

我正在尝试为以下方程编写方程解析器:4*sin(1+cos(10/2)) 我使用 lex 来获取标记,并使用 yacc 作为解析器模块。

我现在的实际问题是我不知道如何定义函数的语法。函数通常是这样构造的 FunctionName( Expression) 因此对于解析器语法来说它将是 function : FUNCTION LPAREN expression RPAREN (我希望)。

但是我将如何处理像 sin(3+cos(0)*10) 这样构建的函数。这将是一个函数中的一个函数,同时不要忘记关心 3+*10。希望我已经足够好地指出了我的问题。

这是我的代码:

import ply.lex as lex
import ply.yacc as yacc
import math

tokens = (
    'DIV',
    'TIMES',
    'MINUS',
    'PLUS',
    'FUNCTION',
    'NUMBER',
    'LPAREN',
    'RPAREN',
)

t_PLUS = r'\+'
t_MINUS = r'-'
t_TIMES = r'\*'
t_DIV = r'/'
t_LPAREN = r'\('
t_RPAREN = r'\)'

t_ignore = ' '

def t_NUMBER(t):
    r'([0-9]*\.[0-9]+|[0-9]+)'
    t.value = float(t.value)
    return t

def t_FUNCTION(t):
    r'sin|cos|tan'
    return t

def t_error(t):
    print("Illegal character '%s'" % t.value[0])
    t.lexer.skip(1)

# Parser
'''
Here i need some help
'''
def p_function_exp(p):
    'function : expression PLUS function'
    p[0] = p[1] + p[3]

def p_function(p):
    'function : FUNCTION LPAREN expression RPAREN'
    if p[1] == 'sin':
        p[0] = math.sin(p[3])

def p_expression_minus(p):
    'expression : expression MINUS term'
    p[0] = p[1] - p[3]

def p_expression_plus(p):
    'expression : expression PLUS term'
    p[0] = p[1] + p[3]

def p_expression_term(p):
    'expression : term'
    p[0] = p[1]

def p_term_div(p):
    'term : term DIV factor'
    p[0] = p[1] / p[3]

def p_term_times(p):
    'term : term TIMES factor'
    p[0] = p[1] * p[3]

def p_term_factor(p):
    'term : factor'
    p[0] = p[1]

def p_factor(p):
    'factor : NUMBER'
    p[0] = p[1]

def p_factor_exp(p):
    'factor : LPAREN expression RPAREN'
    p[0] = p[2]

# Error rule for syntax errors
def p_error(p):
    print("Syntax error in input!")

# Build the parser
parser = yacc.yacc()

while True:
    try:
        s = input('>> ')
        equation = lex.lex()
        equation.input(s)
        while True:
            tok = equation.token()
            if not tok: break
            print(tok)
    except EOFError:
        break
    if not s: continue
    result = parser.parse(s)
    print(result)

提前致谢!约翰

最佳答案

简单表达式的传统 Yacc 语法通常如下所示:

expression
    : add_sub_expr
    ;

add_sub_expr
    : mul_div_expr
    | mul_div_expr '+' add_sub_expr
    | mul_div_expr '-' add_sub_expr
    ;

mul_div_expr
    : funcall_expr
    | funcall_expr '*' mul_div_expr
    | funcall_expr '/' mul_div_expr
    ;

funcall_expr
    : prim_expr
    | FUNCTION_NAME '(' expression_list ')'
    ;

prim_expr
    : NUMBER
    | '(' expression ')'
    ;

expression_list
    : expression
    | expression ','  expression_list
    ;

上述语法将使函数调用成为表达式的直接部分,其优先级高于乘法和除法。

对于FUNCTION_NAME,您可以为每个函数各占一行(如果函数列表很短),也可以使用包含函数标识符列表的非终端,或者使用特殊终端(就像我的语法一样)或只是一个通用标识符终端。

关于python - Yacc - 具有函数支持的方程解析器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12227597/

相关文章:

python - 轨迹球转动不正确

python - 如何从 SQLAlchemy 结果中获取列名(声明性语法)

ocaml - 关于 ocamlyacc,函数应用语法和优先级

python - 在特征向量中估算多个缺失值

Python 属性返回属性对象

jQuery AJAX 调用数据库工作,但不按顺序

c++ - 'double'和 'double'类型的无效操作数

function - perl6 如何将用户给出的字符串评估为函数?

python - NLTK FCFG 语法标准/规范是什么?

kotlin - 当用 `@` 表示接收者时, `this` 标签在 Kotlin 中的位置