首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何使用pycparser删除AST节点?

如何使用pycparser删除AST节点?
EN

Stack Overflow用户
提问于 2020-02-13 03:41:48
回答 1查看 336关注 0票数 1

让我们从考虑这段代码开始:

代码语言:javascript
复制
import sys

from pycparser import c_parser, c_ast, c_generator


text = r"""
void main() {
    foo(1,3);

    foo1(4);

    x = 1;

     foo2(4,

        10,


        3);
    foo3(
        "xxx"

    );
}
"""


class FuncCallVisitor(c_ast.NodeVisitor):

    def visit_FuncCall(self, node):
        print('%s called at %s' % (node.name.name, node.name.coord))

        if node.args:
            self.visit(node.args)


class RemoveFuncCalls(c_generator.CGenerator):

    def visit_FuncCall(self, n):
        # fref = self._parenthesize_unless_simple(n.name)
        # return fref + '(' + self.visit(n.args) + ')'
        return ""


if __name__ == '__main__':
    parser = c_parser.CParser()
    ast = parser.parse(text)
    v = FuncCallVisitor()
    v.visit(ast)
    print('-' * 80)

    ast.show(showcoord=True)
    generator = RemoveFuncCalls()

    print('-' * 80)
    print(generator.visit(ast))

上面的输出将是:

代码语言:javascript
复制
void main()
{
  ;
  ;
  x = 1;
  ;
  ;
}

但我希望它变成这样:

代码语言:javascript
复制
void main()
{
  x = 1;
}

所以我的问题是,使用pycparser从AST中删除节点/子树的规范/惯用方法是什么?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2020-02-15 06:45:44

它看起来像是c_generator.CGenerator为类作用域结构调用了_generate_stmt methodwhich appends ';\n' (带有缩进)是visit for语句的结果,即使它是一个空字符串。

要移除函数调用,我们可以重载它,如下所示

代码语言:javascript
复制
class RemoveFuncCalls(c_generator.CGenerator):
    def _generate_stmt(self, n, add_indent=False):
        if isinstance(n, c_ast.FuncCall):
            return ''
        else:
            return super()._generate_stmt(n, add_indent)

这样就可以了

代码语言:javascript
复制
void main()
{
  x = 1;
}

这看起来就是你想要的。

让我们考虑一个案例

代码语言:javascript
复制
if (bar(42, "something"))
    return;

如果我们需要它成为

代码语言:javascript
复制
if ()
    return;

然后我们需要添加

代码语言:javascript
复制
    def visit_FuncCall(self, n):
        return ''

就像在OP中一样,因为RemoveFuncCalls.visit_If方法不会调用_generate_stmt来进行cond字段序列化。

更进一步

我不知道什么是“使用pycparser从AST中删除节点/子树的规范/惯用方法”,但我知道一个来自stdlib的ast模块-- ast.NodeTransformer class (由于某种原因,它在pycparser中是没有的)。

它将允许我们避免通过重写私有方法和修改AST本身来扰乱如何将AST序列化为str

代码语言:javascript
复制
from pycparser import c_ast

class NodeTransformer(c_ast.NodeVisitor):
    def generic_visit(self, node):
        for field, old_value in iter_fields(node):
            if isinstance(old_value, list):
                new_values = []
                for value in old_value:
                    if isinstance(value, c_ast.Node):
                        value = self.visit(value)
                        if value is None:
                            continue
                        elif not isinstance(value, c_ast.Node):
                            new_values.extend(value)
                            continue
                    new_values.append(value)
                old_value[:] = new_values
            elif isinstance(old_value, c_ast.Node):
                new_node = self.visit(old_value)
                setattr(node, field, new_node)
        return node


def iter_fields(node):
    # this doesn't look pretty because `pycparser` decided to have structure 
    # for AST node classes different from stdlib ones
    index = 0
    children = node.children()
    while index < len(children):
        name, child = children[index]
        try:
            bracket_index = name.index('[')
        except ValueError:
            yield name, child
            index += 1
        else:
            name = name[:bracket_index]
            child = getattr(node, name)
            index += len(child)
            yield name, child

对于我们的情况,可以简单地将其子类

代码语言:javascript
复制
class FuncCallsRemover(NodeTransformer):
    def visit_FuncCall(self, node):
        return None

并像这样使用

代码语言:javascript
复制
...
ast = parser.parse(text)
v = FuncCallsRemover()
ast = v.visit(ast)  # note that `NodeTransformer` returns modified AST instead of `None`

之后,我们可以使用未修改的c_generator.CGenerator实例,并得到相同的结果。

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/60195762

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档