2

我正在尝试为以下等式编写一个等式解析器:4*sin(1+cos(10/2))lex用来获取令牌并yacc作为解析器模块。

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

但是我将如何处理这样构建的功能sin(3+cos(0)*10)。这将是一个函数中的一个函数,不要忘记关心3+and *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)

提前致谢!约翰

4

1 回答 1

3

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

于 2012-09-01T12:24:26.707 回答