libclang:如何获取令牌语义

libclang: how to get token semantics

libclang 只定义了 5 种类型的标记:

是否可以获得有关令牌的更详细信息?例如,对于以下源代码:

struct Type;
void foo(Type param);

我希望输出如下:

我还需要将这些实体映射到文件位置。

首先,您可能需要了解一些有关解析工作原理的背景知识。关于编译器的教科书将是一个有用的资源。首先,文件被转换成一系列的令牌;为您提供标识符、标点符号等。执行此操作的代码称为词法分析器。然后,解析器运行;这会将标记列表转换为 AST(结构化 declarations/expressions/etc..

clang 确实跟踪声明和表达式的各个部分,但不是以您描述的方式。对于给定的函数声明,它会跟踪函数名称的位置和参数列表的开头等内容,但它会根据文件中的位置而不是标记来保留这些内容。

一个CXToken只是一个token;除了您列出的五种类型之外,没有任何其他关联的语义信息。 (您可以使用 clang_getTokenSpelling 获取令牌的实际文本,使用 clang_getTokenExtent 获取位置。)clang_annotateTokens 为您提供 CXCursors,让您检查相关声明。

请注意,libclang 没有公开一些细节 API;如果您需要更多详细信息,您可能需要改用 clang 的 C++ API。

您正在查找 libclang 公开的令牌 spellinglocation 属性。在 C++ 中,这些可以使用函数 clang_getTokenLocation and clang_getTokenSpelling 检索。这些函数的最少使用(使用它们的 python 等价物是:

s = '''
struct Type;
void foo(Type param);
'''

idx = clang.cindex.Index.create()
tu = idx.parse('tmp.cpp', args=['-std=c++11'],  unsaved_files=[('tmp.cpp', s)],  options=0)
for t in tu.get_tokens(extent=tu.cursor.extent):
    print t.kind, t.spelling, t.location

给出:

TokenKind.KEYWORD struct <SourceLocation file 'tmp.cpp', line 2, column 1>
TokenKind.IDENTIFIER Type <SourceLocation file 'tmp.cpp', line 2, column 8>
TokenKind.PUNCTUATION ; <SourceLocation file 'tmp.cpp', line 2, column 12>
TokenKind.KEYWORD void <SourceLocation file 'tmp.cpp', line 3, column 1>
TokenKind.IDENTIFIER foo <SourceLocation file 'tmp.cpp', line 3, column 6>
TokenKind.PUNCTUATION ( <SourceLocation file 'tmp.cpp', line 3, column 9>
TokenKind.IDENTIFIER Type <SourceLocation file 'tmp.cpp', line 3, column 10>
TokenKind.IDENTIFIER param <SourceLocation file 'tmp.cpp', line 3, column 15>
TokenKind.PUNCTUATION ) <SourceLocation file 'tmp.cpp', line 3, column 20>
TokenKind.PUNCTUATION ; <SourceLocation file 'tmp.cpp', line 3, column 21>