如何使用 libclang 获取枚举元素的数值?
How do I get an enum element's numerical value using libclang?
假设我有一个枚举定义,例如:
// myenum.h
enum MyEnum {
First = 1,
Second,
Third,
TwoAgain = Second
};
我想以编程方式从任何给定的枚举定义生成映射,其中键是枚举元素的名称,值是枚举元素的数值(例如myMap["TwoAgain"] == 2
)
到目前为止,我知道如何使用 clang_visitChildren()
遍历源文件,并使用 clang_tokenize()
提取单个标记。通过 AST 递归,我按以下顺序得到 cursors/tokens:
- "MyEnum" (CXType_Enum)
- "First" (CXToken_Identifier)
- "=" (CXToken_Punctuation)
- "1" (CXToken_Literal)
- "unsigned int" (CXType_UInt)
- "1" (CXToken_Literal)
- "MyEnum" (CXType_Enum)
- "Second" (CXToken_Identifier)
- "MyEnum" (CXType_Enum)
- "Third" (CXToken_Identifier)
- "MyEnum" (CXType_Enum)
- "TwoAgain" (CXToken_Identifier)
- "=" (CXToken_Punctuation)
- "Second" (CXToken_Identifier)
- "unsigned int" (CXType_UInt)
- "Second" (CXToken_Identifier)
我想我可以编写一个算法,使用这些信息来计算每个值。但是,我想知道是否有更简单的方法? 我可以直接从 libclang 中获取数值吗 API?
正如 id256 所说,我不认为你可以用 libclang
做到这一点。但是,Clang 的 libtooling
and plugin interface 允许您访问 AST 并直接对其进行操作。对于枚举,您需要查看 EnumDecl
class,它允许您迭代内部声明。那么这只是一个构建地图的例子:
for (auto declIterator = myEnumDecl.decls_begin();
declIterator != myEnumDecl.decls_end();
++declIterator)
{
myMap[declIterator->getNameAsString()] = declIterator->getInitVal;
}
libclang 通过 clang_getEnumConstantDeclValue
and clang_getEnumConstantDeclUnsignedValue
公开此信息。可以通过访问 CXCursor_EnumDecl
:
的子项来构建您描述的地图
static enum CXChildVisitResult VisitCursor(CXCursor cursor, CXCursor parent, CXClientData client_data) {
if (cursor.kind == CXCursor_EnumConstantDecl) {
CXString spelling = clang_getCursorSpelling(cursor);
myMap[clang_getCString(spelling)] = clang_getEnumConstantDeclValue(cursor);
clang_disposeString(spelling);
}
return CXChildVisit_Continue;
}
您可以使用以下方式获取地图的名称和值。我正在使用 clang 8.
bool VisitEnumDecl(EnumDecl *ED)
{
for (auto it = ED->enumerator_begin(); it != ED->enumerator_end(); it++)
{
std::cout <<it->getNameAsString()<<" "<<it->getInitVal().getSExtValue()<<std::endl;
}
return true;
}
假设我有一个枚举定义,例如:
// myenum.h
enum MyEnum {
First = 1,
Second,
Third,
TwoAgain = Second
};
我想以编程方式从任何给定的枚举定义生成映射,其中键是枚举元素的名称,值是枚举元素的数值(例如myMap["TwoAgain"] == 2
)
到目前为止,我知道如何使用 clang_visitChildren()
遍历源文件,并使用 clang_tokenize()
提取单个标记。通过 AST 递归,我按以下顺序得到 cursors/tokens:
- "MyEnum" (CXType_Enum)
- "First" (CXToken_Identifier)
- "=" (CXToken_Punctuation)
- "1" (CXToken_Literal)
- "unsigned int" (CXType_UInt)
- "1" (CXToken_Literal)
- "MyEnum" (CXType_Enum)
- "Second" (CXToken_Identifier)
- "MyEnum" (CXType_Enum)
- "Third" (CXToken_Identifier)
- "MyEnum" (CXType_Enum)
- "TwoAgain" (CXToken_Identifier)
- "=" (CXToken_Punctuation)
- "Second" (CXToken_Identifier)
- "unsigned int" (CXType_UInt)
- "Second" (CXToken_Identifier)
我想我可以编写一个算法,使用这些信息来计算每个值。但是,我想知道是否有更简单的方法? 我可以直接从 libclang 中获取数值吗 API?
正如 id256 所说,我不认为你可以用 libclang
做到这一点。但是,Clang 的 libtooling
and plugin interface 允许您访问 AST 并直接对其进行操作。对于枚举,您需要查看 EnumDecl
class,它允许您迭代内部声明。那么这只是一个构建地图的例子:
for (auto declIterator = myEnumDecl.decls_begin();
declIterator != myEnumDecl.decls_end();
++declIterator)
{
myMap[declIterator->getNameAsString()] = declIterator->getInitVal;
}
libclang 通过 clang_getEnumConstantDeclValue
and clang_getEnumConstantDeclUnsignedValue
公开此信息。可以通过访问 CXCursor_EnumDecl
:
static enum CXChildVisitResult VisitCursor(CXCursor cursor, CXCursor parent, CXClientData client_data) {
if (cursor.kind == CXCursor_EnumConstantDecl) {
CXString spelling = clang_getCursorSpelling(cursor);
myMap[clang_getCString(spelling)] = clang_getEnumConstantDeclValue(cursor);
clang_disposeString(spelling);
}
return CXChildVisit_Continue;
}
您可以使用以下方式获取地图的名称和值。我正在使用 clang 8.
bool VisitEnumDecl(EnumDecl *ED)
{
for (auto it = ED->enumerator_begin(); it != ED->enumerator_end(); it++)
{
std::cout <<it->getNameAsString()<<" "<<it->getInitVal().getSExtValue()<<std::endl;
}
return true;
}