2

私は次のような方程式の方程式パーサーを作成しようとしています。トークンを取得するため、およびパーサーモジュールとして4*sin(1+cos(10/2)) 使用します。lexyacc

私の実際の問題は、関数の文法を定義する方法がわからないことです。関数は通常この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)

前もって感謝します!ジョン

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関数ごとに1行ずつ(関数のリストが短い場合)、関数識別子のリストを含む非終端記号、または特別な終端記号(私の文法のように)、または単に一般的な識別子の終端記号を使用できます。。

于 2012-09-01T12:24:26.707 に答える