2016-03-16 59 views
1

我正在使用pycparser來解析C文件。我希望在C文件中獲得每個函數定義的開始和結束。 但是我實際得到的只是函數定義的開始。pycparser:如何在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)) 
+0

你需要知道末端的位置,或者你只是想提取函數體? –

+0

我只需要函數結束的行號。 –

回答

0

你不能用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) 

但是,這可能與原始略有不同的格式,因此不能被用來制定出功能到底有多少行後從開始。

+0

非常感謝Martin!我應該寫我自己的解析機制嗎?我想到了實現堆棧來檢測匹配的右括號「}」,描述了函數的結尾。或者有沒有更好的辦法呢。謝謝 –

0

我對你的問題有一個快速和骯髒的解決方案。你需要做的是從AST獲得最近的一行。除非必須修改庫,否則我不喜歡。我假設你熟悉解析和數據操作。如果不是,我可以添加更多的細節。parser.parse方法生成一個AST類對象。 gcc_or_cpp_output是由gcc或cpp生成的一些中間代碼。

ast = parser.parse(gcc_or_cpp_output,filename) 

AST的函數有一個show方法和默認參數。您需要爲您的問題設置showco 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 

然後,您需要更改從sys.stdout的BUF將默認爲您自己的緩衝區類,因此可以捕捉到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作爲列表。函數聲明將靠近底部。現在你只需要解析出所有額外的東西,並獲得該函數的最大座標。

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

ABC 始終編碼

相關問題