Yacc - 具有功能支持的方程解析器

时间:2012-09-01 12:12:43

标签: 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)

提前致谢!约翰

1 个答案:

答案 0 :(得分:2)

简单表达式的传统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,每个函数可以有一行(如果函数列表很短),或者包含函数标识符列表的非终端,或者特殊终端(如我的语法)或只是一个通用的标识符终端。