mirror of https://github.com/x64dbg/btparser
Basic support for parsing virtual functions
This commit is contained in:
parent
6d3f1f75c4
commit
2973445c5f
|
@ -44,3 +44,10 @@ DEF_KEYWORD(double)
|
||||||
DEF_KEYWORD(true)
|
DEF_KEYWORD(true)
|
||||||
DEF_KEYWORD(false)
|
DEF_KEYWORD(false)
|
||||||
DEF_KEYWORD(nullptr)
|
DEF_KEYWORD(nullptr)
|
||||||
|
|
||||||
|
DEF_KEYWORD(virtual)
|
||||||
|
DEF_KEYWORD(private)
|
||||||
|
DEF_KEYWORD(public)
|
||||||
|
DEF_KEYWORD(protected)
|
||||||
|
DEF_KEYWORD(override)
|
||||||
|
DEF_KEYWORD(class)
|
||||||
|
|
|
@ -258,14 +258,24 @@ Lexer::Token Lexer::getToken(size_t & tokenLineIndex)
|
||||||
}
|
}
|
||||||
|
|
||||||
//identifier/keyword
|
//identifier/keyword
|
||||||
if(isalpha(mLastChar) || mLastChar == '_') //[a-zA-Z_]
|
if(isalpha(mLastChar) || mLastChar == '_' || (mLastChar == ':' && peekChar() == ':')) //[a-zA-Z_]
|
||||||
{
|
{
|
||||||
tokenLineIndex = mState.LineIndex - 1;
|
tokenLineIndex = mState.LineIndex - 1;
|
||||||
mState.IdentifierStr = mLastChar;
|
mState.IdentifierStr = mLastChar;
|
||||||
|
if (mLastChar == ':') //consume the '::'
|
||||||
|
{
|
||||||
|
mState.IdentifierStr += ':';
|
||||||
|
nextChar();
|
||||||
|
}
|
||||||
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);
|
mState.IdentifierStr.push_back(mLastChar);
|
||||||
|
if(mLastChar == ':') //consume the '::'
|
||||||
|
{
|
||||||
|
mState.IdentifierStr += ':';
|
||||||
|
nextChar();
|
||||||
|
}
|
||||||
nextChar();
|
nextChar();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -110,7 +110,8 @@ bool DebugParser(const std::string & filename)
|
||||||
FileHelper::WriteAllText("tests\\" + filename + ".pp.h", ppData);
|
FileHelper::WriteAllText("tests\\" + filename + ".pp.h", ppData);
|
||||||
|
|
||||||
std::vector<std::string> errors;
|
std::vector<std::string> errors;
|
||||||
if (!ParseTypes(ppData, filename, errors))
|
Types::TypeManager typeManager;
|
||||||
|
if (!typeManager.ParseTypes(ppData, filename, errors))
|
||||||
{
|
{
|
||||||
puts("Failed to parse types:");
|
puts("Failed to parse types:");
|
||||||
for (const auto& error : errors)
|
for (const auto& error : errors)
|
||||||
|
@ -126,7 +127,7 @@ int main()
|
||||||
{
|
{
|
||||||
//GenerateExpectedTests();
|
//GenerateExpectedTests();
|
||||||
auto ticks = GetTickCount();
|
auto ticks = GetTickCount();
|
||||||
DebugParser("simple.bt");
|
DebugParser("cursor.hpp");
|
||||||
//Lexer lexer;
|
//Lexer lexer;
|
||||||
//DebugLexer(lexer, "AndroidManifestTemplate.bt", false);
|
//DebugLexer(lexer, "AndroidManifestTemplate.bt", false);
|
||||||
//RunLexerTests();
|
//RunLexerTests();
|
||||||
|
|
|
@ -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;
|
||||||
|
};
|
|
@ -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;
|
||||||
|
};
|
|
@ -6,8 +6,6 @@
|
||||||
|
|
||||||
using namespace Types;
|
using namespace Types;
|
||||||
|
|
||||||
static TypeManager typeManager;
|
|
||||||
|
|
||||||
#define EXCLUSIVE_ACQUIRE(x)
|
#define EXCLUSIVE_ACQUIRE(x)
|
||||||
#define SHARED_ACQUIRE(x)
|
#define SHARED_ACQUIRE(x)
|
||||||
|
|
||||||
|
@ -300,7 +298,7 @@ static std::string getKind(const Function & f)
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename K, typename V>
|
template<typename K, typename V>
|
||||||
static void enumType(const std::unordered_map<K, V> & map, std::vector<TypeManager::Summary> & types)
|
static void enumType(const TypeManager& typeManager, const std::unordered_map<K, V> & map, std::vector<TypeManager::Summary> & types)
|
||||||
{
|
{
|
||||||
for(auto i = map.begin(); i != map.end(); ++i)
|
for(auto i = map.begin(); i != map.end(); ++i)
|
||||||
{
|
{
|
||||||
|
@ -308,7 +306,7 @@ static void enumType(const std::unordered_map<K, V> & map, std::vector<TypeManag
|
||||||
s.kind = getKind(i->second);
|
s.kind = getKind(i->second);
|
||||||
s.name = i->second.name;
|
s.name = i->second.name;
|
||||||
s.owner = i->second.owner;
|
s.owner = i->second.owner;
|
||||||
s.size = SizeofType(s.name);
|
s.size = typeManager.Sizeof(s.name);
|
||||||
types.push_back(s);
|
types.push_back(s);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -316,9 +314,9 @@ static void enumType(const std::unordered_map<K, V> & map, std::vector<TypeManag
|
||||||
void TypeManager::Enumerate(std::vector<Summary> & typeList) const
|
void TypeManager::Enumerate(std::vector<Summary> & typeList) const
|
||||||
{
|
{
|
||||||
typeList.clear();
|
typeList.clear();
|
||||||
enumType(types, typeList);
|
enumType(*this, types, typeList);
|
||||||
enumType(structs, typeList);
|
enumType(*this, structs, typeList);
|
||||||
enumType(functions, typeList);
|
enumType(*this, functions, typeList);
|
||||||
//nasty hacks to sort in a nice way
|
//nasty hacks to sort in a nice way
|
||||||
std::sort(typeList.begin(), typeList.end(), [](const Summary & a, const Summary & b)
|
std::sort(typeList.begin(), typeList.end(), [](const Summary & a, const Summary & b)
|
||||||
{
|
{
|
||||||
|
@ -612,342 +610,9 @@ bool TypeManager::GenerateStubs() const
|
||||||
puts("{");
|
puts("{");
|
||||||
for(const auto& hook : hooks)
|
for(const auto& hook : hooks)
|
||||||
{
|
{
|
||||||
printf(" HOOK(%s);\n", hook.c_str(), hook.c_str());
|
printf(" HOOK(%s);\n", hook.c_str());
|
||||||
}
|
}
|
||||||
puts("}");
|
puts("}");
|
||||||
|
|
||||||
return false;
|
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<Types::TypeManager::Summary> & 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<Member> & 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<StructUnion> & 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<Function> & 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();
|
|
||||||
}
|
|
||||||
|
|
|
@ -81,29 +81,6 @@ namespace Types
|
||||||
int offset = -1; //Member offset (only stored for reference)
|
int offset = -1; //Member offset (only stored for reference)
|
||||||
};
|
};
|
||||||
|
|
||||||
struct StructUnion
|
|
||||||
{
|
|
||||||
std::string owner; //StructUnion owner
|
|
||||||
std::string name; //StructUnion identifier
|
|
||||||
std::vector<Member> 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<EnumValue> values; // Enum values
|
|
||||||
Primitive type; // Enum value type
|
|
||||||
};
|
|
||||||
|
|
||||||
enum CallingConvention
|
enum CallingConvention
|
||||||
{
|
{
|
||||||
DefaultDecl,
|
DefaultDecl,
|
||||||
|
@ -125,6 +102,38 @@ namespace Types
|
||||||
std::vector<Member> args; //Function arguments
|
std::vector<Member> args; //Function arguments
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct StructUnion
|
||||||
|
{
|
||||||
|
std::string owner; //StructUnion owner
|
||||||
|
std::string name; //StructUnion identifier
|
||||||
|
std::vector<Member> members; //StructUnion members
|
||||||
|
std::vector<Function> 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<EnumValue> values; // Enum values
|
||||||
|
Primitive type; // Enum value type
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Model
|
||||||
|
{
|
||||||
|
std::vector<Member> types;
|
||||||
|
std::vector<std::pair<Enum, std::string>> enums;
|
||||||
|
std::vector<StructUnion> structUnions;
|
||||||
|
std::vector<Function> functions;
|
||||||
|
};
|
||||||
|
|
||||||
struct TypeManager
|
struct TypeManager
|
||||||
{
|
{
|
||||||
struct Visitor
|
struct Visitor
|
||||||
|
@ -163,6 +172,8 @@ namespace Types
|
||||||
bool RemoveType(const std::string & type);
|
bool RemoveType(const std::string & type);
|
||||||
void Enumerate(std::vector<Summary> & typeList) const;
|
void Enumerate(std::vector<Summary> & typeList) const;
|
||||||
std::string StructUnionPtrType(const std::string & pointto) const;
|
std::string StructUnionPtrType(const std::string & pointto) const;
|
||||||
|
|
||||||
|
bool ParseTypes(const std::string& code, const std::string& owner, std::vector<std::string>& errors);
|
||||||
bool GenerateStubs() const;
|
bool GenerateStubs() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -184,31 +195,5 @@ namespace Types
|
||||||
bool addType(const Type & t);
|
bool addType(const Type & t);
|
||||||
bool visitMember(const Member & root, Visitor & visitor) const;
|
bool visitMember(const Member & root, Visitor & visitor) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Model
|
|
||||||
{
|
|
||||||
std::vector<Member> types;
|
|
||||||
std::vector<std::pair<Enum, std::string>> enums;
|
|
||||||
std::vector<StructUnion> structUnions;
|
|
||||||
std::vector<Function> 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<Types::TypeManager::Summary> & 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<std::string> & errors);
|
|
||||||
std::string StructUnionPtrType(const std::string & pointto);
|
|
||||||
bool GenerateStubs();
|
|
|
@ -5,7 +5,8 @@ using namespace Types;
|
||||||
|
|
||||||
#include "lexer.h"
|
#include "lexer.h"
|
||||||
|
|
||||||
void LoadModel(const std::string& owner, Model& model);
|
#define dprintf printf
|
||||||
|
#define QT_TRANSLATE_NOOP(ctx, s) s
|
||||||
|
|
||||||
struct Parser
|
struct Parser
|
||||||
{
|
{
|
||||||
|
@ -41,6 +42,21 @@ struct Parser
|
||||||
return getToken(index).Token == token;
|
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<Lexer::Token> il)
|
bool isTokenList(std::initializer_list<Lexer::Token> il)
|
||||||
{
|
{
|
||||||
size_t i = 0;
|
size_t i = 0;
|
||||||
|
@ -119,7 +135,7 @@ struct Parser
|
||||||
return false;
|
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())
|
if (type.empty())
|
||||||
{
|
{
|
||||||
|
@ -177,20 +193,31 @@ struct Parser
|
||||||
return false;
|
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");
|
errLine(curToken(), "expected * in function pointer type");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
index++;
|
index++;
|
||||||
|
|
||||||
if (!isToken(Lexer::tok_identifier)) // TODO: support unnamed function pointers
|
if (!isToken(Lexer::tok_identifier))
|
||||||
{
|
{
|
||||||
errLine(curToken(), "expected identifier in function pointer type");
|
if (isToken(Lexer::tok_parclose))
|
||||||
return false;
|
{
|
||||||
|
// 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))
|
if (!isToken(Lexer::tok_parclose))
|
||||||
{
|
{
|
||||||
|
@ -237,6 +264,19 @@ struct Parser
|
||||||
return false;
|
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();
|
const auto& t = curToken();
|
||||||
if (t.IsType() || t.Is(Lexer::tok_identifier) || t.Is(Lexer::tok_const))
|
if (t.IsType() || t.Is(Lexer::tok_identifier) || t.Is(Lexer::tok_const))
|
||||||
{
|
{
|
||||||
|
@ -245,7 +285,7 @@ struct Parser
|
||||||
// Primitive type
|
// Primitive type
|
||||||
tlist.push_back(t);
|
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
|
// Pointer to the type on the left
|
||||||
if (tlist.empty())
|
if (tlist.empty())
|
||||||
|
@ -396,7 +436,7 @@ struct Parser
|
||||||
return false;
|
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)
|
if (tlist.empty() && getToken(index + 1).Token == Lexer::tok_identifier)
|
||||||
{
|
{
|
||||||
|
@ -416,7 +456,7 @@ struct Parser
|
||||||
// Primitive type / name
|
// Primitive type / name
|
||||||
tlist.push_back(t);
|
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
|
// Pointer to the type on the left
|
||||||
if (tlist.empty())
|
if (tlist.empty())
|
||||||
|
@ -425,7 +465,7 @@ struct Parser
|
||||||
return false;
|
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");
|
errLine(curToken(), "unexpected * in member");
|
||||||
return false;
|
return false;
|
||||||
|
@ -511,12 +551,27 @@ struct Parser
|
||||||
tlist.pop_back();
|
tlist.pop_back();
|
||||||
|
|
||||||
// Remove the pointer from the type
|
// 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();
|
tlist.pop_back();
|
||||||
sawPointer = false;
|
sawPointer = false;
|
||||||
|
|
||||||
m = Member();
|
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
|
else
|
||||||
{
|
{
|
||||||
__debugbreak();
|
__debugbreak();
|
||||||
|
@ -539,7 +594,7 @@ struct Parser
|
||||||
bool parseStructUnion()
|
bool parseStructUnion()
|
||||||
{
|
{
|
||||||
auto startToken = curToken();
|
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;
|
StructUnion su;
|
||||||
su.isunion = isToken(Lexer::tok_union);
|
su.isunion = isToken(Lexer::tok_union);
|
||||||
|
@ -745,7 +800,7 @@ struct Parser
|
||||||
return false;
|
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)
|
if (tlist.empty() && getToken(index + 1).Token == Lexer::tok_identifier)
|
||||||
{
|
{
|
||||||
|
@ -765,7 +820,7 @@ struct Parser
|
||||||
index++;
|
index++;
|
||||||
tlist.push_back(t);
|
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
|
// Pointer to the type on the left
|
||||||
if (tlist.empty())
|
if (tlist.empty())
|
||||||
|
@ -774,7 +829,7 @@ struct Parser
|
||||||
return false;
|
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");
|
errLine(curToken(), "unexpected * in member");
|
||||||
return false;
|
return false;
|
||||||
|
@ -832,8 +887,10 @@ struct Parser
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool parseFunctionTop()
|
bool parseFunctionTop(Function& fn, bool isVirtual)
|
||||||
{
|
{
|
||||||
|
fn = {};
|
||||||
|
|
||||||
bool sawPointer = false;
|
bool sawPointer = false;
|
||||||
std::vector<Lexer::TokenState> tlist;
|
std::vector<Lexer::TokenState> tlist;
|
||||||
while (!isToken(Lexer::tok_semic))
|
while (!isToken(Lexer::tok_semic))
|
||||||
|
@ -844,7 +901,7 @@ struct Parser
|
||||||
return false;
|
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)
|
if (tlist.empty() && getToken(index + 1).Token == Lexer::tok_identifier)
|
||||||
{
|
{
|
||||||
|
@ -864,7 +921,7 @@ struct Parser
|
||||||
// Primitive type / name
|
// Primitive type / name
|
||||||
tlist.push_back(t);
|
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
|
// Pointer to the type on the left
|
||||||
if (tlist.empty())
|
if (tlist.empty())
|
||||||
|
@ -873,7 +930,7 @@ struct Parser
|
||||||
return false;
|
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");
|
errLine(curToken(), "unexpected * in function");
|
||||||
return false;
|
return false;
|
||||||
|
@ -889,7 +946,6 @@ struct Parser
|
||||||
index++;
|
index++;
|
||||||
|
|
||||||
// Function pointer type
|
// Function pointer type
|
||||||
Function fn;
|
|
||||||
if (!parseFunction(tlist, fn, false))
|
if (!parseFunction(tlist, fn, false))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
|
@ -897,13 +953,56 @@ struct Parser
|
||||||
|
|
||||||
if (!isToken(Lexer::tok_semic))
|
if (!isToken(Lexer::tok_semic))
|
||||||
{
|
{
|
||||||
errLine(curToken(), "expected ; after function type");
|
if (isVirtual)
|
||||||
return false;
|
{
|
||||||
|
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();
|
eatSemic();
|
||||||
|
|
||||||
model.functions.push_back(fn);
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -914,7 +1013,103 @@ struct Parser
|
||||||
return false;
|
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;
|
std::string error;
|
||||||
if (!lexer.DoLexing(tokens, error))
|
if (!lexer.DoLexing(tokens, error))
|
||||||
|
@ -935,19 +1130,19 @@ struct Parser
|
||||||
eatSemic();
|
eatSemic();
|
||||||
if (curIndex == index)
|
if (curIndex == index)
|
||||||
{
|
{
|
||||||
if (!parseFunctionTop())
|
Function fn;
|
||||||
|
if (!parseFunctionTop(fn, false))
|
||||||
return false;
|
return false;
|
||||||
else
|
model.functions.push_back(fn);
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
LoadModel(owner, model);
|
LoadModel(typeManager, owner, model);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
bool ParseTypes(const std::string& code, const std::string& owner, std::vector<std::string>& errors)
|
bool TypeManager::ParseTypes(const std::string& code, const std::string& owner, std::vector<std::string>& errors)
|
||||||
{
|
{
|
||||||
return Parser(code, owner, errors)();
|
return Parser(code, owner, errors)(*this);
|
||||||
}
|
}
|
Loading…
Reference in New Issue