refactor(gsc): remove static allocations (#63)
This commit is contained in:
parent
b3ac7d2562
commit
bd05f90a34
@ -310,7 +310,7 @@ auto assembler::assemble_instruction(instruction const& inst) -> void
|
||||
assemble_formal_params(inst);
|
||||
break;
|
||||
default:
|
||||
throw asm_error(fmt::format("unhandled opcode {} at index {:04X}", opcode_name(inst.opcode), inst.index));
|
||||
throw asm_error(fmt::format("unhandled opcode {} at index {:04X}", ctx_->opcode_name(inst.opcode), inst.index));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -9,30 +9,57 @@
|
||||
namespace xsk::gsc
|
||||
{
|
||||
|
||||
read_cb_type read_callback = nullptr;
|
||||
std::unordered_map<std::string, buffer> header_files;
|
||||
std::set<std::string_view> includes;
|
||||
std::unordered_map<std::string, std::vector<std::string>> include_cache;
|
||||
std::set<std::string> new_func_map;
|
||||
std::set<std::string> new_meth_map;
|
||||
extern std::array<std::pair<opcode, std::string_view>, opcode_count> const opcode_list;
|
||||
|
||||
context::context(gsc::props props, gsc::engine engine, gsc::endian endian, gsc::system system, u32 str_count)
|
||||
: props_{ props }, engine_{ engine }, endian_{ endian }, system_{ system }, str_count_{ str_count },
|
||||
source_{ this }, assembler_{ this }, disassembler_{ this }, compiler_{ this }, decompiler_{ this }
|
||||
{
|
||||
opcode_map_.reserve(opcode_list.size());
|
||||
opcode_map_rev_.reserve(opcode_list.size());
|
||||
|
||||
for (auto const& entry : opcode_list)
|
||||
{
|
||||
opcode_map_.insert({ entry.first, entry.second });
|
||||
opcode_map_rev_.insert({ entry.second, entry.first });
|
||||
}
|
||||
}
|
||||
|
||||
auto context::init(gsc::build build, read_cb_type callback) -> void
|
||||
auto context::init(gsc::build build, fs_callback callback) -> void
|
||||
{
|
||||
build_ = build;
|
||||
read_callback = callback;
|
||||
fs_callback_ = callback;
|
||||
}
|
||||
|
||||
auto context::cleanup() -> void
|
||||
{
|
||||
header_files.clear();
|
||||
include_cache.clear();
|
||||
includes.clear();
|
||||
source_ = gsc::source{ this };
|
||||
assembler_ = gsc::assembler{ this };
|
||||
disassembler_ = gsc::disassembler{ this };
|
||||
compiler_ = gsc::compiler{ this };
|
||||
decompiler_ = gsc::decompiler{ this };
|
||||
header_files_.clear();
|
||||
include_cache_.clear();
|
||||
includes_.clear();
|
||||
}
|
||||
|
||||
auto context::engine_name() const -> std::string_view
|
||||
{
|
||||
switch (engine_)
|
||||
{
|
||||
case engine::iw5: return "IW5";
|
||||
case engine::iw6: return "IW6";
|
||||
case engine::iw7: return "IW7";
|
||||
case engine::iw8: return "IW8";
|
||||
case engine::iw9: return "IW9";
|
||||
case engine::s1: return "S1";
|
||||
case engine::s2: return "S2";
|
||||
case engine::s4: return "S4";
|
||||
case engine::h1: return "H1";
|
||||
case engine::h2: return "H2";
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
auto context::opcode_size(opcode op) const -> u32
|
||||
@ -273,6 +300,30 @@ auto context::opcode_id(opcode op) const -> u8
|
||||
throw error(fmt::format("couldn't resolve opcode id for '{}'", opcode_name(op)));
|
||||
}
|
||||
|
||||
auto context::opcode_name(opcode op) const -> std::string
|
||||
{
|
||||
auto const itr = opcode_map_.find(op);
|
||||
|
||||
if (itr != opcode_map_.end())
|
||||
{
|
||||
return std::string{ itr->second };
|
||||
}
|
||||
|
||||
throw std::runtime_error(fmt::format("couldn't resolve opcode string for enum '{}'", static_cast<std::underlying_type_t<opcode>>(op)));
|
||||
}
|
||||
|
||||
auto context::opcode_enum(std::string const& name) const -> opcode
|
||||
{
|
||||
auto const itr = opcode_map_rev_.find(name);
|
||||
|
||||
if (itr != opcode_map_rev_.end())
|
||||
{
|
||||
return itr->second;
|
||||
}
|
||||
|
||||
throw std::runtime_error(fmt::format("couldn't resolve opcode enum for name '{}'", name));
|
||||
}
|
||||
|
||||
auto context::opcode_enum(u8 id) const -> opcode
|
||||
{
|
||||
auto const itr = code_map_.find(id);
|
||||
@ -337,16 +388,16 @@ auto context::func_add(std::string const& name, u16 id) -> void
|
||||
throw error(fmt::format("builtin function '{}' already defined", name));
|
||||
}
|
||||
|
||||
auto const str = new_func_map.find(name);
|
||||
auto const str = new_func_map_.find(name);
|
||||
|
||||
if (str != new_func_map.end())
|
||||
if (str != new_func_map_.end())
|
||||
{
|
||||
func_map_.insert({ id, *str });
|
||||
func_map_rev_.insert({ *str, id });
|
||||
}
|
||||
else
|
||||
{
|
||||
auto ins = new_func_map.insert(name);
|
||||
auto ins = new_func_map_.insert(name);
|
||||
|
||||
if (ins.second)
|
||||
{
|
||||
@ -408,16 +459,16 @@ auto context::meth_add(std::string const& name, u16 id) -> void
|
||||
throw error(fmt::format("builtin method '{}' already defined", name));
|
||||
}
|
||||
|
||||
auto const str = new_meth_map.find(name);
|
||||
auto const str = new_meth_map_.find(name);
|
||||
|
||||
if (str != new_meth_map.end())
|
||||
if (str != new_meth_map_.end())
|
||||
{
|
||||
meth_map_.insert({ id, *str });
|
||||
meth_map_rev_.insert({ *str, id });
|
||||
}
|
||||
else
|
||||
{
|
||||
auto ins = new_meth_map.insert(name);
|
||||
auto ins = new_meth_map_.insert(name);
|
||||
|
||||
if (ins.second)
|
||||
{
|
||||
@ -552,20 +603,21 @@ auto context::make_token(std::string_view str) const -> std::string
|
||||
return data;
|
||||
}
|
||||
|
||||
auto context::header_file_data(std::string const& name) const -> std::tuple<std::string const*, char const*, usize>
|
||||
auto context::load_header(std::string const& name) -> std::tuple<std::string const*, char const*, usize>
|
||||
{
|
||||
auto const itr = header_files.find(name);
|
||||
// todo: remove cache to prevent use after free if files are read from fs by the game
|
||||
auto const itr = header_files_.find(name);
|
||||
|
||||
if (itr != header_files.end())
|
||||
if (itr != header_files_.end())
|
||||
{
|
||||
return { &itr->first, reinterpret_cast<char const*>(itr->second.data), itr->second.size };
|
||||
}
|
||||
|
||||
auto data = read_callback(name);
|
||||
auto data = fs_callback_(name);
|
||||
|
||||
if (data.first.data != nullptr && data.first.size != 0 && data.second.data == nullptr && data.second.size == 0)
|
||||
if (data.first.data != nullptr && data.first.size != 0 && data.second.size() == 0)
|
||||
{
|
||||
auto const res = header_files.insert({ name, data.first });
|
||||
auto const res = header_files_.insert({ name, data.first });
|
||||
|
||||
if (res.second)
|
||||
{
|
||||
@ -580,22 +632,22 @@ auto context::load_include(std::string const& name) -> bool
|
||||
{
|
||||
try
|
||||
{
|
||||
if (includes.contains(name))
|
||||
if (includes_.contains(name))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
includes.insert(name);
|
||||
includes_.insert(name);
|
||||
|
||||
if (include_cache.contains(name))
|
||||
if (include_cache_.contains(name))
|
||||
return true;
|
||||
|
||||
auto file = read_callback(name);
|
||||
auto file = fs_callback_(name);
|
||||
|
||||
if (file.first.data == nullptr && file.first.size == 0)
|
||||
throw std::runtime_error("empty file");
|
||||
|
||||
if (file.second.data == nullptr && file.second.size == 0)
|
||||
if (file.second.size() == 0)
|
||||
{
|
||||
// process RawFile
|
||||
auto prog = source_.parse_program(name, file.first);
|
||||
@ -610,12 +662,12 @@ auto context::load_include(std::string const& name) -> bool
|
||||
}
|
||||
}
|
||||
|
||||
include_cache.insert({ name, std::move(funcs) });
|
||||
include_cache_.insert({ name, std::move(funcs) });
|
||||
}
|
||||
else
|
||||
{
|
||||
// process ScriptFile
|
||||
auto data = disassembler_.disassemble(file.first, file.second);
|
||||
auto data = disassembler_.disassemble(file.first, buffer{ file.second.data(), file.second.size() });
|
||||
|
||||
auto funcs = std::vector<std::string>{};
|
||||
|
||||
@ -624,7 +676,7 @@ auto context::load_include(std::string const& name) -> bool
|
||||
funcs.push_back(fun->name);
|
||||
}
|
||||
|
||||
include_cache.insert({ name, std::move(funcs) });
|
||||
include_cache_.insert({ name, std::move(funcs) });
|
||||
}
|
||||
|
||||
return true;
|
||||
@ -637,14 +689,14 @@ auto context::load_include(std::string const& name) -> bool
|
||||
|
||||
auto context::init_includes() -> void
|
||||
{
|
||||
includes.clear();
|
||||
includes_.clear();
|
||||
}
|
||||
|
||||
auto context::is_includecall(std::string const& name, std::string& path) -> bool
|
||||
{
|
||||
for (auto const& inc : includes)
|
||||
for (auto const& inc : includes_)
|
||||
{
|
||||
for (auto const& fun : include_cache.at(std::string{ inc }))
|
||||
for (auto const& fun : include_cache_.at(std::string{ inc }))
|
||||
{
|
||||
if (name == fun)
|
||||
{
|
||||
@ -657,4 +709,213 @@ auto context::is_includecall(std::string const& name, std::string& path) -> bool
|
||||
return false;
|
||||
}
|
||||
|
||||
extern std::array<std::pair<opcode, std::string_view>, opcode_count> const opcode_list
|
||||
{{
|
||||
{ opcode::vm_invalid, "vm_invalid" },
|
||||
{ opcode::OP_CastFieldObject, "OP_CastFieldObject" },
|
||||
{ opcode::OP_SetLocalVariableFieldCached, "OP_SetLocalVariableFieldCached" },
|
||||
{ opcode::OP_plus, "OP_plus" },
|
||||
{ opcode::OP_RemoveLocalVariables, "OP_RemoveLocalVariables" },
|
||||
{ opcode::OP_EvalSelfFieldVariableRef, "OP_EvalSelfFieldVariableRef" },
|
||||
{ opcode::OP_ScriptFarMethodChildThreadCall, "OP_ScriptFarMethodChildThreadCall" },
|
||||
{ opcode::OP_GetGameRef, "OP_GetGameRef" },
|
||||
{ opcode::OP_EvalAnimFieldVariable, "OP_EvalAnimFieldVariable" },
|
||||
{ opcode::OP_EvalLevelFieldVariableRef, "OP_EvalLevelFieldVariableRef" },
|
||||
{ opcode::OP_GetThisthread, "OP_GetThisthread" },
|
||||
{ opcode::OP_greater, "OP_greater" },
|
||||
{ opcode::OP_waittillmatch, "OP_waittillmatch" },
|
||||
{ opcode::OP_shift_right, "OP_shift_right" },
|
||||
{ opcode::OP_dec, "OP_dec" },
|
||||
{ opcode::OP_JumpOnTrue, "OP_JumpOnTrue" },
|
||||
{ opcode::OP_bit_or, "OP_bit_or" },
|
||||
{ opcode::OP_equality, "OP_equality" },
|
||||
{ opcode::OP_ClearLocalVariableFieldCached0, "OP_ClearLocalVariableFieldCached0" },
|
||||
{ opcode::OP_notify, "OP_notify" },
|
||||
{ opcode::OP_GetVector, "OP_GetVector" },
|
||||
{ opcode::OP_ScriptMethodChildThreadCallPointer, "OP_ScriptMethodChildThreadCallPointer" },
|
||||
{ opcode::OP_PreScriptCall, "OP_PreScriptCall" },
|
||||
{ opcode::OP_GetByte, "OP_GetByte" },
|
||||
{ opcode::OP_ScriptFarThreadCall, "OP_ScriptFarThreadCall" },
|
||||
{ opcode::OP_SetSelfFieldVariableField, "OP_SetSelfFieldVariableField" },
|
||||
{ opcode::OP_JumpOnFalseExpr, "OP_JumpOnFalseExpr" },
|
||||
{ opcode::OP_GetUndefined, "OP_GetUndefined" },
|
||||
{ opcode::OP_jumpback, "OP_jumpback" },
|
||||
{ opcode::OP_JumpOnTrueExpr, "OP_JumpOnTrueExpr" },
|
||||
{ opcode::OP_CallBuiltin0, "OP_CallBuiltin0" },
|
||||
{ opcode::OP_CallBuiltin1, "OP_CallBuiltin1" },
|
||||
{ opcode::OP_CallBuiltin2, "OP_CallBuiltin2" },
|
||||
{ opcode::OP_CallBuiltin3, "OP_CallBuiltin3" },
|
||||
{ opcode::OP_CallBuiltin4, "OP_CallBuiltin4" },
|
||||
{ opcode::OP_CallBuiltin5, "OP_CallBuiltin5" },
|
||||
{ opcode::OP_CallBuiltin, "OP_CallBuiltin" },
|
||||
{ opcode::OP_SetLocalVariableFieldCached0, "OP_SetLocalVariableFieldCached0" },
|
||||
{ opcode::OP_ClearFieldVariable, "OP_ClearFieldVariable" },
|
||||
{ opcode::OP_GetLevel, "OP_GetLevel" },
|
||||
{ opcode::OP_size, "OP_size" },
|
||||
{ opcode::OP_SafeSetWaittillVariableFieldCached, "OP_SafeSetWaittillVariableFieldCached" },
|
||||
{ opcode::OP_ScriptLocalMethodThreadCall, "OP_ScriptLocalMethodThreadCall" },
|
||||
{ opcode::OP_AddArray, "OP_AddArray" },
|
||||
{ opcode::OP_endon, "OP_endon" },
|
||||
{ opcode::OP_EvalFieldVariable, "OP_EvalFieldVariable" },
|
||||
{ opcode::OP_shift_left, "OP_shift_left" },
|
||||
{ opcode::OP_EvalLocalArrayRefCached0, "OP_EvalLocalArrayRefCached0" },
|
||||
{ opcode::OP_Return, "OP_Return" },
|
||||
{ opcode::OP_CreateLocalVariable, "OP_CreateLocalVariable" },
|
||||
{ opcode::OP_SafeSetVariableFieldCached0, "OP_SafeSetVariableFieldCached0" },
|
||||
{ opcode::OP_GetBuiltinFunction, "OP_GetBuiltinFunction" },
|
||||
{ opcode::OP_ScriptLocalMethodCall, "OP_ScriptLocalMethodCall" },
|
||||
{ opcode::OP_CallBuiltinMethodPointer, "OP_CallBuiltinMethodPointer" },
|
||||
{ opcode::OP_ScriptLocalChildThreadCall, "OP_ScriptLocalChildThreadCall" },
|
||||
{ opcode::OP_GetSelfObject, "OP_GetSelfObject" },
|
||||
{ opcode::OP_GetGame, "OP_GetGame" },
|
||||
{ opcode::OP_SetLevelFieldVariableField, "OP_SetLevelFieldVariableField" },
|
||||
{ opcode::OP_EvalArray, "OP_EvalArray" },
|
||||
{ opcode::OP_GetSelf, "OP_GetSelf" },
|
||||
{ opcode::OP_End, "OP_End" },
|
||||
{ opcode::OP_EvalSelfFieldVariable, "OP_EvalSelfFieldVariable" },
|
||||
{ opcode::OP_less_equal, "OP_less_equal" },
|
||||
{ opcode::OP_EvalLocalVariableCached0, "OP_EvalLocalVariableCached0" },
|
||||
{ opcode::OP_EvalLocalVariableCached1, "OP_EvalLocalVariableCached1" },
|
||||
{ opcode::OP_EvalLocalVariableCached2, "OP_EvalLocalVariableCached2" },
|
||||
{ opcode::OP_EvalLocalVariableCached3, "OP_EvalLocalVariableCached3" },
|
||||
{ opcode::OP_EvalLocalVariableCached4, "OP_EvalLocalVariableCached4" },
|
||||
{ opcode::OP_EvalLocalVariableCached5, "OP_EvalLocalVariableCached5" },
|
||||
{ opcode::OP_EvalLocalVariableCached, "OP_EvalLocalVariableCached" },
|
||||
{ opcode::OP_EvalNewLocalArrayRefCached0, "OP_EvalNewLocalArrayRefCached0" },
|
||||
{ opcode::OP_ScriptChildThreadCallPointer, "OP_ScriptChildThreadCallPointer" },
|
||||
{ opcode::OP_EvalLocalVariableObjectCached, "OP_EvalLocalVariableObjectCached" },
|
||||
{ opcode::OP_ScriptLocalThreadCall, "OP_ScriptLocalThreadCall" },
|
||||
{ opcode::OP_GetInteger, "OP_GetInteger" },
|
||||
{ opcode::OP_ScriptMethodCallPointer, "OP_ScriptMethodCallPointer" },
|
||||
{ opcode::OP_checkclearparams, "OP_checkclearparams" },
|
||||
{ opcode::OP_SetAnimFieldVariableField, "OP_SetAnimFieldVariableField" },
|
||||
{ opcode::OP_waittillmatch2, "OP_waittillmatch2" },
|
||||
{ opcode::OP_minus, "OP_minus" },
|
||||
{ opcode::OP_ScriptLocalFunctionCall2, "OP_ScriptLocalFunctionCall2" },
|
||||
{ opcode::OP_GetNegUnsignedShort, "OP_GetNegUnsignedShort" },
|
||||
{ opcode::OP_GetNegByte, "OP_GetNegByte" },
|
||||
{ opcode::OP_SafeCreateVariableFieldCached, "OP_SafeCreateVariableFieldCached" },
|
||||
{ opcode::OP_greater_equal, "OP_greater_equal" },
|
||||
{ opcode::OP_vector, "OP_vector" },
|
||||
{ opcode::OP_GetBuiltinMethod, "OP_GetBuiltinMethod" },
|
||||
{ opcode::OP_endswitch, "OP_endswitch" },
|
||||
{ opcode::OP_ClearArray, "OP_ClearArray" },
|
||||
{ opcode::OP_DecTop, "OP_DecTop" },
|
||||
{ opcode::OP_CastBool, "OP_CastBool" },
|
||||
{ opcode::OP_EvalArrayRef, "OP_EvalArrayRef" },
|
||||
{ opcode::OP_SetNewLocalVariableFieldCached0, "OP_SetNewLocalVariableFieldCached0" },
|
||||
{ opcode::OP_GetZero, "OP_GetZero" },
|
||||
{ opcode::OP_wait, "OP_wait" },
|
||||
{ opcode::OP_waittill, "OP_waittill" },
|
||||
{ opcode::OP_GetIString, "OP_GetIString" },
|
||||
{ opcode::OP_ScriptFarFunctionCall, "OP_ScriptFarFunctionCall" },
|
||||
{ opcode::OP_GetAnimObject, "OP_GetAnimObject" },
|
||||
{ opcode::OP_GetAnimTree, "OP_GetAnimTree" },
|
||||
{ opcode::OP_EvalLocalArrayCached, "OP_EvalLocalArrayCached" },
|
||||
{ opcode::OP_mod, "OP_mod" },
|
||||
{ opcode::OP_ScriptFarMethodThreadCall, "OP_ScriptFarMethodThreadCall" },
|
||||
{ opcode::OP_GetUnsignedShort, "OP_GetUnsignedShort" },
|
||||
{ opcode::OP_clearparams, "OP_clearparams" },
|
||||
{ opcode::OP_ScriptMethodThreadCallPointer, "OP_ScriptMethodThreadCallPointer" },
|
||||
{ opcode::OP_ScriptFunctionCallPointer, "OP_ScriptFunctionCallPointer" },
|
||||
{ opcode::OP_EmptyArray, "OP_EmptyArray" },
|
||||
{ opcode::OP_SafeSetVariableFieldCached, "OP_SafeSetVariableFieldCached" },
|
||||
{ opcode::OP_ClearVariableField, "OP_ClearVariableField" },
|
||||
{ opcode::OP_EvalFieldVariableRef, "OP_EvalFieldVariableRef" },
|
||||
{ opcode::OP_ScriptLocalMethodChildThreadCall, "OP_ScriptLocalMethodChildThreadCall" },
|
||||
{ opcode::OP_EvalNewLocalVariableRefCached0, "OP_EvalNewLocalVariableRefCached0" },
|
||||
{ opcode::OP_GetFloat, "OP_GetFloat" },
|
||||
{ opcode::OP_EvalLocalVariableRefCached, "OP_EvalLocalVariableRefCached" },
|
||||
{ opcode::OP_JumpOnFalse, "OP_JumpOnFalse" },
|
||||
{ opcode::OP_BoolComplement, "OP_BoolComplement" },
|
||||
{ opcode::OP_ScriptThreadCallPointer, "OP_ScriptThreadCallPointer" },
|
||||
{ opcode::OP_ScriptFarFunctionCall2, "OP_ScriptFarFunctionCall2" },
|
||||
{ opcode::OP_less, "OP_less" },
|
||||
{ opcode::OP_BoolNot, "OP_BoolNot" },
|
||||
{ opcode::OP_waittillFrameEnd, "OP_waittillFrameEnd" },
|
||||
{ opcode::OP_waitframe, "OP_waitframe" },
|
||||
{ opcode::OP_GetString, "OP_GetString" },
|
||||
{ opcode::OP_EvalLevelFieldVariable, "OP_EvalLevelFieldVariable" },
|
||||
{ opcode::OP_GetLevelObject, "OP_GetLevelObject" },
|
||||
{ opcode::OP_inc, "OP_inc" },
|
||||
{ opcode::OP_CallBuiltinMethod0, "OP_CallBuiltinMethod0" },
|
||||
{ opcode::OP_CallBuiltinMethod1, "OP_CallBuiltinMethod1" },
|
||||
{ opcode::OP_CallBuiltinMethod2, "OP_CallBuiltinMethod2" },
|
||||
{ opcode::OP_CallBuiltinMethod3, "OP_CallBuiltinMethod3" },
|
||||
{ opcode::OP_CallBuiltinMethod4, "OP_CallBuiltinMethod4" },
|
||||
{ opcode::OP_CallBuiltinMethod5, "OP_CallBuiltinMethod5" },
|
||||
{ opcode::OP_CallBuiltinMethod, "OP_CallBuiltinMethod" },
|
||||
{ opcode::OP_GetAnim, "OP_GetAnim" },
|
||||
{ opcode::OP_switch, "OP_switch" },
|
||||
{ opcode::OP_SetVariableField, "OP_SetVariableField" },
|
||||
{ opcode::OP_divide, "OP_divide" },
|
||||
{ opcode::OP_GetLocalFunction, "OP_GetLocalFunction" },
|
||||
{ opcode::OP_ScriptFarChildThreadCall, "OP_ScriptFarChildThreadCall" },
|
||||
{ opcode::OP_multiply, "OP_multiply" },
|
||||
{ opcode::OP_ClearLocalVariableFieldCached, "OP_ClearLocalVariableFieldCached" },
|
||||
{ opcode::OP_EvalAnimFieldVariableRef, "OP_EvalAnimFieldVariableRef" },
|
||||
{ opcode::OP_EvalLocalArrayRefCached, "OP_EvalLocalArrayRefCached" },
|
||||
{ opcode::OP_EvalLocalVariableRefCached0, "OP_EvalLocalVariableRefCached0" },
|
||||
{ opcode::OP_bit_and, "OP_bit_and" },
|
||||
{ opcode::OP_GetAnimation, "OP_GetAnimation" },
|
||||
{ opcode::OP_GetFarFunction, "OP_GetFarFunction" },
|
||||
{ opcode::OP_CallBuiltinPointer, "OP_CallBuiltinPointer" },
|
||||
{ opcode::OP_jump, "OP_jump" },
|
||||
{ opcode::OP_voidCodepos, "OP_voidCodepos" },
|
||||
{ opcode::OP_ScriptFarMethodCall, "OP_ScriptFarMethodCall" },
|
||||
{ opcode::OP_inequality, "OP_inequality" },
|
||||
{ opcode::OP_ScriptLocalFunctionCall, "OP_ScriptLocalFunctionCall" },
|
||||
{ opcode::OP_bit_ex_or, "OP_bit_ex_or" },
|
||||
{ opcode::OP_NOP, "OP_NOP" },
|
||||
{ opcode::OP_abort, "OP_abort" },
|
||||
{ opcode::OP_object, "OP_object" },
|
||||
{ opcode::OP_thread_object, "OP_thread_object" },
|
||||
{ opcode::OP_EvalLocalVariable, "OP_EvalLocalVariable" },
|
||||
{ opcode::OP_EvalLocalVariableRef, "OP_EvalLocalVariableRef" },
|
||||
{ opcode::OP_prof_begin, "OP_prof_begin" },
|
||||
{ opcode::OP_prof_end, "OP_prof_end" },
|
||||
{ opcode::OP_breakpoint, "OP_breakpoint" },
|
||||
{ opcode::OP_assignmentBreakpoint, "OP_assignmentBreakpoint" },
|
||||
{ opcode::OP_manualAndAssignmentBreakpoint, "OP_manualAndAssignmentBreakpoint" },
|
||||
{ opcode::OP_BoolNotAfterAnd, "OP_BoolNotAfterAnd" },
|
||||
{ opcode::OP_FormalParams, "OP_FormalParams" },
|
||||
{ opcode::OP_IsDefined, "OP_IsDefined" },
|
||||
{ opcode::OP_IsTrue, "OP_IsTrue" },
|
||||
{ opcode::OP_NativeGetLocalFunction, "OP_NativeGetLocalFunction" },
|
||||
{ opcode::OP_NativeLocalFunctionCall, "OP_NativeLocalFunctionCall" },
|
||||
{ opcode::OP_NativeLocalFunctionCall2, "OP_NativeLocalFunctionCall2" },
|
||||
{ opcode::OP_NativeLocalMethodCall, "OP_NativeLocalMethodCall" },
|
||||
{ opcode::OP_NativeLocalFunctionThreadCall, "OP_NativeLocalFunctionThreadCall" },
|
||||
{ opcode::OP_NativeLocalMethodThreadCall, "OP_NativeLocalMethodThreadCall" },
|
||||
{ opcode::OP_NativeLocalFunctionChildThreadCall, "OP_NativeLocalFunctionChildThreadCall" },
|
||||
{ opcode::OP_NativeLocalMethodChildThreadCall, "OP_NativeLocalMethodChildThreadCall" },
|
||||
{ opcode::OP_NativeGetFarFunction, "OP_NativeGetFarFunction" },
|
||||
{ opcode::OP_NativeFarFunctionCall, "OP_NativeFarFunctionCall" },
|
||||
{ opcode::OP_NativeFarFunctionCall2, "OP_NativeFarFunctionCall2" },
|
||||
{ opcode::OP_NativeFarMethodCall, "OP_NativeFarMethodCall" },
|
||||
{ opcode::OP_NativeFarFunctionThreadCall, "OP_NativeFarFunctionThreadCall" },
|
||||
{ opcode::OP_NativeFarMethodThreadCall, "OP_NativeFarMethodThreadCall" },
|
||||
{ opcode::OP_NativeFarFunctionChildThreadCall, "OP_NativeFarFunctionChildThreadCall" },
|
||||
{ opcode::OP_NativeFarMethodChildThreadCall, "OP_NativeFarMethodChildThreadCall" },
|
||||
{ opcode::OP_EvalNewLocalArrayRefCached0_Precompiled, "OP_EvalNewLocalArrayRefCached0_Precompiled" },
|
||||
{ opcode::OP_SetNewLocalVariableFieldCached0_Precompiled, "OP_SetNewLocalVariableFieldCached0_Precompiled" },
|
||||
{ opcode::OP_CreateLocalVariable_Precompiled, "OP_CreateLocalVariable_Precompiled" },
|
||||
{ opcode::OP_SafeCreateVariableFieldCached_Precompiled, "OP_SafeCreateVariableFieldCached_Precompiled" },
|
||||
{ opcode::OP_FormalParams_Precompiled, "OP_FormalParams_Precompiled" },
|
||||
{ opcode::OP_GetStatHash, "OP_GetStatHash" },
|
||||
{ opcode::OP_GetUnkxHash, "OP_GetUnkxHash" },
|
||||
{ opcode::OP_GetEnumHash, "OP_GetEnumHash" },
|
||||
{ opcode::OP_GetDvarHash, "OP_GetDvarHash" },
|
||||
{ opcode::OP_GetUnsignedInt, "OP_GetUnsignedInt" },
|
||||
{ opcode::OP_GetNegUnsignedInt, "OP_GetNegUnsignedInt" },
|
||||
{ opcode::OP_GetInteger64, "OP_GetInteger64" },
|
||||
{ opcode::OP_iw9_139, "OP_iw9_139" },
|
||||
{ opcode::OP_iw9_140, "OP_iw9_140" },
|
||||
{ opcode::OP_iw9_141, "OP_iw9_141" },
|
||||
{ opcode::OP_iw9_142, "OP_iw9_142" },
|
||||
{ opcode::OP_iw9_143, "OP_iw9_143" },
|
||||
{ opcode::OP_iw9_144, "OP_iw9_144" },
|
||||
{ opcode::OP_iw9_166, "OP_iw9_166" },
|
||||
}};
|
||||
|
||||
} // namespace xsk::gsc
|
||||
|
@ -18,6 +18,8 @@ namespace xsk::gsc
|
||||
class context
|
||||
{
|
||||
public:
|
||||
using fs_callback = std::function<std::pair<buffer, std::vector<u8>>(std::string const&)>;
|
||||
|
||||
context(props props, engine engine, endian endian, system system, u32 str_count);
|
||||
|
||||
auto props() const -> props { return props_; }
|
||||
@ -45,14 +47,20 @@ public:
|
||||
auto func_map() const -> std::unordered_map<std::string_view, u16> const& { return func_map_rev_; }
|
||||
auto meth_map() const -> std::unordered_map<std::string_view, u16> const& { return meth_map_rev_; }
|
||||
|
||||
auto init(gsc::build build, read_cb_type callback) -> void;
|
||||
auto init(gsc::build build, fs_callback callback) -> void;
|
||||
|
||||
auto cleanup() -> void;
|
||||
|
||||
auto engine_name() const -> std::string_view;
|
||||
|
||||
auto opcode_size(opcode op) const -> u32;
|
||||
|
||||
auto opcode_id(opcode op) const -> u8;
|
||||
|
||||
auto opcode_name(opcode op) const -> std::string;
|
||||
|
||||
auto opcode_enum(std::string const& name) const -> opcode;
|
||||
|
||||
auto opcode_enum(u8 id) const -> opcode;
|
||||
|
||||
auto func_id(std::string const& name) const -> u16;
|
||||
@ -85,9 +93,7 @@ public:
|
||||
|
||||
auto make_token(std::string_view str) const -> std::string;
|
||||
|
||||
auto header_file_data(std::string const& name) const -> std::tuple<std::string const*, char const*, usize>;
|
||||
|
||||
auto fs_to_game_path(std::filesystem::path const& file) const -> std::filesystem::path;
|
||||
auto load_header(std::string const& name) -> std::tuple<std::string const*, char const*, usize>;
|
||||
|
||||
auto load_include(std::string const& name) -> bool;
|
||||
|
||||
@ -107,6 +113,9 @@ protected:
|
||||
gsc::disassembler disassembler_;
|
||||
gsc::compiler compiler_;
|
||||
gsc::decompiler decompiler_;
|
||||
fs_callback fs_callback_;
|
||||
std::unordered_map<opcode, std::string_view> opcode_map_;
|
||||
std::unordered_map<std::string_view, opcode> opcode_map_rev_;
|
||||
std::unordered_map<u8, opcode> code_map_;
|
||||
std::unordered_map<opcode, u8> code_map_rev_;
|
||||
std::unordered_map<u16, std::string_view> func_map_;
|
||||
@ -117,6 +126,11 @@ protected:
|
||||
std::unordered_map<std::string_view, u32> token_map_rev_;
|
||||
std::unordered_map<u64, std::string_view> path_map_;
|
||||
std::unordered_map<u64, std::string_view> hash_map_;
|
||||
std::unordered_map<std::string, buffer> header_files_;
|
||||
std::unordered_set<std::string_view> includes_;
|
||||
std::unordered_map<std::string, std::vector<std::string>> include_cache_;
|
||||
std::unordered_set<std::string> new_func_map_;
|
||||
std::unordered_set<std::string> new_meth_map_;
|
||||
};
|
||||
|
||||
} // namespace xsk::gsc
|
||||
|
@ -1505,7 +1505,7 @@ auto decompiler::decompile_instruction(instruction const& inst) -> void
|
||||
case opcode::OP_CastBool:
|
||||
break;
|
||||
default:
|
||||
throw decomp_error(fmt::format("unhandled opcode {}", opcode_name(inst.opcode)));
|
||||
throw decomp_error(fmt::format("unhandled opcode {}", ctx_->opcode_name(inst.opcode)));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -313,7 +313,7 @@ auto disassembler::dissasemble_instruction(instruction& inst) -> void
|
||||
disassemble_formal_params(inst);
|
||||
break;
|
||||
default:
|
||||
throw disasm_error(fmt::format("unhandled opcode {} at index {:04X}", opcode_name(inst.opcode), inst.index));
|
||||
throw disasm_error(fmt::format("unhandled opcode {} at index {:04X}", ctx_->opcode_name(inst.opcode), inst.index));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,267 +0,0 @@
|
||||
// Copyright 2023 xensik. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a GNU GPLv3 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
#include "stdinc.hpp"
|
||||
#include "assembly.hpp"
|
||||
|
||||
namespace xsk::gsc
|
||||
{
|
||||
|
||||
std::array<std::pair<opcode, std::string_view>, opcode_count> const opcode_list
|
||||
{{
|
||||
{ opcode::vm_invalid, "vm_invalid" },
|
||||
{ opcode::OP_CastFieldObject, "OP_CastFieldObject" },
|
||||
{ opcode::OP_SetLocalVariableFieldCached, "OP_SetLocalVariableFieldCached" },
|
||||
{ opcode::OP_plus, "OP_plus" },
|
||||
{ opcode::OP_RemoveLocalVariables, "OP_RemoveLocalVariables" },
|
||||
{ opcode::OP_EvalSelfFieldVariableRef, "OP_EvalSelfFieldVariableRef" },
|
||||
{ opcode::OP_ScriptFarMethodChildThreadCall, "OP_ScriptFarMethodChildThreadCall" },
|
||||
{ opcode::OP_GetGameRef, "OP_GetGameRef" },
|
||||
{ opcode::OP_EvalAnimFieldVariable, "OP_EvalAnimFieldVariable" },
|
||||
{ opcode::OP_EvalLevelFieldVariableRef, "OP_EvalLevelFieldVariableRef" },
|
||||
{ opcode::OP_GetThisthread, "OP_GetThisthread" },
|
||||
{ opcode::OP_greater, "OP_greater" },
|
||||
{ opcode::OP_waittillmatch, "OP_waittillmatch" },
|
||||
{ opcode::OP_shift_right, "OP_shift_right" },
|
||||
{ opcode::OP_dec, "OP_dec" },
|
||||
{ opcode::OP_JumpOnTrue, "OP_JumpOnTrue" },
|
||||
{ opcode::OP_bit_or, "OP_bit_or" },
|
||||
{ opcode::OP_equality, "OP_equality" },
|
||||
{ opcode::OP_ClearLocalVariableFieldCached0, "OP_ClearLocalVariableFieldCached0" },
|
||||
{ opcode::OP_notify, "OP_notify" },
|
||||
{ opcode::OP_GetVector, "OP_GetVector" },
|
||||
{ opcode::OP_ScriptMethodChildThreadCallPointer, "OP_ScriptMethodChildThreadCallPointer" },
|
||||
{ opcode::OP_PreScriptCall, "OP_PreScriptCall" },
|
||||
{ opcode::OP_GetByte, "OP_GetByte" },
|
||||
{ opcode::OP_ScriptFarThreadCall, "OP_ScriptFarThreadCall" },
|
||||
{ opcode::OP_SetSelfFieldVariableField, "OP_SetSelfFieldVariableField" },
|
||||
{ opcode::OP_JumpOnFalseExpr, "OP_JumpOnFalseExpr" },
|
||||
{ opcode::OP_GetUndefined, "OP_GetUndefined" },
|
||||
{ opcode::OP_jumpback, "OP_jumpback" },
|
||||
{ opcode::OP_JumpOnTrueExpr, "OP_JumpOnTrueExpr" },
|
||||
{ opcode::OP_CallBuiltin0, "OP_CallBuiltin0" },
|
||||
{ opcode::OP_CallBuiltin1, "OP_CallBuiltin1" },
|
||||
{ opcode::OP_CallBuiltin2, "OP_CallBuiltin2" },
|
||||
{ opcode::OP_CallBuiltin3, "OP_CallBuiltin3" },
|
||||
{ opcode::OP_CallBuiltin4, "OP_CallBuiltin4" },
|
||||
{ opcode::OP_CallBuiltin5, "OP_CallBuiltin5" },
|
||||
{ opcode::OP_CallBuiltin, "OP_CallBuiltin" },
|
||||
{ opcode::OP_SetLocalVariableFieldCached0, "OP_SetLocalVariableFieldCached0" },
|
||||
{ opcode::OP_ClearFieldVariable, "OP_ClearFieldVariable" },
|
||||
{ opcode::OP_GetLevel, "OP_GetLevel" },
|
||||
{ opcode::OP_size, "OP_size" },
|
||||
{ opcode::OP_SafeSetWaittillVariableFieldCached, "OP_SafeSetWaittillVariableFieldCached" },
|
||||
{ opcode::OP_ScriptLocalMethodThreadCall, "OP_ScriptLocalMethodThreadCall" },
|
||||
{ opcode::OP_AddArray, "OP_AddArray" },
|
||||
{ opcode::OP_endon, "OP_endon" },
|
||||
{ opcode::OP_EvalFieldVariable, "OP_EvalFieldVariable" },
|
||||
{ opcode::OP_shift_left, "OP_shift_left" },
|
||||
{ opcode::OP_EvalLocalArrayRefCached0, "OP_EvalLocalArrayRefCached0" },
|
||||
{ opcode::OP_Return, "OP_Return" },
|
||||
{ opcode::OP_CreateLocalVariable, "OP_CreateLocalVariable" },
|
||||
{ opcode::OP_SafeSetVariableFieldCached0, "OP_SafeSetVariableFieldCached0" },
|
||||
{ opcode::OP_GetBuiltinFunction, "OP_GetBuiltinFunction" },
|
||||
{ opcode::OP_ScriptLocalMethodCall, "OP_ScriptLocalMethodCall" },
|
||||
{ opcode::OP_CallBuiltinMethodPointer, "OP_CallBuiltinMethodPointer" },
|
||||
{ opcode::OP_ScriptLocalChildThreadCall, "OP_ScriptLocalChildThreadCall" },
|
||||
{ opcode::OP_GetSelfObject, "OP_GetSelfObject" },
|
||||
{ opcode::OP_GetGame, "OP_GetGame" },
|
||||
{ opcode::OP_SetLevelFieldVariableField, "OP_SetLevelFieldVariableField" },
|
||||
{ opcode::OP_EvalArray, "OP_EvalArray" },
|
||||
{ opcode::OP_GetSelf, "OP_GetSelf" },
|
||||
{ opcode::OP_End, "OP_End" },
|
||||
{ opcode::OP_EvalSelfFieldVariable, "OP_EvalSelfFieldVariable" },
|
||||
{ opcode::OP_less_equal, "OP_less_equal" },
|
||||
{ opcode::OP_EvalLocalVariableCached0, "OP_EvalLocalVariableCached0" },
|
||||
{ opcode::OP_EvalLocalVariableCached1, "OP_EvalLocalVariableCached1" },
|
||||
{ opcode::OP_EvalLocalVariableCached2, "OP_EvalLocalVariableCached2" },
|
||||
{ opcode::OP_EvalLocalVariableCached3, "OP_EvalLocalVariableCached3" },
|
||||
{ opcode::OP_EvalLocalVariableCached4, "OP_EvalLocalVariableCached4" },
|
||||
{ opcode::OP_EvalLocalVariableCached5, "OP_EvalLocalVariableCached5" },
|
||||
{ opcode::OP_EvalLocalVariableCached, "OP_EvalLocalVariableCached" },
|
||||
{ opcode::OP_EvalNewLocalArrayRefCached0, "OP_EvalNewLocalArrayRefCached0" },
|
||||
{ opcode::OP_ScriptChildThreadCallPointer, "OP_ScriptChildThreadCallPointer" },
|
||||
{ opcode::OP_EvalLocalVariableObjectCached, "OP_EvalLocalVariableObjectCached" },
|
||||
{ opcode::OP_ScriptLocalThreadCall, "OP_ScriptLocalThreadCall" },
|
||||
{ opcode::OP_GetInteger, "OP_GetInteger" },
|
||||
{ opcode::OP_ScriptMethodCallPointer, "OP_ScriptMethodCallPointer" },
|
||||
{ opcode::OP_checkclearparams, "OP_checkclearparams" },
|
||||
{ opcode::OP_SetAnimFieldVariableField, "OP_SetAnimFieldVariableField" },
|
||||
{ opcode::OP_waittillmatch2, "OP_waittillmatch2" },
|
||||
{ opcode::OP_minus, "OP_minus" },
|
||||
{ opcode::OP_ScriptLocalFunctionCall2, "OP_ScriptLocalFunctionCall2" },
|
||||
{ opcode::OP_GetNegUnsignedShort, "OP_GetNegUnsignedShort" },
|
||||
{ opcode::OP_GetNegByte, "OP_GetNegByte" },
|
||||
{ opcode::OP_SafeCreateVariableFieldCached, "OP_SafeCreateVariableFieldCached" },
|
||||
{ opcode::OP_greater_equal, "OP_greater_equal" },
|
||||
{ opcode::OP_vector, "OP_vector" },
|
||||
{ opcode::OP_GetBuiltinMethod, "OP_GetBuiltinMethod" },
|
||||
{ opcode::OP_endswitch, "OP_endswitch" },
|
||||
{ opcode::OP_ClearArray, "OP_ClearArray" },
|
||||
{ opcode::OP_DecTop, "OP_DecTop" },
|
||||
{ opcode::OP_CastBool, "OP_CastBool" },
|
||||
{ opcode::OP_EvalArrayRef, "OP_EvalArrayRef" },
|
||||
{ opcode::OP_SetNewLocalVariableFieldCached0, "OP_SetNewLocalVariableFieldCached0" },
|
||||
{ opcode::OP_GetZero, "OP_GetZero" },
|
||||
{ opcode::OP_wait, "OP_wait" },
|
||||
{ opcode::OP_waittill, "OP_waittill" },
|
||||
{ opcode::OP_GetIString, "OP_GetIString" },
|
||||
{ opcode::OP_ScriptFarFunctionCall, "OP_ScriptFarFunctionCall" },
|
||||
{ opcode::OP_GetAnimObject, "OP_GetAnimObject" },
|
||||
{ opcode::OP_GetAnimTree, "OP_GetAnimTree" },
|
||||
{ opcode::OP_EvalLocalArrayCached, "OP_EvalLocalArrayCached" },
|
||||
{ opcode::OP_mod, "OP_mod" },
|
||||
{ opcode::OP_ScriptFarMethodThreadCall, "OP_ScriptFarMethodThreadCall" },
|
||||
{ opcode::OP_GetUnsignedShort, "OP_GetUnsignedShort" },
|
||||
{ opcode::OP_clearparams, "OP_clearparams" },
|
||||
{ opcode::OP_ScriptMethodThreadCallPointer, "OP_ScriptMethodThreadCallPointer" },
|
||||
{ opcode::OP_ScriptFunctionCallPointer, "OP_ScriptFunctionCallPointer" },
|
||||
{ opcode::OP_EmptyArray, "OP_EmptyArray" },
|
||||
{ opcode::OP_SafeSetVariableFieldCached, "OP_SafeSetVariableFieldCached" },
|
||||
{ opcode::OP_ClearVariableField, "OP_ClearVariableField" },
|
||||
{ opcode::OP_EvalFieldVariableRef, "OP_EvalFieldVariableRef" },
|
||||
{ opcode::OP_ScriptLocalMethodChildThreadCall, "OP_ScriptLocalMethodChildThreadCall" },
|
||||
{ opcode::OP_EvalNewLocalVariableRefCached0, "OP_EvalNewLocalVariableRefCached0" },
|
||||
{ opcode::OP_GetFloat, "OP_GetFloat" },
|
||||
{ opcode::OP_EvalLocalVariableRefCached, "OP_EvalLocalVariableRefCached" },
|
||||
{ opcode::OP_JumpOnFalse, "OP_JumpOnFalse" },
|
||||
{ opcode::OP_BoolComplement, "OP_BoolComplement" },
|
||||
{ opcode::OP_ScriptThreadCallPointer, "OP_ScriptThreadCallPointer" },
|
||||
{ opcode::OP_ScriptFarFunctionCall2, "OP_ScriptFarFunctionCall2" },
|
||||
{ opcode::OP_less, "OP_less" },
|
||||
{ opcode::OP_BoolNot, "OP_BoolNot" },
|
||||
{ opcode::OP_waittillFrameEnd, "OP_waittillFrameEnd" },
|
||||
{ opcode::OP_waitframe, "OP_waitframe" },
|
||||
{ opcode::OP_GetString, "OP_GetString" },
|
||||
{ opcode::OP_EvalLevelFieldVariable, "OP_EvalLevelFieldVariable" },
|
||||
{ opcode::OP_GetLevelObject, "OP_GetLevelObject" },
|
||||
{ opcode::OP_inc, "OP_inc" },
|
||||
{ opcode::OP_CallBuiltinMethod0, "OP_CallBuiltinMethod0" },
|
||||
{ opcode::OP_CallBuiltinMethod1, "OP_CallBuiltinMethod1" },
|
||||
{ opcode::OP_CallBuiltinMethod2, "OP_CallBuiltinMethod2" },
|
||||
{ opcode::OP_CallBuiltinMethod3, "OP_CallBuiltinMethod3" },
|
||||
{ opcode::OP_CallBuiltinMethod4, "OP_CallBuiltinMethod4" },
|
||||
{ opcode::OP_CallBuiltinMethod5, "OP_CallBuiltinMethod5" },
|
||||
{ opcode::OP_CallBuiltinMethod, "OP_CallBuiltinMethod" },
|
||||
{ opcode::OP_GetAnim, "OP_GetAnim" },
|
||||
{ opcode::OP_switch, "OP_switch" },
|
||||
{ opcode::OP_SetVariableField, "OP_SetVariableField" },
|
||||
{ opcode::OP_divide, "OP_divide" },
|
||||
{ opcode::OP_GetLocalFunction, "OP_GetLocalFunction" },
|
||||
{ opcode::OP_ScriptFarChildThreadCall, "OP_ScriptFarChildThreadCall" },
|
||||
{ opcode::OP_multiply, "OP_multiply" },
|
||||
{ opcode::OP_ClearLocalVariableFieldCached, "OP_ClearLocalVariableFieldCached" },
|
||||
{ opcode::OP_EvalAnimFieldVariableRef, "OP_EvalAnimFieldVariableRef" },
|
||||
{ opcode::OP_EvalLocalArrayRefCached, "OP_EvalLocalArrayRefCached" },
|
||||
{ opcode::OP_EvalLocalVariableRefCached0, "OP_EvalLocalVariableRefCached0" },
|
||||
{ opcode::OP_bit_and, "OP_bit_and" },
|
||||
{ opcode::OP_GetAnimation, "OP_GetAnimation" },
|
||||
{ opcode::OP_GetFarFunction, "OP_GetFarFunction" },
|
||||
{ opcode::OP_CallBuiltinPointer, "OP_CallBuiltinPointer" },
|
||||
{ opcode::OP_jump, "OP_jump" },
|
||||
{ opcode::OP_voidCodepos, "OP_voidCodepos" },
|
||||
{ opcode::OP_ScriptFarMethodCall, "OP_ScriptFarMethodCall" },
|
||||
{ opcode::OP_inequality, "OP_inequality" },
|
||||
{ opcode::OP_ScriptLocalFunctionCall, "OP_ScriptLocalFunctionCall" },
|
||||
{ opcode::OP_bit_ex_or, "OP_bit_ex_or" },
|
||||
{ opcode::OP_NOP, "OP_NOP" },
|
||||
{ opcode::OP_abort, "OP_abort" },
|
||||
{ opcode::OP_object, "OP_object" },
|
||||
{ opcode::OP_thread_object, "OP_thread_object" },
|
||||
{ opcode::OP_EvalLocalVariable, "OP_EvalLocalVariable" },
|
||||
{ opcode::OP_EvalLocalVariableRef, "OP_EvalLocalVariableRef" },
|
||||
{ opcode::OP_prof_begin, "OP_prof_begin" },
|
||||
{ opcode::OP_prof_end, "OP_prof_end" },
|
||||
{ opcode::OP_breakpoint, "OP_breakpoint" },
|
||||
{ opcode::OP_assignmentBreakpoint, "OP_assignmentBreakpoint" },
|
||||
{ opcode::OP_manualAndAssignmentBreakpoint, "OP_manualAndAssignmentBreakpoint" },
|
||||
{ opcode::OP_BoolNotAfterAnd, "OP_BoolNotAfterAnd" },
|
||||
{ opcode::OP_FormalParams, "OP_FormalParams" },
|
||||
{ opcode::OP_IsDefined, "OP_IsDefined" },
|
||||
{ opcode::OP_IsTrue, "OP_IsTrue" },
|
||||
{ opcode::OP_NativeGetLocalFunction, "OP_NativeGetLocalFunction" },
|
||||
{ opcode::OP_NativeLocalFunctionCall, "OP_NativeLocalFunctionCall" },
|
||||
{ opcode::OP_NativeLocalFunctionCall2, "OP_NativeLocalFunctionCall2" },
|
||||
{ opcode::OP_NativeLocalMethodCall, "OP_NativeLocalMethodCall" },
|
||||
{ opcode::OP_NativeLocalFunctionThreadCall, "OP_NativeLocalFunctionThreadCall" },
|
||||
{ opcode::OP_NativeLocalMethodThreadCall, "OP_NativeLocalMethodThreadCall" },
|
||||
{ opcode::OP_NativeLocalFunctionChildThreadCall, "OP_NativeLocalFunctionChildThreadCall" },
|
||||
{ opcode::OP_NativeLocalMethodChildThreadCall, "OP_NativeLocalMethodChildThreadCall" },
|
||||
{ opcode::OP_NativeGetFarFunction, "OP_NativeGetFarFunction" },
|
||||
{ opcode::OP_NativeFarFunctionCall, "OP_NativeFarFunctionCall" },
|
||||
{ opcode::OP_NativeFarFunctionCall2, "OP_NativeFarFunctionCall2" },
|
||||
{ opcode::OP_NativeFarMethodCall, "OP_NativeFarMethodCall" },
|
||||
{ opcode::OP_NativeFarFunctionThreadCall, "OP_NativeFarFunctionThreadCall" },
|
||||
{ opcode::OP_NativeFarMethodThreadCall, "OP_NativeFarMethodThreadCall" },
|
||||
{ opcode::OP_NativeFarFunctionChildThreadCall, "OP_NativeFarFunctionChildThreadCall" },
|
||||
{ opcode::OP_NativeFarMethodChildThreadCall, "OP_NativeFarMethodChildThreadCall" },
|
||||
{ opcode::OP_EvalNewLocalArrayRefCached0_Precompiled, "OP_EvalNewLocalArrayRefCached0_Precompiled" },
|
||||
{ opcode::OP_SetNewLocalVariableFieldCached0_Precompiled, "OP_SetNewLocalVariableFieldCached0_Precompiled" },
|
||||
{ opcode::OP_CreateLocalVariable_Precompiled, "OP_CreateLocalVariable_Precompiled" },
|
||||
{ opcode::OP_SafeCreateVariableFieldCached_Precompiled, "OP_SafeCreateVariableFieldCached_Precompiled" },
|
||||
{ opcode::OP_FormalParams_Precompiled, "OP_FormalParams_Precompiled" },
|
||||
{ opcode::OP_GetStatHash, "OP_GetStatHash" },
|
||||
{ opcode::OP_GetUnkxHash, "OP_GetUnkxHash" },
|
||||
{ opcode::OP_GetEnumHash, "OP_GetEnumHash" },
|
||||
{ opcode::OP_GetDvarHash, "OP_GetDvarHash" },
|
||||
{ opcode::OP_GetUnsignedInt, "OP_GetUnsignedInt" },
|
||||
{ opcode::OP_GetNegUnsignedInt, "OP_GetNegUnsignedInt" },
|
||||
{ opcode::OP_GetInteger64, "OP_GetInteger64" },
|
||||
{ opcode::OP_iw9_139, "OP_iw9_139" },
|
||||
{ opcode::OP_iw9_140, "OP_iw9_140" },
|
||||
{ opcode::OP_iw9_141, "OP_iw9_141" },
|
||||
{ opcode::OP_iw9_142, "OP_iw9_142" },
|
||||
{ opcode::OP_iw9_143, "OP_iw9_143" },
|
||||
{ opcode::OP_iw9_144, "OP_iw9_144" },
|
||||
{ opcode::OP_iw9_166, "OP_iw9_166" },
|
||||
}};
|
||||
|
||||
std::unordered_map<opcode, std::string_view> opcode_map;
|
||||
std::unordered_map<std::string_view, opcode> opcode_map_rev;
|
||||
|
||||
auto opcode_name(opcode op) -> std::string
|
||||
{
|
||||
auto const itr = opcode_map.find(op);
|
||||
|
||||
if (itr != opcode_map.end())
|
||||
{
|
||||
return std::string{ itr->second };
|
||||
}
|
||||
|
||||
throw std::runtime_error(fmt::format("couldn't resolve opcode string for enum '{}'", static_cast<std::underlying_type_t<opcode>>(op)));
|
||||
}
|
||||
|
||||
auto opcode_enum(std::string const& name) -> opcode
|
||||
{
|
||||
auto const itr = opcode_map_rev.find(name);
|
||||
|
||||
if (itr != opcode_map_rev.end())
|
||||
{
|
||||
return itr->second;
|
||||
}
|
||||
|
||||
throw std::runtime_error(fmt::format("couldn't resolve opcode enum for name '{}'", name));
|
||||
}
|
||||
|
||||
struct __init__
|
||||
{
|
||||
__init__()
|
||||
{
|
||||
static bool init = false;
|
||||
if (init) return;
|
||||
init = true;
|
||||
|
||||
opcode_map.reserve(opcode_list.size());
|
||||
opcode_map_rev.reserve(opcode_list.size());
|
||||
|
||||
for (auto const& entry : opcode_list)
|
||||
{
|
||||
opcode_map.insert({ entry.first, entry.second });
|
||||
opcode_map_rev.insert({ entry.second, entry.first });
|
||||
}
|
||||
}
|
||||
} _;
|
||||
|
||||
} // namespace xsk::gsc
|
@ -264,7 +264,4 @@ inline auto make_assembly() -> std::unique_ptr<assembly>
|
||||
return std::unique_ptr<assembly>(new assembly);
|
||||
}
|
||||
|
||||
auto opcode_name(opcode op) -> std::string;
|
||||
auto opcode_enum(std::string const& name) -> opcode;
|
||||
|
||||
} // namespace xsk::gsc
|
||||
|
20
src/gsc/misc/buffer.hpp
Normal file
20
src/gsc/misc/buffer.hpp
Normal file
@ -0,0 +1,20 @@
|
||||
// Copyright 2023 xensik. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a GNU GPLv3 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace xsk::gsc
|
||||
{
|
||||
|
||||
struct buffer
|
||||
{
|
||||
u8 const* data;
|
||||
usize const size;
|
||||
|
||||
buffer() : data{ nullptr }, size{ 0 } {}
|
||||
buffer(u8 const* data, usize size) : data{ data }, size{ size } {}
|
||||
};
|
||||
|
||||
} // namespace xsk::gsc
|
@ -1,31 +0,0 @@
|
||||
// Copyright 2023 xensik. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a GNU GPLv3 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
#include "stdinc.hpp"
|
||||
#include "types.hpp"
|
||||
|
||||
namespace xsk::gsc
|
||||
{
|
||||
|
||||
auto engine_name(engine engine) -> std::string_view
|
||||
{
|
||||
switch (engine)
|
||||
{
|
||||
case engine::iw5: return "IW5";
|
||||
case engine::iw6: return "IW6";
|
||||
case engine::iw7: return "IW7";
|
||||
case engine::iw8: return "IW8";
|
||||
case engine::iw9: return "IW9";
|
||||
case engine::s1: return "S1";
|
||||
case engine::s2: return "S2";
|
||||
case engine::s4: return "S4";
|
||||
case engine::h1: return "H1";
|
||||
case engine::h2: return "H2";
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
} // namespace xsk::gsc
|
@ -7,6 +7,7 @@
|
||||
|
||||
#include "asset.hpp"
|
||||
#include "scope.hpp"
|
||||
#include "buffer.hpp"
|
||||
#include "assembly.hpp"
|
||||
#include "location.hpp"
|
||||
#include "exception.hpp"
|
||||
@ -98,19 +99,6 @@ enum class switch_type
|
||||
string,
|
||||
};
|
||||
|
||||
struct buffer
|
||||
{
|
||||
u8 const* data;
|
||||
usize const size;
|
||||
|
||||
buffer() : data{ nullptr }, size{ 0 } {}
|
||||
buffer(u8 const* data, usize size) : data{ data }, size{ size } {}
|
||||
};
|
||||
|
||||
using read_cb_type = std::function<std::pair<buffer, buffer>(std::string const&)>;
|
||||
|
||||
auto engine_name(engine engine) -> std::string_view;
|
||||
|
||||
// fordward decl for modules ref
|
||||
class context;
|
||||
|
||||
|
@ -11,7 +11,7 @@
|
||||
namespace xsk::gsc
|
||||
{
|
||||
|
||||
preprocessor::preprocessor(context const* ctx, std::string const& name, char const* data, usize size) : ctx_{ ctx }, curr_expr_{ 0 }, expand_{ 0 }, skip_{ false }
|
||||
preprocessor::preprocessor(context* ctx, std::string const& name, char const* data, usize size) : ctx_{ ctx }, curr_expr_{ 0 }, expand_{ 0 }, skip_{ false }
|
||||
{
|
||||
lexer_.push(lexer{ ctx, name, data, size });
|
||||
defines_.reserve(4);
|
||||
@ -100,7 +100,7 @@ auto preprocessor::push_header(std::string const& file) -> void
|
||||
throw ppr_error(location{}, fmt::format("recursive header inclusion {} at {}", name, includes_.back()));
|
||||
}
|
||||
|
||||
auto data = ctx_->header_file_data(name);
|
||||
auto data = ctx_->load_header(name);
|
||||
|
||||
includes_.push_back(*std::get<0>(data));
|
||||
lexer_.push(lexer{ ctx_, *std::get<0>(data), std::get<1>(data), std::get<2>(data) });
|
||||
|
@ -13,7 +13,7 @@ namespace xsk::gsc
|
||||
|
||||
class preprocessor
|
||||
{
|
||||
context const* ctx_;
|
||||
context* ctx_;
|
||||
std::stack<lexer> lexer_;
|
||||
std::stack<directive> indents_;
|
||||
std::vector<std::string> includes_;
|
||||
@ -27,7 +27,7 @@ class preprocessor
|
||||
u32 skip_;
|
||||
|
||||
public:
|
||||
preprocessor(context const* ctx, std::string const& name, char const* data, usize size);
|
||||
preprocessor(context* ctx, std::string const& name, char const* data, usize size);
|
||||
auto process() -> token;
|
||||
auto push_header(std::string const& file) -> void;
|
||||
auto pop_header() -> void;
|
||||
|
@ -13,7 +13,7 @@
|
||||
namespace xsk::gsc
|
||||
{
|
||||
|
||||
source::source(context const* ctx) : ctx_{ ctx }, indent_{ 0 }
|
||||
source::source(context* ctx) : ctx_{ ctx }, indent_{ 0 }
|
||||
{
|
||||
}
|
||||
|
||||
@ -86,7 +86,7 @@ auto source::parse_assembly(u8 const* data, usize size) -> assembly::ptr
|
||||
{
|
||||
auto inst = make_instruction();
|
||||
inst->index = index;
|
||||
inst->opcode = opcode_enum(opdata[0]);
|
||||
inst->opcode = ctx_->opcode_enum(opdata[0]);
|
||||
inst->size = ctx_->opcode_size(inst->opcode);
|
||||
opdata.erase(opdata.begin());
|
||||
inst->data = std::move(opdata);
|
||||
@ -157,7 +157,7 @@ auto source::dump(assembly const& data) -> std::vector<u8>
|
||||
buf_ = std::vector<u8>{};
|
||||
buf_.reserve(0x10000);
|
||||
|
||||
fmt::format_to(std::back_inserter(buf_), "// {} GSC ASSEMBLY\n", engine_name(ctx_->engine()));
|
||||
fmt::format_to(std::back_inserter(buf_), "// {} GSC ASSEMBLY\n", ctx_->engine_name());
|
||||
fmt::format_to(std::back_inserter(buf_), "// Dumped by https://github.com/xensik/gsc-tool\n");
|
||||
|
||||
dump_assembly(data);
|
||||
@ -170,7 +170,7 @@ auto source::dump(program const& data) -> std::vector<u8>
|
||||
buf_ = std::vector<u8>{};
|
||||
buf_.reserve(0x10000);
|
||||
|
||||
fmt::format_to(std::back_inserter(buf_), "// {} GSC SOURCE\n", engine_name(ctx_->engine()));
|
||||
fmt::format_to(std::back_inserter(buf_), "// {} GSC SOURCE\n", ctx_->engine_name());
|
||||
fmt::format_to(std::back_inserter(buf_), "// Dumped by https://github.com/xensik/gsc-tool\n");
|
||||
|
||||
dump_program(data);
|
||||
@ -207,7 +207,7 @@ auto source::dump_function(function const& func) -> void
|
||||
|
||||
auto source::dump_instruction(instruction const& inst) -> void
|
||||
{
|
||||
fmt::format_to(std::back_inserter(buf_), "\t\t{}", opcode_name(inst.opcode));
|
||||
fmt::format_to(std::back_inserter(buf_), "\t\t{}", ctx_->opcode_name(inst.opcode));
|
||||
|
||||
switch (inst.opcode)
|
||||
{
|
||||
|
@ -12,12 +12,12 @@ namespace xsk::gsc
|
||||
|
||||
class source
|
||||
{
|
||||
context const* ctx_;
|
||||
context* ctx_;
|
||||
std::vector<u8> buf_;
|
||||
u32 indent_;
|
||||
|
||||
public:
|
||||
source(context const* ctx);
|
||||
source(context* ctx);
|
||||
auto parse_assembly(buffer const& data) -> assembly::ptr;
|
||||
auto parse_assembly(std::vector<u8> const& data) -> assembly::ptr;
|
||||
auto parse_assembly(u8 const* data, usize size) -> assembly::ptr;
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
|
||||
using namespace std::literals;
|
||||
|
@ -439,7 +439,7 @@ auto rename_file(game game, fs::path file, fs::path rel) -> void
|
||||
|
||||
std::unordered_map<std::string, std::vector<std::uint8_t>> files;
|
||||
|
||||
auto read_file_cb(std::string const& name) -> std::pair<buffer, buffer>
|
||||
auto fs_callback(std::string const& name) -> std::pair<buffer, std::vector<u8>>
|
||||
{
|
||||
auto data = utils::file::read(fs::path{ name });
|
||||
|
||||
@ -448,12 +448,11 @@ auto read_file_cb(std::string const& name) -> std::pair<buffer, buffer>
|
||||
asset s;
|
||||
s.deserialize(data);
|
||||
auto stk = utils::zlib::decompress(s.buffer, s.len);
|
||||
auto res1 = files.insert({ name + "1", std::move(s.bytecode) });
|
||||
auto res2 = files.insert({ name + "2", std::move(stk) });
|
||||
auto res = files.insert({ name, std::move(s.bytecode) });
|
||||
|
||||
if(res1.second && res2.second)
|
||||
if (res.second)
|
||||
{
|
||||
return { {res1.first->second.data(), res1.first->second.size() }, {res2.first->second.data(), res2.first->second.size() } };
|
||||
return { {res.first->second.data(), res.first->second.size() }, std::move(stk) };
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -474,7 +473,7 @@ auto init_iw5() -> void
|
||||
if (!contexts.contains(game::iw5))
|
||||
{
|
||||
contexts[game::iw5] = std::make_unique<iw5_pc::context>();
|
||||
contexts[game::iw5]->init(build::prod, read_file_cb);
|
||||
contexts[game::iw5]->init(build::prod, fs_callback);
|
||||
}
|
||||
}
|
||||
|
||||
@ -483,7 +482,7 @@ auto init_iw5_ps() -> void
|
||||
if (!contexts.contains(game::iw5ps))
|
||||
{
|
||||
contexts[game::iw5ps] = std::make_unique<iw5_ps::context>();
|
||||
contexts[game::iw5ps]->init(build::prod, read_file_cb);
|
||||
contexts[game::iw5ps]->init(build::prod, fs_callback);
|
||||
}
|
||||
}
|
||||
|
||||
@ -492,7 +491,7 @@ auto init_iw5_xb() -> void
|
||||
if (!contexts.contains(game::iw5xb))
|
||||
{
|
||||
contexts[game::iw5xb] = std::make_unique<iw5_xb::context>();
|
||||
contexts[game::iw5xb]->init(build::prod, read_file_cb);
|
||||
contexts[game::iw5xb]->init(build::prod, fs_callback);
|
||||
}
|
||||
}
|
||||
|
||||
@ -501,7 +500,7 @@ auto init_iw6() -> void
|
||||
if (!contexts.contains(game::iw6))
|
||||
{
|
||||
contexts[game::iw6] = std::make_unique<iw6_pc::context>();
|
||||
contexts[game::iw6]->init(build::prod, read_file_cb);
|
||||
contexts[game::iw6]->init(build::prod, fs_callback);
|
||||
}
|
||||
}
|
||||
|
||||
@ -510,7 +509,7 @@ auto init_iw6_ps() -> void
|
||||
if (!contexts.contains(game::iw6ps))
|
||||
{
|
||||
contexts[game::iw6ps] = std::make_unique<iw6_ps::context>();
|
||||
contexts[game::iw6ps]->init(build::prod, read_file_cb);
|
||||
contexts[game::iw6ps]->init(build::prod, fs_callback);
|
||||
}
|
||||
}
|
||||
|
||||
@ -519,7 +518,7 @@ auto init_iw6_xb() -> void
|
||||
if (!contexts.contains(game::iw6xb))
|
||||
{
|
||||
contexts[game::iw6xb] = std::make_unique<iw6_xb::context>();
|
||||
contexts[game::iw6xb]->init(build::prod, read_file_cb);
|
||||
contexts[game::iw6xb]->init(build::prod, fs_callback);
|
||||
}
|
||||
}
|
||||
|
||||
@ -528,7 +527,7 @@ auto init_iw7() -> void
|
||||
if (!contexts.contains(game::iw7))
|
||||
{
|
||||
contexts[game::iw7] = std::make_unique<iw7::context>();
|
||||
contexts[game::iw7]->init(build::prod, read_file_cb);
|
||||
contexts[game::iw7]->init(build::prod, fs_callback);
|
||||
}
|
||||
}
|
||||
|
||||
@ -537,7 +536,7 @@ auto init_iw8() -> void
|
||||
if (!contexts.contains(game::iw8))
|
||||
{
|
||||
contexts[game::iw8] = std::make_unique<iw8::context>();
|
||||
contexts[game::iw8]->init(build::prod, read_file_cb);
|
||||
contexts[game::iw8]->init(build::prod, fs_callback);
|
||||
}
|
||||
}
|
||||
|
||||
@ -546,7 +545,7 @@ auto init_iw9() -> void
|
||||
if (!contexts.contains(game::iw9))
|
||||
{
|
||||
contexts[game::iw9] = std::make_unique<iw9::context>();
|
||||
contexts[game::iw9]->init(build::prod, read_file_cb);
|
||||
contexts[game::iw9]->init(build::prod, fs_callback);
|
||||
}
|
||||
}
|
||||
|
||||
@ -555,7 +554,7 @@ auto init_s1() -> void
|
||||
if (!contexts.contains(game::s1))
|
||||
{
|
||||
contexts[game::s1] = std::make_unique<s1_pc::context>();
|
||||
contexts[game::s1]->init(build::prod, read_file_cb);
|
||||
contexts[game::s1]->init(build::prod, fs_callback);
|
||||
}
|
||||
}
|
||||
|
||||
@ -564,7 +563,7 @@ auto init_s1_ps() -> void
|
||||
if (!contexts.contains(game::s1ps))
|
||||
{
|
||||
contexts[game::s1ps] = std::make_unique<s1_ps::context>();
|
||||
contexts[game::s1ps]->init(build::prod, read_file_cb);
|
||||
contexts[game::s1ps]->init(build::prod, fs_callback);
|
||||
}
|
||||
}
|
||||
|
||||
@ -573,7 +572,7 @@ auto init_s1_xb() -> void
|
||||
if (!contexts.contains(game::s1xb))
|
||||
{
|
||||
contexts[game::s1xb] = std::make_unique<s1_xb::context>();
|
||||
contexts[game::s1xb]->init(build::prod, read_file_cb);
|
||||
contexts[game::s1xb]->init(build::prod, fs_callback);
|
||||
}
|
||||
}
|
||||
|
||||
@ -582,7 +581,7 @@ auto init_s2() -> void
|
||||
if (!contexts.contains(game::s2))
|
||||
{
|
||||
contexts[game::s2] = std::make_unique<s2::context>();
|
||||
contexts[game::s2]->init(build::prod, read_file_cb);
|
||||
contexts[game::s2]->init(build::prod, fs_callback);
|
||||
}
|
||||
}
|
||||
|
||||
@ -591,7 +590,7 @@ auto init_s4() -> void
|
||||
if (!contexts.contains(game::s4))
|
||||
{
|
||||
contexts[game::s4] = std::make_unique<s4::context>();
|
||||
contexts[game::s4]->init(build::prod, read_file_cb);
|
||||
contexts[game::s4]->init(build::prod, fs_callback);
|
||||
}
|
||||
}
|
||||
|
||||
@ -600,7 +599,7 @@ auto init_h1() -> void
|
||||
if (!contexts.contains(game::h1))
|
||||
{
|
||||
contexts[game::h1] = std::make_unique<h1::context>();
|
||||
contexts[game::h1]->init(build::prod, read_file_cb);
|
||||
contexts[game::h1]->init(build::prod, fs_callback);
|
||||
}
|
||||
}
|
||||
|
||||
@ -609,7 +608,7 @@ auto init_h2() -> void
|
||||
if (!contexts.contains(game::h2))
|
||||
{
|
||||
contexts[game::h2] = std::make_unique<h2::context>();
|
||||
contexts[game::h2]->init(build::prod, read_file_cb);
|
||||
contexts[game::h2]->init(build::prod, fs_callback);
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user