(Somewhat) correctly handle function declarations and function pointer types

This commit is contained in:
Duncan Ogilvie 2023-02-10 14:00:44 +01:00
parent c1c257ce7a
commit a87d84cc5b
3 changed files with 173 additions and 46 deletions

View File

@ -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());
} }
} }
} }

View File

@ -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;
}; };

View File

@ -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;
} }