6

我想使用AST python模块将python数学表达式转换为postfix表示法。这是我走到这一步:如何使用AST python模块将infix转换为postfix/prefix?

import parser 
import ast 
from math import sin, cos, tan 

formulas = [ 
    "1+2", 
    "1+2*3", 
    "1/2", 
    "(1+2)*3", 
    "sin(x)*x**2", 
    "cos(x)", 
    "True and False", 
    "sin(w*time)" 
] 


class v(ast.NodeVisitor): 

    def __init__(self): 
     self.tokens = [] 

    def f_continue(self, node): 
     super(v, self).generic_visit(node) 

    def visit_Add(self, node): 
     self.tokens.append('+') 
     self.f_continue(node) 

    def visit_And(self, node): 
     self.tokens.append('&&') 
     self.f_continue(node) 

    def visit_BinOp(self, node): 
     # print('visit_BinOp') 
     # for child in ast.iter_fields(node): 
      # print(' child %s ' % str(child)) 

     self.f_continue(node) 

    def visit_BoolOp(self, node): 
     # print('visit_BoolOp') 
     self.f_continue(node) 

    def visit_Call(self, node): 
     # print('visit_Call') 
     self.f_continue(node) 

    def visit_Div(self, node): 
     self.tokens.append('/') 
     self.f_continue(node) 

    def visit_Expr(self, node): 
     # print('visit_Expr') 
     self.f_continue(node) 

    def visit_Import(self, stmt_import): 
     for alias in stmt_import.names: 
      print('import name "%s"' % alias.name) 
      print('import object %s' % alias) 
     self.f_continue(stmt_import) 

    def visit_Load(self, node): 
     # print('visit_Load') 
     self.f_continue(node) 

    def visit_Module(self, node): 
     # print('visit_Module') 
     self.f_continue(node) 

    def visit_Mult(self, node): 
     self.tokens.append('*') 
     self.f_continue(node) 

    def visit_Name(self, node): 
     self.tokens.append(node.id) 
     self.f_continue(node) 

    def visit_NameConstant(self, node): 
     self.tokens.append(node.value) 
     self.f_continue(node) 

    def visit_Num(self, node): 
     self.tokens.append(node.n) 
     self.f_continue(node) 

    def visit_Pow(self, node): 
     self.tokens.append('pow') 
     self.f_continue(node) 

for index, f in enumerate(formulas): 
    print('{} - {:*^76}'.format(index, f)) 
    visitor = v() 
    visitor.visit(ast.parse(f)) 
    print(visitor.tokens) 
    print() 


# 0 - ************************************1+2************************************* 
# [1, '+', 2] 

# 1 - ***********************************1+2*3************************************ 
# [1, '+', 2, '*', 3] 

# 2 - ************************************1/2************************************* 
# [1, '/', 2] 

# 3 - **********************************(1+2)*3*********************************** 
# [1, '+', 2, '*', 3] 

# 4 - ********************************sin(x)*x**2********************************* 
# ['sin', 'x', '*', 'x', 'pow', 2] 

# 5 - ***********************************cos(x)*********************************** 
# ['cos', 'x'] 

# 6 - *******************************True and False******************************* 
# ['&&', True, False] 

# 7 - ********************************sin(w*time)********************************* 
# ['sin', 'w', '*', 'time'] 

我想了解如何将复杂缀数学表达式转换为后缀表达式被送到了一大口C包装,要做到这一点,我试图使用AST模块。

任何人都可以在这里建议吗?

回答

3

您可以使用ast.dump获取有关节点和AST结构的更多信息:

>>> import ast 
>>> node = ast.parse("sin(x)*x**2") 
>>> ast.dump(node) 
"Module(body=[Expr(value=BinOp(left=Call(func=Name(id='sin', ctx=Load()), args=[Name(id='x', ctx=Load())], keywords=[]), op=Mult(), right=BinOp(left=Name(id='x', ctx=Load()), op=Pow(), right=Num(n=2))))])" 

通过以上信息,您可以更改该节点的孩子们的参观秩序,它允许您生成后缀或前缀表达式。为了让他们访问操作/函数之前参观的参数生成后缀表达变化visit_BinOpvisit_BoolOpvisit_Call

def visit_BinOp(self, node): 
    self.visit(node.left) 
    self.visit(node.right) 
    self.visit(node.op) 

def visit_BoolOp(self, node): 
    for val in node.values: 
     self.visit(val) 
    self.visit(node.op) 

def visit_Call(self, node): 
    for arg in node.args: 
     self.visit(arg) 
    self.visit(node.func) 

随着上述变化,你得到以下的输出:

0 - ************************************1+2************************************* 

[1, 2, '+'] 

1 - ***********************************1+2*3************************************ 

[1, 2, 3, '*', '+'] 

2 - ************************************1/2************************************* 

[1, 2, '/'] 

3 - **********************************(1+2)*3*********************************** 

[1, 2, '+', 3, '*'] 

4 - ********************************sin(x)*x**2********************************* 

['x', 'sin', 'x', 2, 'pow', '*'] 

5 - ***********************************cos(x)*********************************** 

['x', 'cos'] 

6 - *******************************True and False******************************* 

[True, False, '&&'] 

7 - ********************************sin(w*time)********************************* 

['w', 'time', '*', 'sin'] 

如果你想前缀表达,而不是交换顺序,所以操作员/功能首先访问:

def visit_BinOp(self, node): 
    self.visit(node.op) 
    self.visit(node.left) 
    self.visit(node.right) 

def visit_BoolOp(self, node): 
    self.visit(node.op) 
    for val in node.values: 
     self.visit(val) 

def visit_Call(self, node): 
    self.visit(node.func) 
    for arg in node.args: 
     self.visit(arg) 

输出:

0 - ************************************1+2************************************* 

['+', 1, 2] 

1 - ***********************************1+2*3************************************ 

['+', 1, '*', 2, 3] 

2 - ************************************1/2************************************* 

['/', 1, 2] 

3 - **********************************(1+2)*3*********************************** 

['*', '+', 1, 2, 3] 

4 - ********************************sin(x)*x**2********************************* 

['*', 'sin', 'x', 'pow', 'x', 2] 

5 - ***********************************cos(x)*********************************** 

['cos', 'x'] 

6 - *******************************True and False******************************* 

['&&', True, False] 

7 - ********************************sin(w*time)********************************* 

['sin', '*', 'w', 'time'] 
+0

非常感谢你的回答,我没有想过那个,很酷。当你说'如果你想要前缀符号只是交换命令,所以操作符/函数首先被访问,你能否请详细说明一下。',你是什么意思? +1 – BPL

+0

@BPL新增前缀表达式的例子,希望它有帮助! – niemmi

+0

太棒了,谢谢 – BPL