Let's start by considering this snippet:
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))
The output of the above will be:
void main()
{
;
;
x = 1;
;
;
}
But I'd like it to become this instead:
void main()
{
x = 1;
}
So my question is, what's the canonical/idiomatic way to delete nodes/subtrees from the AST with pycparser?
It looks like
c_generator.CGeneratorcalls_generate_stmtmethod for scope-like structures which appends';\n'(with indentation) to result ofvisitfor statement even if it is an empty string.To remove function calls we can overload it like
with that
which looks like what you want.
Let's consider a case
if we need it to become
then we need to add
like in OP, because
_generate_stmtisn't called byRemoveFuncCalls.visit_Ifmethod forcondfield serialization.Going further
I don't know what "canonical/idiomatic way to delete nodes/subtrees from the AST with pycparser", but I do know one for
astmodule from stdlib --ast.NodeTransformerclass (which is absent inpycparserfor some reason).It will allow us to avoid messing with how AST is serialized to
strby overriding private'ish methods and modify AST itselfand for our case it can be simply subclassed
and used like
after that we can use unmodified
c_generator.CGeneratorinstance and get the same result.