mirror of https://github.com/x64dbg/btparser
(Somewhat) correctly handle function declarations and function pointer types
This commit is contained in:
parent
c1c257ce7a
commit
a87d84cc5b
|
@ -16,7 +16,10 @@ TypeManager::TypeManager()
|
||||||
primitivesizes[p] = size;
|
primitivesizes[p] = size;
|
||||||
auto splits = StringUtils::Split(n, ',');
|
auto splits = StringUtils::Split(n, ',');
|
||||||
for (const auto& split : splits)
|
for (const auto& split : splits)
|
||||||
|
{
|
||||||
|
primitivenames.emplace(p, split);
|
||||||
addType("", p, split);
|
addType("", p, split);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
p("int8_t,int8,char,byte,bool,signed char", Int8, sizeof(char));
|
p("int8_t,int8,char,byte,bool,signed char", Int8, sizeof(char));
|
||||||
p("uint8_t,uint8,uchar,unsigned char,ubyte", Uint8, sizeof(unsigned char));
|
p("uint8_t,uint8,uchar,unsigned char,ubyte", Uint8, sizeof(unsigned char));
|
||||||
|
@ -27,14 +30,20 @@ TypeManager::TypeManager()
|
||||||
p("int64_t,int64,long long", Int64, sizeof(long long));
|
p("int64_t,int64,long long", Int64, sizeof(long long));
|
||||||
p("uint64_t,uint64,unsigned long long", Uint64, sizeof(unsigned long long));
|
p("uint64_t,uint64,unsigned long long", Uint64, sizeof(unsigned long long));
|
||||||
p("dsint", Dsint, sizeof(void*));
|
p("dsint", Dsint, sizeof(void*));
|
||||||
p("duint,size_t", Duint, sizeof(void*));
|
p("size_t,duint", Duint, sizeof(void*));
|
||||||
p("float", Float, sizeof(float));
|
p("float", Float, sizeof(float));
|
||||||
p("double", Double, sizeof(double));
|
p("double", Double, sizeof(double));
|
||||||
p("ptr,void*", Pointer, sizeof(void*));
|
p("void*,ptr", Pointer, sizeof(void*));
|
||||||
p("char*,const char*", PtrString, sizeof(char*));
|
p("char*,const char*", PtrString, sizeof(char*));
|
||||||
p("wchar_t*,const wchar_t*", PtrWString, sizeof(wchar_t*));
|
p("wchar_t*,const wchar_t*", PtrWString, sizeof(wchar_t*));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string Types::TypeManager::PrimitiveName(Primitive primitive)
|
||||||
|
{
|
||||||
|
auto found = primitivenames.find(primitive);
|
||||||
|
return found == primitivenames.end() ? "" : found->second;
|
||||||
|
}
|
||||||
|
|
||||||
bool TypeManager::AddType(const std::string & owner, const std::string & type, const std::string & name)
|
bool TypeManager::AddType(const std::string & owner, const std::string & type, const std::string & name)
|
||||||
{
|
{
|
||||||
if(owner.empty())
|
if(owner.empty())
|
||||||
|
@ -46,6 +55,32 @@ bool TypeManager::AddType(const std::string & owner, const std::string & type, c
|
||||||
return addType(owner, found->second.primitive, name);
|
return addType(owner, found->second.primitive, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Types::TypeManager::AddEnum(const std::string& owner, const std::string& name, const std::string& type)
|
||||||
|
{
|
||||||
|
Enum e;
|
||||||
|
e.name = name;
|
||||||
|
e.owner = owner;
|
||||||
|
auto found = types.find(type);
|
||||||
|
if (found == types.end())
|
||||||
|
return false;
|
||||||
|
if (!found->second.pointto.empty())
|
||||||
|
return false;
|
||||||
|
switch (found->second.primitive)
|
||||||
|
{
|
||||||
|
case Void:
|
||||||
|
case Float:
|
||||||
|
case Double:
|
||||||
|
case Pointer:
|
||||||
|
case PtrString:
|
||||||
|
case PtrWString:
|
||||||
|
return false;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
e.type = found->second.primitive;
|
||||||
|
return addEnum(e);
|
||||||
|
}
|
||||||
|
|
||||||
bool TypeManager::AddStruct(const std::string & owner, const std::string & name)
|
bool TypeManager::AddStruct(const std::string & owner, const std::string & name)
|
||||||
{
|
{
|
||||||
StructUnion s;
|
StructUnion s;
|
||||||
|
@ -122,7 +157,25 @@ bool TypeManager::AppendMember(const std::string & type, const std::string & nam
|
||||||
return AddMember(laststruct, type, name, arrsize, offset);
|
return AddMember(laststruct, type, name, arrsize, offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TypeManager::AddFunction(const std::string & owner, const std::string & name, const std::string & rettype, CallingConvention callconv, bool noreturn)
|
bool Types::TypeManager::AddEnumerator(const std::string& enumType, const std::string& name, uint64_t value)
|
||||||
|
{
|
||||||
|
auto found = enums.find(enumType);
|
||||||
|
if (found == enums.end())
|
||||||
|
return false;
|
||||||
|
auto& e = found->second;
|
||||||
|
for (const auto& v : e.values)
|
||||||
|
{
|
||||||
|
if (v.name == name || v.value == value)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
EnumValue v;
|
||||||
|
v.name = name;
|
||||||
|
v.value = value;
|
||||||
|
e.values.push_back(v);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TypeManager::AddFunction(const std::string & owner, const std::string & name, const std::string & rettype, CallingConvention callconv, bool noreturn, bool typeonly)
|
||||||
{
|
{
|
||||||
auto found = functions.find(name);
|
auto found = functions.find(name);
|
||||||
if(found != functions.end() || name.empty() || owner.empty())
|
if(found != functions.end() || name.empty() || owner.empty())
|
||||||
|
@ -136,16 +189,16 @@ bool TypeManager::AddFunction(const std::string & owner, const std::string & nam
|
||||||
f.rettype = rettype;
|
f.rettype = rettype;
|
||||||
f.callconv = callconv;
|
f.callconv = callconv;
|
||||||
f.noreturn = noreturn;
|
f.noreturn = noreturn;
|
||||||
functions.insert({f.name, f});
|
functions.emplace(f.name, f);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TypeManager::AddArg(const std::string & function, const std::string & type, const std::string & name)
|
bool TypeManager::AddArg(const std::string & function, const std::string & type, const std::string & name)
|
||||||
{
|
{
|
||||||
if(!isDefined(type) && !validPtr(type))
|
|
||||||
return false;
|
|
||||||
auto found = functions.find(function);
|
auto found = functions.find(function);
|
||||||
if(found == functions.end() || function.empty() || name.empty() || !isDefined(type))
|
if (found == functions.end() || name.empty())
|
||||||
|
return false;
|
||||||
|
if(type != "..." && !isDefined(type) && !validPtr(type))
|
||||||
return false;
|
return false;
|
||||||
lastfunction = function;
|
lastfunction = function;
|
||||||
Member arg;
|
Member arg;
|
||||||
|
@ -255,7 +308,7 @@ static void enumType(const std::unordered_map<K, V> & map, std::vector<TypeManag
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void TypeManager::Enum(std::vector<Summary> & typeList) const
|
void TypeManager::Enumerate(std::vector<Summary> & typeList) const
|
||||||
{
|
{
|
||||||
typeList.clear();
|
typeList.clear();
|
||||||
enumType(types, typeList);
|
enumType(types, typeList);
|
||||||
|
@ -310,7 +363,7 @@ static bool mapContains(const std::unordered_map<K, V> & map, const K & k)
|
||||||
|
|
||||||
bool TypeManager::isDefined(const std::string & id) const
|
bool TypeManager::isDefined(const std::string & id) const
|
||||||
{
|
{
|
||||||
return mapContains(types, id) || mapContains(structs, id);
|
return mapContains(types, id) || mapContains(structs, id) || mapContains(enums, id) || mapContains(functions, id);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TypeManager::validPtr(const std::string & id)
|
bool TypeManager::validPtr(const std::string & id)
|
||||||
|
@ -337,16 +390,22 @@ bool TypeManager::addStructUnion(const StructUnion & s)
|
||||||
laststruct = s.name;
|
laststruct = s.name;
|
||||||
if(s.owner.empty() || s.name.empty() || isDefined(s.name))
|
if(s.owner.empty() || s.name.empty() || isDefined(s.name))
|
||||||
return false;
|
return false;
|
||||||
structs.insert({s.name, s});
|
return structs.emplace(s.name, s).second;
|
||||||
return true;
|
}
|
||||||
|
|
||||||
|
bool Types::TypeManager::addEnum(const Enum& e)
|
||||||
|
{
|
||||||
|
lastenum = e.name;
|
||||||
|
if (e.owner.empty() || e.name.empty() || isDefined(e.name))
|
||||||
|
return false;
|
||||||
|
return enums.emplace(e.name, e).second;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TypeManager::addType(const Type & t)
|
bool TypeManager::addType(const Type & t)
|
||||||
{
|
{
|
||||||
if(t.name.empty() || isDefined(t.name))
|
if(t.name.empty() || isDefined(t.name))
|
||||||
return false;
|
return false;
|
||||||
types.insert({t.name, t});
|
return types.emplace(t.name, t).second;
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TypeManager::addType(const std::string & owner, Primitive primitive, const std::string & name, const std::string & pointto)
|
bool TypeManager::addType(const std::string & owner, Primitive primitive, const std::string & name, const std::string & pointto)
|
||||||
|
@ -483,7 +542,7 @@ bool RemoveType(const std::string & type)
|
||||||
void EnumTypes(std::vector<Types::TypeManager::Summary> & typeList)
|
void EnumTypes(std::vector<Types::TypeManager::Summary> & typeList)
|
||||||
{
|
{
|
||||||
SHARED_ACQUIRE(LockTypeManager);
|
SHARED_ACQUIRE(LockTypeManager);
|
||||||
return typeManager.Enum(typeList);
|
return typeManager.Enumerate(typeList);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
|
@ -602,7 +661,6 @@ static void loadFunctions(const JSON froot, std::vector<Function> & functions)
|
||||||
void LoadModel(const std::string & owner, Model & model)
|
void LoadModel(const std::string & owner, Model & model)
|
||||||
{
|
{
|
||||||
//Add all base struct/union types first to avoid errors later
|
//Add all base struct/union types first to avoid errors later
|
||||||
// TODO: handle forward declarations
|
|
||||||
for(auto & su : model.structUnions)
|
for(auto & su : model.structUnions)
|
||||||
{
|
{
|
||||||
auto success = su.isunion ? typeManager.AddUnion(owner, su.name) : typeManager.AddStruct(owner, su.name);
|
auto success = su.isunion ? typeManager.AddUnion(owner, su.name) : typeManager.AddStruct(owner, su.name);
|
||||||
|
@ -626,15 +684,32 @@ void LoadModel(const std::string & owner, Model & model)
|
||||||
}
|
}
|
||||||
|
|
||||||
//Add enums
|
//Add enums
|
||||||
for (auto& enumm : model.enums)
|
for (auto& kv : model.enums)
|
||||||
{
|
{
|
||||||
__debugbreak();
|
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
|
//Add base function types to avoid errors later
|
||||||
for(auto & function : model.functions)
|
for(auto & function : model.functions)
|
||||||
{
|
{
|
||||||
auto success = typeManager.AddFunction(owner, function.name, function.rettype, function.callconv, function.noreturn);
|
auto success = typeManager.AddFunction(owner, function.name, function.rettype, function.callconv, function.noreturn, function.typeonly);
|
||||||
if(!success)
|
if(!success)
|
||||||
{
|
{
|
||||||
//TODO properly handle errors
|
//TODO properly handle errors
|
||||||
|
@ -664,13 +739,16 @@ void LoadModel(const std::string & owner, Model & model)
|
||||||
{
|
{
|
||||||
if(function.name.empty()) //skip error-signalled functions
|
if(function.name.empty()) //skip error-signalled functions
|
||||||
continue;
|
continue;
|
||||||
for(auto & arg : function.args)
|
for (size_t i = 0; i < function.args.size(); i++)
|
||||||
{
|
{
|
||||||
|
auto& arg = function.args[i];
|
||||||
|
if (arg.name.empty())
|
||||||
|
arg.name = "__unnamed" + std::to_string(i);
|
||||||
auto success = typeManager.AddArg(function.name, arg.type, arg.name);
|
auto success = typeManager.AddArg(function.name, arg.type, arg.name);
|
||||||
if(!success)
|
if(!success)
|
||||||
{
|
{
|
||||||
//TODO properly handle errors
|
//TODO properly handle errors
|
||||||
dprintf(QT_TRANSLATE_NOOP("DBG", "Failed to add argument %s %s.%s;\n"), arg.type.c_str(), function.name.c_str(), arg.name.c_str());
|
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());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,14 +23,15 @@ namespace Types
|
||||||
Double,
|
Double,
|
||||||
Pointer,
|
Pointer,
|
||||||
PtrString, //char* (null-terminated)
|
PtrString, //char* (null-terminated)
|
||||||
PtrWString //wchar_t* (null-terminated)
|
PtrWString, //wchar_t* (null-terminated)
|
||||||
|
Varargs,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Type
|
struct Type
|
||||||
{
|
{
|
||||||
std::string owner; //Type owner
|
std::string owner; //Type owner
|
||||||
std::string name; //Type identifier.
|
std::string name; //Type identifier.
|
||||||
std::string pointto; //Type identifier of *Type
|
std::string pointto; //Type identifier of *Type (empty when the type is a primitive type)
|
||||||
Primitive primitive = Void; //Primitive type.
|
Primitive primitive = Void; //Primitive type.
|
||||||
int size = 0; //Size in bytes.
|
int size = 0; //Size in bytes.
|
||||||
};
|
};
|
||||||
|
@ -64,7 +65,7 @@ namespace Types
|
||||||
std::string owner; // Enum owner
|
std::string owner; // Enum owner
|
||||||
std::string name; // Enum name
|
std::string name; // Enum name
|
||||||
std::vector<EnumValue> values; // Enum values
|
std::vector<EnumValue> values; // Enum values
|
||||||
Type type; // Enum value type
|
Primitive type; // Enum value type
|
||||||
};
|
};
|
||||||
|
|
||||||
enum CallingConvention
|
enum CallingConvention
|
||||||
|
@ -83,6 +84,7 @@ namespace Types
|
||||||
std::string rettype; //Function return type
|
std::string rettype; //Function return type
|
||||||
CallingConvention callconv = DefaultDecl; //Function calling convention
|
CallingConvention callconv = DefaultDecl; //Function calling convention
|
||||||
bool noreturn = false; //Function does not return (ExitProcess, _exit)
|
bool noreturn = false; //Function does not return (ExitProcess, _exit)
|
||||||
|
bool typeonly = false; //Function is only used as a type (the name is based on where it's used)
|
||||||
std::vector<Member> args; //Function arguments
|
std::vector<Member> args; //Function arguments
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -107,32 +109,39 @@ namespace Types
|
||||||
};
|
};
|
||||||
|
|
||||||
explicit TypeManager();
|
explicit TypeManager();
|
||||||
|
std::string PrimitiveName(Primitive primitive);
|
||||||
bool AddType(const std::string & owner, const std::string & type, const std::string & name);
|
bool AddType(const std::string & owner, const std::string & type, const std::string & name);
|
||||||
|
bool AddEnum(const std::string& owner, const std::string& name, const std::string & type);
|
||||||
bool AddStruct(const std::string & owner, 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 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 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 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, CallingConvention callconv = Cdecl, bool noreturn = false);
|
bool AddFunction(const std::string & owner, const std::string & name, const std::string & rettype, CallingConvention callconv = Cdecl, bool noreturn = false, bool typeonly = false);
|
||||||
|
bool AddEnumerator(const std::string& enumType, const std::string& name, uint64_t value);
|
||||||
bool AddArg(const std::string & function, const std::string & type, const std::string & name);
|
bool AddArg(const std::string & function, const std::string & type, const std::string & name);
|
||||||
bool AppendArg(const std::string & type, const std::string & name);
|
bool AppendArg(const std::string & type, const std::string & name);
|
||||||
int Sizeof(const std::string & type) const;
|
int Sizeof(const std::string & type) const;
|
||||||
bool Visit(const std::string & type, const std::string & name, Visitor & visitor) const;
|
bool Visit(const std::string & type, const std::string & name, Visitor & visitor) const;
|
||||||
void Clear(const std::string & owner = "");
|
void Clear(const std::string & owner = "");
|
||||||
bool RemoveType(const std::string & type);
|
bool RemoveType(const std::string & type);
|
||||||
void Enum(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;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::unordered_map<Primitive, int> primitivesizes;
|
std::unordered_map<Primitive, int> primitivesizes;
|
||||||
|
std::unordered_map<Primitive, std::string> primitivenames;
|
||||||
std::unordered_map<std::string, Type> types;
|
std::unordered_map<std::string, Type> types;
|
||||||
|
std::unordered_map<std::string, Types::Enum> enums;
|
||||||
std::unordered_map<std::string, StructUnion> structs;
|
std::unordered_map<std::string, StructUnion> structs;
|
||||||
std::unordered_map<std::string, Function> functions;
|
std::unordered_map<std::string, Function> functions;
|
||||||
|
std::string lastenum;
|
||||||
std::string laststruct;
|
std::string laststruct;
|
||||||
std::string lastfunction;
|
std::string lastfunction;
|
||||||
|
|
||||||
bool isDefined(const std::string & id) const;
|
bool isDefined(const std::string & id) const;
|
||||||
bool validPtr(const std::string & id);
|
bool validPtr(const std::string & id);
|
||||||
bool addStructUnion(const StructUnion & s);
|
bool addStructUnion(const StructUnion & s);
|
||||||
|
bool addEnum(const Enum& e);
|
||||||
bool addType(const std::string & owner, Primitive primitive, const std::string & name, const std::string & pointto = "");
|
bool addType(const std::string & owner, Primitive primitive, const std::string & name, const std::string & pointto = "");
|
||||||
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;
|
||||||
|
@ -141,7 +150,7 @@ namespace Types
|
||||||
struct Model
|
struct Model
|
||||||
{
|
{
|
||||||
std::vector<Member> types;
|
std::vector<Member> types;
|
||||||
std::vector<Enum> enums;
|
std::vector<std::pair<Enum, std::string>> enums;
|
||||||
std::vector<StructUnion> structUnions;
|
std::vector<StructUnion> structUnions;
|
||||||
std::vector<Function> functions;
|
std::vector<Function> functions;
|
||||||
};
|
};
|
||||||
|
|
|
@ -16,6 +16,7 @@ struct Parser
|
||||||
std::vector<Lexer::TokenState> tokens;
|
std::vector<Lexer::TokenState> tokens;
|
||||||
size_t index = 0;
|
size_t index = 0;
|
||||||
Model model;
|
Model model;
|
||||||
|
std::unordered_map<std::string, size_t> structUnions;
|
||||||
|
|
||||||
Parser(const std::string& code, const std::string& owner, std::vector<std::string>& errors)
|
Parser(const std::string& code, const std::string& owner, std::vector<std::string>& errors)
|
||||||
: owner(owner), errors(errors)
|
: owner(owner), errors(errors)
|
||||||
|
@ -296,20 +297,17 @@ struct Parser
|
||||||
|
|
||||||
// Function pointer argument to a function
|
// Function pointer argument to a function
|
||||||
Function subfn;
|
Function subfn;
|
||||||
|
subfn.typeonly = true;
|
||||||
if(!parseFunction(tlist, subfn, true))
|
if(!parseFunction(tlist, subfn, true))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// TODO: store this somewhere
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Create fake tokens
|
// Create fake tokens
|
||||||
// TODO: handle this properly somehow
|
|
||||||
auto typeToken = tlist.back();
|
auto typeToken = tlist.back();
|
||||||
typeToken.Token = Lexer::tok_identifier;
|
typeToken.Token = Lexer::tok_identifier;
|
||||||
typeToken.IdentifierStr = fn.name + "_" + subfn.name + "_fnptr";
|
typeToken.IdentifierStr = fn.name + "_" + subfn.name + "_fnptr";
|
||||||
|
|
||||||
printf("TODO function pointer: %s %s\n", typeToken.IdentifierStr.c_str(), subfn.name.c_str());
|
subfn.name = typeToken.IdentifierStr;
|
||||||
|
model.functions.push_back(subfn);
|
||||||
|
|
||||||
auto nameToken = startToken;
|
auto nameToken = startToken;
|
||||||
nameToken.Token = Lexer::tok_identifier;
|
nameToken.Token = Lexer::tok_identifier;
|
||||||
|
@ -455,8 +453,9 @@ struct Parser
|
||||||
index++;
|
index++;
|
||||||
|
|
||||||
// Function pointer type
|
// Function pointer type
|
||||||
Function fn;
|
Function subfn;
|
||||||
if (!parseFunction(tlist, fn, true))
|
subfn.typeonly = true;
|
||||||
|
if (!parseFunction(tlist, subfn, true))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -468,9 +467,22 @@ struct Parser
|
||||||
}
|
}
|
||||||
eatSemic();
|
eatSemic();
|
||||||
|
|
||||||
// TODO: put the function somewhere
|
// Create fake tokens
|
||||||
|
auto typeToken = tlist.back();
|
||||||
|
typeToken.Token = Lexer::tok_identifier;
|
||||||
|
typeToken.IdentifierStr = su.name + "_" + subfn.name + "_fnptr";
|
||||||
|
|
||||||
printf("TODO function pointer: %s\n", fn.name.c_str());
|
subfn.name = typeToken.IdentifierStr;
|
||||||
|
model.functions.push_back(subfn);
|
||||||
|
|
||||||
|
auto nameToken = startToken;
|
||||||
|
nameToken.Token = Lexer::tok_identifier;
|
||||||
|
nameToken.IdentifierStr = subfn.name;
|
||||||
|
|
||||||
|
// Replace the return type with the fake tokens
|
||||||
|
tlist.clear();
|
||||||
|
tlist.push_back(typeToken);
|
||||||
|
tlist.push_back(nameToken);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -515,6 +527,7 @@ struct Parser
|
||||||
|
|
||||||
bool parseStructUnion()
|
bool parseStructUnion()
|
||||||
{
|
{
|
||||||
|
auto startToken = curToken();
|
||||||
if (isToken(Lexer::tok_struct) || isToken(Lexer::tok_union))
|
if (isToken(Lexer::tok_struct) || isToken(Lexer::tok_union))
|
||||||
{
|
{
|
||||||
StructUnion su;
|
StructUnion su;
|
||||||
|
@ -547,7 +560,25 @@ struct Parser
|
||||||
}
|
}
|
||||||
index++;
|
index++;
|
||||||
|
|
||||||
|
// Handle forward declarations
|
||||||
|
auto found = structUnions.find(su.name);
|
||||||
|
if (found != structUnions.end())
|
||||||
|
{
|
||||||
|
auto& oldSu = model.structUnions[found->second];
|
||||||
|
if (oldSu.size != -1)
|
||||||
|
{
|
||||||
|
errLine(startToken, "cannot redeclare type");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// Replace the forward declared type with the full type
|
||||||
|
oldSu = su;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
structUnions.emplace(su.name, model.structUnions.size());
|
||||||
model.structUnions.push_back(su);
|
model.structUnions.push_back(su);
|
||||||
|
}
|
||||||
|
|
||||||
if (!isToken(Lexer::tok_semic))
|
if (!isToken(Lexer::tok_semic))
|
||||||
{
|
{
|
||||||
errLine(curToken(), "expected semicolon!");
|
errLine(curToken(), "expected semicolon!");
|
||||||
|
@ -559,7 +590,13 @@ struct Parser
|
||||||
else if (isToken(Lexer::tok_semic))
|
else if (isToken(Lexer::tok_semic))
|
||||||
{
|
{
|
||||||
// Forward declaration
|
// Forward declaration
|
||||||
|
su.size = -1;
|
||||||
|
auto found = structUnions.find(su.name);
|
||||||
|
if (found == structUnions.end())
|
||||||
|
{
|
||||||
|
structUnions.emplace(su.name, model.structUnions.size());
|
||||||
model.structUnions.push_back(su);
|
model.structUnions.push_back(su);
|
||||||
|
}
|
||||||
eatSemic();
|
eatSemic();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -577,12 +614,16 @@ struct Parser
|
||||||
if (isToken(Lexer::tok_enum))
|
if (isToken(Lexer::tok_enum))
|
||||||
{
|
{
|
||||||
Enum e;
|
Enum e;
|
||||||
|
std::string etype;
|
||||||
index++;
|
index++;
|
||||||
if (isTokenList({ Lexer::tok_identifier, Lexer::tok_bropen }))
|
if (isTokenList({ Lexer::tok_identifier, Lexer::tok_bropen }))
|
||||||
{
|
{
|
||||||
e.name = lexer.TokString(curToken());
|
e.name = lexer.TokString(curToken());
|
||||||
index += 2;
|
index += 2;
|
||||||
|
|
||||||
|
// TODO: support custom enum types (: type)
|
||||||
|
etype = "int";
|
||||||
|
|
||||||
while (!isToken(Lexer::tok_brclose))
|
while (!isToken(Lexer::tok_brclose))
|
||||||
{
|
{
|
||||||
if (isToken(Lexer::tok_eof))
|
if (isToken(Lexer::tok_eof))
|
||||||
|
@ -653,7 +694,7 @@ struct Parser
|
||||||
}
|
}
|
||||||
index++; //eat tok_brclose
|
index++; //eat tok_brclose
|
||||||
|
|
||||||
model.enums.push_back(e);
|
model.enums.emplace_back(e, etype);
|
||||||
if (!isToken(Lexer::tok_semic))
|
if (!isToken(Lexer::tok_semic))
|
||||||
{
|
{
|
||||||
errLine(curToken(), "expected semicolon!");
|
errLine(curToken(), "expected semicolon!");
|
||||||
|
@ -740,6 +781,7 @@ struct Parser
|
||||||
index++;
|
index++;
|
||||||
|
|
||||||
Function fn;
|
Function fn;
|
||||||
|
fn.typeonly = true;
|
||||||
if (!parseFunction(tlist, fn, true))
|
if (!parseFunction(tlist, fn, true))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
|
@ -752,9 +794,9 @@ struct Parser
|
||||||
}
|
}
|
||||||
eatSemic();
|
eatSemic();
|
||||||
|
|
||||||
// TODO: put the function somewhere
|
model.functions.push_back(fn);
|
||||||
|
|
||||||
printf("TODO function pointer: %s\n", fn.name.c_str());
|
// TODO: handle pointer stuff correctly?
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -849,9 +891,7 @@ struct Parser
|
||||||
}
|
}
|
||||||
eatSemic();
|
eatSemic();
|
||||||
|
|
||||||
// TODO: put the function somewhere
|
model.functions.push_back(fn);
|
||||||
|
|
||||||
printf("TODO function: %s\n", fn.name.c_str());
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue