You can use ast.dump
to get more information about AST nodes and structure:
>>> 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))))])"
Using the above information, you can change the order of visits to the children of a node, which allows you to generate a postfix or prefix expression. To generate the postfix expression change visit_BinOp
, visit_BoolOp
and visit_Call
so that they visit the arguments before visiting the statement / function:
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)
With the above changes, you get the following result:
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']
If you want to use a prefix expression instead of just changing the order, since the operator / function is searched first:
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)
Output:
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']