python - 如何使用 AST python 模块从中缀转换为后缀/前缀?

标签 python python-3.x abstract-syntax-tree postfix-notation infix-notation

我正在尝试使用 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_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']

关于python - 如何使用 AST python 模块从中缀转换为后缀/前缀?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42590512/

相关文章:

python - 如何检查列表中的数字与其他列表中的数字的顺序?

python - django 电子邮件中没有这样的文件或目录 attach_file

python charmap 编解码器无法将位置 Y 字符映射中的字节 X 解码为 <undefined>

scala - 代数数据类型的类型级别集

python - 继承QAbstrctitemModel、PyQt时使用Lists作为QModelIndex中的internalPointer

python - 如何在python中使用plotly绘制现有矢量值?

python - 在 pandas 数据框单元格中插入列表

python - 如何在 python 中反转句子的部分内容?

python - 使用 Python ast 模块访问语法树中的节点

c - 使用 Bison 构建 AST 时指针无效