Как получить числовое значение элемента enum с помощью libclang?
Предположим, у меня есть определение enum, например:
// myenum.h
enum MyEnum {
First = 1,
Second,
Third,
TwoAgain = Second
};
Я хотел бы программно сгенерировать карту из любого заданного определения перечисления, где ключ - это имя элемента перечисления, а значение - числовое значение элемента перечисления (например, myMap["TwoAgain"] == 2
)
До сих пор я знаю, как пройти исходный файл, используя clang_visitChildren()
и извлекать отдельные токены, используя clang_tokenize()
, Повторяя через AST, я получаю курсоры / токены в следующем порядке:
- "MyEnum" (CXType_Enum)
- "Первый" (CXToken_Identifier)
- "=" (CXToken_Punctuation)
- "1" (CXToken_Literal)
- "unsigned int" (CXType_UInt)
- "1" (CXToken_Literal)
- "MyEnum" (CXType_Enum)
- "Второй" (CXToken_Identifier)
- "MyEnum" (CXType_Enum)
- "Третий" (CXToken_Identifier)
- "MyEnum" (CXType_Enum)
- "TwoAgain" (CXToken_Identifier)
- "=" (CXToken_Punctuation)
- "Второй" (CXToken_Identifier)
- "unsigned int" (CXType_UInt)
- "Второй" (CXToken_Identifier)
Я думаю, я мог бы написать алгоритм, который использует эту информацию для расчета каждого значения. Однако мне было интересно, есть ли более простой способ? Могу ли я получить числовые значения непосредственно из API libclang?
2 ответа
libclang раскрывает эту информацию через clang_getEnumConstantDeclValue
а также 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;
}
Как сказал id256, я не думаю, что вы можете сделать это с libclang
, Тем не менее, Clang's libtooling
и интерфейс плагина позволит вам получить доступ к AST и работать с ним напрямую. Для перечислений, вы хотите посмотреть на EnumDecl
класс, который позволяет перебирать внутренние decls. Тогда это всего лишь случай построения карты, например:
for (auto declIterator = myEnumDecl.decls_begin();
declIterator != myEnumDecl.decls_end();
++declIterator)
{
myMap[declIterator->getNameAsString()] = declIterator->getInitVal;
}
Вы можете использовать следующий способ для получения имени и значения для вашей карты. Я использую 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;
}