如何使用 AST python 模块从中缀转换为 postfix/prefix?
How to convert from infix to postfix/prefix using AST python module?
我正在尝试使用 AST python 模块将 python 数学表达式转换为后缀表示法。这是我到目前为止得到的:
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']
我试图了解如何将复杂的中缀数学表达式转换为后缀表达式以发送到 swig c 包装器,为此我正在尝试使用 AST 模块。
这里有人能给点建议吗?
您可以使用 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_BinOp
、visit_BoolOp
和 visit_Call
以便它们在访问 operator/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)
通过以上更改,您将获得以下输出:
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']
如果您想要前缀表达式,只需调换顺序,以便首先访问 operator/function:
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']
我正在尝试使用 AST python 模块将 python 数学表达式转换为后缀表示法。这是我到目前为止得到的:
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']
我试图了解如何将复杂的中缀数学表达式转换为后缀表达式以发送到 swig c 包装器,为此我正在尝试使用 AST 模块。
这里有人能给点建议吗?
您可以使用 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_BinOp
、visit_BoolOp
和 visit_Call
以便它们在访问 operator/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)
通过以上更改,您将获得以下输出:
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']
如果您想要前缀表达式,只需调换顺序,以便首先访问 operator/function:
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']