如何使用libclang获取原始文字的值?
例如,如果我有一个游标类型CXCursor_IntegerLiteral的CXCursor,我该如何提取文字值。
更新:
我使用libclang遇到了很多问题。我强烈建议完全避免它,而是使用clang提供的C ++接口。 C ++界面非常有用,并且有很好的文档记录:http://clang.llvm.org/doxygen/annotated.html
我现在看到libclang的唯一目的是为你生成ASTUnit对象,就像下面的代码一样(否则不容易):
ASTUnit * astUnit;
{
index = clang_createIndex(0, 0);
tu = clang_parseTranslationUnit(
index, 0,
clangArgs, nClangArgs,
0, 0, CXTranslationUnit_None
);
astUnit = static_cast<ASTUnit *>(tu->TUData);
}
现在你可能会说libclang是稳定的而C ++接口不是。这几乎不重要,因为你用libclang计算AST并用它创造kludges的时间浪费了你的大部分时间。我只是花了几个小时来修复在版本升级后无法编译的代码(如果需要的话)。
答案 0 :(得分:7)
您已经拥有翻译单元内所需的所有信息,而不是重新分析原文:
if (kind == CXCursor_IntegerLiteral)
{
CXSourceRange range = clang_getCursorExtent(cursor);
CXToken *tokens = 0;
unsigned int nTokens = 0;
clang_tokenize(tu, range, &tokens, &nTokens);
for (unsigned int i = 0; i < nTokens; i++)
{
CXString spelling = clang_getTokenSpelling(tu, tokens[i]);
printf("token = %s\n", clang_getCString(spelling));
clang_disposeString(spelling);
}
clang_disposeTokens(tu, tokens, nTokens);
}
您将看到第一个标记是整数本身,下一个标记不相关(例如;
为int i = 42;
。
答案 1 :(得分:2)
您实际上可以使用libclang和C ++接口的组合。
libclang CXCursor
类型包含data
字段,其中包含对基础AST节点的引用。
通过将IntegerLiteral
转换为data[1]
类型,我能够成功访问IntegerLiteral
值。
我在Nim中实现了这一点,因此我将提供Nim代码,但您可以在C ++中执行相同操作。
let literal = cast[clang.IntegerLiteral](cursor.data[1])
echo literal.getValue().getLimitedValue()
IntegerLiteral
类型包含如下:
type
APIntObj* {.importcpp: "llvm::APInt", header: "llvm/ADT/APInt.h".} = object
# https://github.com/llvm-mirror/llvm/blob/master/include/llvm/ADT/APInt.h
APInt* = ptr APIntObj
IntegerLiteralObj* {.importcpp: "clang::IntegerLiteral", header: "clang/AST/Expr.h".} = object
IntegerLiteral* = ptr IntegerLiteralObj
proc getValue*(i: IntegerLiteral): APIntObj {.importcpp: "#.getValue()".}
# This is implemented by the superclass: https://clang.llvm.org/doxygen/classclang_1_1APIntStorage.html
proc getLimitedValue*(a: APInt | APIntObj): culonglong {.importcpp: "#.getLimitedValue()".}
希望这有助于某人:)
答案 2 :(得分:1)
如果您有权访问CXCursor
,则可以使用clang_Cursor_Evaluate
函数,例如:
CXChildVisitResult var_decl_visitor(
CXCursor cursor, CXCursor parent, CXClientData data) {
auto kind = clang_getCursorKind(cursor);
switch (kind) {
case CXCursor_IntegerLiteral: {
auto res = clang_Cursor_Evaluate(cursor);
auto value = clang_EvalResult_getAsInt(res);
clang_EvalResult_dispose(res);
std::cout << "IntegerLiteral " << value << std::endl;
break;
}
default:
break;
}
return CXChildVisit_Recurse;
}
输出:
IntegerLiteral 42
答案 3 :(得分:0)
我通过引用原始文件找到了一种方法:
std::string getCursorText (CXCursor cur) {
CXSourceRange range = clang_getCursorExtent(cur);
CXSourceLocation begin = clang_getRangeStart(range);
CXSourceLocation end = clang_getRangeEnd(range);
CXFile cxFile;
unsigned int beginOff;
unsigned int endOff;
clang_getExpansionLocation(begin, &cxFile, 0, 0, &beginOff);
clang_getExpansionLocation(end, 0, 0, 0, &endOff);
ClangString filename = clang_getFileName(cxFile);
unsigned int textSize = endOff - beginOff;
FILE * file = fopen(filename.c_str(), "r");
if (file == 0) {
exit(ExitCode::CANT_OPEN_FILE);
}
fseek(file, beginOff, SEEK_SET);
char buff[4096];
char * pBuff = buff;
if (textSize + 1 > sizeof(buff)) {
pBuff = new char[textSize + 1];
}
pBuff[textSize] = '\0';
fread(pBuff, 1, textSize, file);
std::string res(pBuff);
if (pBuff != buff) {
delete [] pBuff;
}
fclose(file);
return res;
}