From 2973445c5fd4b0e8b344242fcdbab0e4ade346fe Mon Sep 17 00:00:00 2001 From: Duncan Ogilvie Date: Thu, 6 Apr 2023 09:29:09 +0200 Subject: [PATCH] Basic support for parsing virtual functions --- btparser/keywords.h | 7 + btparser/lexer.cpp | 14 +- btparser/main.cpp | 5 +- btparser/tests/cursor.hpp | 55 ++++++ btparser/tests/cursor.hpp.pp.h | 55 ++++++ btparser/types.cpp | 347 +-------------------------------- btparser/types.h | 83 ++++---- btparser/typesparser.cpp | 261 +++++++++++++++++++++---- 8 files changed, 400 insertions(+), 427 deletions(-) create mode 100644 btparser/tests/cursor.hpp create mode 100644 btparser/tests/cursor.hpp.pp.h diff --git a/btparser/keywords.h b/btparser/keywords.h index 80b5eec..e8a3435 100644 --- a/btparser/keywords.h +++ b/btparser/keywords.h @@ -44,3 +44,10 @@ DEF_KEYWORD(double) DEF_KEYWORD(true) DEF_KEYWORD(false) DEF_KEYWORD(nullptr) + +DEF_KEYWORD(virtual) +DEF_KEYWORD(private) +DEF_KEYWORD(public) +DEF_KEYWORD(protected) +DEF_KEYWORD(override) +DEF_KEYWORD(class) diff --git a/btparser/lexer.cpp b/btparser/lexer.cpp index ad8d50a..263a459 100644 --- a/btparser/lexer.cpp +++ b/btparser/lexer.cpp @@ -258,14 +258,24 @@ Lexer::Token Lexer::getToken(size_t & tokenLineIndex) } //identifier/keyword - if(isalpha(mLastChar) || mLastChar == '_') //[a-zA-Z_] + if(isalpha(mLastChar) || mLastChar == '_' || (mLastChar == ':' && peekChar() == ':')) //[a-zA-Z_] { tokenLineIndex = mState.LineIndex - 1; mState.IdentifierStr = mLastChar; + if (mLastChar == ':') //consume the '::' + { + mState.IdentifierStr += ':'; + nextChar(); + } nextChar(); - while(isalnum(mLastChar) || mLastChar == '_') //[0-9a-zA-Z_] + while(isalnum(mLastChar) || mLastChar == '_' || (mLastChar == ':' && peekChar() == ':')) //[0-9a-zA-Z_] { mState.IdentifierStr.push_back(mLastChar); + if(mLastChar == ':') //consume the '::' + { + mState.IdentifierStr += ':'; + nextChar(); + } nextChar(); } diff --git a/btparser/main.cpp b/btparser/main.cpp index b5e189d..1c796bc 100644 --- a/btparser/main.cpp +++ b/btparser/main.cpp @@ -110,7 +110,8 @@ bool DebugParser(const std::string & filename) FileHelper::WriteAllText("tests\\" + filename + ".pp.h", ppData); std::vector errors; - if (!ParseTypes(ppData, filename, errors)) + Types::TypeManager typeManager; + if (!typeManager.ParseTypes(ppData, filename, errors)) { puts("Failed to parse types:"); for (const auto& error : errors) @@ -126,7 +127,7 @@ int main() { //GenerateExpectedTests(); auto ticks = GetTickCount(); - DebugParser("simple.bt"); + DebugParser("cursor.hpp"); //Lexer lexer; //DebugLexer(lexer, "AndroidManifestTemplate.bt", false); //RunLexerTests(); diff --git a/btparser/tests/cursor.hpp b/btparser/tests/cursor.hpp new file mode 100644 index 0000000..fe0d67c --- /dev/null +++ b/btparser/tests/cursor.hpp @@ -0,0 +1,55 @@ +struct TTD::Replay::IReplayEngine +{ + virtual void const * TTD::Replay::ReplayEngine::UnsafeAsInterface(struct _GUID const &) const = 0; + virtual void * TTD::Replay::ReplayEngine::UnsafeAsInterface(struct _GUID const &) = 0; + virtual enum Nirvana::GuestAddress TTD::Replay::ReplayEngine::GetPebAddress() const = 0; + virtual struct TTD::SystemInfo const & TTD::Replay::ReplayEngine::GetSystemInfo() const = 0; + virtual struct TTD::Replay::PositionRange const & TTD::Replay::ReplayEngine::GetLifetime() const = 0; + virtual struct TTD::Replay::Position const & TTD::Replay::ReplayEngine::GetLastPosition() const = 0; + virtual struct TTD::Replay::Position const & TTD::Replay::ReplayEngine::GetFirstPosition() const = 0; + virtual enum TTD::Replay::RecordingType TTD::Replay::ReplayEngine::GetRecordingType() const = 0; + virtual struct TTD::Replay::ThreadInfo const & TTD::Replay::ReplayEngine::GetThreadInfo(enum TTD::Replay::UniqueThreadId) const = 0; + virtual uint64_t TTD::Replay::ReplayEngine::GetThreadCount() const = 0; + virtual struct TTD::Replay::ThreadInfo const * TTD::Replay::ReplayEngine::GetThreadList() const = 0; + virtual uint64_t const * TTD::Replay::ReplayEngine::GetThreadFirstPositionIndex() const = 0; + virtual uint64_t const * TTD::Replay::ReplayEngine::GetThreadLastPositionIndex() const = 0; + virtual uint64_t const * TTD::Replay::ReplayEngine::GetThreadLifetimeFirstPositionIndex() const = 0; + virtual uint64_t const * TTD::Replay::ReplayEngine::GetThreadLifetimeLastPositionIndex() const = 0; + virtual uint64_t TTD::Replay::ReplayEngine::GetThreadCreatedEventCount() const = 0; + virtual struct TTD::Replay::ThreadCreatedEvent const * TTD::Replay::ReplayEngine::GetThreadCreatedEventList() const = 0; + virtual uint64_t TTD::Replay::ReplayEngine::GetThreadTerminatedEventCount() const = 0; + virtual struct TTD::Replay::ThreadTerminatedEvent const * TTD::Replay::ReplayEngine::GetThreadTerminatedEventList() const = 0; + virtual uint64_t TTD::Replay::ReplayEngine::GetModuleCount() const = 0; + virtual struct TTD::Replay::Module const * TTD::Replay::ReplayEngine::GetModuleList() const = 0; + virtual uint64_t TTD::Replay::ReplayEngine::GetModuleInstanceCount() const = 0; + virtual struct TTD::Replay::ModuleInstance const * TTD::Replay::ReplayEngine::GetModuleInstanceList() const = 0; + virtual uint64_t const * TTD::Replay::ReplayEngine::GetModuleInstanceUnloadIndex() const = 0; + virtual uint64_t TTD::Replay::ReplayEngine::GetModuleLoadedEventCount() const = 0; + virtual struct TTD::Replay::ModuleLoadedEvent const * TTD::Replay::ReplayEngine::GetModuleLoadedEventList() const = 0; + virtual uint64_t TTD::Replay::ReplayEngine::GetModuleUnloadedEventCount() const = 0; + virtual struct TTD::Replay::ModuleUnloadedEvent const * TTD::Replay::ReplayEngine::GetModuleUnloadedEventList() const = 0; + virtual uint64_t TTD::Replay::ReplayEngine::GetExceptionEventCount() const = 0; + virtual struct TTD::Replay::ExceptionEvent const * TTD::Replay::ReplayEngine::GetExceptionEventList() const = 0; + virtual struct TTD::Replay::ExceptionEvent const * TTD::Replay::ReplayEngine::GetExceptionAtOrAfterPosition(struct TTD::Replay::Position const &) const = 0; + virtual uint64_t TTD::Replay::ReplayEngine::GetKeyframeCount() const = 0; + virtual struct TTD::Replay::Position const * TTD::Replay::ReplayEngine::GetKeyframeList() const = 0; + virtual uint64_t TTD::Replay::ReplayEngine::GetRecordClientCount() const = 0; + virtual struct TTD::Replay::RecordClient const * TTD::Replay::ReplayEngine::GetRecordClientList() const = 0; + virtual struct TTD::Replay::RecordClient const & TTD::Replay::ReplayEngine::GetRecordClient(enum TTD::RecordClientId) const = 0; + virtual uint64_t TTD::Replay::ReplayEngine::GetCustomEventCount() const = 0; + virtual struct TTD::Replay::CustomEvent const * TTD::Replay::ReplayEngine::GetCustomEventList() const = 0; + virtual uint64_t TTD::Replay::ReplayEngine::GetActivityCount() const = 0; + virtual struct TTD::Replay::Activity const * TTD::Replay::ReplayEngine::GetActivityList() const = 0; + virtual uint64_t TTD::Replay::ReplayEngine::GetIslandCount() const = 0; + virtual struct TTD::Replay::Island const * TTD::Replay::ReplayEngine::GetIslandList() const = 0; + virtual class TTD::Replay::ICursor * TTD::Replay::ReplayEngine::NewCursor(struct _GUID const &) = 0; + virtual enum TTD::Replay::IndexStatus TTD::Replay::ReplayEngine::BuildIndex(void (*)(void const *, struct TTD::Replay::IndexBuildProgressType const *), void const *, enum TTD::Replay::IndexBuildFlags) = 0; + virtual enum TTD::Replay::IndexStatus TTD::Replay::ReplayEngine::GetIndexStatus() const = 0; + virtual struct TTD::Replay::IndexFileStats TTD::Replay::ReplayEngine::GetIndexFileStats() const = 0; + virtual void TTD::Replay::ReplayEngine::RegisterDebugModeAndLogging(enum TTD::Replay::DebugModeType, class TTD::ErrorReporting *) = 0; + virtual class TTD::Replay::ICursorInternals * TTD::Replay::Cursor::GetInternals() = 0; + virtual class TTD::Replay::IEngineInternals const * TTD::Replay::ReplayEngine::GetInternals() const = 0; + virtual void * TTD::Replay::ReplayEngine::scalar_deleting_dtor(unsigned int) = 0; + virtual void TTD::Replay::ReplayEngine::Destroy() = 0; + virtual bool TTD::Replay::ReplayEngine::Initialize(wchar_t const *) = 0; +}; \ No newline at end of file diff --git a/btparser/tests/cursor.hpp.pp.h b/btparser/tests/cursor.hpp.pp.h new file mode 100644 index 0000000..a5862a8 --- /dev/null +++ b/btparser/tests/cursor.hpp.pp.h @@ -0,0 +1,55 @@ +struct TTD::Replay::IReplayEngine +{ + virtual void const * TTD::Replay::ReplayEngine::UnsafeAsInterface(struct _GUID const &) const = 0; + virtual void * TTD::Replay::ReplayEngine::UnsafeAsInterface(struct _GUID const &) = 0; + virtual enum Nirvana::GuestAddress TTD::Replay::ReplayEngine::GetPebAddress() const = 0; + virtual struct TTD::SystemInfo const & TTD::Replay::ReplayEngine::GetSystemInfo() const = 0; + virtual struct TTD::Replay::PositionRange const & TTD::Replay::ReplayEngine::GetLifetime() const = 0; + virtual struct TTD::Replay::Position const & TTD::Replay::ReplayEngine::GetLastPosition() const = 0; + virtual struct TTD::Replay::Position const & TTD::Replay::ReplayEngine::GetFirstPosition() const = 0; + virtual enum TTD::Replay::RecordingType TTD::Replay::ReplayEngine::GetRecordingType() const = 0; + virtual struct TTD::Replay::ThreadInfo const & TTD::Replay::ReplayEngine::GetThreadInfo(enum TTD::Replay::UniqueThreadId) const = 0; + virtual uint64_t TTD::Replay::ReplayEngine::GetThreadCount() const = 0; + virtual struct TTD::Replay::ThreadInfo const * TTD::Replay::ReplayEngine::GetThreadList() const = 0; + virtual uint64_t const * TTD::Replay::ReplayEngine::GetThreadFirstPositionIndex() const = 0; + virtual uint64_t const * TTD::Replay::ReplayEngine::GetThreadLastPositionIndex() const = 0; + virtual uint64_t const * TTD::Replay::ReplayEngine::GetThreadLifetimeFirstPositionIndex() const = 0; + virtual uint64_t const * TTD::Replay::ReplayEngine::GetThreadLifetimeLastPositionIndex() const = 0; + virtual uint64_t TTD::Replay::ReplayEngine::GetThreadCreatedEventCount() const = 0; + virtual struct TTD::Replay::ThreadCreatedEvent const * TTD::Replay::ReplayEngine::GetThreadCreatedEventList() const = 0; + virtual uint64_t TTD::Replay::ReplayEngine::GetThreadTerminatedEventCount() const = 0; + virtual struct TTD::Replay::ThreadTerminatedEvent const * TTD::Replay::ReplayEngine::GetThreadTerminatedEventList() const = 0; + virtual uint64_t TTD::Replay::ReplayEngine::GetModuleCount() const = 0; + virtual struct TTD::Replay::Module const * TTD::Replay::ReplayEngine::GetModuleList() const = 0; + virtual uint64_t TTD::Replay::ReplayEngine::GetModuleInstanceCount() const = 0; + virtual struct TTD::Replay::ModuleInstance const * TTD::Replay::ReplayEngine::GetModuleInstanceList() const = 0; + virtual uint64_t const * TTD::Replay::ReplayEngine::GetModuleInstanceUnloadIndex() const = 0; + virtual uint64_t TTD::Replay::ReplayEngine::GetModuleLoadedEventCount() const = 0; + virtual struct TTD::Replay::ModuleLoadedEvent const * TTD::Replay::ReplayEngine::GetModuleLoadedEventList() const = 0; + virtual uint64_t TTD::Replay::ReplayEngine::GetModuleUnloadedEventCount() const = 0; + virtual struct TTD::Replay::ModuleUnloadedEvent const * TTD::Replay::ReplayEngine::GetModuleUnloadedEventList() const = 0; + virtual uint64_t TTD::Replay::ReplayEngine::GetExceptionEventCount() const = 0; + virtual struct TTD::Replay::ExceptionEvent const * TTD::Replay::ReplayEngine::GetExceptionEventList() const = 0; + virtual struct TTD::Replay::ExceptionEvent const * TTD::Replay::ReplayEngine::GetExceptionAtOrAfterPosition(struct TTD::Replay::Position const &) const = 0; + virtual uint64_t TTD::Replay::ReplayEngine::GetKeyframeCount() const = 0; + virtual struct TTD::Replay::Position const * TTD::Replay::ReplayEngine::GetKeyframeList() const = 0; + virtual uint64_t TTD::Replay::ReplayEngine::GetRecordClientCount() const = 0; + virtual struct TTD::Replay::RecordClient const * TTD::Replay::ReplayEngine::GetRecordClientList() const = 0; + virtual struct TTD::Replay::RecordClient const & TTD::Replay::ReplayEngine::GetRecordClient(enum TTD::RecordClientId) const = 0; + virtual uint64_t TTD::Replay::ReplayEngine::GetCustomEventCount() const = 0; + virtual struct TTD::Replay::CustomEvent const * TTD::Replay::ReplayEngine::GetCustomEventList() const = 0; + virtual uint64_t TTD::Replay::ReplayEngine::GetActivityCount() const = 0; + virtual struct TTD::Replay::Activity const * TTD::Replay::ReplayEngine::GetActivityList() const = 0; + virtual uint64_t TTD::Replay::ReplayEngine::GetIslandCount() const = 0; + virtual struct TTD::Replay::Island const * TTD::Replay::ReplayEngine::GetIslandList() const = 0; + virtual class TTD::Replay::ICursor * TTD::Replay::ReplayEngine::NewCursor(struct _GUID const &) = 0; + virtual enum TTD::Replay::IndexStatus TTD::Replay::ReplayEngine::BuildIndex(void (*)(void const *, struct TTD::Replay::IndexBuildProgressType const *), void const *, enum TTD::Replay::IndexBuildFlags) = 0; + virtual enum TTD::Replay::IndexStatus TTD::Replay::ReplayEngine::GetIndexStatus() const = 0; + virtual struct TTD::Replay::IndexFileStats TTD::Replay::ReplayEngine::GetIndexFileStats() const = 0; + virtual void TTD::Replay::ReplayEngine::RegisterDebugModeAndLogging(enum TTD::Replay::DebugModeType, class TTD::ErrorReporting *) = 0; + virtual class TTD::Replay::ICursorInternals * TTD::Replay::Cursor::GetInternals() = 0; + virtual class TTD::Replay::IEngineInternals const * TTD::Replay::ReplayEngine::GetInternals() const = 0; + virtual void * TTD::Replay::ReplayEngine::scalar_deleting_dtor(unsigned int) = 0; + virtual void TTD::Replay::ReplayEngine::Destroy() = 0; + virtual bool TTD::Replay::ReplayEngine::Initialize(wchar_t const *) = 0; +}; diff --git a/btparser/types.cpp b/btparser/types.cpp index bc116a1..eb9df5c 100644 --- a/btparser/types.cpp +++ b/btparser/types.cpp @@ -6,8 +6,6 @@ using namespace Types; -static TypeManager typeManager; - #define EXCLUSIVE_ACQUIRE(x) #define SHARED_ACQUIRE(x) @@ -300,7 +298,7 @@ static std::string getKind(const Function & f) } template -static void enumType(const std::unordered_map & map, std::vector & types) +static void enumType(const TypeManager& typeManager, const std::unordered_map & map, std::vector & types) { for(auto i = map.begin(); i != map.end(); ++i) { @@ -308,7 +306,7 @@ static void enumType(const std::unordered_map & map, std::vectorsecond); s.name = i->second.name; s.owner = i->second.owner; - s.size = SizeofType(s.name); + s.size = typeManager.Sizeof(s.name); types.push_back(s); } } @@ -316,9 +314,9 @@ static void enumType(const std::unordered_map & map, std::vector & typeList) const { typeList.clear(); - enumType(types, typeList); - enumType(structs, typeList); - enumType(functions, typeList); + enumType(*this, types, typeList); + enumType(*this, structs, typeList); + enumType(*this, functions, typeList); //nasty hacks to sort in a nice way std::sort(typeList.begin(), typeList.end(), [](const Summary & a, const Summary & b) { @@ -612,342 +610,9 @@ bool TypeManager::GenerateStubs() const puts("{"); for(const auto& hook : hooks) { - printf(" HOOK(%s);\n", hook.c_str(), hook.c_str()); + printf(" HOOK(%s);\n", hook.c_str()); } puts("}"); return false; } - -bool AddType(const std::string & owner, const std::string & type, const std::string & name) -{ - EXCLUSIVE_ACQUIRE(LockTypeManager); - return typeManager.AddType(owner, type, name); -} - -bool AddStruct(const std::string & owner, const std::string & name) -{ - EXCLUSIVE_ACQUIRE(LockTypeManager); - return typeManager.AddStruct(owner, name); -} - -bool AddUnion(const std::string & owner, const std::string & name) -{ - EXCLUSIVE_ACQUIRE(LockTypeManager); - return typeManager.AddUnion(owner, name); -} - -bool AddMember(const std::string & parent, const std::string & type, const std::string & name, int arrsize, int offset) -{ - EXCLUSIVE_ACQUIRE(LockTypeManager); - return typeManager.AddMember(parent, type, name, arrsize, offset); -} - -bool AppendMember(const std::string & type, const std::string & name, int arrsize, int offset) -{ - EXCLUSIVE_ACQUIRE(LockTypeManager); - return typeManager.AppendMember(type, name, arrsize, offset); -} - -bool AddFunction(const std::string & owner, const std::string & name, const std::string & rettype, Types::CallingConvention callconv, bool noreturn) -{ - EXCLUSIVE_ACQUIRE(LockTypeManager); - return typeManager.AddFunction(owner, name, rettype, callconv, noreturn); -} - -bool AddArg(const std::string & function, const std::string & type, const std::string & name, const QualifiedType& qtype) -{ - EXCLUSIVE_ACQUIRE(LockTypeManager); - return typeManager.AddArg(function, type, name, qtype); -} - -bool AppendArg(const std::string & type, const std::string & name, const QualifiedType& qtype) -{ - EXCLUSIVE_ACQUIRE(LockTypeManager); - return typeManager.AppendArg(type, name, qtype); -} - -int SizeofType(const std::string & type) -{ - SHARED_ACQUIRE(LockTypeManager); - return typeManager.Sizeof(type); -} - -bool VisitType(const std::string & type, const std::string & name, Types::TypeManager::Visitor & visitor) -{ - SHARED_ACQUIRE(LockTypeManager); - return typeManager.Visit(type, name, visitor); -} - -void ClearTypes(const std::string & owner) -{ - EXCLUSIVE_ACQUIRE(LockTypeManager); - return typeManager.Clear(owner); -} - -bool RemoveType(const std::string & type) -{ - EXCLUSIVE_ACQUIRE(LockTypeManager); - return typeManager.RemoveType(type); -} - -void EnumTypes(std::vector & typeList) -{ - SHARED_ACQUIRE(LockTypeManager); - return typeManager.Enumerate(typeList); -} - -#if 0 -int json_default_int(const JSON object, const char* key, int defaultVal) -{ - auto jint = json_object_get(object, key); - if(jint && json_is_integer(jint)) - return int(json_integer_value(jint)); - return defaultVal; -} - -static void loadTypes(const JSON troot, std::vector & types) -{ - if(!troot) - return; - size_t i; - JSON vali; - Member curType; - json_array_foreach(troot, i, vali) - { - auto type = json_string_value(json_object_get(vali, "type")); - auto name = json_string_value(json_object_get(vali, "name")); - if(!type || !*type || !name || !*name) - continue; - curType.type = type; - curType.name = name; - types.push_back(curType); - } -} - -static void loadStructUnions(const JSON suroot, bool isunion, std::vector & structUnions) -{ - if(!suroot) - return; - size_t i; - JSON vali; - StructUnion curSu; - curSu.isunion = isunion; - json_array_foreach(suroot, i, vali) - { - auto suname = json_string_value(json_object_get(vali, "name")); - if(!suname || !*suname) - continue; - curSu.name = suname; - curSu.members.clear(); - auto members = json_object_get(vali, "members"); - size_t j; - JSON valj; - Member curMember; - json_array_foreach(members, j, valj) - { - auto type = json_string_value(json_object_get(valj, "type")); - auto name = json_string_value(json_object_get(valj, "name")); - if(!type || !*type || !name || !*name) - continue; - curMember.type = type; - curMember.name = name; - curMember.arrsize = json_default_int(valj, "arrsize", 0); - curMember.offset = json_default_int(valj, "offset", -1); - curSu.members.push_back(curMember); - } - structUnions.push_back(curSu); - } -} - -static void loadFunctions(const JSON froot, std::vector & functions) -{ - if(!froot) - return; - size_t i; - JSON vali; - Function curFunction; - json_array_foreach(froot, i, vali) - { - auto rettype = json_string_value(json_object_get(vali, "rettype")); - auto fname = json_string_value(json_object_get(vali, "name")); - if(!rettype || !*rettype || !fname || !*fname) - continue; - curFunction.rettype = rettype; - curFunction.name = fname; - curFunction.args.clear(); - auto callconv = json_string_value(json_object_get(vali, "callconv")); - curFunction.noreturn = json_boolean_value(json_object_get(vali, "noreturn")); - if(scmp(callconv, "cdecl")) - curFunction.callconv = Cdecl; - else if(scmp(callconv, "stdcall")) - curFunction.callconv = Stdcall; - else if(scmp(callconv, "thiscall")) - curFunction.callconv = Thiscall; - else if(scmp(callconv, "delphi")) - curFunction.callconv = Delphi; - else - curFunction.callconv = Cdecl; - auto args = json_object_get(vali, "args"); - size_t j; - JSON valj; - Member curArg; - json_array_foreach(args, j, valj) - { - auto type = json_string_value(json_object_get(valj, "type")); - auto name = json_string_value(json_object_get(valj, "name")); - if(!type || !*type || !name || !*name) - continue; - curArg.type = type; - curArg.name = name; - curFunction.args.push_back(curArg); - } - functions.push_back(curFunction); - } -} -#endif - -#define dprintf printf -#define QT_TRANSLATE_NOOP(ctx, s) s - -void LoadModel(const std::string & owner, Model & model) -{ - //Add all base struct/union types first to avoid errors later - for(auto & su : model.structUnions) - { - auto success = su.isunion ? typeManager.AddUnion(owner, su.name) : typeManager.AddStruct(owner, su.name); - if(!success) - { - //TODO properly handle errors - dprintf(QT_TRANSLATE_NOOP("DBG", "Failed to add %s %s;\n"), su.isunion ? "union" : "struct", su.name.c_str()); - su.name.clear(); //signal error - } - } - - //Add simple typedefs - for(auto & type : model.types) - { - auto success = typeManager.AddType(owner, type.type, type.name); - if(!success) - { - //TODO properly handle errors - dprintf(QT_TRANSLATE_NOOP("DBG", "Failed to add typedef %s %s;\n"), type.type.c_str(), type.name.c_str()); - } - } - - //Add enums - for (auto& kv : model.enums) - { - auto& e = kv.first; - const auto& etype = kv.second; - auto success = typeManager.AddEnum(owner, e.name, etype); - if (!success) - { - dprintf(QT_TRANSLATE_NOOP("DBG", "Failed to add enum %s;\n"), e.name.c_str()); - e.name.clear(); // signal error - } - else - { - for (const auto& v : e.values) - { - if (!typeManager.AddEnumerator(e.name, v.name, v.value)) - { - dprintf(QT_TRANSLATE_NOOP("DBG", "Failed to add enum member %s.%s = %llu;\n"), e.name.c_str(), v.name.c_str(), v.value); - } - } - } - } - - //Add base function types to avoid errors later - for(auto & function : model.functions) - { - auto success = typeManager.AddFunction(owner, function.name, function.rettype, function.callconv, function.noreturn, function.typeonly, function.retqtype); - if(!success) - { - //TODO properly handle errors - dprintf(QT_TRANSLATE_NOOP("DBG", "Failed to add function %s %s()\n"), function.rettype.c_str(), function.name.c_str()); - function.name.clear(); //signal error - } - } - - //Add struct/union members - for(auto & su : model.structUnions) - { - if(su.name.empty()) //skip error-signalled structs/unions - continue; - for(auto & member : su.members) - { - auto success = typeManager.AddMember(su.name, member.type, member.name, member.arrsize, member.offset); - if(!success) - { - //TODO properly handle errors - dprintf(QT_TRANSLATE_NOOP("DBG", "Failed to add member %s %s.%s;\n"), member.type.c_str(), su.name.c_str(), member.name.c_str()); - } - } - } - - //Add function arguments - for(auto & function : model.functions) - { - if(function.name.empty()) //skip error-signalled functions - continue; - for (size_t i = 0; i < function.args.size(); i++) - { - auto& arg = function.args[i]; - if (arg.name.empty()) - arg.name = "__unnamed_arg_" + std::to_string(i); - auto success = typeManager.AddArg(function.name, arg.type, arg.name, arg.qtype); - if(!success) - { - //TODO properly handle errors - dprintf(QT_TRANSLATE_NOOP("DBG", "Failed to add argument %s[%zu]: %s %s;\n"), function.name.c_str(), i, arg.type.c_str(), arg.name.c_str()); - } - } - } -} - -#if 0 -bool LoadTypesJson(const std::string & json, const std::string & owner) -{ - EXCLUSIVE_ACQUIRE(LockTypeManager); - auto root = json_loads(json.c_str(), 0, 0); - if(root) - { - Model model; - loadTypes(json_object_get(root, "types"), model.types); - loadTypes(json_object_get(root, ArchValue("types32", "types64")), model.types); - loadStructUnions(json_object_get(root, "structs"), false, model.structUnions); - loadStructUnions(json_object_get(root, ArchValue("structs32", "structs64")), false, model.structUnions); - loadStructUnions(json_object_get(root, "unions"), true, model.structUnions); - loadStructUnions(json_object_get(root, ArchValue("unions32", "unions64")), true, model.structUnions); - loadFunctions(json_object_get(root, "functions"), model.functions); - loadFunctions(json_object_get(root, ArchValue("functions32", "functions64")), model.functions); - - LoadModel(owner, model); - - // Free root - json_decref(root); - } - else - return false; - return true; -} - -bool LoadTypesFile(const std::string & path, const std::string & owner) -{ - std::string json; - if(!FileHelper::ReadAllText(path, json)) - return false; - return LoadTypesJson(json, owner); -} -#endif - -std::string StructUnionPtrType(const std::string & pointto) -{ - return typeManager.StructUnionPtrType(pointto); -} - -bool GenerateStubs() -{ - return typeManager.GenerateStubs(); -} diff --git a/btparser/types.h b/btparser/types.h index ae375bf..c6b060a 100644 --- a/btparser/types.h +++ b/btparser/types.h @@ -81,29 +81,6 @@ namespace Types int offset = -1; //Member offset (only stored for reference) }; - struct StructUnion - { - std::string owner; //StructUnion owner - std::string name; //StructUnion identifier - std::vector members; //StructUnion members - bool isunion = false; //Is this a union? - int size = 0; - }; - - struct EnumValue - { - std::string name; - uint64_t value = 0; - }; - - struct Enum - { - std::string owner; // Enum owner - std::string name; // Enum name - std::vector values; // Enum values - Primitive type; // Enum value type - }; - enum CallingConvention { DefaultDecl, @@ -125,6 +102,38 @@ namespace Types std::vector args; //Function arguments }; + struct StructUnion + { + std::string owner; //StructUnion owner + std::string name; //StructUnion identifier + std::vector members; //StructUnion members + std::vector vtable; + bool isunion = false; //Is this a union? + int size = 0; + }; + + struct EnumValue + { + std::string name; + uint64_t value = 0; + }; + + struct Enum + { + std::string owner; // Enum owner + std::string name; // Enum name + std::vector values; // Enum values + Primitive type; // Enum value type + }; + + struct Model + { + std::vector types; + std::vector> enums; + std::vector structUnions; + std::vector functions; + }; + struct TypeManager { struct Visitor @@ -163,6 +172,8 @@ namespace Types bool RemoveType(const std::string & type); void Enumerate(std::vector & typeList) const; std::string StructUnionPtrType(const std::string & pointto) const; + + bool ParseTypes(const std::string& code, const std::string& owner, std::vector& errors); bool GenerateStubs() const; private: @@ -184,31 +195,5 @@ namespace Types bool addType(const Type & t); bool visitMember(const Member & root, Visitor & visitor) const; }; - - struct Model - { - std::vector types; - std::vector> enums; - std::vector structUnions; - std::vector functions; - }; }; -bool AddType(const std::string & owner, const std::string & type, const std::string & name); -bool AddStruct(const std::string & owner, const std::string & name); -bool AddUnion(const std::string & owner, const std::string & name); -bool AddMember(const std::string & parent, const std::string & type, const std::string & name, int arrsize = 0, int offset = -1); -bool AppendMember(const std::string & type, const std::string & name, int arrsize = 0, int offset = -1); -bool AddFunction(const std::string & owner, const std::string & name, const std::string & rettype, Types::CallingConvention callconv = Types::Cdecl, bool noreturn = false); -bool AddArg(const std::string & function, const std::string & type, const std::string & name, const Types::QualifiedType& qtype); -bool AppendArg(const std::string & type, const std::string & name, const Types::QualifiedType& qtype); -int SizeofType(const std::string & type); -bool VisitType(const std::string & type, const std::string & name, Types::TypeManager::Visitor & visitor); -void ClearTypes(const std::string & owner = ""); -bool RemoveType(const std::string & type); -void EnumTypes(std::vector & typeList); -bool LoadTypesJson(const std::string & json, const std::string & owner); -bool LoadTypesFile(const std::string & path, const std::string & owner); -bool ParseTypes(const std::string & code, const std::string & owner, std::vector & errors); -std::string StructUnionPtrType(const std::string & pointto); -bool GenerateStubs(); \ No newline at end of file diff --git a/btparser/typesparser.cpp b/btparser/typesparser.cpp index ee5733d..8122787 100644 --- a/btparser/typesparser.cpp +++ b/btparser/typesparser.cpp @@ -5,7 +5,8 @@ using namespace Types; #include "lexer.h" -void LoadModel(const std::string& owner, Model& model); +#define dprintf printf +#define QT_TRANSLATE_NOOP(ctx, s) s struct Parser { @@ -41,6 +42,21 @@ struct Parser return getToken(index).Token == token; } + bool isStructLike() + { + auto tok = getToken(index).Token; + switch (tok) + { + case Lexer::tok_struct: + case Lexer::tok_union: + case Lexer::tok_enum: + case Lexer::tok_class: + return true; + default: + return false; + } + } + bool isTokenList(std::initializer_list il) { size_t i = 0; @@ -119,7 +135,7 @@ struct Parser return false; } } - else if (t.Is(Lexer::tok_op_mul)) + else if (t.Is(Lexer::tok_op_mul) || t.Is(Lexer::tok_op_and)) { if (type.empty()) { @@ -177,20 +193,31 @@ struct Parser return false; } - if (!isToken(Lexer::tok_op_mul)) + if (!isToken(Lexer::tok_op_mul) && !isToken(Lexer::tok_op_and)) { errLine(curToken(), "expected * in function pointer type"); return false; } index++; - if (!isToken(Lexer::tok_identifier)) // TODO: support unnamed function pointers + if (!isToken(Lexer::tok_identifier)) { - errLine(curToken(), "expected identifier in function pointer type"); - return false; + if (isToken(Lexer::tok_parclose)) + { + // unnamed function pointer + fn.name = ""; + } + else + { + errLine(curToken(), "expected identifier in function pointer type"); + return false; + } + } + else + { + fn.name = lexer.TokString(curToken()); + index++; } - fn.name = lexer.TokString(curToken()); - index++; if (!isToken(Lexer::tok_parclose)) { @@ -237,6 +264,19 @@ struct Parser return false; } + if (isStructLike()) + { + if (tlist.empty() && getToken(index + 1).Token == Lexer::tok_identifier) + { + index++; + } + else + { + errLine(curToken(), "unsupported struct/union/enum in function argument"); + return false; + } + } + const auto& t = curToken(); if (t.IsType() || t.Is(Lexer::tok_identifier) || t.Is(Lexer::tok_const)) { @@ -245,7 +285,7 @@ struct Parser // Primitive type tlist.push_back(t); } - else if (t.Is(Lexer::tok_op_mul)) + else if (t.Is(Lexer::tok_op_mul) || t.Is(Lexer::tok_op_and)) { // Pointer to the type on the left if (tlist.empty()) @@ -396,7 +436,7 @@ struct Parser return false; } - if (isToken(Lexer::tok_struct) || isToken(Lexer::tok_union) || isToken(Lexer::tok_enum)) + if (isStructLike()) { if (tlist.empty() && getToken(index + 1).Token == Lexer::tok_identifier) { @@ -416,7 +456,7 @@ struct Parser // Primitive type / name tlist.push_back(t); } - else if (t.Is(Lexer::tok_op_mul)) + else if (t.Is(Lexer::tok_op_mul) || t.Is(Lexer::tok_op_and)) { // Pointer to the type on the left if (tlist.empty()) @@ -425,7 +465,7 @@ struct Parser return false; } - if (sawPointer && tlist.back().Token != Lexer::tok_op_mul) + if (sawPointer && tlist.back().Token != Lexer::tok_op_mul && tlist.back().Token != Lexer::tok_op_and) { errLine(curToken(), "unexpected * in member"); return false; @@ -511,12 +551,27 @@ struct Parser tlist.pop_back(); // Remove the pointer from the type - while (!tlist.empty() && tlist.back().Token == Lexer::tok_op_mul) + while (!tlist.empty() && (tlist.back().Token == Lexer::tok_op_mul || tlist.back().Token == Lexer::tok_op_and)) tlist.pop_back(); sawPointer = false; m = Member(); } + else if (t.Is(Lexer::tok_virtual)) + { + // Parse a virtual function declaration + index++; + + // Parse the function declaration + Function vfunction; + if (!parseFunctionTop(vfunction, true)) + return false; + su.vtable.push_back(vfunction); + } + else if (t.Is(Lexer::tok_brclose) && tlist.empty()) + { + return true; + } else { __debugbreak(); @@ -539,7 +594,7 @@ struct Parser bool parseStructUnion() { auto startToken = curToken(); - if (isToken(Lexer::tok_struct) || isToken(Lexer::tok_union)) + if (isToken(Lexer::tok_struct) || isToken(Lexer::tok_class) || isToken(Lexer::tok_union)) { StructUnion su; su.isunion = isToken(Lexer::tok_union); @@ -745,7 +800,7 @@ struct Parser return false; } - if (isToken(Lexer::tok_struct) || isToken(Lexer::tok_union) || isToken(Lexer::tok_enum)) + if (isStructLike()) { if (tlist.empty() && getToken(index + 1).Token == Lexer::tok_identifier) { @@ -765,7 +820,7 @@ struct Parser index++; tlist.push_back(t); } - else if (t.Token == Lexer::tok_op_mul) + else if (t.Is(Lexer::tok_op_mul) || t.Is(Lexer::tok_op_and)) { // Pointer to the type on the left if (tlist.empty()) @@ -774,7 +829,7 @@ struct Parser return false; } - if (sawPointer && tlist.back().Token != Lexer::tok_op_mul) + if (sawPointer && tlist.back().Token != Lexer::tok_op_mul && tlist.back().Token != Lexer::tok_op_and) { errLine(curToken(), "unexpected * in member"); return false; @@ -832,8 +887,10 @@ struct Parser return true; } - bool parseFunctionTop() + bool parseFunctionTop(Function& fn, bool isVirtual) { + fn = {}; + bool sawPointer = false; std::vector tlist; while (!isToken(Lexer::tok_semic)) @@ -844,7 +901,7 @@ struct Parser return false; } - if (isToken(Lexer::tok_struct) || isToken(Lexer::tok_union) || isToken(Lexer::tok_enum)) + if (isStructLike()) { if (tlist.empty() && getToken(index + 1).Token == Lexer::tok_identifier) { @@ -864,7 +921,7 @@ struct Parser // Primitive type / name tlist.push_back(t); } - else if (t.Is(Lexer::tok_op_mul)) + else if (t.Is(Lexer::tok_op_mul) || t.Is(Lexer::tok_op_and)) { // Pointer to the type on the left if (tlist.empty()) @@ -873,7 +930,7 @@ struct Parser return false; } - if (sawPointer && tlist.back().Token != Lexer::tok_op_mul) + if (sawPointer && tlist.back().Token != Lexer::tok_op_mul && tlist.back().Token != Lexer::tok_op_and) { errLine(curToken(), "unexpected * in function"); return false; @@ -889,7 +946,6 @@ struct Parser index++; // Function pointer type - Function fn; if (!parseFunction(tlist, fn, false)) { return false; @@ -897,13 +953,56 @@ struct Parser if (!isToken(Lexer::tok_semic)) { - errLine(curToken(), "expected ; after function type"); - return false; + if (isVirtual) + { + auto endToken = curToken(); + while (true) + { + auto tEnd = curToken(); + if (tEnd.Is(Lexer::tok_eof)) + { + errLine(curToken(), "unexpected eof after virtual function"); + return false; + } + + if (tEnd.Is(Lexer::tok_const) || tEnd.Is(Lexer::tok_override)) + { + index++; + continue; + } + + if (tEnd.Is(Lexer::tok_semic)) + { + break; + } + + if (tEnd.Is(Lexer::tok_assign)) + { + index++; + tEnd = curToken(); + if (!tEnd.Is(Lexer::tok_number) || tEnd.NumberVal != 0) + { + errLine(endToken, "expected = 0 after virtual function type"); + return false; + } + index++; + break; + } + else + { + errLine(endToken, "expected = 0 after virtual function type"); + return false; + } + } + } + if (!isToken(Lexer::tok_semic)) + { + errLine(curToken(), "expected ; after function type"); + return false; + } } eatSemic(); - model.functions.push_back(fn); - return true; } else @@ -914,7 +1013,103 @@ struct Parser return false; } - bool operator()() + void LoadModel(TypeManager typeManager, const std::string& owner, Model& model) + { + //Add all base struct/union types first to avoid errors later + for (auto& su : model.structUnions) + { + auto success = su.isunion ? typeManager.AddUnion(owner, su.name) : typeManager.AddStruct(owner, su.name); + if (!success) + { + //TODO properly handle errors + dprintf(QT_TRANSLATE_NOOP("DBG", "Failed to add %s %s;\n"), su.isunion ? "union" : "struct", su.name.c_str()); + su.name.clear(); //signal error + } + } + + //Add simple typedefs + for (auto& type : model.types) + { + auto success = typeManager.AddType(owner, type.type, type.name); + if (!success) + { + //TODO properly handle errors + dprintf(QT_TRANSLATE_NOOP("DBG", "Failed to add typedef %s %s;\n"), type.type.c_str(), type.name.c_str()); + } + } + + //Add enums + for (auto& kv : model.enums) + { + auto& e = kv.first; + const auto& etype = kv.second; + auto success = typeManager.AddEnum(owner, e.name, etype); + if (!success) + { + dprintf(QT_TRANSLATE_NOOP("DBG", "Failed to add enum %s;\n"), e.name.c_str()); + e.name.clear(); // signal error + } + else + { + for (const auto& v : e.values) + { + if (!typeManager.AddEnumerator(e.name, v.name, v.value)) + { + dprintf(QT_TRANSLATE_NOOP("DBG", "Failed to add enum member %s.%s = %llu;\n"), e.name.c_str(), v.name.c_str(), v.value); + } + } + } + } + + //Add base function types to avoid errors later + for (auto& function : model.functions) + { + auto success = typeManager.AddFunction(owner, function.name, function.rettype, function.callconv, function.noreturn, function.typeonly, function.retqtype); + if (!success) + { + //TODO properly handle errors + dprintf(QT_TRANSLATE_NOOP("DBG", "Failed to add function %s %s()\n"), function.rettype.c_str(), function.name.c_str()); + function.name.clear(); //signal error + } + } + + //Add struct/union members + for (auto& su : model.structUnions) + { + if (su.name.empty()) //skip error-signalled structs/unions + continue; + for (auto& member : su.members) + { + auto success = typeManager.AddMember(su.name, member.type, member.name, member.arrsize, member.offset); + if (!success) + { + //TODO properly handle errors + dprintf(QT_TRANSLATE_NOOP("DBG", "Failed to add member %s %s.%s;\n"), member.type.c_str(), su.name.c_str(), member.name.c_str()); + } + } + } + + //Add function arguments + for (auto& function : model.functions) + { + if (function.name.empty()) //skip error-signalled functions + continue; + for (size_t i = 0; i < function.args.size(); i++) + { + auto& arg = function.args[i]; + if (arg.name.empty()) + arg.name = "__unnamed_arg_" + std::to_string(i); + auto success = typeManager.AddArg(function.name, arg.type, arg.name, arg.qtype); + if (!success) + { + //TODO properly handle errors + dprintf(QT_TRANSLATE_NOOP("DBG", "Failed to add argument %s[%zu]: %s %s;\n"), function.name.c_str(), i, arg.type.c_str(), arg.name.c_str()); + } + } + } + } + + bool operator()(TypeManager& typeManager) { std::string error; if (!lexer.DoLexing(tokens, error)) @@ -935,19 +1130,19 @@ struct Parser eatSemic(); if (curIndex == index) { - if (!parseFunctionTop()) + Function fn; + if (!parseFunctionTop(fn, false)) return false; - else - continue; + model.functions.push_back(fn); } } - LoadModel(owner, model); + LoadModel(typeManager, owner, model); return true; } }; -bool ParseTypes(const std::string& code, const std::string& owner, std::vector& errors) +bool TypeManager::ParseTypes(const std::string& code, const std::string& owner, std::vector& errors) { - return Parser(code, owner, errors)(); + return Parser(code, owner, errors)(*this); } \ No newline at end of file