C++ libclang:如何获取令牌语义

C++ libclang:如何获取令牌语义,c++,libclang,C++,Libclang,libclang只定义了5种类型的令牌: 标点符号 CXU关键字 CXU标识符 CXU文本 CXU注释 是否有可能获得有关令牌的更详细信息?例如,对于以下源代码: struct Type; void foo(Type param); 我希望输出结果如下: 结构关键字 类型-类型名称 -标点符号 void-类型/关键字 foo-函数名 (-标点符号 Type-函数参数的类型 param-函数参数名 )-标点符号 -标点符号 我还需要将这些实体映射到文件位置。首先,您可能需要了解一些解

libclang只定义了5种类型的令牌:

  • 标点符号
  • CXU关键字
  • CXU标识符
  • CXU文本
  • CXU注释
是否有可能获得有关令牌的更详细信息?例如,对于以下源代码:

struct Type;
void foo(Type param);
我希望输出结果如下:

  • 结构关键字
  • 类型-类型名称
  • -标点符号
  • void-类型/关键字
  • foo-函数名
  • (-标点符号
  • Type-函数参数的类型
  • param-函数参数名
  • )-标点符号
  • -标点符号

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

首先,您可能需要了解一些解析工作的背景知识。关于编译器的教科书将是一个有用的资源。首先,将文件转换为一系列令牌;它为您提供标识符、标点符号等。执行此操作的代码称为lexer。然后,解析器运行;这会将令牌列表转换为AST(结构化声明/表达式等)

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

CXToken
只是一个令牌;除了您列出的五种类型之外,没有任何其他相关的语义信息。(您可以使用
clang\u getTokenSpelling
获取令牌的实际文本,以及使用
clang\u getTokenExtent
获取令牌的位置)
clang\u annotatedTokens
为您提供
CXCursor
s,让您可以检查相关声明


请注意,libclangapi没有公开某些细节;如果您需要更多的细节,您可能需要使用CLAN的C++ API。在C++中,可以使用函数和这些函数的最低限度使用(使用它们的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>
TokenKind.KEYWORD结构
TokenKind.IDENTIFIER类型
标点符号;
TokenKind.keywordvoid
TokenKind.IDENTIFIER foo
标记种类.标点符号(
TokenKind.IDENTIFIER类型
TokenKind.IDENTIFIER参数
标记(例如标点符号)
标点符号;

一些链接将非常有用(不是说你错了,事实上我自己在探索libclang时看到了你的大部分言论,只是指出有一些链接来支持你的言论是多么有教育意义)。我知道解析器是如何工作的,我已经实现了不止一个。稍后我将为我的问题添加更多细节。目前我使用的是
clang_annotatedTokens
,但它返回的游标带有意外的
CXCursorKind
s。@piotrekg2:如果你真的知道解析器是如何工作的,为什么你希望令牌流包含像这样的非令牌信息“函数名"等等?这是基于解析器的信息,而不是基于令牌的。@Nicolas可能我表达得不够清楚。我想要实现的是一系列命名实体。对我来说,这样的实体应该是包含给定令牌的AST的最低节点。目前我正在使用
clangu annotateTokens
将令牌映射到curs不过,它的实现似乎有一些bug。请看。我想我从链接中发现了不止这些bug。