2012-05-21 75 views
4

如何使用libclang获取原始文字的值?libclang获取原始值

例如,如果我有一个CXCursor类型的CXCursor_IntegerLiteral,我如何提取字面值。


UPDATE:

我碰到使用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

我找到了一种方法参照原始文件要做到这一点:

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; 
} 
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;

+0

那太酷了!这就是说,你知道如何让你的或我的解决方案在原始源代码中使用宏吗?也就是说,如果我有'#define N 1'' int x = N',最好从这里取代'1'而不是'N'或空字符串。那么复杂的宏又如何呢? –

+0

为什么它会返回一个额外的;之后1.我观察到clang_getCursorExtent()也返回一个额外的列之后的整数文字。为什么这样做是因为游标是INTEGERLITERAL类型的 – simar

1

您实际上可以使用libclang和C++接口的组合。

libclang CXCursor类型包含一个data字段,其​​中包含对基础AST节点的引用。 通过将转换为IntegerLiteral类型,我能够成功访问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()".} 

希望这可以帮助别人:)