我正在尝试为等式编写方程解析器: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)
提前致谢!约翰
答案 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
,每个函数可以有一行(如果函数列表很短),或者包含函数标识符列表的非终端,或者特殊终端(如我的语法)或只是一个通用的标识符终端。