From e17068c4d647c5d1175811209c9fba92cb8cab11 Mon Sep 17 00:00:00 2001 From: Duncan Ogilvie Date: Tue, 28 Nov 2023 14:13:10 +0100 Subject: [PATCH] Add support for parsing jni.h --- btparser/keywords.h | 2 + btparser/tests/typedefStruct.h | 10 ++ btparser/typesparser.cpp | 169 +++++++++++++++++++++++++++------ 3 files changed, 151 insertions(+), 30 deletions(-) create mode 100644 btparser/tests/typedefStruct.h diff --git a/btparser/keywords.h b/btparser/keywords.h index cb8c279..322f454 100644 --- a/btparser/keywords.h +++ b/btparser/keywords.h @@ -52,3 +52,5 @@ DEF_KEYWORD(public) DEF_KEYWORD(protected) DEF_KEYWORD(override) DEF_KEYWORD(class) + +DEF_KEYWORD(__attribute__) diff --git a/btparser/tests/typedefStruct.h b/btparser/tests/typedefStruct.h new file mode 100644 index 0000000..4b1dd60 --- /dev/null +++ b/btparser/tests/typedefStruct.h @@ -0,0 +1,10 @@ +typedef struct { + int member1; + int member2; +} JNINativeMethod; + +typedef struct JNINativeMethod2 { + int member1; + int member2; +} JNINativeMethod2; + diff --git a/btparser/typesparser.cpp b/btparser/typesparser.cpp index fde5ced..fa8ee63 100644 --- a/btparser/typesparser.cpp +++ b/btparser/typesparser.cpp @@ -18,6 +18,7 @@ struct Parser size_t index = 0; Model model; std::unordered_map structUnions; + int anonymousId = 0; Parser(const std::string& code, const std::string& owner, std::vector& errors) : owner(owner), errors(errors) @@ -466,7 +467,7 @@ struct Parser if (isStructLike()) { - if (tlist.empty() && getToken(index + 1).Token == Lexer::tok_identifier) + if (getToken(index + 1).Token == Lexer::tok_identifier) { kind = curToken().Token; index++; @@ -565,7 +566,7 @@ struct Parser subfn.name = typeToken.IdentifierStr; model.functions.push_back(subfn); - return true; + return finalizeMember(); } else if (t.Is(Lexer::tok_comma)) { @@ -621,7 +622,7 @@ struct Parser return true; } - bool parseStructUnion() + bool parseStructUnion(bool inTypedef, std::string* outName = nullptr) { auto startToken = curToken(); if (isToken(Lexer::tok_struct) || isToken(Lexer::tok_class) || isToken(Lexer::tok_union)) @@ -629,13 +630,20 @@ struct Parser StructUnion su; su.isunion = isToken(Lexer::tok_union); index++; - if (!isToken(Lexer::tok_identifier)) + if (isToken(Lexer::tok_identifier)) { - errLine(curToken(), "expected identifier after struct"); - return false; + su.name = curToken().IdentifierStr; + index++; } - su.name = lexer.TokString(curToken()); - index++; + else + { + su.name = "__anonymous_" + std::to_string(anonymousId++); + } + if(outName != nullptr) + { + *outName = su.name; + } + if (isToken(Lexer::tok_bropen)) { index++; @@ -675,15 +683,18 @@ struct Parser model.structUnions.push_back(su); } - if (!isToken(Lexer::tok_semic)) + if(!inTypedef) { - errLine(curToken(), "expected semicolon!"); - return false; + if (!isToken(Lexer::tok_semic)) + { + errLine(curToken(), "expected semicolon!"); + return false; + } + eatSemic(); } - eatSemic(); return true; } - else if (isToken(Lexer::tok_semic)) + else if (isToken(Lexer::tok_semic) && !su.name.empty()) { // Forward declaration su.size = -1; @@ -693,7 +704,8 @@ struct Parser structUnions.emplace(su.name, model.structUnions.size()); model.structUnions.push_back(su); } - eatSemic(); + if(!inTypedef) + eatSemic(); return true; } else @@ -705,19 +717,33 @@ struct Parser return true; } - bool parseEnum() + bool parseEnum(bool inTypedef, std::string* outName = nullptr) { if (isToken(Lexer::tok_enum)) { Enum e; std::string etype; index++; - if (isTokenList({ Lexer::tok_identifier, Lexer::tok_bropen })) + if(curToken().Is(Lexer::tok_identifier)) { - e.name = lexer.TokString(curToken()); - index += 2; + e.name = curToken().IdentifierStr; + index++; + } + else + { + e.name = "__anonymous_" + std::to_string(anonymousId++); + } + if(outName != nullptr) + { + *outName = e.name; + } + + // TODO: support custom enum types (: type) + + if (curToken().Is(Lexer::tok_bropen)) + { + index++; - // TODO: support custom enum types (: type) etype = "int"; while (!isToken(Lexer::tok_brclose)) @@ -791,12 +817,15 @@ struct Parser index++; //eat tok_brclose model.enums.emplace_back(e, etype); - if (!isToken(Lexer::tok_semic)) + if(!inTypedef) { - errLine(curToken(), "expected semicolon!"); - return false; + if (!isToken(Lexer::tok_semic)) + { + errLine(curToken(), "expected semicolon!"); + return false; + } + eatSemic(); } - eatSemic(); return true; } else @@ -831,17 +860,50 @@ struct Parser return false; } + if(isToken(Lexer::tok_comma)) + { + // TODO + errLine(curToken(), "unsupported comma in typedef"); + return false; + } + if (isStructLike()) { - if (tlist.empty() && getToken(index + 1).Is(Lexer::tok_identifier)) + // typedef struct/enum/union + // Consume the 'struct'-like token + kind = curToken().Token; + index++; + + if(curToken().Is(Lexer::tok_bropen) || isTokenList({ Lexer::tok_identifier, Lexer::tok_bropen })) { - kind = curToken().Token; - index++; + // 'typedef struct {' OR 'typedef struct Name {' + index--; + std::string structName; + if(kind == Lexer::tok_enum) + { + if(!parseEnum(true, &structName)) + return false; + } + else + { + if(!parseStructUnion(true, &structName)) + return false; + } + tlist.push_back({ Lexer::tok_identifier, structName }); + } + else if(isTokenList({Lexer::tok_identifier, Lexer::tok_identifier})) + { + // typedef struct Name Name + // NOTE: fallthrough + } + else if(isTokenList({Lexer::tok_identifier, Lexer::tok_op_mul})) + { + // typedef struct Name1 * + // NOTE: fallthrough } else { - errLine(curToken(), "unsupported struct/union/enum in typedef"); - return false; + errLine(curToken(), "unsupported typedef struct"); } } @@ -1053,6 +1115,53 @@ struct Parser return true; } + else if(t.Is(Lexer::tok___attribute__)) + { + index++; + + if(!isTokenList({Lexer::tok_paropen, Lexer::tok_paropen})) + { + errLine(curToken(), "expected (( after __attribute__"); + return false; + } + index += 2; + + std::vector attrTokens; + + int parStack = 0; + while(true) + { + attrTokens.push_back(curToken()); + + if(curToken().Is(Lexer::tok_paropen)) + { + index++; + parStack++; + } + else if(curToken().Is(Lexer::tok_parclose)) + { + index++; + if(parStack == 0 && curToken().Is(Lexer::tok_parclose)) + { + index++; + attrTokens.pop_back(); + break; + } + + parStack--; + if(parStack < 0) + { + errLine(curToken(), "mismatched parens"); + } + } + else + { + index++; + } + } + + // TODO: attach attribute tokens to the function? + } else { __debugbreak(); @@ -1183,9 +1292,9 @@ struct Parser auto curIndex = index; if (!parseTypedef()) return false; - if (!parseStructUnion()) + if (!parseStructUnion(false)) return false; - if (!parseEnum()) + if (!parseEnum(false)) return false; eatSemic(); if (curIndex == index)