tss*_*sch 5 c++ python templates clang abstract-syntax-tree
我正在使用 clang 通过 python 接口提供的抽象语法树,尝试解析包含 std::vector 的简单结构:
#include <vector>
struct outer_t
{
std::vector<int> vec_of_ints;
};
Run Code Online (Sandbox Code Playgroud)
我想获取向量的模板参数,但在 AST 的相应节点中找不到对它的引用。get_num_template_arguments() 成员函数返回 -1。因此我认为 get_template_* 函数不能使用。我尝试了以下方法:
import sys
import clang.cindex
clang.cindex.Config.set_library_file("/usr/lib/llvm-6.0/lib/libclang.so.1")
class Walker:
def __init__(self, filename):
self.filename = filename
def walk(self, node):
node_in_file = bool(node.location.file and node.location.file.name == self.filename)
if node_in_file:
print(f"node.spelling = {node.spelling:14}, node.kind = {node.kind}")
if node.kind == clang.cindex.CursorKind.TEMPLATE_REF:
print(f"node.get_num_template_arguments = {node.get_num_template_arguments()}")
for child in node.get_children():
self.walk(child)
filename = sys.argv[1]
index = clang.cindex.Index.create()
translation_unit = index.parse(filename)
root = translation_unit.cursor
walker = Walker(filename)
walker.walk(root)
Run Code Online (Sandbox Code Playgroud)
这会产生以下结果:
node.spelling = vec_of_ints , node.kind = CursorKind.FIELD_DECL
node.spelling = std , node.kind = CursorKind.NAMESPACE_REF
node.spelling = vector , node.kind = CursorKind.TEMPLATE_REF
node.get_num_template_arguments = -1
Run Code Online (Sandbox Code Playgroud)
还有另一种方法来获取模板参数还是我做错了什么?
游标TEMPLATE_REF类型似乎没有任何关于其参数的信息,至少对于这个例子来说是这样;我不知道为什么。但FIELD_DECL有一个type可以有模板参数。vec_of_ints以下是代码的最小修改版本,用于打印示例代码中字段的模板参数数量:
import sys
import clang.cindex
clang.cindex.Config.set_library_file("/usr/lib/llvm-6.0/lib/libclang.so.1")
class Walker:
def __init__(self, filename):
self.filename = filename
def walk(self, node):
node_in_file = bool(node.location.file and node.location.file.name == self.filename)
if node_in_file:
print(f"node.spelling = {node.spelling:14}, node.kind = {node.kind}")
# -------- BEGIN modified section --------
type = node.type
if type is not None:
ntargs = type.get_num_template_arguments()
if ntargs > 0:
print(f" type.spelling = {type.spelling}")
print(f" type.get_num_template_arguments = {ntargs}")
# -------- END modified section --------
for child in node.get_children():
self.walk(child)
filename = sys.argv[1]
index = clang.cindex.Index.create()
translation_unit = index.parse(filename)
root = translation_unit.cursor
walker = Walker(filename)
walker.walk(root)
Run Code Online (Sandbox Code Playgroud)
当在示例输入文件上运行时,我得到:
node.spelling = outer_t , node.kind = CursorKind.STRUCT_DECL
node.spelling = vec_of_ints , node.kind = CursorKind.FIELD_DECL
type.spelling = std::vector<int>
type.get_num_template_arguments = 1
node.spelling = std , node.kind = CursorKind.NAMESPACE_REF
node.spelling = vector , node.kind = CursorKind.TEMPLATE_REF
Run Code Online (Sandbox Code Playgroud)
我并不声称这可以处理代码中出现的所有模板情况。我通过反复试验和阅读clang/cindex.py库模块源文件发现了上述内容。但它希望可以作为一个有用的起点。
无论如何,关于 Clang AST(以及几乎所有 C/C++ AST)需要理解的一件重要事情是类型不是主语法树中的节点。相反,类型是该树中某些节点的语义解释,因此有点放在一边。这就是为什么它们不作为 的参数出现walk。