1

我正在使用 pycparser 来解析 C 文件。我希望在 C 文件中获取每个函数定义的开始和结束。但我实际上得到的只是函数定义的开始。

memmgr_init at examples/c_files/memmgr.c:46
get_mem_from_pool at examples/c_files/memmgr.c:55

我希望得到类似的东西:

memmgr_init at examples/c_files/memmgr.c: start :46 end : 52

class FuncDefVisitor(c_ast.NodeVisitor):

def visit_FuncDef(self, node):
print('%s at %s' % (node.decl.name, node.decl.coord))
4

2 回答 2

1

pycparser 不能这样做,因为它在解析时不记录函数的结束位置。

您可以从 AST 重新生成函数体:

from pycparser import c_parser, c_ast, parse_file, c_generator

class FuncDefVisitor(c_ast.NodeVisitor):
def __init__(self, bodies):
    self.bodies = bodies
    self.generator = c_generator.CGenerator()
def visit_FuncDef(self, node):
    self.bodies.append(self.generator.visit(node))

def show_func_defs(filename):
    ast = parse_file(filename, use_cpp=True,
                 cpp_args=r'-Iutils/fake_libc_include')
    bodies = []
    v = FuncDefVisitor(bodies)
    v.visit(ast)
    for body in bodies:
        print(body)

但这可能与原始格式略有不同,因此不能用于计算函数末尾从开头开始的行数。

于 2016-03-21T07:45:19.257 回答
0

我有一个快速而肮脏的解决方案来解决你的问题。您需要做的是从 AST 获取最近的线路。除非必须,否则我不喜欢修改库。我假设您熟悉解析和数据操作。如果没有,我可以添加更多细节。parser.parse 方法生成一个 AST 类对象。gcc_or_cpp_output 是 gcc 或 cpp 生成的一些中间代码。

ast = parser.parse(gcc_or_cpp_output,filename)

AST 的函数有一个 show 方法和默认参数。您需要为您的问题设置 showcoord True。

ast.show(buf=fb,attrnames=True, nodenames=True, showcoord=True)

        buf:
            Open IO buffer into which the Node is printed.

        offset:
            Initial offset (amount of leading spaces)

        attrnames:
            True if you want to see the attribute names in
            name=value pairs. False to only see the values.

        nodenames:
            True if you want to see the actual node names
            within their parents.

        showcoord:
            Do you want the coordinates of each Node to be
            displayed

然后,您需要将 buf 默认值从 sys.stdout 更改为您自己的缓冲区类,以便捕获 ast 图。您也可以遍历树,但我将在另一天保存树遍历解决方案。我在下面写了一个简单的 fake_buffer。

class fake_buffer():
    def __init__(self):
        self.buffer =[]
    def write(self,string):
        self.buffer.append(string)
    def get_buffer(self):
        return self.buffer

所以你现在需要做的就是保存将你的假缓冲区传递给 ast.show() 方法以获取 AST。

fb = fake_buffer()
ast.show(buf=fb,attrnames=True, nodenames=True, showcoord=True)

此时,您将拥有 AST 作为列表。函数声明将在底部附近。现在你只需要解析出所有额外的东西并获得该函数 delectation 中的最大坐标。

  FuncCall <block_items[12]>:  (at ...blah_path_stuff.../year.c:48)

ABC 永远在编码

于 2016-10-29T04:22:53.467 回答