diff --git a/src/iw9/xsk/context.cpp b/src/iw9/xsk/context.cpp index 6b837d4d..4240c773 100644 --- a/src/iw9/xsk/context.cpp +++ b/src/iw9/xsk/context.cpp @@ -9,9 +9,8 @@ namespace xsk::gsc::iw9 { -void context::init(build mode, read_cb_type callback) +void context::init(build, read_cb_type callback) { - compiler_.mode(mode); resolver::init(callback); } diff --git a/src/iw9/xsk/context.hpp b/src/iw9/xsk/context.hpp index 6dc76419..337c25fb 100644 --- a/src/iw9/xsk/context.hpp +++ b/src/iw9/xsk/context.hpp @@ -11,6 +11,7 @@ namespace xsk::gsc::iw9 class context : public gsc::context { iw9::disassembler disassembler_; + iw9::decompiler decompiler_; public: void init(build mode, read_cb_type callback); @@ -19,7 +20,7 @@ public: auto assembler() -> gsc::assembler& { throw std::runtime_error("not impl"); } auto disassembler() -> gsc::disassembler& { return disassembler_; } auto compiler() -> gsc::compiler& { throw std::runtime_error("not impl"); } - auto decompiler() -> gsc::decompiler& { throw std::runtime_error("not impl"); } + auto decompiler() -> gsc::decompiler& { return decompiler_; } }; } // namespace xsk::gsc::iw9 diff --git a/src/iw9/xsk/decompiler.cpp b/src/iw9/xsk/decompiler.cpp new file mode 100644 index 00000000..6fa9a2ab --- /dev/null +++ b/src/iw9/xsk/decompiler.cpp @@ -0,0 +1,3120 @@ +// Copyright 2022 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 "stdafx.hpp" +#include "iw9.hpp" + +namespace xsk::gsc::iw9 +{ + +auto decompiler::output() -> std::vector +{ + std::vector output; + + auto data = std::make_unique(0x100000); + data->write_string("// IW9 GSC SOURCE\n"); + data->write_string("// Decompiled by https://github.com/xensik/gsc-tool\n"); + data->write_string(program_->print()); + + output.resize(data->pos()); + std::memcpy(output.data(), data->buffer().data(), output.size()); + + return output; +} + +void decompiler::decompile(const std::string& file, std::vector& funcs) +{ + filename_ = file; + program_ = std::make_unique(); + + for (const auto& func : funcs) + { + auto name = std::make_unique(func->name); + auto params = std::make_unique(); + auto block = std::make_unique(); + func_ = std::make_unique(std::move(name), std::move(params), std::move(block)); + + stack_ = std::stack(); + labels_ = func->labels; + expr_labels_.clear(); + tern_labels_.clear(); + blocks_.clear(); + + decompile_function(func); + + process_stack(func_); + + program_->declarations.push_back(ast::decl(std::move(func_))); + } +} + +void decompiler::decompile_function(const function::ptr& func) +{ + in_waittill_ = false; + + for (const auto& inst : func->instructions) + { + decompile_instruction(inst); + } + + if (stack_.size() > 0) + { + throw decomp_error("stack isn't empty at function end"); + } + + const auto& stmt = func_->stmt; + + block blk; + blk.loc_end = utils::string::va("loc_%X", stmt->list.back().as_node->loc().begin.line); + + // remove last return + stmt->list.pop_back(); + + blocks_.push_back(blk); + + decompile_statements(stmt); + + blocks_.pop_back(); +} + +void decompiler::decompile_instruction(const instruction::ptr& inst) +{ + decompile_expressions(inst); + + auto loc = location(&filename_, inst->index); + + switch (static_cast(inst->opcode)) + { + case opcode::OP_End: + { + auto expr = ast::expr(std::make_unique()); + auto stmt = ast::stmt(std::make_unique(loc, std::move(expr))); + func_->stmt->list.push_back(std::move(stmt)); + break; + } + case opcode::OP_Return: + { + auto expr = ast::expr(std::move(stack_.top())); stack_.pop(); + auto stmt = ast::stmt(std::make_unique(expr.loc(), std::move(expr))); + func_->stmt->list.push_back(std::move(stmt)); + break; + } + case opcode::OP_GetZero: + { + auto node = std::make_unique(loc, "0"); + stack_.push(std::move(node)); + break; + } + case opcode::OP_GetByte: + case opcode::OP_GetUnsignedShort: + case opcode::OP_GetInteger: + { + auto node = std::make_unique(loc, inst->data[0]); + stack_.push(std::move(node)); + break; + } + case opcode::OP_GetNegByte: + case opcode::OP_GetNegUnsignedShort: + { + auto node = std::make_unique(loc, "-" + inst->data[0]); + stack_.push(std::move(node)); + break; + } + case opcode::OP_GetFloat: + { + auto node = std::make_unique(loc, inst->data[0]); + stack_.push(std::move(node)); + break; + } + case opcode::OP_GetVector: + { + auto x = ast::expr(std::make_unique(loc, inst->data[0])); + auto y = ast::expr(std::make_unique(loc, inst->data[1])); + auto z = ast::expr(std::make_unique(loc, inst->data[2])); + auto node = std::make_unique(loc, std::move(x), std::move(y), std::move(z)); + stack_.push(std::move(node)); + break; + } + case opcode::OP_GetString: + { + auto node = std::make_unique(loc, inst->data[0]); + stack_.push(std::move(node)); + break; + } + case opcode::OP_GetIString: + { + auto node = std::make_unique(loc, inst->data[0]); + stack_.push(std::move(node)); + break; + } + case opcode::OP_GetUndefined: + { + auto node = std::make_unique(loc); + stack_.push(std::move(node)); + break; + } + case opcode::OP_EmptyArray: + { + auto node = std::make_unique(loc); + stack_.push(std::move(node)); + break; + } + case opcode::OP_GetLevel: + case opcode::OP_GetLevelObject: + { + auto node = std::make_unique(loc); + stack_.push(std::move(node)); + break; + } + case opcode::OP_GetAnim: + case opcode::OP_GetAnimObject: + { + auto node = std::make_unique(loc); + stack_.push(std::move(node)); + break; + } + case opcode::OP_GetSelf: + case opcode::OP_GetSelfObject: + { + auto node = std::make_unique(loc); + stack_.push(std::move(node)); + break; + } + case opcode::OP_GetGame: + case opcode::OP_GetGameRef: + { + auto node = std::make_unique(loc); + stack_.push(std::move(node)); + break; + } + case opcode::OP_GetAnimation: + { + auto value = utils::string::unquote(inst->data[0]); + + if (value != "") + { + auto tree = std::make_unique(loc, inst->data[0]); + auto decl = std::make_unique(loc, std::move(tree)); + program_->declarations.push_back(ast::decl(std::move(decl))); + } + + auto node = std::make_unique(loc, utils::string::unquote(inst->data[1])); + stack_.push(std::move(node)); + break; + } + case opcode::OP_GetAnimTree: + { + auto value = utils::string::unquote(inst->data[0]); + + if (value != "") + { + auto tree = std::make_unique(loc, inst->data[0]); + auto decl = std::make_unique(loc, std::move(tree)); + program_->declarations.push_back(ast::decl(std::move(decl))); + } + + auto node = std::make_unique(loc); + stack_.push(std::move(node)); + break; + } + case opcode::OP_GetThisthread: + { + auto node = std::make_unique(loc); + stack_.push(std::move(node)); + break; + } + case opcode::OP_GetBuiltinFunction: + case opcode::OP_GetBuiltinMethod: + { + auto path = std::make_unique(loc); + auto name = std::make_unique(loc, inst->data[0]); + auto node = std::make_unique(loc, std::move(path), std::move(name)); + stack_.push(std::move(node)); + break; + } + case opcode::OP_GetFarFunction: + { + auto path = std::make_unique(loc, inst->data[0]); + auto name = std::make_unique(loc, inst->data[1]); + auto node = std::make_unique(loc, std::move(path), std::move(name)); + stack_.push(std::move(node)); + break; + } + case opcode::OP_CreateLocalVariable: + { + if (in_waittill_) + { + auto node = std::make_unique(loc, inst->data[0]); + stack_.push(std::move(node)); + } + else + { + auto stmt = ast::stmt(std::make_unique(loc, inst->data[0])); + func_->stmt->list.push_back(std::move(stmt)); + } + break; + } + case opcode::OP_RemoveLocalVariables: + { + auto stmt = ast::stmt(std::make_unique(loc, inst->data[0])); + func_->stmt->list.push_back(std::move(stmt)); + break; + } + case opcode::OP_EvalLocalVariableCached0: + { + auto node = std::make_unique(loc, "0"); + stack_.push(std::move(node)); + break; + } + case opcode::OP_EvalLocalVariableCached1: + { + auto node = std::make_unique(loc, "1"); + stack_.push(std::move(node)); + break; + } + case opcode::OP_EvalLocalVariableCached2: + { + auto node = std::make_unique(loc, "2"); + stack_.push(std::move(node)); + break; + } + case opcode::OP_EvalLocalVariableCached3: + { + auto node = std::make_unique(loc, "3"); + stack_.push(std::move(node)); + break; + } + case opcode::OP_EvalLocalVariableCached4: + { + auto node = std::make_unique(loc, "4"); + stack_.push(std::move(node)); + break; + } + case opcode::OP_EvalLocalVariableCached5: + { + auto node = std::make_unique(loc, "5"); + stack_.push(std::move(node)); + break; + } + case opcode::OP_EvalLocalVariableCached: + { + auto node = std::make_unique(loc, inst->data[0]); + stack_.push(std::move(node)); + break; + } + case opcode::OP_EvalLocalArrayCached: + { + auto key = ast::expr(std::move(stack_.top())); stack_.pop(); + auto obj = ast::expr(std::make_unique(loc, inst->data[0])); + auto node = std::make_unique(key.loc(), std::move(obj), std::move(key)); + stack_.push(std::move(node)); + break; + } + case opcode::OP_EvalArray: + { + auto obj = ast::expr(std::move(stack_.top())); stack_.pop(); + auto key = ast::expr(std::move(stack_.top())); stack_.pop(); + auto node = std::make_unique(key.loc(), std::move(obj), std::move(key)); + stack_.push(std::move(node)); + break; + } + case opcode::OP_EvalNewLocalArrayRefCached0: + { + auto key = ast::expr(std::move(stack_.top())); stack_.pop(); + auto obj = ast::expr(std::make_unique(loc, inst->data[0])); + auto node = std::make_unique(key.loc(), std::move(obj), std::move(key)); + stack_.push(std::move(node)); + break; + } + case opcode::OP_EvalLocalArrayRefCached0: + { + auto key = ast::expr(std::move(stack_.top())); stack_.pop(); + auto obj = ast::expr(std::make_unique(loc, "0")); + auto node = std::make_unique(key.loc(), std::move(obj), std::move(key)); + stack_.push(std::move(node)); + break; + } + case opcode::OP_EvalLocalArrayRefCached: + { + auto key = ast::expr(std::move(stack_.top())); stack_.pop(); + auto obj = ast::expr(std::make_unique(loc, inst->data[0])); + auto node = std::make_unique(key.loc(), std::move(obj), std::move(key)); + stack_.push(std::move(node)); + break; + } + case opcode::OP_EvalArrayRef: + { + auto obj = ast::expr(std::move(stack_.top())); stack_.pop(); + auto key = ast::expr(std::move(stack_.top())); stack_.pop(); + auto node = std::make_unique(key.loc(), std::move(obj), std::move(key)); + stack_.push(std::move(node)); + break; + } + case opcode::OP_ClearArray: + { + auto obj = ast::expr(std::move(stack_.top())); stack_.pop(); + auto key = ast::expr(std::move(stack_.top())); stack_.pop(); + loc = key.loc(); + auto lvalue = ast::expr(std::make_unique(loc, std::move(obj), std::move(key))); + auto rvalue = ast::expr(std::make_unique(loc)); + auto expr = ast::expr(std::make_unique(loc, std::move(lvalue), std::move(rvalue))); + auto stmt = ast::stmt(std::make_unique(loc, std::move(expr))); + func_->stmt->list.push_back(std::move(stmt)); + break; + } + case opcode::OP_AddArray: + { + auto value = ast::expr(std::move(stack_.top())); stack_.pop(); + auto array = std::move(stack_.top()); stack_.pop(); + + if (array->kind() == ast::kind::expr_empty_array) + { + auto args = std::make_unique(loc); + args->list.push_back(std::move(value)); + auto node = std::make_unique(array->loc(), std::move(args)); + stack_.push(std::move(node)); + } + else if (array->kind() == ast::kind::expr_add_array) + { + (*(ast::expr_add_array::ptr*)&array)->args->list.push_back(std::move(value)); + stack_.push(std::move(array)); + } + else + { + throw decomp_error("unknown add array type (could be an array variable name?)"); + } + break; + } + case opcode::OP_PreScriptCall: + { + auto node = std::make_unique(loc); + stack_.push(std::move(node)); + break; + } + case opcode::OP_ScriptFarFunctionCall: + { + auto args = std::make_unique(loc); + auto path = std::make_unique(loc, inst->data[0]); + auto name = std::make_unique(loc, inst->data[1]); + + auto var = std::move(stack_.top()); stack_.pop(); + loc = var->loc(); + + while (var->kind() != ast::kind::asm_prescriptcall) + { + args->list.push_back(std::move(var)); + var = std::move(stack_.top()); stack_.pop(); + loc = var->loc(); + } + + auto call = ast::call(std::make_unique(loc, std::move(path), std::move(name), std::move(args), ast::call::mode::normal)); + auto node = std::make_unique(loc, std::move(call)); + stack_.push(std::move(node)); + break; + } + case opcode::OP_ScriptFarMethodCall: + { + auto obj = ast::expr(std::move(stack_.top())); stack_.pop(); + loc = obj.as_node->loc(); + + auto args = std::make_unique(loc); + auto path = std::make_unique(loc, inst->data[0]); + auto name = std::make_unique(loc, inst->data[1]); + + auto var = std::move(stack_.top()); stack_.pop(); + loc = var->loc(); + + while (var->kind() != ast::kind::asm_prescriptcall) + { + args->list.push_back(std::move(var)); + var = std::move(stack_.top()); stack_.pop(); + loc = var->loc(); + } + + auto call = ast::call(std::make_unique(loc, std::move(path), std::move(name), std::move(args), ast::call::mode::normal)); + auto node = std::make_unique(loc, std::move(obj), std::move(call)); + stack_.push(std::move(node)); + break; + } + case opcode::OP_ScriptFarThreadCall: + { + auto args = std::make_unique(loc); + auto path = std::make_unique(loc, inst->data[0]); + auto name = std::make_unique(loc, inst->data[1]); + + for (auto i = std::stoul(inst->data[2]); i > 0; i--) + { + auto var = std::move(stack_.top()); stack_.pop(); + loc = var->loc(); + args->list.push_back(std::move(var)); + } + + auto call = ast::call(std::make_unique(loc, std::move(path), std::move(name), std::move(args), ast::call::mode::thread)); + auto node = std::make_unique(loc, std::move(call)); + stack_.push(std::move(node)); + break; + } + case opcode::OP_ScriptFarChildThreadCall: + { + auto args = std::make_unique(loc); + auto path = std::make_unique(loc, inst->data[0]); + auto name = std::make_unique(loc, inst->data[1]); + + for (auto i = std::stoul(inst->data[2]); i > 0; i--) + { + auto var = std::move(stack_.top()); stack_.pop(); + loc = var->loc(); + args->list.push_back(std::move(var)); + } + + auto call = ast::call(std::make_unique(loc, std::move(path), std::move(name), std::move(args), ast::call::mode::childthread)); + auto node = std::make_unique(loc, std::move(call)); + stack_.push(std::move(node)); + break; + } + case opcode::OP_ScriptFarMethodThreadCall: + { + auto obj = ast::expr(std::move(stack_.top())); stack_.pop(); + loc = obj.as_node->loc(); + + auto args = std::make_unique(loc); + auto path = std::make_unique(loc, inst->data[0]); + auto name = std::make_unique(loc, inst->data[1]); + + for (auto i = std::stoul(inst->data[2]); i > 0; i--) + { + auto var = std::move(stack_.top()); stack_.pop(); + loc = var->loc(); + args->list.push_back(std::move(var)); + } + + auto call = ast::call(std::make_unique(loc, std::move(path), std::move(name), std::move(args), ast::call::mode::thread)); + auto node = std::make_unique(loc, std::move(obj), std::move(call)); + stack_.push(std::move(node)); + break; + } + case opcode::OP_ScriptFarMethodChildThreadCall: + { + auto obj = ast::expr(std::move(stack_.top())); stack_.pop(); + loc = obj.as_node->loc(); + + auto args = std::make_unique(loc); + auto path = std::make_unique(loc, inst->data[0]); + auto name = std::make_unique(loc, inst->data[1]); + + for (auto i = std::stoul(inst->data[2]); i > 0; i--) + { + auto var = std::move(stack_.top()); stack_.pop(); + loc = var->loc(); + args->list.push_back(std::move(var)); + } + + auto call = ast::call(std::make_unique(loc, std::move(path), std::move(name), std::move(args), ast::call::mode::childthread)); + auto node = std::make_unique(loc, std::move(obj), std::move(call)); + stack_.push(std::move(node)); + break; + } + case opcode::OP_ScriptFunctionCallPointer: + { + auto args = std::make_unique(loc); + auto func = ast::expr(std::move(stack_.top())); stack_.pop(); + auto var = std::move(stack_.top()); stack_.pop(); + loc = var->loc(); + + while (var->kind() != ast::kind::asm_prescriptcall) + { + args->list.push_back(std::move(var)); + var = std::move(stack_.top()); stack_.pop(); + loc = var->loc(); + } + + auto call = ast::call(std::make_unique(loc, std::move(func), std::move(args), ast::call::mode::normal)); + auto node = std::make_unique(loc, std::move(call)); + stack_.push(std::move(node)); + break; + } + case opcode::OP_ScriptMethodCallPointer: + { + auto args = std::make_unique(loc); + auto func = ast::expr(std::move(stack_.top())); stack_.pop(); + auto obj = ast::expr(std::move(stack_.top())); stack_.pop(); + auto var = std::move(stack_.top()); stack_.pop(); + loc = var->loc(); + + while (var->kind() != ast::kind::asm_prescriptcall) + { + args->list.push_back(std::move(var)); + var = std::move(stack_.top()); stack_.pop(); + loc = var->loc(); + } + + auto call = ast::call(std::make_unique(loc, std::move(func), std::move(args), ast::call::mode::normal)); + auto node = std::make_unique(loc, std::move(obj), std::move(call)); + stack_.push(std::move(node)); + break; + } + case opcode::OP_ScriptThreadCallPointer: + { + auto args = std::make_unique(loc); + auto func = ast::expr(std::move(stack_.top())); stack_.pop(); + loc = func.as_node->loc(); + + for (auto i = std::stoul(inst->data[0]); i > 0; i--) + { + auto var = std::move(stack_.top()); stack_.pop(); + loc = var->loc(); + args->list.push_back(std::move(var)); + } + + auto call = ast::call(std::make_unique(loc, std::move(func), std::move(args), ast::call::mode::thread)); + auto node = std::make_unique(loc, std::move(call)); + stack_.push(std::move(node)); + break; + } + case opcode::OP_ScriptChildThreadCallPointer: + { + auto args = std::make_unique(loc); + auto func = ast::expr(std::move(stack_.top())); stack_.pop(); + loc = func.as_node->loc(); + + for (auto i = std::stoul(inst->data[0]); i > 0; i--) + { + auto var = std::move(stack_.top()); stack_.pop(); + loc = var->loc(); + args->list.push_back(std::move(var)); + } + + auto call = ast::call(std::make_unique(loc, std::move(func), std::move(args), ast::call::mode::childthread)); + auto node = std::make_unique(loc, std::move(call)); + stack_.push(std::move(node)); + break; + } + case opcode::OP_ScriptMethodThreadCallPointer: + { + auto args = std::make_unique(loc); + auto func = ast::expr(std::move(stack_.top())); stack_.pop(); + auto obj = ast::expr(std::move(stack_.top())); stack_.pop(); + loc = obj.as_node->loc(); + + for (auto i = std::stoul(inst->data[0]); i > 0; i--) + { + auto var = std::move(stack_.top()); stack_.pop(); + loc = var->loc(); + args->list.push_back(std::move(var)); + } + + auto call = ast::call(std::make_unique(loc, std::move(func), std::move(args), ast::call::mode::thread)); + auto node = std::make_unique(loc, std::move(obj), std::move(call)); + stack_.push(std::move(node)); + break; + } + case opcode::OP_ScriptMethodChildThreadCallPointer: + { + auto args = std::make_unique(loc); + auto func = ast::expr(std::move(stack_.top())); stack_.pop(); + auto obj = ast::expr(std::move(stack_.top())); stack_.pop(); + loc = obj.as_node->loc(); + + for (auto i = std::stoul(inst->data[0]); i > 0; i--) + { + auto var = std::move(stack_.top()); stack_.pop(); + loc = var->loc(); + args->list.push_back(std::move(var)); + } + + auto call = ast::call(std::make_unique(loc, std::move(func), std::move(args), ast::call::mode::childthread)); + auto node = std::make_unique(loc, std::move(obj), std::move(call)); + stack_.push(std::move(node)); + break; + } + case opcode::OP_CallBuiltinPointer: + { + auto args = std::make_unique(loc); + auto func = ast::expr(std::move(stack_.top())); stack_.pop(); + loc = func.as_node->loc(); + + for (auto i = std::stoul(inst->data[0]); i > 0; i--) + { + auto var = std::move(stack_.top()); stack_.pop(); + loc = var->loc(); + args->list.push_back(std::move(var)); + } + + auto call = ast::call(std::make_unique(loc, std::move(func), std::move(args), ast::call::mode::builtin)); + auto node = std::make_unique(loc, std::move(call)); + stack_.push(std::move(node)); + break; + } + case opcode::OP_CallBuiltinMethodPointer: + { + auto args = std::make_unique(loc); + auto func = ast::expr(std::move(stack_.top())); stack_.pop(); + auto obj = ast::expr(std::move(stack_.top())); stack_.pop(); + loc = obj.as_node->loc(); + + for (auto i = std::stoul(inst->data[0]); i > 0; i--) + { + auto var = std::move(stack_.top()); stack_.pop(); + loc = var->loc(); + args->list.push_back(std::move(var)); + } + + auto call = ast::call(std::make_unique(loc, std::move(func), std::move(args), ast::call::mode::builtin)); + auto node = std::make_unique(loc, std::move(obj), std::move(call)); + stack_.push(std::move(node)); + break; + } + case opcode::OP_CallBuiltin: + { + auto args = std::make_unique(loc); + auto path = std::make_unique(loc); + auto name = std::make_unique(loc, inst->data[0]); + + for (auto i = std::stoul(inst->data[1]); i > 0; i--) + { + auto var = std::move(stack_.top()); stack_.pop(); + loc = var->loc(); + args->list.push_back(std::move(var)); + } + + auto func = ast::call(std::make_unique(loc, std::move(path), std::move(name), std::move(args), ast::call::mode::builtin)); + auto node = std::make_unique(loc, std::move(func)); + stack_.push(std::move(node)); + break; + } + case opcode::OP_CallBuiltinMethod: + { + auto args = std::make_unique(loc); + auto path = std::make_unique(loc); + auto name = std::make_unique(loc, inst->data[0]); + auto obj = ast::expr(std::move(stack_.top())); stack_.pop(); + loc = obj.as_node->loc(); + + for (auto i = std::stoul(inst->data[1]); i > 0; i--) + { + auto var = std::move(stack_.top()); stack_.pop(); + loc = var->loc(); + args->list.push_back(std::move(var)); + } + + auto call = ast::call(std::make_unique(loc, std::move(path), std::move(name), std::move(args), ast::call::mode::builtin)); + auto node = std::make_unique(loc, std::move(obj), std::move(call)); + stack_.push(std::move(node)); + break; + } + case opcode::OP_DecTop: + { + auto expr = ast::expr(std::move(stack_.top())); stack_.pop(); + auto stmt = ast::stmt(std::make_unique(expr.loc(), std::move(expr))); + func_->stmt->list.push_back(std::move(stmt)); + break; + } + case opcode::OP_inc: + { + auto lvalue = ast::expr(std::move(stack_.top())); stack_.pop(); + loc = lvalue.as_node->loc(); + auto node = std::make_unique(loc, std::move(lvalue), false); + stack_.push(std::move(node)); + break; + } + case opcode::OP_dec: + { + auto lvalue = ast::expr(std::move(stack_.top())); stack_.pop(); + loc = lvalue.as_node->loc(); + auto node = std::make_unique(loc, std::move(lvalue), false); + stack_.push(std::move(node)); + break; + } + case opcode::OP_bit_or: + { + auto rvalue = ast::expr(std::move(stack_.top())); stack_.pop(); + auto lvalue = ast::expr(std::move(stack_.top())); stack_.pop(); + loc = lvalue.as_node->loc(); + auto node = std::make_unique(loc, std::move(lvalue), std::move(rvalue)); + stack_.push(std::move(node)); + break; + } + case opcode::OP_bit_ex_or: + { + auto rvalue = ast::expr(std::move(stack_.top())); stack_.pop(); + auto lvalue = ast::expr(std::move(stack_.top())); stack_.pop(); + loc = lvalue.as_node->loc(); + auto node = std::make_unique(loc, std::move(lvalue), std::move(rvalue)); + stack_.push(std::move(node)); + break; + } + case opcode::OP_bit_and: + { + auto rvalue = ast::expr(std::move(stack_.top())); stack_.pop(); + auto lvalue = ast::expr(std::move(stack_.top())); stack_.pop(); + loc = lvalue.as_node->loc(); + auto node = std::make_unique(loc, std::move(lvalue), std::move(rvalue)); + stack_.push(std::move(node)); + break; + } + case opcode::OP_equality: + { + auto rvalue = ast::expr(std::move(stack_.top())); stack_.pop(); + auto lvalue = ast::expr(std::move(stack_.top())); stack_.pop(); + loc = lvalue.as_node->loc(); + auto node = std::make_unique(loc, std::move(lvalue), std::move(rvalue)); + stack_.push(std::move(node)); + break; + } + case opcode::OP_inequality: + { + auto rvalue = ast::expr(std::move(stack_.top())); stack_.pop(); + auto lvalue = ast::expr(std::move(stack_.top())); stack_.pop(); + loc = lvalue.as_node->loc(); + auto node = std::make_unique(loc, std::move(lvalue), std::move(rvalue)); + stack_.push(std::move(node)); + break; + } + case opcode::OP_less: + { + auto rvalue = ast::expr(std::move(stack_.top())); stack_.pop(); + auto lvalue = ast::expr(std::move(stack_.top())); stack_.pop(); + loc = lvalue.as_node->loc(); + auto node = std::make_unique(loc, std::move(lvalue), std::move(rvalue)); + stack_.push(std::move(node)); + break; + } + case opcode::OP_greater: + { + auto rvalue = ast::expr(std::move(stack_.top())); stack_.pop(); + auto lvalue = ast::expr(std::move(stack_.top())); stack_.pop(); + loc = lvalue.as_node->loc(); + auto node = std::make_unique(loc, std::move(lvalue), std::move(rvalue)); + stack_.push(std::move(node)); + break; + } + case opcode::OP_less_equal: + { + auto rvalue = ast::expr(std::move(stack_.top())); stack_.pop(); + auto lvalue = ast::expr(std::move(stack_.top())); stack_.pop(); + loc = lvalue.as_node->loc(); + auto node = std::make_unique(loc, std::move(lvalue), std::move(rvalue)); + stack_.push(std::move(node)); + break; + } + case opcode::OP_greater_equal: + { + auto rvalue = ast::expr(std::move(stack_.top())); stack_.pop(); + auto lvalue = ast::expr(std::move(stack_.top())); stack_.pop(); + loc = lvalue.as_node->loc(); + auto node = std::make_unique(loc, std::move(lvalue), std::move(rvalue)); + stack_.push(std::move(node)); + break; + } + case opcode::OP_shift_left: + { + auto rvalue = ast::expr(std::move(stack_.top())); stack_.pop(); + auto lvalue = ast::expr(std::move(stack_.top())); stack_.pop(); + loc = lvalue.as_node->loc(); + auto node = std::make_unique(loc, std::move(lvalue), std::move(rvalue)); + stack_.push(std::move(node)); + break; + } + case opcode::OP_shift_right: + { + auto rvalue = ast::expr(std::move(stack_.top())); stack_.pop(); + auto lvalue = ast::expr(std::move(stack_.top())); stack_.pop(); + loc = lvalue.as_node->loc(); + auto node = std::make_unique(loc, std::move(lvalue), std::move(rvalue)); + stack_.push(std::move(node)); + break; + } + case opcode::OP_plus: + { + auto rvalue = ast::expr(std::move(stack_.top())); stack_.pop(); + auto lvalue = ast::expr(std::move(stack_.top())); stack_.pop(); + loc = lvalue.as_node->loc(); + auto node = std::make_unique(loc, std::move(lvalue), std::move(rvalue)); + stack_.push(std::move(node)); + break; + } + case opcode::OP_minus: + { + auto rvalue = ast::expr(std::move(stack_.top())); stack_.pop(); + auto lvalue = ast::expr(std::move(stack_.top())); stack_.pop(); + loc = lvalue.as_node->loc(); + auto node = std::make_unique(loc, std::move(lvalue), std::move(rvalue)); + stack_.push(std::move(node)); + break; + } + case opcode::OP_multiply: + { + auto rvalue = ast::expr(std::move(stack_.top())); stack_.pop(); + auto lvalue = ast::expr(std::move(stack_.top())); stack_.pop(); + loc = lvalue.as_node->loc(); + auto node = std::make_unique(loc, std::move(lvalue), std::move(rvalue)); + stack_.push(std::move(node)); + break; + } + case opcode::OP_divide: + { + auto rvalue = ast::expr(std::move(stack_.top())); stack_.pop(); + auto lvalue = ast::expr(std::move(stack_.top())); stack_.pop(); + loc = lvalue.as_node->loc(); + auto node = std::make_unique(loc, std::move(lvalue), std::move(rvalue)); + stack_.push(std::move(node)); + break; + } + case opcode::OP_mod: + { + auto rvalue = ast::expr(std::move(stack_.top())); stack_.pop(); + auto lvalue = ast::expr(std::move(stack_.top())); stack_.pop(); + loc = lvalue.as_node->loc(); + auto node = std::make_unique(loc, std::move(lvalue), std::move(rvalue)); + stack_.push(std::move(node)); + break; + } + case opcode::OP_wait: + { + auto expr = ast::expr(std::move(stack_.top())); stack_.pop(); + loc = expr.loc(); + auto stmt = ast::stmt(std::make_unique(loc, std::move(expr))); + func_->stmt->list.push_back(std::move(stmt)); + break; + } + case opcode::OP_waittillFrameEnd: + { + auto stmt = ast::stmt(std::make_unique(loc)); + func_->stmt->list.push_back(std::move(stmt)); + break; + } + case opcode::OP_waitframe: + { + auto stmt = ast::stmt(std::make_unique(loc)); + func_->stmt->list.push_back(std::move(stmt)); + break; + } + case opcode::OP_waittill: + { + auto obj = ast::expr(std::move(stack_.top())); stack_.pop(); + auto event = ast::expr(std::move(stack_.top())); stack_.pop(); + loc = event.as_node->loc(); + auto args = std::make_unique(loc); + auto node = std::make_unique(loc, std::move(obj) , std::move(event), std::move(args)); + stack_.push(std::move(node)); + in_waittill_ = true; + break; + } + case opcode::OP_waittillmatch: + { + auto args = std::make_unique(loc); + auto obj = ast::expr(std::move(stack_.top())); stack_.pop(); + auto event = ast::expr(std::move(stack_.top())); stack_.pop(); + loc = event.as_node->loc(); + + for (auto i = std::stoul(inst->data[0]); i > 0; i--) + { + auto node = std::move(stack_.top()); stack_.pop(); + loc = node->loc(); + args->list.push_back(std::move(node)); + } + + auto stmt = ast::stmt(std::make_unique(loc, std::move(obj), std::move(event), std::move(args))); + func_->stmt->list.push_back(std::move(stmt)); + break; + } + case opcode::OP_clearparams: + { + if (in_waittill_) + { + auto args = std::make_unique(loc); + auto node = std::move(stack_.top()); stack_.pop(); + + while (node->kind() != ast::kind::stmt_waittill) + { + args->list.push_back(std::move(node)); + node = std::move(stack_.top()); stack_.pop(); + } + + if (node->kind() == ast::kind::stmt_waittill) + { + std::reverse(args->list.begin(), args->list.end()); + (*(ast::stmt_waittill::ptr*)&node)->args = std::move(args); + in_waittill_ = false; + } + + func_->stmt->list.push_back(ast::stmt(std::move(node))); + } + break; + } + case opcode::OP_notify: + { + auto obj = ast::expr(std::move(stack_.top())); stack_.pop(); + auto event = ast::expr(std::move(stack_.top())); stack_.pop(); + auto args = std::make_unique(loc); + auto node = std::move(stack_.top()); stack_.pop(); + loc = node->loc(); + + while (node->kind() != ast::kind::asm_voidcodepos) + { + args->list.push_back(std::move(node)); + node = std::move(stack_.top()); stack_.pop(); + loc = node->loc(); + } + + auto stmt = ast::stmt(std::make_unique(loc, std::move(obj), std::move(event), std::move(args))); + func_->stmt->list.push_back(std::move(stmt)); + break; + } + case opcode::OP_endon: + { + auto obj = ast::expr(std::move(stack_.top())); stack_.pop(); + auto event = ast::expr(std::move(stack_.top())); stack_.pop(); + loc = event.as_node->loc(); + auto stmt = ast::stmt(std::make_unique(loc, std::move(obj), std::move(event))); + func_->stmt->list.push_back(std::move(stmt)); + break; + } + case opcode::OP_voidCodepos: + { + auto node = std::make_unique(loc); + stack_.push(std::move(node)); + break; + } + case opcode::OP_vector: + { + auto x = ast::expr(std::move(stack_.top())); stack_.pop(); + auto y = ast::expr(std::move(stack_.top())); stack_.pop(); + auto z = ast::expr(std::move(stack_.top())); stack_.pop(); + loc = z.as_node->loc(); + auto node = std::make_unique(loc, std::move(x), std::move(y), std::move(z)); + stack_.push(std::move(node)); + break; + } + case opcode::OP_size: + { + auto lvalue = ast::expr(std::move(stack_.top())); stack_.pop(); + loc = lvalue.as_node->loc(); + auto node = std::make_unique(loc, std::move(lvalue)); + stack_.push(std::move(node)); + break; + } + case opcode::OP_EvalLevelFieldVariable: + { + auto obj = ast::expr(std::make_unique(loc)); + auto field = std::make_unique(loc, inst->data[0]); + auto node = std::make_unique(loc, std::move(obj), std::move(field)); + stack_.push(std::move(node)); + break; + } + case opcode::OP_EvalAnimFieldVariable: + { + auto obj = ast::expr(std::make_unique(loc)); + auto field = std::make_unique(loc, inst->data[0]); + auto node = std::make_unique(loc, std::move(obj), std::move(field)); + stack_.push(std::move(node)); + break; + } + case opcode::OP_EvalSelfFieldVariable: + { + auto obj = ast::expr(std::make_unique(loc)); + auto field = std::make_unique(loc, inst->data[0]); + auto node = std::make_unique(loc, std::move(obj), std::move(field)); + stack_.push(std::move(node)); + break; + } + case opcode::OP_EvalFieldVariable: + { + auto obj = ast::expr(std::move(stack_.top())); stack_.pop(); + loc = obj.as_node->loc(); + auto field = std::make_unique(loc, inst->data[0]); + auto node = std::make_unique(loc, std::move(obj), std::move(field)); + stack_.push(std::move(node)); + break; + } + case opcode::OP_EvalLevelFieldVariableRef: + { + auto obj = ast::expr(std::make_unique(loc)); + auto field = std::make_unique(loc, inst->data[0]); + auto node = std::make_unique(loc, std::move(obj), std::move(field)); + stack_.push(std::move(node)); + break; + } + case opcode::OP_EvalAnimFieldVariableRef: + { + auto obj = ast::expr(std::make_unique(loc)); + auto field = std::make_unique(loc, inst->data[0]); + auto node = std::make_unique(loc, std::move(obj), std::move(field)); + stack_.push(std::move(node)); + break; + } + case opcode::OP_EvalSelfFieldVariableRef: + { + auto obj = ast::expr(std::make_unique(loc)); + auto field = std::make_unique(loc, inst->data[0]); + auto node = std::make_unique(loc, std::move(obj), std::move(field)); + stack_.push(std::move(node)); + break; + } + case opcode::OP_EvalFieldVariableRef: + { + auto obj = ast::expr(std::move(stack_.top())); stack_.pop(); + loc = obj.as_node->loc(); + auto field = std::make_unique(loc, inst->data[0]); + auto node = std::make_unique(loc, std::move(obj), std::move(field)); + stack_.push(std::move(node)); + break; + } + case opcode::OP_ClearFieldVariable: + { + auto obj = ast::expr(std::move(stack_.top())); stack_.pop(); + loc = obj.as_node->loc(); + auto name = std::make_unique(loc, inst->data[0]); + auto field = ast::expr(std::make_unique(loc, std::move(obj), std::move(name))); + auto undef = ast::expr(std::make_unique(loc)); + auto expr = ast::expr(std::make_unique(loc, std::move(field), std::move(undef))); + auto stmt = ast::stmt(std::make_unique(loc, std::move(expr))); + func_->stmt->list.push_back(std::move(stmt)); + break; + } + case opcode::OP_SafeCreateVariableFieldCached: + { + auto expr = std::make_unique(loc, inst->data[0]); + func_->params->list.push_back(std::move(expr)); + break; + } + case opcode::OP_SafeSetWaittillVariableFieldCached: + { + if (stack_.top()->kind() != ast::kind::asm_create) + { + auto node = std::make_unique(loc, inst->data[0]); + stack_.push(std::move(node)); + } + break; + } + /*case opcode::OP_SafeSetVariableFieldCached0: + { + auto expr = std::make_unique(loc, "var_0"); + func_->params->list.push_back(std::move(expr)); + break; + } + case opcode::OP_SafeSetVariableFieldCached: + { + auto expr = std::make_unique(loc, "var_" + inst->data[0]); + func_->params->list.push_back(std::move(expr)); + break; + }*/ + case opcode::OP_EvalLocalVariableRefCached0: + { + auto node = std::make_unique(loc, "0"); + stack_.push(std::move(node)); + break; + } + case opcode::OP_EvalLocalVariableRefCached: + { + auto node = std::make_unique(loc, inst->data[0]); + stack_.push(std::move(node)); + break; + } + case opcode::OP_SetLevelFieldVariableField: + { + auto obj = ast::expr(std::make_unique(loc)); + auto field = std::make_unique(loc, inst->data[0]); + auto lvalue = ast::expr(std::make_unique(loc, std::move(obj), std::move(field))); + auto rvalue = ast::expr(std::move(stack_.top())); stack_.pop(); + loc = rvalue.as_node->loc(); + auto expr = ast::expr(std::make_unique(loc, std::move(lvalue), std::move(rvalue))); + auto stmt = ast::stmt(std::make_unique(loc, std::move(expr))); + func_->stmt->list.push_back(std::move(stmt)); + break; + } + case opcode::OP_SetVariableField: + { + auto lvalue = ast::expr(std::move(stack_.top())); stack_.pop(); + loc = lvalue.as_node->loc(); + + if (lvalue.as_node->kind() == ast::kind::expr_increment) + { + auto stmt = ast::stmt(std::make_unique(loc, std::move(lvalue))); + func_->stmt->list.push_back(std::move(stmt)); + } + else if (lvalue.as_node->kind() == ast::kind::expr_decrement) + { + auto stmt = ast::stmt(std::make_unique(loc, std::move(lvalue))); + func_->stmt->list.push_back(std::move(stmt)); + } + else + { + auto rvalue = ast::expr(std::move(stack_.top())); stack_.pop(); + loc = rvalue.as_node->loc(); + auto expr = ast::expr(std::make_unique(loc, std::move(lvalue), std::move(rvalue))); + auto stmt = ast::stmt(std::make_unique(loc, std::move(expr))); + func_->stmt->list.push_back(std::move(stmt)); + } + break; + } + case opcode::OP_SetAnimFieldVariableField: + { + auto obj = ast::expr(std::make_unique(loc)); + auto field = std::make_unique(loc, inst->data[0]); + auto lvalue = ast::expr(std::make_unique(loc, std::move(obj), std::move(field))); + auto rvalue = ast::expr(std::move(stack_.top())); stack_.pop(); + loc = rvalue.as_node->loc(); + auto expr = ast::expr(std::make_unique(loc, std::move(lvalue), std::move(rvalue))); + auto stmt = ast::stmt(std::make_unique(loc, std::move(expr))); + func_->stmt->list.push_back(std::move(stmt)); + break; + } + case opcode::OP_SetSelfFieldVariableField: + { + auto obj = ast::expr(std::make_unique(loc)); + auto field = std::make_unique(loc, inst->data[0]); + auto lvalue = ast::expr(std::make_unique(loc, std::move(obj), std::move(field))); + auto rvalue = ast::expr(std::move(stack_.top())); stack_.pop(); + loc = rvalue.as_node->loc(); + auto expr = ast::expr(std::make_unique(loc, std::move(lvalue), std::move(rvalue))); + auto stmt = ast::stmt(std::make_unique(loc, std::move(expr))); + func_->stmt->list.push_back(std::move(stmt)); + break; + } + case opcode::OP_SetLocalVariableFieldCached0: + { + auto lvalue = ast::expr(std::make_unique(loc, "0")); + auto rvalue = ast::expr(std::move(stack_.top())); stack_.pop(); + loc = rvalue.as_node->loc(); + auto expr = ast::expr(std::make_unique(loc, std::move(lvalue), std::move(rvalue))); + auto stmt = ast::stmt(std::make_unique(loc, std::move(expr))); + func_->stmt->list.push_back(std::move(stmt)); + break; + } + case opcode::OP_SetNewLocalVariableFieldCached0: + { + auto lvalue = ast::expr(std::make_unique(loc, inst->data[0])); + auto rvalue = ast::expr(std::move(stack_.top())); stack_.pop(); + loc = rvalue.as_node->loc(); + + if (func_->stmt->list.size() > 0) + { + std::vector vars; + + while (func_->stmt->list.back().as_node->kind() == ast::kind::asm_create) + { + auto& entry = func_->stmt->list.back(); + if (loc.begin.line < entry.as_node->loc().begin.line) + { + vars.push_back(entry.as_asm_create->index); + func_->stmt->list.pop_back(); + continue; + } + break; + } + + std::reverse(vars.begin(), vars.end()); + lvalue.as_asm_create->vars = vars; + } + + auto expr = ast::expr(std::make_unique(loc, std::move(lvalue), std::move(rvalue))); + auto stmt = ast::stmt(std::make_unique(loc, std::move(expr))); + func_->stmt->list.push_back(std::move(stmt)); + break; + } + case opcode::OP_SetLocalVariableFieldCached: + { + auto lvalue = ast::expr(std::make_unique(loc, inst->data[0])); + auto rvalue = ast::expr(std::move(stack_.top())); stack_.pop(); + loc = rvalue.as_node->loc(); + auto expr = ast::expr(std::make_unique(loc, std::move(lvalue), std::move(rvalue))); + auto stmt = ast::stmt(std::make_unique(loc, std::move(expr))); + func_->stmt->list.push_back(std::move(stmt)); + break; + } + case opcode::OP_ClearLocalVariableFieldCached: + { + auto stmt = ast::stmt(std::make_unique(loc, inst->data[0])); + func_->stmt->list.push_back(std::move(stmt)); + break; + } + case opcode::OP_ClearLocalVariableFieldCached0: + { + auto stmt = ast::stmt(std::make_unique(loc, "0")); + func_->stmt->list.push_back(std::move(stmt)); + break; + } + case opcode::OP_EvalLocalVariableObjectCached: + { + auto node = std::make_unique(loc, inst->data[0]); + stack_.push(std::move(node)); + break; + } + case opcode::OP_BoolNot: + { + auto lvalue = ast::expr(std::move(stack_.top())); stack_.pop(); + loc = lvalue.as_node->loc(); + auto node = std::make_unique(loc, std::move(lvalue)); + stack_.push(std::move(node)); + break; + } + case opcode::OP_BoolComplement: + { + auto lvalue = ast::expr(std::move(stack_.top())); stack_.pop(); + loc = lvalue.as_node->loc(); + auto node = std::make_unique(loc, std::move(lvalue)); + stack_.push(std::move(node)); + break; + } + case opcode::OP_switch: + { + auto expr = ast::expr(std::move(stack_.top())); stack_.pop(); + loc = expr.as_node->loc(); + auto stmt = ast::stmt(std::make_unique(loc, std::move(expr), inst->data[0])); + func_->stmt->list.push_back(std::move(stmt)); + break; + } + case opcode::OP_endswitch: + { + auto count = inst->data[0]; + inst->data.erase(inst->data.begin()); + auto data = inst->data; + auto stmt = ast::stmt(std::make_unique(loc, data, count)); + func_->stmt->list.push_back(std::move(stmt)); + break; + } + case opcode::OP_jump: + { + auto stmt = ast::stmt(std::make_unique(loc, inst->data[0])); + func_->stmt->list.push_back(std::move(stmt)); + if (stack_.size() != 0) tern_labels_.push_back(inst->data[0]); + break; + } + case opcode::OP_jumpback: + { + auto stmt = ast::stmt(std::make_unique(loc, inst->data[0])); + func_->stmt->list.push_back(std::move(stmt)); + break; + } + case opcode::OP_JumpOnTrue: + { + auto lvalue = ast::expr(std::move(stack_.top())); stack_.pop(); + loc = lvalue.as_node->loc(); + auto expr = ast::expr(std::make_unique(loc, std::move(lvalue))); + auto stmt = ast::stmt(std::make_unique(loc, std::move(expr), inst->data[0])); + func_->stmt->list.push_back(std::move(stmt)); + break; + } + case opcode::OP_JumpOnFalse: + { + auto lvalue = ast::expr(std::move(stack_.top())); stack_.pop(); + loc = lvalue.as_node->loc(); + auto stmt = ast::stmt(std::make_unique(loc, std::move(lvalue), inst->data[0])); + func_->stmt->list.push_back(std::move(stmt)); + break; + } + case opcode::OP_JumpOnTrueExpr: + { + auto lvalue = ast::expr(std::move(stack_.top())); stack_.pop(); + loc = lvalue.as_node->loc(); + auto node = std::make_unique(loc, std::move(lvalue), inst->data[0]); + stack_.push(std::move(node)); + expr_labels_.push_back(inst->data[0]); + break; + } + case opcode::OP_JumpOnFalseExpr: + { + auto lvalue = ast::expr(std::move(stack_.top())); stack_.pop(); + loc = lvalue.as_node->loc(); + auto node = std::make_unique(loc, std::move(lvalue), inst->data[0]); + stack_.push(std::move(node)); + expr_labels_.push_back(inst->data[0]); + break; + } + case opcode::OP_FormalParams: + { + auto count = std::stoi(inst->data[0]); + + for (auto i = 1; i <= count; i++) + { + func_->params->list.push_back(std::make_unique(loc, "var_" + inst->data[i])); + } + break; + } + case opcode::OP_IsDefined: + { + auto expr = ast::expr(std::move(stack_.top())); stack_.pop(); + auto node = std::make_unique(expr.loc(), std::move(expr)); + stack_.push(std::move(node)); + break; + } + case opcode::OP_IsTrue: + { + auto expr = ast::expr(std::move(stack_.top())); stack_.pop(); + auto node = std::make_unique(expr.loc(), std::move(expr)); + stack_.push(std::move(node)); + break; + } + case opcode::OP_BoolNotAfterAnd: + { + auto expr = ast::expr(std::move(stack_.top())); stack_.pop(); + auto node = std::make_unique(expr.loc(), std::move(expr)); + stack_.push(std::move(node)); + break; + } + case opcode::OP_waittillmatch2: + case opcode::OP_checkclearparams: + case opcode::OP_CastFieldObject: + case opcode::OP_CastBool: + break; + // case opcode::OP_ClearVariableField + // case opcode::OP_EvalNewLocalVariableRefCached0 + default: + throw decomp_error("unhandled opcode " + resolver::opcode_name(inst->opcode)); + } +} + +void decompiler::decompile_expressions(const instruction::ptr& inst) +{ + const auto itr = labels_.find(inst->index); + + if (itr == labels_.end()) + return; + + for (const auto& expr : expr_labels_) + { + if (expr == itr->second) + { + auto rvalue = ast::expr(std::move(stack_.top())); stack_.pop(); + auto jump = std::move(stack_.top()); stack_.pop(); + auto loc = jump->loc(); + + if (jump->kind() == ast::kind::asm_jump_true_expr) + { + auto lvalue = std::move((*(ast::asm_jump_true_expr::ptr*)&jump)->expr); + auto node = std::make_unique(loc, std::move(lvalue), std::move(rvalue)); + stack_.push(std::move(node)); + } + else if (jump->kind() == ast::kind::asm_jump_false_expr) + { + auto lvalue = std::move((*(ast::asm_jump_false_expr::ptr*)&jump)->expr); + auto node = std::make_unique(loc, std::move(lvalue), std::move(rvalue)); + stack_.push(std::move(node)); + } + else + { + throw decomp_error("TRIED TO DECOMPILE INVALID JUMP EXPR!"); + } + } + } + + for (const auto& tern : tern_labels_) + { + if (tern == itr->second) + { + auto rvalue = ast::expr(std::move(stack_.top())); stack_.pop(); + auto lvalue = ast::expr(std::move(stack_.top())); stack_.pop(); + + func_->stmt->list.pop_back(); + auto stmt = std::move(func_->stmt->list.back()); + func_->stmt->list.pop_back(); + + if (stmt == ast::kind::asm_jump_cond) + { + auto loc = stmt.as_cond->loc(); + auto node = std::make_unique(loc, std::move(stmt.as_cond->expr), std::move(lvalue), std::move(rvalue)); + stack_.push(std::move(node)); + } + else + { + throw decomp_error("TRIED TO DECOMPILE INVALID TERNARY EXPR!"); + } + } + } +} + +void decompiler::decompile_statements(const ast::stmt_list::ptr& stmt) +{ + decompile_loops(stmt); + decompile_switches(stmt); + decompile_ifelses(stmt); + decompile_aborts(stmt); + decompile_tuples(stmt); +} + +void decompiler::decompile_loops(const ast::stmt_list::ptr& stmt) +{ + if (stmt->list.size() == 0) + return; + + for (auto i = static_cast(stmt->list.size() - 1); i >= 0; i--) + { + if (stmt->list.at(i) == ast::kind::asm_jump_back) + { + auto break_loc = last_location_index(stmt, i) ? blocks_.back().loc_end : stmt->list.at(i + 1).loc().label(); + auto start = find_location_index(stmt, stmt->list.at(i).as_jump_back->value); + + if (i > 0 && stmt->list.at(i - 1).as_node->kind() == ast::kind::asm_jump_cond) + { + if (i - 1 == static_cast(start)) // condition belongs to empty loop + { + decompile_while(stmt, start, i); + i = static_cast(stmt->list.size()); + continue; + } + else if (static_cast(i) < find_location_index(stmt, stmt->list.at(i - 1).as_cond->value)) + { + decompile_dowhile(stmt, i - 1, i); + i = static_cast(stmt->list.size()); + continue; + } + } + + if (i == static_cast(start)) // empty inf loop + { + decompile_inf(stmt, start, i); + } + else if (stmt->list.at(start).as_node->kind() != ast::kind::asm_jump_cond) // no condition + { + decompile_inf(stmt, start, i); + } + else if (stmt->list.at(start).as_cond->value != break_loc) // condition belong to other stmt + { + decompile_inf(stmt, start, i); + } + else // condition belong to loop + { + decompile_loop(stmt, start, i); + } + + i = static_cast(stmt->list.size()); + } + } +} + +void decompiler::decompile_switches(const ast::stmt_list::ptr& stmt) +{ + for (auto i = 0u; i < stmt->list.size(); i++) + { + if (stmt->list.at(i) == ast::kind::asm_switch) + { + decompile_switch(stmt, i); + } + } +} + +void decompiler::decompile_ifelses(const ast::stmt_list::ptr& stmt) +{ + for (auto i = 0u; i < stmt->list.size(); i++) + { + const auto& entry = stmt->list.at(i); + + if (entry == ast::kind::asm_jump_cond) + { + auto j = (entry.as_cond->value == blocks_.back().loc_end) ? (stmt->list.size() - 1) : (find_location_index(stmt, entry.as_cond->value) - 1); + auto last_loc = blocks_.back().loc_end; + + if (stmt->list.at(j) == ast::kind::asm_jump) + { + // if block is a loop check break, continue + if (stmt->list.at(j).as_jump->value == blocks_.back().loc_continue) + { + // check for if/else or if/continue + if (j - i > 1 && stmt->list.at(j - 1) == ast::kind::stmt_return) + { + // block ends with a return, so jump belows to if/else + decompile_ifelse(stmt, i, j); + } + else if (j - i > 1 && stmt->list.at(j - 1) == ast::kind::asm_jump) + { + if (stmt->list.at(j - 1).as_jump->value == blocks_.back().loc_break) + { + // block ends with a break, so jump belows to if/else + decompile_ifelse(stmt, i, j); + } + else if (stmt->list.at(j - 1).as_jump->value == blocks_.back().loc_continue) + { + // if { break/return } else { continue } at loop block end + if (j - i > 2 && (stmt->list.at(j - 2) == ast::kind::asm_jump || stmt->list.at(j - 2) == ast::kind::stmt_return)) + { + decompile_if(stmt, i, j); + } + else + { + // block ends with a continue, so jump belows to if/else + decompile_ifelse(stmt, i, j); + } + } + else + { + // jump belows to if/continue + decompile_if(stmt, i, j); + } + } + else + { // last if/else inside a loop still trigger this :( + decompile_if(stmt, i, j); + } + } + else if (stmt->list.at(j).as_jump->value == blocks_.back().loc_break) + { + decompile_if(stmt, i, j); + } + else if (stmt->list.at(j).as_jump->value == entry.as_cond->value) + { + if (find_location_reference(stmt, i + 1, j, entry.as_cond->value)) + { + // if block, have a empty else inside at end + decompile_if(stmt, i, j); + } + else + { + decompile_ifelse(stmt, i, j); // if block with empty else + } + } + else + { + decompile_ifelse(stmt, i, j); + } + } + else if (stmt->list.at(j) == ast::kind::stmt_return && stmt->list.at(j).as_return->expr == ast::kind::null) + { + if(entry.as_cond->value != blocks_.back().loc_end) + { + auto ref = stmt->list.at(j + 1).loc().label(); + + if (find_location_reference(stmt, i + 1, j, ref)) + { + // after return is referenced inside the block + decompile_if(stmt, i, j); + continue; + } + } + + if (blocks_.back().loc_break != "" || blocks_.back().loc_continue != "") + { + decompile_if(stmt, i, j); // inside a loop cant be last + } + else if (j - i == 1) + { + decompile_if(stmt, i, j); // only one explicit return + } + else if (stmt->list.back().as_node->kind() != ast::kind::stmt_return) + { + decompile_if(stmt, i, j); // block end is not a last return + } + else if (blocks_.back().is_last && stmt->list.back().as_node->kind() != ast::kind::stmt_return) + { + decompile_if(stmt, i, j); // inside a last block but is not and inner last + } + else if (find_location_reference(stmt, j, stmt->list.size(), last_loc)) + { + decompile_if(stmt, i, j); // reference to func end after the if + } + else if (blocks_.size() > 1 && !blocks_.back().is_last) + { + decompile_if(stmt, i, j); // fake last ifelse + } + else + { + decompile_ifelse_end(stmt, i, j); // special case + } + } + else + { + decompile_if(stmt, i, j); + } + } + } +} + +void decompiler::decompile_aborts(const ast::stmt_list::ptr& block) +{ + for (auto i = 0u; i < block->list.size(); i++) + { + if (block->list.at(i) == ast::kind::asm_jump) + { + auto loc = block->list.at(i).loc(); + auto jump_loc = block->list.at(i).as_jump->value; + + if (jump_loc == blocks_.back().loc_continue) + { + block->list.erase(block->list.begin() + i); + auto stmt = ast::stmt(std::make_unique(loc)); + block->list.insert(block->list.begin() + i, std::move(stmt)); + } + else if (jump_loc == blocks_.back().loc_break) + { + block->list.erase(block->list.begin() + i); + auto stmt = ast::stmt(std::make_unique(loc)); + block->list.insert(block->list.begin() + i, std::move(stmt)); + } + else + { + std::cout << "WARNING: unresolved jump to '" + jump_loc + "', maybe incomplete for loop\n"; + } + } + } +} + +void decompiler::decompile_tuples(const ast::stmt_list::ptr& block) +{ + for (auto i = 1u; i < block->list.size(); i++) + { + if (block->list.at(i) == ast::kind::asm_clear) + { + auto j = i - 1; + auto found = false, done = false; + + while (j >= 0 && block->list.at(j) == ast::kind::stmt_assign) + { + const auto& expr = block->list.at(j).as_assign->expr; + + if (expr != ast::kind::expr_assign_equal) + break; + + if (!done) + { + if (expr.as_assign_equal->rvalue != ast::kind::expr_array) + break; + + if (expr.as_assign_equal->rvalue.as_array->key != ast::kind::expr_integer) + break; + + if (expr.as_assign_equal->rvalue.as_array->key.as_integer->value == "0") + done = true; + + j--; + } + else + { + if (expr.as_assign_equal->lvalue == ast::kind::asm_create || expr.as_assign_equal->lvalue == ast::kind::asm_access) + found = true; + + break; + } + } + + if (found) + { + auto& stmt = block->list.at(j); // temp = expr; + auto new_expr = std::make_unique(stmt.loc()); + new_expr->temp = std::move(stmt.as_assign->expr.as_assign_equal->lvalue); + j++; + + while (j < i) + { + new_expr->list.push_back(std::move(block->list.at(j).as_assign->expr.as_assign_equal->lvalue)); + block->list.erase(block->list.begin() + j); + i--; + } + + block->list.erase(block->list.begin() + j); // clear temp array + i--; + + stmt.as_assign->expr.as_assign_equal->lvalue = ast::expr(std::move(new_expr)); + } + } + } +} + +void decompiler::decompile_if(const ast::stmt_list::ptr& stmt, std::size_t begin, std::size_t end) +{ + block blk; + blk.loc_end = stmt->list.at(begin).as_cond->value; + blk.loc_break = blocks_.back().loc_break; + blk.loc_continue = blocks_.back().loc_continue; + + auto loc = stmt->list.at(begin).loc(); + auto test = std::move(stmt->list.at(begin).as_cond->expr); + + stmt->list.erase(stmt->list.begin() + begin); // remove 'test' + + auto if_stmt = std::make_unique(loc); + + for (auto i = begin; i < end; i++) + { + if_stmt->list.push_back(std::move(stmt->list[begin])); + stmt->list.erase(stmt->list.begin() + begin); + } + + blocks_.push_back(blk); + decompile_statements(if_stmt); + blocks_.pop_back(); + + auto new_stmt = ast::stmt(std::make_unique(loc, std::move(test), ast::stmt(std::move(if_stmt)))); + stmt->list.insert(stmt->list.begin() + begin, std::move(new_stmt)); +} + +void decompiler::decompile_ifelse(const ast::stmt_list::ptr& stmt, std::size_t begin, std::size_t end) +{ + block if_blk; + if_blk.loc_end = stmt->list.at(end).loc().label(); + if_blk.loc_break = blocks_.back().loc_break; + if_blk.loc_continue = blocks_.back().loc_continue; + + auto loc = stmt->list.at(begin).loc(); + auto test = std::move(stmt->list.at(begin).as_cond->expr); + + stmt->list.erase(stmt->list.begin() + begin); // remove 'test' + end--; + + auto if_stmt = std::make_unique(loc); + + for (auto i = begin; i < end; i++) + { + if_stmt->list.push_back(std::move(stmt->list[begin])); + stmt->list.erase(stmt->list.begin() + begin); + } + + blocks_.push_back(if_blk); + decompile_statements(if_stmt); + blocks_.pop_back(); + + auto end_loc = stmt->list.at(begin).as_jump->value; + stmt->list.erase(stmt->list.begin() + begin); // remove 'jump' + + auto end_idx = (end_loc == blocks_.back().loc_end) ? stmt->list.size() : find_location_index(stmt, end_loc); + + block else_blk; + else_blk.loc_end = end_loc; + else_blk.loc_break = blocks_.back().loc_break; + else_blk.loc_continue = blocks_.back().loc_continue; + + auto else_stmt = std::make_unique(loc); + + for (auto i = begin; i < end_idx; i++) + { + else_stmt->list.push_back(std::move(stmt->list[begin])); + stmt->list.erase(stmt->list.begin() + begin); + } + + blocks_.push_back(else_blk); + decompile_statements(else_stmt); + blocks_.pop_back(); + + auto new_stmt = ast::stmt(std::make_unique(loc, std::move(test), ast::stmt(std::move(if_stmt)), ast::stmt(std::move(else_stmt)))); + stmt->list.insert(stmt->list.begin() + begin, std::move(new_stmt)); +} + +void decompiler::decompile_ifelse_end(const ast::stmt_list::ptr& stmt, std::size_t begin, std::size_t end) +{ + block if_blk; + if_blk.is_last = true; + + auto if_end = find_location_index(stmt, stmt->list.at(begin).as_cond->value) - 1; + if_blk.loc_end = stmt->list.at(if_end).loc().label(); + + auto loc = stmt->list.at(begin).loc(); + auto test = std::move(stmt->list.at(begin).as_cond->expr); + + stmt->list.erase(stmt->list.begin() + begin); // remove 'test' + end--; + + auto if_stmt = std::make_unique(loc); + + for (auto i = begin; i < end; i++) + { + if_stmt->list.push_back(std::move(stmt->list[begin])); + stmt->list.erase(stmt->list.begin() + begin); + } + + stmt->list.erase(stmt->list.begin() + begin); // remove 'return' + + blocks_.push_back(if_blk); + decompile_statements(if_stmt); + blocks_.pop_back(); + + if (begin == stmt->list.size()) + { + auto new_stmt = ast::stmt(std::make_unique(loc, std::move(test), ast::stmt(std::move(if_stmt)))); + stmt->list.insert(stmt->list.begin() + begin, std::move(new_stmt)); + } + else + { + block else_blk; + else_blk.is_last = true; + + end = stmt->list.size() - 1; + else_blk.loc_end = stmt->list.at(end).loc().label(); + + auto else_stmt = std::make_unique(loc); + + for (auto i = begin; i < end; i++) + { + else_stmt->list.push_back(std::move(stmt->list[begin])); + stmt->list.erase(stmt->list.begin() + begin); + } + + stmt->list.erase(stmt->list.begin() + begin); // remove 'return' + + blocks_.push_back(else_blk); + decompile_statements(else_stmt); + blocks_.pop_back(); + + auto new_stmt = ast::stmt(std::make_unique(loc, std::move(test), ast::stmt(std::move(if_stmt)), ast::stmt(std::move(else_stmt)))); + stmt->list.insert(stmt->list.begin() + begin, std::move(new_stmt)); + } +} + +void decompiler::decompile_inf(const ast::stmt_list::ptr& stmt, std::size_t begin, std::size_t end) +{ + block blk; + blk.loc_break = last_location_index(stmt, end) ? blocks_.back().loc_end : stmt->list.at(end + 1).loc().label(); + blk.loc_end = stmt->list.at(end).loc().label(); + blk.loc_continue = stmt->list.at(end).loc().label(); + + auto loc = stmt->list.at(begin).loc(); + + stmt->list.erase(stmt->list.begin() + end); // remove 'jumpback' + + auto for_stmt = std::make_unique(loc); + + for (auto i = begin; i < end; i++) + { + for_stmt->list.push_back(std::move(stmt->list[begin])); + stmt->list.erase(stmt->list.begin() + begin); + } + + blocks_.push_back(blk); + decompile_statements(for_stmt); + blocks_.pop_back(); + + auto init = ast::stmt(std::make_unique()); + auto test = ast::expr(std::make_unique()); + auto iter = ast::stmt(std::make_unique()); + auto new_stmt = ast::stmt(std::make_unique(loc, std::move(init), std::move(test), std::move(iter), ast::stmt(std::move(for_stmt)))); + stmt->list.insert(stmt->list.begin() + begin, std::move(new_stmt)); +} + +void decompiler::decompile_loop(const ast::stmt_list::ptr& block, std::size_t start, std::size_t end) +{ + const auto& last = block->list.at(end - 1); + + if (last == ast::kind::stmt_assign) + { + if (last.as_assign->expr == ast::kind::expr_assign_equal) + { + auto& call = last.as_assign->expr.as_assign_equal->rvalue; + + if (call == ast::kind::expr_call && call.as_call->call == ast::kind::expr_function) + { + if (utils::string::to_lower(call.as_call->call.as_function->name->value) == "getnextarraykey") + { + auto ref = block->list.at(start).loc().label(); + + if (!find_location_reference(block, 0, start, ref)) + { + decompile_foreach(block, start, end); + return; + } + } + } + } + + if (start > 0) // while at func start + { + auto index = 1; + while (block->list.at(start - index) == ast::kind::asm_create) + { + if (start - index > 0) + index++; + else + break; + } + + if (block->list.at(start - index) == ast::kind::stmt_assign) + { + auto ref = block->list.at(end).loc().label(); + auto ref2 = block->list.at(start - index + 1).loc().label(); + + if (find_location_reference(block, start, end, ref)) + { + // continue is at jumpback, not post-expr + decompile_while(block, start, end); + return; + } + else if (find_location_reference(block, 0, start, ref2)) + { + // begin is at condition or localVarCreate, not pre-expr + decompile_while(block, start, end); + return; + } + else + { + decompile_for(block, start, end); + return; + } + } + } + } + + decompile_while(block, start, end); +} + +void decompiler::decompile_while(const ast::stmt_list::ptr& stmt, std::size_t begin, std::size_t end) +{ + block blk; + blk.loc_break = stmt->list.at(begin).as_cond->value; + blk.loc_end = stmt->list.at(end).loc().label(); + blk.loc_continue = stmt->list.at(end).loc().label(); + + auto loc = stmt->list.at(begin).loc(); + auto test = std::move(stmt->list.at(begin).as_cond->expr); + + stmt->list.erase(stmt->list.begin() + end); // remove 'jumpback' + stmt->list.erase(stmt->list.begin() + begin); // remove 'test' + end--; + + auto while_stmt = std::make_unique(loc); + + for (auto i = begin; i < end; i++) + { + while_stmt->list.push_back(std::move(stmt->list[begin])); + stmt->list.erase(stmt->list.begin() + begin); + } + + blocks_.push_back(blk); + decompile_statements(while_stmt); + blocks_.pop_back(); + + auto new_stmt = ast::stmt(std::make_unique(loc, std::move(test), ast::stmt(std::move(while_stmt)))); + stmt->list.insert(stmt->list.begin() + begin, std::move(new_stmt)); +} + +void decompiler::decompile_dowhile(const ast::stmt_list::ptr& stmt, std::size_t begin, std::size_t end) +{ + block blk; + blk.loc_break = stmt->list.at(begin).as_cond->value; + blk.loc_end = stmt->list.at(begin).loc().label(); + blk.loc_continue = stmt->list.at(begin).loc().label(); + + auto test = std::move(stmt->list.at(begin).as_cond->expr); + begin = find_location_index(stmt, stmt->list.at(end).as_jump_back->value); + auto loc = stmt->list.at(begin).loc(); + + end--; + stmt->list.erase(stmt->list.begin() + end); // remove 'test' + stmt->list.erase(stmt->list.begin() + end); // remove 'jumpback' + + auto while_stmt = std::make_unique(loc); + + for (auto i = begin; i < end; i++) + { + while_stmt->list.push_back(std::move(stmt->list[begin])); + stmt->list.erase(stmt->list.begin() + begin); + } + + blocks_.push_back(blk); + decompile_statements(while_stmt); + blocks_.pop_back(); + + auto new_stmt = ast::stmt(std::make_unique(loc, std::move(test), ast::stmt(std::move(while_stmt)))); + stmt->list.insert(stmt->list.begin() + begin, std::move(new_stmt)); +} + +void decompiler::decompile_for(const ast::stmt_list::ptr& stmt, std::size_t begin, std::size_t end) +{ + block blk; + blk.loc_break = stmt->list.at(begin).as_cond->value; + blk.loc_end = stmt->list.at(end - 1).loc().label(); + blk.loc_continue = stmt->list.at(end - 1).loc().label(); + + // collect local vars + std::vector vars; + while (stmt->list.at(begin - 1) == ast::kind::asm_create) + { + vars.push_back(stmt->list.at(begin - 1).as_asm_create->index); + stmt->list.erase(stmt->list.begin() + begin - 1); + begin--; + end--; + } + + std::reverse(vars.begin(), vars.end()); + + auto loc = stmt->list.at(begin - 1).loc(); + auto test = std::move(stmt->list.at(begin).as_cond->expr); + + auto init = ast::stmt(std::make_unique()); + init.as_list->list.push_back(std::move(stmt->list.at(begin - 1))); + init.as_list->is_expr = true; + + auto iter = ast::stmt(std::make_unique()); + iter.as_list->list.push_back(std::move(stmt->list.at(end - 1))); + iter.as_list->is_expr = true; + + begin--; // move begin from 'test' to 'init' + stmt->list.erase(stmt->list.begin() + begin); // remove 'init' + stmt->list.erase(stmt->list.begin() + begin); // remove 'test' + end -= 3; // move end to 'iter' ( minus 'init' & 'test' ) + stmt->list.erase(stmt->list.begin() + end); // remove 'iter' + stmt->list.erase(stmt->list.begin() + end); // remove 'jumpback' + + auto for_stmt = std::make_unique(loc); + + for (auto i = begin; i < end; i++) + { + for_stmt->list.push_back(std::move(stmt->list[begin])); + stmt->list.erase(stmt->list.begin() + begin); + } + + blocks_.push_back(blk); + decompile_statements(for_stmt); + blocks_.pop_back(); + + auto new_stmt = ast::stmt(std::make_unique(loc, std::move(init), std::move(test), std::move(iter), ast::stmt(std::move(for_stmt)))); + new_stmt.as_for->vars = vars; + stmt->list.insert(stmt->list.begin() + begin, std::move(new_stmt)); +} + +void decompiler::decompile_foreach(const ast::stmt_list::ptr& stmt, std::size_t begin, std::size_t end) +{ + block blk; + blk.loc_break = stmt->list.at(begin).as_cond->value; + blk.loc_end = stmt->list.at(end - 1).loc().label(); + blk.loc_continue = stmt->list.at(end - 1).loc().label(); + + // collect local vars + std::vector vars; + while (stmt->list.at(begin - 1) == ast::kind::asm_create) + { + vars.push_back(stmt->list.at(begin - 1).as_asm_create->index); + stmt->list.erase(stmt->list.begin() + begin - 1); + begin--; + end--; + } + + std::reverse(vars.begin(), vars.end()); + + auto loc = stmt->list.at(begin - 2).loc(); + + auto init = ast::stmt(std::make_unique()); + init.as_list->list.push_back(std::move(stmt->list[begin-2])); + init.as_list->list.push_back(std::move(stmt->list[begin-1])); + auto stmt0 = std::move(stmt->list[begin+1]); + + begin -= 2; // move begin from 'test' to 'array' + stmt->list.erase(stmt->list.begin() + begin); // remove 'array' + stmt->list.erase(stmt->list.begin() + begin); // remove 'elem' + stmt->list.erase(stmt->list.begin() + begin); // remove 'test' + stmt->list.erase(stmt->list.begin() + begin); // remove 'set' + end -= 5; // move end to 'iter' ( minus 'array', 'elem', 'test' & 'set' ) + stmt->list.erase(stmt->list.begin() + end); // remove 'iter' + stmt->list.erase(stmt->list.begin() + end); // remove 'jumpback + + if (stmt->list.size() > end && stmt->list.at(end) == ast::kind::asm_clear) + { + stmt->list.erase(stmt->list.begin() + end); // remove temp var 'array' + } + + auto use_key = true; + + if (stmt->list.size() > end && stmt->list.at(end) == ast::kind::asm_clear) + { + stmt->list.erase(stmt->list.begin() + end); // remove temp var 'key' + use_key = false; + } + + auto foreach_stmt = std::make_unique(loc); + + for (auto i = begin; i < end; i++) + { + foreach_stmt->list.push_back(std::move(stmt->list[begin])); + stmt->list.erase(stmt->list.begin() + begin); + } + + blocks_.push_back(blk); + decompile_statements(foreach_stmt); + blocks_.pop_back(); + + auto new_stmt = ast::stmt(std::make_unique(loc, ast::stmt(std::move(foreach_stmt)), use_key)); + new_stmt.as_foreach->vars = vars; + new_stmt.as_foreach->pre_expr = std::move(init); + new_stmt.as_foreach->stmt0 = std::move(stmt0); + stmt->list.insert(stmt->list.begin() + begin, std::move(new_stmt)); +} + +void decompiler::decompile_switch(const ast::stmt_list::ptr& stmt, std::size_t start) +{ + block blk; + blk.loc_continue = blocks_.back().loc_continue; + blk.loc_end = stmt->list.at(start).as_asm_switch->value; + + auto loc = stmt->list.at(start).loc(); + auto test = std::move(stmt->list.at(start).as_asm_switch->expr); + auto end_loc = stmt->list.at(start).as_asm_switch->value; + auto end = find_location_index(stmt, end_loc); + + blk.loc_break = (end == stmt->list.size() - 1) ? blocks_.back().loc_end : stmt->list.at(end + 1).loc().label(); + + // collect cases + auto casenum = std::atol(stmt->list.at(end).as_asm_endswitch->count.data()); + auto data = stmt->list.at(end).as_asm_endswitch->data; + auto idx = 0; + + for (auto i = 0; i < casenum; i++) + { + if (data.at(idx) == "case") + { + auto loc_str = data.at(idx + 2); + auto loc_idx = find_location_index(stmt, loc_str); + auto loc_pos = location(&filename_, std::stol(loc_str.substr(4), 0, 16)); + auto value = ast::expr(std::make_unique(loc_pos, data.at(idx + 1))); + auto list = std::make_unique(loc); + list->is_case = true; + auto case_stmt = ast::stmt(std::make_unique(loc_pos, std::move(value), std::move(list))); + stmt->list.insert(stmt->list.begin() + loc_idx, std::move(case_stmt)); + idx += 3; + } + else if (data.at(idx) == "default") + { + auto loc_str = data.at(idx + 1); + auto loc_idx = find_location_index(stmt, loc_str); + auto loc_pos = location(&filename_, std::stol(loc_str.substr(4), 0, 16)); + auto list = std::make_unique(loc); + list->is_case = true; + auto def_stmt = ast::stmt(std::make_unique(loc_pos, std::move(list))); + while (stmt->list.at(loc_idx) == ast::kind::stmt_case) + loc_idx++; + stmt->list.insert(stmt->list.begin() + loc_idx, std::move(def_stmt)); + idx += 2; + } + } + + end = find_location_index(stmt, end_loc); // update end + + while (stmt->list.size() > (end + 1) && stmt->list.at(end) != ast::kind::asm_endswitch) + end++; + + if (stmt->list.at(end) != ast::kind::asm_endswitch) + decomp_error("bad empty cases in switch block!"); + + end--; + stmt->list.erase(stmt->list.begin() + start); // remove 'switch' + stmt->list.erase(stmt->list.begin() + end); // remove 'endswitch' + + //decompile block + auto sw_stmt = std::make_unique(loc); + + for (auto i = start; i < end; i++) + { + sw_stmt->list.push_back(std::move(stmt->list[start])); + stmt->list.erase(stmt->list.begin() + start); + } + + blocks_.push_back(blk); + decompile_statements(sw_stmt); + blocks_.pop_back(); + + auto stmt_list = std::make_unique(loc); + auto current_case = ast::stmt(std::make_unique()); + + auto num = sw_stmt->list.size(); + for (auto i = 0u; i < num; i++) + { + auto& entry = sw_stmt->list[0]; + + if (entry == ast::kind::stmt_case || entry == ast::kind::stmt_default) + { + if (current_case.kind() != ast::kind::null) + { + stmt_list->list.push_back(std::move(current_case)); + } + + current_case = std::move(sw_stmt->list[0]); + sw_stmt->list.erase(sw_stmt->list.begin()); + } + else + { + if (current_case.kind() != ast::kind::null) + { + if (current_case == ast::kind::stmt_case) + { + current_case.as_case->stmt->list.push_back(std::move(sw_stmt->list[0])); + sw_stmt->list.erase(sw_stmt->list.begin()); + } + else + { + current_case.as_default->stmt->list.push_back(std::move(sw_stmt->list[0])); + sw_stmt->list.erase(sw_stmt->list.begin()); + } + } + else + { + decomp_error("missing case before stmt inside switch!"); + } + } + } + + if (current_case.kind() != ast::kind::null) + { + stmt_list->list.push_back(std::move(current_case)); + } + + auto new_stmt = ast::stmt(std::make_unique(loc, std::move(test), std::move(stmt_list))); + stmt->list.insert(stmt->list.begin() + start, std::move(new_stmt)); +} + +auto decompiler::find_location_reference(const ast::stmt_list::ptr& stmt, std::size_t begin, std::size_t end, const std::string& location) -> bool +{ + for (auto i = begin; i < end; i++) + { + const auto& entry = stmt->list.at(i); + + if (entry == ast::kind::asm_jump_cond && entry.as_cond->value == location) + { + return true; + } + else if (entry == ast::kind::asm_jump && entry.as_jump->value == location) + { + return true; + } + } + + return false; +} + +auto decompiler::find_location_index(const ast::stmt_list::ptr& stmt, const std::string& location) -> std::size_t +{ + auto index = 0u; + + if (location == blocks_.back().loc_end) + return stmt->list.size(); + + for (const auto& entry : stmt->list) + { + if (entry.loc().label() == location) + return index; + + index++; + } + + throw decomp_error("LOCATION NOT FOUND! (" + location + ")"); +} + +auto decompiler::last_location_index(const ast::stmt_list::ptr& stmt, std::size_t index) -> bool +{ + if (index == stmt->list.size() - 1) + return true; + + return false; +} + +void decompiler::process_stack(const ast::decl_thread::ptr& thread) +{ + auto blk = std::make_unique(); + + process_parameters(thread->params, blk); + process_stmt_list(thread->stmt, blk); +} + +void decompiler::process_parameters(const ast::expr_parameters::ptr& params, const block::ptr& blk) +{ + for (const auto& entry : params->list) + { + blk->local_vars.push_back({ entry->value, static_cast(blk->local_vars_create_count), true }); + blk->local_vars_create_count++; + } +} + +void decompiler::process_stmt(const ast::stmt& stmt, const block::ptr& blk) +{ + switch (stmt.kind()) + { + case ast::kind::stmt_list: + process_stmt_list(stmt.as_list, blk); + break; + case ast::kind::stmt_expr: + process_stmt_expr(stmt.as_expr, blk); + break; + case ast::kind::stmt_call: + process_stmt_call(stmt.as_call, blk); + break; + case ast::kind::stmt_assign: + process_stmt_assign(stmt.as_assign, blk); + break; + case ast::kind::stmt_endon: + process_stmt_endon(stmt.as_endon, blk); + break; + case ast::kind::stmt_notify: + process_stmt_notify(stmt.as_notify, blk); + break; + case ast::kind::stmt_wait: + process_stmt_wait(stmt.as_wait, blk); + break; + case ast::kind::stmt_waittill: + process_stmt_waittill(stmt.as_waittill, blk); + break; + case ast::kind::stmt_waittillmatch: + process_stmt_waittillmatch(stmt.as_waittillmatch, blk); + break; + case ast::kind::stmt_if: + process_stmt_if(stmt.as_if, blk); + break; + case ast::kind::stmt_ifelse: + process_stmt_ifelse(stmt.as_ifelse, blk); + break; + case ast::kind::stmt_while: + process_stmt_while(stmt.as_while, blk); + break; + case ast::kind::stmt_dowhile: + process_stmt_dowhile(stmt.as_dowhile, blk); + break; + case ast::kind::stmt_for: + process_stmt_for(stmt.as_for, blk); + break; + case ast::kind::stmt_foreach: + process_stmt_foreach(stmt.as_foreach, blk); + break; + case ast::kind::stmt_switch: + process_stmt_switch(stmt.as_switch, blk); + break; + case ast::kind::stmt_break: + process_stmt_break(stmt.as_break, blk); + break; + case ast::kind::stmt_continue: + process_stmt_continue(stmt.as_continue, blk); + break; + case ast::kind::stmt_return: + process_stmt_return(stmt.as_return, blk); + break; + case ast::kind::asm_remove: + process_var_remove(stmt.as_asm_remove, blk); + break; + case ast::kind::asm_create: + { + auto expr = ast::expr(std::make_unique(stmt.as_asm_create->index)); + process_var_create(expr, blk, true); + break; + } + default: + break; + } +} + +void decompiler::process_stmt_list(const ast::stmt_list::ptr& stmt, const block::ptr& blk) +{ + for (const auto& entry : stmt->list) + { + process_stmt(entry, blk); + } + + auto i = 0u; + + while (i < stmt->list.size()) + { + auto type = stmt->list.at(i).kind(); + + if (type == ast::kind::asm_create || type == ast::kind::asm_remove) + { + stmt->list.erase(stmt->list.begin() + i); + continue; + } + + i++; + } +} + +void decompiler::process_stmt_expr(const ast::stmt_expr::ptr& stmt, const block::ptr& blk) +{ + switch (stmt->expr.kind()) + { + case ast::kind::expr_increment: + process_expr_increment(stmt->expr.as_increment, blk); + break; + case ast::kind::expr_decrement: + process_expr_decrement(stmt->expr.as_decrement, blk); + break; + case ast::kind::expr_assign_equal: + case ast::kind::expr_assign_add: + case ast::kind::expr_assign_sub: + case ast::kind::expr_assign_mul: + case ast::kind::expr_assign_div: + case ast::kind::expr_assign_mod: + case ast::kind::expr_assign_shift_left: + case ast::kind::expr_assign_shift_right: + case ast::kind::expr_assign_bitwise_or: + case ast::kind::expr_assign_bitwise_and: + case ast::kind::expr_assign_bitwise_exor: + process_expr_assign(stmt->expr.as_assign, blk); + break; + default: + break; + } +} + +void decompiler::process_stmt_call(const ast::stmt_call::ptr& stmt, const block::ptr& blk) +{ + switch (stmt->expr.kind()) + { + case ast::kind::expr_call: + process_expr_call(stmt->expr.as_call, blk); + break; + case ast::kind::expr_method: + process_expr_method(stmt->expr.as_method, blk); + break; + default: + break; + } +} + +void decompiler::process_stmt_assign(const ast::stmt_assign::ptr& stmt, const block::ptr& blk) +{ + switch (stmt->expr.kind()) + { + case ast::kind::expr_increment: + process_expr_increment(stmt->expr.as_increment, blk); + break; + case ast::kind::expr_decrement: + process_expr_decrement(stmt->expr.as_decrement, blk); + break; + case ast::kind::expr_assign_equal: + case ast::kind::expr_assign_add: + case ast::kind::expr_assign_sub: + case ast::kind::expr_assign_mul: + case ast::kind::expr_assign_div: + case ast::kind::expr_assign_mod: + case ast::kind::expr_assign_shift_left: + case ast::kind::expr_assign_shift_right: + case ast::kind::expr_assign_bitwise_or: + case ast::kind::expr_assign_bitwise_and: + case ast::kind::expr_assign_bitwise_exor: + process_expr_assign(stmt->expr.as_assign, blk); + break; + default: + break; + } +} + +void decompiler::process_stmt_endon(const ast::stmt_endon::ptr& stmt, const block::ptr& blk) +{ + process_expr(stmt->event, blk); + process_expr(stmt->obj, blk); +} + +void decompiler::process_stmt_notify(const ast::stmt_notify::ptr& stmt, const block::ptr& blk) +{ + process_expr_arguments(stmt->args, blk); + process_expr(stmt->event, blk); + process_expr(stmt->obj, blk); +} + +void decompiler::process_stmt_wait(const ast::stmt_wait::ptr& stmt, const block::ptr& blk) +{ + process_expr(stmt->time, blk); +} + +void decompiler::process_stmt_waittill(const ast::stmt_waittill::ptr& stmt, const block::ptr& blk) +{ + process_expr(stmt->event ,blk); + process_expr(stmt->obj, blk); + + for (auto& entry : stmt->args->list) + { + process_expr(entry, blk); + } +} + +void decompiler::process_stmt_waittillmatch(const ast::stmt_waittillmatch::ptr& stmt, const block::ptr& blk) +{ + process_expr_arguments(stmt->args, blk); + process_expr(stmt->event, blk); + process_expr(stmt->obj, blk); +} + +void decompiler::process_stmt_if(const ast::stmt_if::ptr& stmt, const block::ptr& blk) +{ + process_expr(stmt->test, blk); + + stmt->blk = std::make_unique(); + blk->transfer_decompiler(stmt->blk); + + process_stmt(stmt->stmt, stmt->blk); + + if (stmt->stmt.as_list->list.size() == 1 && !stmt->stmt.as_list->list.at(0).as_node->is_special_stmt()) + { + stmt->stmt = std::move(stmt->stmt.as_list->list.back()); + } +} + +void decompiler::process_stmt_ifelse(const ast::stmt_ifelse::ptr& stmt, const block::ptr& blk) +{ + std::vector childs; + auto abort = abort_t::abort_return; + + process_expr(stmt->test, blk); + + stmt->blk_if = std::make_unique(); + blk->transfer_decompiler(stmt->blk_if); + + process_stmt(stmt->stmt_if, stmt->blk_if); + + if (stmt->blk_if->abort <= abort_t::abort_return) + { + abort = stmt->blk_if->abort; + + if (abort == abort_t::abort_none) + childs.push_back(stmt->blk_if.get()); + } + + stmt->blk_else = std::make_unique(); + blk->transfer_decompiler(stmt->blk_else); + + process_stmt(stmt->stmt_else, stmt->blk_else); + + if (stmt->blk_else->abort <= abort) + { + abort = stmt->blk_else->abort; + + if (abort == abort_t::abort_none) + childs.push_back(stmt->blk_else.get()); + } + + if (blk->abort == abort_t::abort_none) + blk->abort = abort; + + blk->append(childs); + + if (stmt->stmt_if.as_list->list.size() == 1 && !stmt->stmt_if.as_list->list.at(0).as_node->is_special_stmt()) + { + stmt->stmt_if = std::move(stmt->stmt_if.as_list->list.back()); + } + + if (stmt->stmt_else.as_list->list.size() == 1 && !stmt->stmt_else.as_list->list.at(0).as_node->is_special_stmt_noif()) + { + stmt->stmt_else = std::move(stmt->stmt_else.as_list->list.back()); + } +} + +void decompiler::process_stmt_while(const ast::stmt_while::ptr& stmt, const block::ptr& blk) +{ + process_expr(stmt->test, blk); + + stmt->blk = std::make_unique(); + blk->transfer_decompiler(stmt->blk); + + process_stmt(stmt->stmt, stmt->blk); + + std::vector childs({ stmt->blk.get() }); + + if (stmt->test.as_node->kind() == ast::kind::null) + blk->append_decompiler(stmt->blk); + + if (stmt->stmt.as_list->list.size() == 1 && !stmt->stmt.as_list->list.at(0).as_node->is_special_stmt()) + { + stmt->stmt = std::move(stmt->stmt.as_list->list.back()); + } +} + +void decompiler::process_stmt_dowhile(const ast::stmt_dowhile::ptr& stmt, const block::ptr& blk) +{ + process_expr(stmt->test, blk); + + stmt->blk = std::make_unique(); + blk->transfer_decompiler(stmt->blk); + + process_stmt(stmt->stmt, stmt->blk); + + std::vector childs({ stmt->blk.get() }); + + if (stmt->test.as_node->kind() == ast::kind::null) + blk->append_decompiler(stmt->blk); + + if (stmt->stmt.as_list->list.size() == 1 && !stmt->stmt.as_list->list.at(0).as_node->is_special_stmt()) + { + stmt->stmt = std::move(stmt->stmt.as_list->list.back()); + } +} + +void decompiler::process_stmt_for(const ast::stmt_for::ptr& stmt, const block::ptr& blk) +{ + process_stmt(stmt->init, blk); + + for (const auto& index : stmt->vars) + { + auto var = utils::string::va("var_%d", std::stoi(index)); + blk->local_vars.push_back({ var, static_cast(std::stoi(index)), true }); + blk->local_vars_create_count++; + } + + stmt->blk = std::make_unique(); + blk->transfer_decompiler(stmt->blk); + + process_expr(stmt->test, blk); + + process_stmt(stmt->stmt, stmt->blk); + + process_stmt(stmt->iter, blk); + + if (stmt->test == ast::kind::null) + blk->append_decompiler(stmt->blk); + + if (stmt->stmt.as_list->list.size() == 1 && !stmt->stmt.as_list->list.at(0).as_node->is_special_stmt()) + { + stmt->stmt = std::move(stmt->stmt.as_list->list.back()); + } +} + +void decompiler::process_stmt_foreach(const ast::stmt_foreach::ptr& stmt, const block::ptr& blk) +{ + process_stmt(stmt->pre_expr, blk); + + for (const auto& index : stmt->vars) + { + auto var1 = utils::string::va("var_%d", std::stoi(index)); + blk->local_vars.push_back({ var1, static_cast(std::stoi(index)), true }); + blk->local_vars_create_count++; + } + + stmt->ctx = std::make_unique(); + blk->transfer_decompiler(stmt->ctx); + + process_stmt(stmt->stmt0, stmt->ctx); + process_stmt(stmt->stmt, stmt->ctx); + + if (stmt->stmt.as_list->list.size() == 1 && !stmt->stmt.as_list->list.at(0).as_node->is_special_stmt()) + { + stmt->stmt = std::move(stmt->stmt.as_list->list.back()); + } + + stmt->array_expr = std::move(stmt->pre_expr.as_list->list[0].as_assign->expr.as_assign->rvalue); + stmt->value_expr = std::move(stmt->stmt0.as_assign->expr.as_assign->lvalue); + stmt->key_expr = std::move(stmt->pre_expr.as_list->list[1].as_assign->expr.as_assign->lvalue); +} + +void decompiler::process_stmt_switch(const ast::stmt_switch::ptr& stmt, const block::ptr& blk) +{ + process_expr(stmt->test, blk); + + stmt->ctx = std::make_unique(); + blk->transfer_decompiler(stmt->ctx); + + process_stmt_cases(stmt->stmt, stmt->ctx); + + blk->append_decompiler(stmt->ctx, true); +} + +void decompiler::process_stmt_cases(const ast::stmt_list::ptr& stmt, const block::ptr& blk) +{ + std::vector childs; + bool has_default = false; + + for (const auto& entry : stmt->list) + { + if (entry == ast::kind::stmt_case) + { + entry.as_case->blk = std::make_unique(); + blk->transfer_decompiler(entry.as_case->blk); + + process_stmt_list(entry.as_case->stmt, entry.as_case->blk); + + if (entry.as_case->blk->abort == abort_t::abort_break) + { + childs.push_back(entry.as_case->blk.get()); + } + } + else if (entry == ast::kind::stmt_default) + { + has_default = true; + entry.as_default->blk = std::make_unique(); + blk->transfer_decompiler(entry.as_default->blk); + + process_stmt_list(entry.as_default->stmt, entry.as_default->blk); + + if (entry.as_default->blk->abort == abort_t::abort_break) + { + childs.push_back(entry.as_default->blk.get()); + } + } + } + + if (has_default) + { + blk->append(childs); + } +} + +void decompiler::process_stmt_break(const ast::stmt_break::ptr&, const block::ptr& blk) +{ + if (blk->abort == abort_t::abort_none) + { + blk->abort = abort_t::abort_break; + } +} + +void decompiler::process_stmt_continue(const ast::stmt_continue::ptr&, const block::ptr& blk) +{ + if (blk->abort == abort_t::abort_none) + { + blk->abort = abort_t::abort_continue; + } +} + +void decompiler::process_stmt_return(const ast::stmt_return::ptr& stmt, const block::ptr& blk) +{ + if (blk->abort == abort_t::abort_none) + { + blk->abort = abort_t::abort_return; + } + + if (stmt->expr != ast::kind::null) + { + process_expr(stmt->expr, blk); + } +} + +void decompiler::process_expr(ast::expr& expr, const block::ptr& blk) +{ + switch (expr.kind()) + { + case ast::kind::expr_ternary: + process_expr_ternary(expr.as_ternary, blk); + break; + case ast::kind::expr_and: + process_expr_and(expr.as_and, blk); + break; + case ast::kind::expr_or: + process_expr_or(expr.as_or, blk); + break; + case ast::kind::expr_equality: + case ast::kind::expr_inequality: + case ast::kind::expr_less: + case ast::kind::expr_greater: + case ast::kind::expr_less_equal: + case ast::kind::expr_greater_equal: + case ast::kind::expr_bitwise_or: + case ast::kind::expr_bitwise_and: + case ast::kind::expr_bitwise_exor: + case ast::kind::expr_shift_left: + case ast::kind::expr_shift_right: + case ast::kind::expr_add: + case ast::kind::expr_sub: + case ast::kind::expr_mul: + case ast::kind::expr_div: + case ast::kind::expr_mod: + process_expr_binary(expr.as_binary, blk); + break; + case ast::kind::expr_complement: + process_expr_complement(expr.as_complement, blk); + break; + case ast::kind::expr_not: + process_expr_not(expr.as_not, blk); + break; + case ast::kind::expr_call: + process_expr_call(expr.as_call, blk); + break; + case ast::kind::expr_method: + process_expr_method(expr.as_method, blk); + break; + case ast::kind::expr_isdefined: + process_expr(expr.as_isdefined->expr, blk); + break; + case ast::kind::expr_istrue: + process_expr(expr.as_istrue->expr, blk); + break; + case ast::kind::expr_add_array: + process_expr_add_array(expr.as_add_array, blk); + break; + case ast::kind::expr_size: + process_expr_size(expr.as_size, blk); + break; + case ast::kind::expr_tuple: + process_expr_tuple(expr.as_tuple, blk); + break; + case ast::kind::expr_array: + process_expr_array(expr.as_array, blk); + break; + case ast::kind::expr_field: + process_expr_field(expr.as_field, blk); + break; + case ast::kind::expr_vector: + process_expr_vector(expr.as_vector, blk); + break; + case ast::kind::asm_create: + process_var_create(expr, blk); + break; + case ast::kind::asm_access: + process_var_access(expr, blk); + break; + default: + break; + } +} + +void decompiler::process_expr_assign(ast::expr_assign::ptr& expr, const block::ptr& blk) +{ + process_expr(expr->rvalue, blk); + process_expr(expr->lvalue, blk); + + if (expr->kind() == ast::kind::expr_assign_equal) + { + switch (expr->rvalue.kind()) + { + case ast::kind::expr_bitwise_or: + if (expr->lvalue == expr->rvalue.as_bitwise_or->lvalue) + expr = std::make_unique(std::move(expr->lvalue), std::move(expr->rvalue.as_bitwise_or->rvalue)); + break; + case ast::kind::expr_bitwise_and: + if (expr->lvalue == expr->rvalue.as_bitwise_and->lvalue) + expr = std::make_unique(std::move(expr->lvalue), std::move(expr->rvalue.as_bitwise_and->rvalue)); + break; + case ast::kind::expr_bitwise_exor: + if (expr->lvalue == expr->rvalue.as_bitwise_exor->lvalue) + expr = std::make_unique(std::move(expr->lvalue), std::move(expr->rvalue.as_bitwise_exor->rvalue)); + break; + case ast::kind::expr_shift_left: + if (expr->lvalue == expr->rvalue.as_shift_left->lvalue) + expr = std::make_unique(std::move(expr->lvalue), std::move(expr->rvalue.as_shift_left->rvalue)); + break; + case ast::kind::expr_shift_right: + if (expr->lvalue == expr->rvalue.as_shift_right->lvalue) + expr = std::make_unique(std::move(expr->lvalue), std::move(expr->rvalue.as_shift_right->rvalue)); + break; + case ast::kind::expr_add: + if (expr->lvalue == expr->rvalue.as_add->lvalue) + expr = std::make_unique(std::move(expr->lvalue), std::move(expr->rvalue.as_add->rvalue)); + break; + case ast::kind::expr_sub: + if (expr->lvalue == expr->rvalue.as_sub->lvalue) + expr = std::make_unique(std::move(expr->lvalue), std::move(expr->rvalue.as_sub->rvalue)); + break; + case ast::kind::expr_mul: + if (expr->lvalue == expr->rvalue.as_mul->lvalue) + expr = std::make_unique(std::move(expr->lvalue), std::move(expr->rvalue.as_mul->rvalue)); + break; + case ast::kind::expr_div: + if (expr->lvalue == expr->rvalue.as_div->lvalue) + expr = std::make_unique(std::move(expr->lvalue), std::move(expr->rvalue.as_div->rvalue)); + break; + case ast::kind::expr_mod: + if (expr->lvalue == expr->rvalue.as_mod->lvalue) + expr = std::make_unique(std::move(expr->lvalue), std::move(expr->rvalue.as_mod->rvalue)); + break; + default: + break; + } + } +} + +void decompiler::process_expr_increment(const ast::expr_increment::ptr& expr, const block::ptr& blk) +{ + process_expr(expr->lvalue, blk); +} + +void decompiler::process_expr_decrement(const ast::expr_decrement::ptr& expr, const block::ptr& blk) +{ + process_expr(expr->lvalue, blk); +} + +void decompiler::process_expr_ternary(const ast::expr_ternary::ptr& expr, const block::ptr& blk) +{ + process_expr(expr->test, blk); + process_expr(expr->true_expr, blk); + process_expr(expr->false_expr, blk); +} + +void decompiler::process_expr_binary(const ast::expr_binary::ptr& expr, const block::ptr& blk) +{ + process_expr(expr->lvalue, blk); + process_expr(expr->rvalue, blk); + + auto prec = expr->lvalue.as_node->precedence(); + + if (prec && prec < expr->precedence()) + { + expr->lvalue = ast::expr(std::make_unique(std::move(expr->lvalue))); + } + + prec = expr->rvalue.as_node->precedence(); + + if ((prec && prec < expr->precedence()) || (prec == expr->precedence() && expr->kind() == expr->rvalue.as_node->kind())) + { + expr->rvalue = ast::expr(std::make_unique(std::move(expr->rvalue))); + } +} + +void decompiler::process_expr_and(const ast::expr_and::ptr& expr, const block::ptr& blk) +{ + process_expr(expr->lvalue, blk); + process_expr(expr->rvalue, blk); + + auto prec = expr->lvalue.as_node->precedence(); + + if (prec && prec < expr->precedence()) + { + expr->lvalue = ast::expr(std::make_unique(std::move(expr->lvalue))); + } + + prec = expr->rvalue.as_node->precedence(); + + if ((prec && prec < expr->precedence()) || (prec == expr->precedence() && expr->kind() == expr->rvalue.kind())) + { + expr->rvalue = ast::expr(std::make_unique(std::move(expr->rvalue))); + } +} + +void decompiler::process_expr_or(const ast::expr_or::ptr& expr, const block::ptr& blk) +{ + process_expr(expr->lvalue, blk); + process_expr(expr->rvalue, blk); +} + +void decompiler::process_expr_complement(const ast::expr_complement::ptr& expr, const block::ptr& blk) +{ + process_expr(expr->rvalue, blk); + + if (expr->rvalue.as_node->is_binary()) + { + expr->rvalue = ast::expr(std::make_unique(std::move(expr->rvalue))); + } +} + +void decompiler::process_expr_not(const ast::expr_not::ptr& expr, const block::ptr& blk) +{ + process_expr(expr->rvalue, blk); + + if (expr->rvalue.as_node->is_binary()) + { + expr->rvalue = ast::expr(std::make_unique(std::move(expr->rvalue))); + } +} + +void decompiler::process_expr_call(const ast::expr_call::ptr& expr, const block::ptr& blk) +{ + switch (expr->call.kind()) + { + case ast::kind::expr_pointer: + process_expr_call_pointer(expr->call.as_pointer, blk); + break; + case ast::kind::expr_function: + process_expr_call_function(expr->call.as_function, blk); + break; + default: + break; + } +} + +void decompiler::process_expr_method(const ast::expr_method::ptr& expr, const block::ptr& blk) +{ + switch (expr->call.kind()) + { + case ast::kind::expr_pointer: + process_expr_method_pointer(expr->call.as_pointer, expr->obj, blk); + break; + case ast::kind::expr_function: + process_expr_method_function(expr->call.as_function, expr->obj, blk); + break; + default: + break; + } +} + +void decompiler::process_expr_call_pointer(const ast::expr_pointer::ptr& expr, const block::ptr& blk) +{ + process_expr_arguments(expr->args, blk); + process_expr(expr->func, blk); +} + +void decompiler::process_expr_call_function(const ast::expr_function::ptr& expr, const block::ptr& blk) +{ + process_expr_arguments(expr->args, blk); +} + +void decompiler::process_expr_method_pointer(const ast::expr_pointer::ptr& expr, ast::expr& obj, const block::ptr& blk) +{ + process_expr_arguments(expr->args, blk); + process_expr(obj, blk); + process_expr(expr->func, blk); +} + +void decompiler::process_expr_method_function(const ast::expr_function::ptr& expr, ast::expr& obj, const block::ptr& blk) +{ + process_expr_arguments(expr->args, blk); + process_expr(obj, blk); +} + +void decompiler::process_expr_arguments(const ast::expr_arguments::ptr& expr, const block::ptr& blk) +{ + for (auto i = expr->list.size(); i > 0; i--) + { + process_expr(expr->list.at(i - 1), blk); + } +} + +void decompiler::process_expr_add_array(const ast::expr_add_array::ptr& expr, const block::ptr& blk) +{ + for (auto& entry : expr->args->list) + { + process_expr(entry, blk); + } +} + +void decompiler::process_expr_size(const ast::expr_size::ptr& expr, const block::ptr& blk) +{ + process_expr(expr->obj, blk); +} + +void decompiler::process_expr_tuple(const ast::expr_tuple::ptr& expr, const block::ptr& blk) +{ + process_expr(expr->temp, blk); + + for (auto& entry : expr->list) + { + process_expr(entry, blk); + } +} + +void decompiler::process_expr_array(const ast::expr_array::ptr& expr, const block::ptr& blk) +{ + process_expr(expr->key, blk); + process_expr(expr->obj, blk); +} + +void decompiler::process_expr_field(const ast::expr_field::ptr& expr, const block::ptr& blk) +{ + process_expr(expr->obj, blk); +} + +void decompiler::process_expr_vector(const ast::expr_vector::ptr& vec, const block::ptr& blk) +{ + process_expr(vec->z, blk); + process_expr(vec->y, blk); + process_expr(vec->x, blk); +} + +void decompiler::process_var_create(ast::expr& expr, const block::ptr& blk, bool fromstmt) +{ + if (fromstmt) + { + auto var = utils::string::va("var_%s", expr.as_asm_create->index.data()); + blk->local_vars.push_back({ var, static_cast(blk->local_vars_create_count), true }); + blk->local_vars_create_count++; + } + else + { + for (const auto& entry : expr.as_asm_create->vars) + { + blk->local_vars.push_back({ utils::string::va("var_%s", entry.data()), static_cast(blk->local_vars_create_count), true }); + blk->local_vars_create_count++; + } + + auto var = utils::string::va("var_%s", expr.as_asm_create->index.data()); + blk->local_vars.push_back({ var, static_cast(blk->local_vars_create_count), true }); + blk->local_vars_create_count++; + + expr = ast::expr(std::make_unique(var)); + } +} + +void decompiler::process_var_access(ast::expr& expr, const block::ptr& blk) +{ + if (blk->local_vars.size() <= std::stoul(expr.as_asm_access->index)) + { + std::cout << "WARNING: bad local var access\n"; + } + else + { + auto var = blk->local_vars.at(blk->local_vars.size() - 1 - std::stoi(expr.as_asm_access->index)).name; + expr = ast::expr(std::make_unique(var)); + } +} + +void decompiler::process_var_remove(const ast::asm_remove::ptr& expr, const block::ptr& blk) +{ + blk->local_vars_public_count = static_cast(blk->local_vars.size() - std::stoi(expr->index)); +} + +} // namespace xsk::gsc::iw9 diff --git a/src/iw9/xsk/decompiler.hpp b/src/iw9/xsk/decompiler.hpp new file mode 100644 index 00000000..09886c7e --- /dev/null +++ b/src/iw9/xsk/decompiler.hpp @@ -0,0 +1,101 @@ +// Copyright 2022 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::iw9 +{ + +class decompiler : public gsc::decompiler +{ + std::string filename_; + ast::program::ptr program_; + ast::decl_thread::ptr func_; + std::unordered_map labels_; + std::vector expr_labels_; + std::vector tern_labels_; + std::stack stack_; + std::vector blocks_; + bool in_waittill_; + +public: + auto output() -> std::vector; + void decompile(const std::string& file, std::vector& funcs); + +private: + void decompile_function(const function::ptr& func); + void decompile_instruction(const instruction::ptr& inst); + void decompile_expressions(const instruction::ptr& inst); + void decompile_statements(const ast::stmt_list::ptr& stmt); + void decompile_loops(const ast::stmt_list::ptr& stmt); + void decompile_switches(const ast::stmt_list::ptr& stmt); + void decompile_ifelses(const ast::stmt_list::ptr& stmt); + void decompile_aborts(const ast::stmt_list::ptr& stmt); + void decompile_tuples(const ast::stmt_list::ptr& stmt); + void decompile_if(const ast::stmt_list::ptr& stmt, std::size_t begin, std::size_t end); + void decompile_ifelse(const ast::stmt_list::ptr& stmt, std::size_t begin, std::size_t end); + void decompile_ifelse_end(const ast::stmt_list::ptr& stmt, std::size_t begin, std::size_t end); + void decompile_inf(const ast::stmt_list::ptr& stmt, std::size_t begin, std::size_t end); + void decompile_loop(const ast::stmt_list::ptr& stmt, std::size_t begin, std::size_t end); + void decompile_while(const ast::stmt_list::ptr& stmt, std::size_t begin, std::size_t end); + void decompile_dowhile(const ast::stmt_list::ptr& stmt, std::size_t begin, std::size_t end); + void decompile_for(const ast::stmt_list::ptr& stmt, std::size_t begin, std::size_t end); + void decompile_foreach(const ast::stmt_list::ptr& stmt, std::size_t begin, std::size_t end); + void decompile_switch(const ast::stmt_list::ptr& stmt, std::size_t begin); + auto find_location_reference(const ast::stmt_list::ptr& stmt, std::size_t begin, std::size_t end, const std::string& location) -> bool; + auto find_location_index(const ast::stmt_list::ptr& stmt, const std::string& location) -> std::size_t; + auto last_location_index(const ast::stmt_list::ptr& stmt, std::size_t index) -> bool; + void process_stack(const ast::decl_thread::ptr& thread); + void process_parameters(const ast::expr_parameters::ptr& params, const block::ptr& blk); + void process_stmt(const ast::stmt& stmt, const block::ptr& blk); + void process_stmt_list(const ast::stmt_list::ptr& stmt, const block::ptr& blk); + void process_stmt_expr(const ast::stmt_expr::ptr& stmt, const block::ptr& blk); + void process_stmt_call(const ast::stmt_call::ptr& stmt, const block::ptr& blk); + void process_stmt_assign(const ast::stmt_assign::ptr& stmt, const block::ptr& blk); + void process_stmt_endon(const ast::stmt_endon::ptr& stmt, const block::ptr& blk); + void process_stmt_notify(const ast::stmt_notify::ptr& stmt, const block::ptr& blk); + void process_stmt_wait(const ast::stmt_wait::ptr& stmt, const block::ptr& blk); + void process_stmt_waittill(const ast::stmt_waittill::ptr& stmt, const block::ptr& blk); + void process_stmt_waittillmatch(const ast::stmt_waittillmatch::ptr& stmt, const block::ptr& blk); + void process_stmt_if(const ast::stmt_if::ptr& stmt, const block::ptr& blk); + void process_stmt_ifelse(const ast::stmt_ifelse::ptr& stmt, const block::ptr& blk); + void process_stmt_while(const ast::stmt_while::ptr& stmt, const block::ptr& blk); + void process_stmt_dowhile(const ast::stmt_dowhile::ptr& stmt, const block::ptr& blk); + void process_stmt_for(const ast::stmt_for::ptr& stmt, const block::ptr& blk); + void process_stmt_foreach(const ast::stmt_foreach::ptr& stmt, const block::ptr& blk); + void process_stmt_switch(const ast::stmt_switch::ptr& stmt, const block::ptr& blk); + void process_stmt_cases(const ast::stmt_list::ptr& stmt, const block::ptr& blk); + void process_stmt_break(const ast::stmt_break::ptr& stmt, const block::ptr& blk); + void process_stmt_continue(const ast::stmt_continue::ptr& stmt, const block::ptr& blk); + void process_stmt_return(const ast::stmt_return::ptr& stmt, const block::ptr& blk); + void process_expr(ast::expr& expr, const block::ptr& blk); + void process_expr_assign(ast::expr_assign::ptr& expr, const block::ptr& blk); + void process_expr_increment(const ast::expr_increment::ptr& expr, const block::ptr& blk); + void process_expr_decrement(const ast::expr_decrement::ptr& expr, const block::ptr& blk); + void process_expr_ternary(const ast::expr_ternary::ptr& expr, const block::ptr& blk); + void process_expr_binary(const ast::expr_binary::ptr& expr, const block::ptr& blk); + void process_expr_and(const ast::expr_and::ptr& expr, const block::ptr& blk); + void process_expr_or(const ast::expr_or::ptr& expr, const block::ptr& blk); + void process_expr_complement(const ast::expr_complement::ptr& expr, const block::ptr& blk); + void process_expr_not(const ast::expr_not::ptr& expr, const block::ptr& blk); + void process_expr_call(const ast::expr_call::ptr& expr, const block::ptr& blk); + void process_expr_method(const ast::expr_method::ptr& expr, const block::ptr& blk); + void process_expr_call_pointer(const ast::expr_pointer::ptr& expr, const block::ptr& blk); + void process_expr_call_function(const ast::expr_function::ptr& expr, const block::ptr& blk); + void process_expr_method_pointer(const ast::expr_pointer::ptr& expr, ast::expr& obj, const block::ptr& blk); + void process_expr_method_function(const ast::expr_function::ptr& expr, ast::expr& obj, const block::ptr& blk); + void process_expr_arguments(const ast::expr_arguments::ptr& expr, const block::ptr& blk); + void process_expr_add_array(const ast::expr_add_array::ptr& expr, const block::ptr& blk); + void process_expr_size(const ast::expr_size::ptr& expr, const block::ptr& blk); + void process_expr_tuple(const ast::expr_tuple::ptr& expr, const block::ptr& blk); + void process_expr_array(const ast::expr_array::ptr& expr, const block::ptr& blk); + void process_expr_field(const ast::expr_field::ptr& expr, const block::ptr& blk); + void process_expr_vector(const ast::expr_vector::ptr& vec, const block::ptr& blk); + void process_var_create(ast::expr& expr, const block::ptr& blk, bool fromstmt = false); + void process_var_access(ast::expr& expr, const block::ptr& blk); + void process_var_remove(const ast::asm_remove::ptr& expr, const block::ptr& blk); +}; + +} // namespace xsk::gsc::iw9 diff --git a/src/iw9/xsk/disassembler.cpp b/src/iw9/xsk/disassembler.cpp index 602991ab..3a64adab 100644 --- a/src/iw9/xsk/disassembler.cpp +++ b/src/iw9/xsk/disassembler.cpp @@ -50,8 +50,7 @@ void disassembler::disassemble(const std::string& file, std::vectorindex = static_cast(script_->pos()); func->size = stack_->read(); - func->id = stack_->read(); - func->name = func->id == 0 ? decrypt_string(stack_->read_c_string()) : resolver::token_name(func->id); + func->name = utils::string::va("id_%016llX", stack_->read()); dissasemble_function(func); @@ -64,7 +63,7 @@ void disassembler::disassemble(const std::string& file, std::vectorsize; + auto size = static_cast(func->size); while (size > 0) { @@ -78,17 +77,243 @@ void disassembler::dissasemble_function(const function::ptr& func) dissasemble_instruction(inst); size -= inst->size; + + if (inst->index + inst->size != script_->pos()) + { + throw error("wrong inst size"); + } + + if (size < 0) + { + throw error("wrong func size"); + } } } void disassembler::dissasemble_instruction(const instruction::ptr& inst) { - /*switch (static_cast(inst->opcode)) + switch (static_cast(inst->opcode)) { - + case opcode::OP_CastFieldObject: + case opcode::OP_plus: + case opcode::OP_GetGameRef: + case opcode::OP_GetThisthread: + case opcode::OP_greater: + case opcode::OP_shift_right: + case opcode::OP_dec: + case opcode::OP_bit_or: + case opcode::OP_equality: + case opcode::OP_ClearLocalVariableFieldCached0: + case opcode::OP_notify: + case opcode::OP_PreScriptCall: + case opcode::OP_GetUndefined: + case opcode::OP_SetLocalVariableFieldCached0: + case opcode::OP_GetLevel: + case opcode::OP_size: + case opcode::OP_AddArray: + case opcode::OP_endon: + case opcode::OP_shift_left: + case opcode::OP_EvalLocalArrayRefCached0: + case opcode::OP_Return: + case opcode::OP_SafeSetVariableFieldCached0: + case opcode::OP_GetSelfObject: + case opcode::OP_GetGame: + case opcode::OP_EvalArray: + case opcode::OP_GetSelf: + case opcode::OP_End: + case opcode::OP_less_equal: + case opcode::OP_EvalLocalVariableCached0: + case opcode::OP_EvalLocalVariableCached1: + case opcode::OP_EvalLocalVariableCached2: + case opcode::OP_EvalLocalVariableCached3: + case opcode::OP_EvalLocalVariableCached4: + case opcode::OP_EvalLocalVariableCached5: + case opcode::OP_ScriptMethodCallPointer: + case opcode::OP_checkclearparams: + case opcode::OP_minus: + case opcode::OP_greater_equal: + case opcode::OP_vector: + case opcode::OP_ClearArray: + case opcode::OP_DecTop: + case opcode::OP_CastBool: + case opcode::OP_EvalArrayRef: + case opcode::OP_GetZero: + case opcode::OP_wait: + case opcode::OP_waittill: + case opcode::OP_GetAnimObject: + case opcode::OP_mod: + case opcode::OP_clearparams: + case opcode::OP_ScriptFunctionCallPointer: + case opcode::OP_EmptyArray: + case opcode::OP_BoolComplement: + case opcode::OP_less: + case opcode::OP_BoolNot: + case opcode::OP_waittillFrameEnd: + case opcode::OP_waitframe: + case opcode::OP_GetLevelObject: + case opcode::OP_inc: + case opcode::OP_GetAnim: + case opcode::OP_SetVariableField: + case opcode::OP_divide: + case opcode::OP_multiply: + case opcode::OP_EvalLocalVariableRefCached0: + case opcode::OP_bit_and: + case opcode::OP_voidCodepos: + case opcode::OP_inequality: + case opcode::OP_bit_ex_or: + case opcode::OP_unk_139: + case opcode::OP_BoolNotAfterAnd: + case opcode::OP_IsDefined: + case opcode::OP_IsTrue: + break; + case opcode::OP_GetByte: + case opcode::OP_GetNegByte: + inst->data.push_back(utils::string::va("%i", script_->read())); + break; + case opcode::OP_GetUnsignedShort: + case opcode::OP_GetNegUnsignedShort: + inst->data.push_back(utils::string::va("%i", script_->read())); + break; + case opcode::OP_GetInteger: + inst->data.push_back(utils::string::va("%i", script_->read())); + break; + case opcode::OP_GetFloat: + inst->data.push_back(utils::string::float_string(script_->read())); + break; + case opcode::OP_GetVector: + inst->data.push_back(utils::string::float_string(script_->read())); + inst->data.push_back(utils::string::float_string(script_->read())); + inst->data.push_back(utils::string::float_string(script_->read())); + break; + case opcode::OP_GetString: + case opcode::OP_GetIString: + script_->seek(4); + inst->data.push_back(utils::string::quote(stack_->read_c_string(), false)); + break; + case opcode::OP_GetAnimTree: + script_->seek(1); + inst->data.push_back(utils::string::quote(stack_->read_c_string(), false)); + break; + case opcode::OP_GetAnimation: + script_->seek(8); + inst->data.push_back(utils::string::quote(stack_->read_c_string(), false)); + inst->data.push_back(utils::string::quote(stack_->read_c_string(), false)); + break; + case opcode::OP_waittillmatch: + inst->data.push_back(utils::string::va("%i", script_->read())); + inst->data.push_back(utils::string::va("%i", script_->read())); + break; + case opcode::OP_EvalSelfFieldVariableRef: + case opcode::OP_EvalAnimFieldVariable: + case opcode::OP_EvalLevelFieldVariableRef: + case opcode::OP_SetSelfFieldVariableField: + case opcode::OP_ClearFieldVariable: + case opcode::OP_EvalFieldVariable: + case opcode::OP_SetLevelFieldVariableField: + case opcode::OP_EvalSelfFieldVariable: + case opcode::OP_SetAnimFieldVariableField: + case opcode::OP_EvalFieldVariableRef: + case opcode::OP_EvalLevelFieldVariable: + case opcode::OP_EvalAnimFieldVariableRef: + inst->data.push_back(utils::string::va("id_%016llX", script_->read())); + break; + case opcode::OP_CreateLocalVariable: + case opcode::OP_EvalNewLocalArrayRefCached0: + case opcode::OP_SafeCreateVariableFieldCached: + case opcode::OP_SetNewLocalVariableFieldCached0: + inst->data.push_back(utils::string::va("%016llX", script_->read())); + break; + case opcode::OP_SetLocalVariableFieldCached: + case opcode::OP_RemoveLocalVariables: + case opcode::OP_SafeSetWaittillVariableFieldCached: + case opcode::OP_EvalLocalVariableCached: + case opcode::OP_EvalLocalVariableObjectCached: + case opcode::OP_EvalLocalArrayCached: + case opcode::OP_SafeSetVariableFieldCached: + case opcode::OP_EvalLocalVariableRefCached: + case opcode::OP_ClearLocalVariableFieldCached: + case opcode::OP_EvalLocalArrayRefCached: + inst->data.push_back(utils::string::va("%i", script_->read())); + break; + case opcode::OP_ScriptMethodChildThreadCallPointer: + case opcode::OP_CallBuiltinMethodPointer: + case opcode::OP_ScriptChildThreadCallPointer: + case opcode::OP_ScriptMethodThreadCallPointer: + case opcode::OP_ScriptThreadCallPointer: + case opcode::OP_CallBuiltinPointer: + inst->data.push_back(utils::string::va("%i", script_->read())); + break; + case opcode::OP_GetFarFunction: + case opcode::OP_ScriptFarFunctionCall: + case opcode::OP_ScriptFarMethodCall: + disassemble_far_call(inst, false); + break; + case opcode::OP_ScriptFarThreadCall: + case opcode::OP_ScriptFarChildThreadCall: + case opcode::OP_ScriptFarMethodThreadCall: + case opcode::OP_ScriptFarMethodChildThreadCall: + disassemble_far_call(inst, true); + break; + case opcode::OP_CallBuiltin: + disassemble_builtin_call(inst, false, true); + break; + case opcode::OP_CallBuiltinMethod: + disassemble_builtin_call(inst, true, true); + break; + case opcode::OP_GetBuiltinFunction: + disassemble_builtin_call(inst, false, false); + break; + case opcode::OP_GetBuiltinMethod: + disassemble_builtin_call(inst, true, false); + break; + case opcode::OP_JumpOnFalse: + case opcode::OP_JumpOnTrue: + case opcode::OP_JumpOnFalseExpr: + case opcode::OP_JumpOnTrueExpr: + disassemble_jump(inst, true, false); + break; + case opcode::OP_jumpback: + disassemble_jump(inst, false, true); + break; + case opcode::OP_jump: + disassemble_jump(inst, false, false); + break; + case opcode::OP_switch: + disassemble_switch(inst); + break; + case opcode::OP_endswitch: + disassemble_end_switch(inst); + break; +/* case opcode::OP_prof_begin: + script_->seek(5); // TODO: skipped data + break; + case opcode::OP_prof_end: + script_->seek(1); // TODO: skipped data + break; + case opcode::OP_EvalNewLocalArrayRefCached0_Precompiled: + case opcode::OP_SetNewLocalVariableFieldCached0_Precompiled: + case opcode::OP_CreateLocalVariable_Precompiled: + case opcode::OP_SafeCreateVariableFieldCached_Precompiled: + script_->seek(8); // TODO: skipped data + break;*/ + case opcode::OP_NativeGetFarFunction: + case opcode::OP_NativeFarFunctionCall: + case opcode::OP_NativeFarMethodCall: + disassemble_native_call(inst, false); + break; + case opcode::OP_NativeFarFunctionThreadCall: + case opcode::OP_NativeFarMethodThreadCall: + case opcode::OP_NativeFarFunctionChildThreadCall: + case opcode::OP_NativeFarMethodChildThreadCall: + disassemble_native_call(inst, true); + break; + case opcode::OP_FormalParams: + case opcode::OP_FormalParams_Precompiled: + disassemble_formal_params(inst); + break; default: throw disasm_error(utils::string::va("unhandled opcode 0x%X at index '%04X'!", inst->opcode, inst->index)); - }*/ + } } void disassembler::disassemble_builtin_call(const instruction::ptr& inst, bool method, bool args) @@ -98,39 +323,55 @@ void disassembler::disassemble_builtin_call(const instruction::ptr& inst, bool m inst->data.push_back(utils::string::va("%i", script_->read())); } - const auto id = script_->read(); - const auto name = method ? resolver::method_name(id) : resolver::function_name(id); - inst->data.emplace(inst->data.begin(), name); + if (method) // TODO + { + auto str = stack_->read_c_string(); + script_->seek(2); + inst->data.emplace(inst->data.begin(), str); + } + else + { + auto str = stack_->read_c_string(); + script_->seek(2); + inst->data.emplace(inst->data.begin(), str); + } } -void disassembler::disassemble_local_call(const instruction::ptr& inst, bool thread) +void disassembler::disassemble_native_call(const instruction::ptr& inst, bool thread) { - const auto offset = disassemble_offset(); - - inst->data.push_back(utils::string::va("%X", offset + inst->index + 1)); + script_->seek(4); if (thread) { inst->data.push_back(utils::string::va("%i", script_->read())); } + + inst->data.emplace(inst->data.begin(), utils::string::va("%08X", stack_->read())); } void disassembler::disassemble_far_call(const instruction::ptr& inst, bool thread) { - script_->seek(3); + auto offs = script_->read(); if (thread) { inst->data.push_back(utils::string::va("%i", script_->read())); } - const auto file_id = stack_->read(); - const auto file_name = file_id == 0 ? decrypt_string(stack_->read_c_string()) : resolver::token_name(file_id); - const auto func_id = stack_->read(); - const auto func_name = func_id == 0 ? decrypt_string(stack_->read_c_string()) : resolver::token_name(func_id); + auto file = stack_->read(); + auto name = stack_->read(); - inst->data.emplace(inst->data.begin(), func_name); - inst->data.emplace(inst->data.begin(), file_name); + if (file == 0) + { + + inst->data.emplace(inst->data.begin(), ""); + inst->data.push_back(utils::string::va("%X", offs + inst->index + 1)); + } + else + { + inst->data.emplace(inst->data.begin(), utils::string::va("id_%016llX", file)); + inst->data.emplace(inst->data.begin(), utils::string::va("id_%016llX", name)); + } } void disassembler::disassemble_switch(const instruction::ptr& inst) @@ -154,65 +395,57 @@ void disassembler::disassemble_end_switch(const instruction::ptr& inst) for (auto i = count; i > 0; i--) { const auto value = script_->read(); + const auto offs = script_->read(); + script_->seek(1); + const auto byte = script_->read(); + + if (byte == 2) + { + auto str = stack_->read_c_string(); - if (value < 0x100000 && value > 0) - { - inst->data.push_back("case"); - inst->data.push_back(utils::string::quote(decrypt_string(stack_->read_c_string()), false)); - } - else if (value == 0) - { - inst->data.push_back("default"); - stack_->read_c_string(); // this should be always [0x01 0x00] unencrypted + if (str[0] == 1) + { + inst->data.push_back("default"); + } + else + { + inst->data.push_back("case"); + inst->data.push_back(utils::string::quote(str, false)); + } } else { inst->data.push_back("case"); - inst->data.push_back(utils::string::va("%i", (value - 0x800000) & 0xFFFFFF)); + inst->data.push_back(utils::string::va("%i", value)); } - index += 4; - - const auto addr = disassemble_offset() + index; + const auto addr = index + 4 + offs; const auto label = utils::string::va("loc_%X", addr); inst->data.push_back(label); labels_.insert({ addr, label }); - index += 3; - inst->size += 7; + index += 8; + inst->size += 8; } } } void disassembler::disassemble_field_variable(const instruction::ptr& inst) { - const auto id = script_->read(); - std::string name; - - if (id > max_string_id) - { - auto temp = stack_->read(); - name = temp == 0 ? decrypt_string(stack_->read_c_string()) : std::to_string(temp); - } - else - { - name = resolver::token_name(id); - } - - inst->data.push_back(name); + inst->data.push_back(utils::string::va("id_%016llX", script_->read())); } void disassembler::disassemble_formal_params(const instruction::ptr& inst) { const auto count = script_->read(); - inst->size += count; + inst->size += count * 8; inst->data.push_back(utils::string::va("%i", count)); for (auto i = 0u; i < count; i++) { - inst->data.push_back(utils::string::va("%d", script_->read())); + inst->data.push_back(utils::string::va("%016llX", script_->read())); } } @@ -222,7 +455,7 @@ void disassembler::disassemble_jump(const instruction::ptr& inst, bool expr, boo if (expr) { - addr = inst->index + 3 + script_->read(); + addr = inst->index + 3 + script_->read(); } else if (back) { @@ -239,43 +472,27 @@ void disassembler::disassemble_jump(const instruction::ptr& inst, bool expr, boo labels_.insert({ addr, label }); } -auto disassembler::disassemble_offset() -> std::int32_t -{ - std::array bytes = {}; - - for (auto i = 0; i < 3; i++) - { - bytes[i] = script_->read(); - } - - auto offset = *reinterpret_cast(bytes.data()); - - offset = (offset << 8) >> 8; - - return offset; -} - void disassembler::resolve_local_functions() { for (const auto& func : functions_) { for (const auto& inst : func->instructions) { - /*switch (static_cast(inst->opcode)) + switch (static_cast(inst->opcode)) { - case opcode::OP_GetLocalFunction: - case opcode::OP_ScriptLocalFunctionCall: - case opcode::OP_ScriptLocalFunctionCall2: - case opcode::OP_ScriptLocalMethodCall: - case opcode::OP_ScriptLocalThreadCall: - case opcode::OP_ScriptLocalChildThreadCall: - case opcode::OP_ScriptLocalMethodThreadCall: - case opcode::OP_ScriptLocalMethodChildThreadCall: - inst->data[0] = resolve_function(inst->data[0]); - break; - default: - break; - }*/ + case opcode::OP_GetFarFunction: + case opcode::OP_ScriptFarFunctionCall: + case opcode::OP_ScriptFarMethodCall: + case opcode::OP_ScriptFarThreadCall: + case opcode::OP_ScriptFarChildThreadCall: + case opcode::OP_ScriptFarMethodThreadCall: + case opcode::OP_ScriptFarMethodChildThreadCall: + if (inst->data[0].empty()) + inst->data[1] = resolve_function(inst->data[1]); + break; + default: + break; + } } } } @@ -300,27 +517,10 @@ auto disassembler::resolve_function(const std::string& index) -> std::string throw disasm_error(utils::string::va("\"%s\" is not valid function address!", index.data())); } -auto disassembler::decrypt_string(const std::string& str) -> std::string -{ - if (str.size() > 0 && ((static_cast(str[0]) & 0xC0) == 0x80)) - { - std::string data = "_encstr_"; - - for (auto i = 0u; i < str.size(); i++) - { - data = utils::string::va("%s%02X", data.data(), static_cast(str[i])); - } - - return data; - } - - return str; -} - void disassembler::print_function(const function::ptr& func) { output_->write_string("\n"); - output_->write_string(utils::string::va("sub_%s\n", func->name.data())); + output_->write_string(utils::string::va("sub_%s %i\n", func->name.data(), func->size)); for (const auto& inst : func->instructions) { @@ -339,7 +539,7 @@ void disassembler::print_function(const function::ptr& func) void disassembler::print_instruction(const instruction::ptr& inst) { - output_->write_string(utils::string::va("\t\t%s", resolver::opcode_name(inst->opcode).data())); + output_->write_string(utils::string::va("%i\t%i\t%s", inst->index, inst->size, resolver::opcode_name(inst->opcode).data())); /*switch (static_cast(inst->opcode)) { diff --git a/src/iw9/xsk/disassembler.hpp b/src/iw9/xsk/disassembler.hpp index e6bffc15..e7eff349 100644 --- a/src/iw9/xsk/disassembler.hpp +++ b/src/iw9/xsk/disassembler.hpp @@ -26,17 +26,15 @@ private: void dissasemble_function(const function::ptr& func); void dissasemble_instruction(const instruction::ptr& inst); void disassemble_builtin_call(const instruction::ptr& inst, bool method, bool args); - void disassemble_local_call(const instruction::ptr& inst, bool thread); + void disassemble_native_call(const instruction::ptr& inst, bool thread); void disassemble_far_call(const instruction::ptr& inst, bool thread); void disassemble_switch(const instruction::ptr& inst); void disassemble_end_switch(const instruction::ptr& inst); void disassemble_field_variable(const instruction::ptr& inst); void disassemble_formal_params(const instruction::ptr& inst); void disassemble_jump(const instruction::ptr& inst, bool expr, bool back); - auto disassemble_offset() -> std::int32_t; void resolve_local_functions(); auto resolve_function(const std::string& index) -> std::string; - auto decrypt_string(const std::string& str) -> std::string; void print_function(const function::ptr& func); void print_instruction(const instruction::ptr& inst); }; diff --git a/src/iw9/xsk/iw9.cpp b/src/iw9/xsk/iw9.cpp index 30ba04fc..0d14f55a 100644 --- a/src/iw9/xsk/iw9.cpp +++ b/src/iw9/xsk/iw9.cpp @@ -11,12 +11,186 @@ namespace xsk::gsc::iw9 auto opcode_size(std::uint8_t id) -> std::uint32_t { - /*switch (static_cast(id)) + switch (static_cast(id)) { - - default:*/ + case opcode::OP_CastFieldObject: + case opcode::OP_plus: + case opcode::OP_GetGameRef: + case opcode::OP_GetThisthread: + case opcode::OP_greater: + case opcode::OP_shift_right: + case opcode::OP_dec: + case opcode::OP_bit_or: + case opcode::OP_equality: + case opcode::OP_ClearLocalVariableFieldCached0: + case opcode::OP_notify: + case opcode::OP_PreScriptCall: + case opcode::OP_GetUndefined: + case opcode::OP_SetLocalVariableFieldCached0: + case opcode::OP_GetLevel: + case opcode::OP_size: + case opcode::OP_AddArray: + case opcode::OP_endon: + case opcode::OP_shift_left: + case opcode::OP_EvalLocalArrayRefCached0: + case opcode::OP_Return: + case opcode::OP_SafeSetVariableFieldCached0: + case opcode::OP_GetSelfObject: + case opcode::OP_GetGame: + case opcode::OP_EvalArray: + case opcode::OP_GetSelf: + case opcode::OP_End: + case opcode::OP_less_equal: + case opcode::OP_EvalLocalVariableCached0: + case opcode::OP_EvalLocalVariableCached1: + case opcode::OP_EvalLocalVariableCached2: + case opcode::OP_EvalLocalVariableCached3: + case opcode::OP_EvalLocalVariableCached4: + case opcode::OP_EvalLocalVariableCached5: + case opcode::OP_ScriptMethodCallPointer: + case opcode::OP_checkclearparams: + case opcode::OP_minus: + case opcode::OP_greater_equal: + case opcode::OP_vector: + case opcode::OP_ClearArray: + case opcode::OP_DecTop: + case opcode::OP_CastBool: + case opcode::OP_EvalArrayRef: + case opcode::OP_GetZero: + case opcode::OP_wait: + case opcode::OP_waittill: + case opcode::OP_GetAnimObject: + case opcode::OP_mod: + case opcode::OP_clearparams: + case opcode::OP_ScriptFunctionCallPointer: + case opcode::OP_EmptyArray: + case opcode::OP_BoolComplement: + case opcode::OP_less: + case opcode::OP_BoolNot: + case opcode::OP_waittillFrameEnd: + case opcode::OP_waitframe: + case opcode::OP_GetLevelObject: + case opcode::OP_inc: + case opcode::OP_GetAnim: + case opcode::OP_SetVariableField: + case opcode::OP_divide: + case opcode::OP_multiply: + case opcode::OP_EvalLocalVariableRefCached0: + case opcode::OP_bit_and: + case opcode::OP_voidCodepos: + case opcode::OP_inequality: + case opcode::OP_bit_ex_or: + case opcode::OP_unk_139: + case opcode::OP_BoolNotAfterAnd: + case opcode::OP_IsDefined: + case opcode::OP_IsTrue: + return 1; + case opcode::OP_SetLocalVariableFieldCached: + case opcode::OP_RemoveLocalVariables: + case opcode::OP_ScriptMethodChildThreadCallPointer: + case opcode::OP_GetByte: + case opcode::OP_SafeSetWaittillVariableFieldCached: + case opcode::OP_CallBuiltinMethodPointer: + case opcode::OP_EvalLocalVariableCached: + case opcode::OP_ScriptChildThreadCallPointer: + case opcode::OP_EvalLocalVariableObjectCached: + case opcode::OP_GetNegByte: + case opcode::OP_GetAnimTree: + case opcode::OP_EvalLocalArrayCached: + case opcode::OP_ScriptMethodThreadCallPointer: + case opcode::OP_SafeSetVariableFieldCached: + case opcode::OP_EvalLocalVariableRefCached: + case opcode::OP_ScriptThreadCallPointer: + case opcode::OP_ClearLocalVariableFieldCached: + case opcode::OP_EvalLocalArrayRefCached: + case opcode::OP_CallBuiltinPointer: + case opcode::OP_prof_end: + case opcode::OP_FormalParams: + case opcode::OP_FormalParams_Precompiled: + return 2; + case opcode::OP_waittillmatch: + case opcode::OP_JumpOnTrue: + case opcode::OP_JumpOnFalseExpr: + case opcode::OP_jumpback: + case opcode::OP_JumpOnTrueExpr: + case opcode::OP_GetBuiltinFunction: + case opcode::OP_GetNegUnsignedShort: + case opcode::OP_GetBuiltinMethod: + case opcode::OP_endswitch: + case opcode::OP_GetUnsignedShort: + case opcode::OP_JumpOnFalse: + return 3; + case opcode::OP_CallBuiltin: + case opcode::OP_CallBuiltinMethod: + return 4; + case opcode::OP_GetInteger: + case opcode::OP_GetIString: + case opcode::OP_ScriptFarFunctionCall: + case opcode::OP_GetFloat: + case opcode::OP_GetString: + case opcode::OP_switch: + case opcode::OP_GetFarFunction: + case opcode::OP_jump: + case opcode::OP_ScriptFarMethodCall: + case opcode::OP_unk_134: + case opcode::OP_unk_137: + case opcode::OP_NativeGetFarFunction: + case opcode::OP_NativeFarFunctionCall: + case opcode::OP_NativeFarMethodCall: + return 5; + case opcode::OP_ScriptFarMethodChildThreadCall: + case opcode::OP_ScriptFarThreadCall: + case opcode::OP_ScriptFarMethodThreadCall: + case opcode::OP_ScriptFarChildThreadCall: + case opcode::OP_prof_begin: + case opcode::OP_NativeFarFunctionThreadCall: + case opcode::OP_NativeFarMethodThreadCall: + case opcode::OP_NativeFarFunctionChildThreadCall: + case opcode::OP_NativeFarMethodChildThreadCall: + return 6; + case opcode::OP_EvalSelfFieldVariableRef: + case opcode::OP_EvalAnimFieldVariable: + case opcode::OP_EvalLevelFieldVariableRef: + case opcode::OP_SetSelfFieldVariableField: + case opcode::OP_ClearFieldVariable: + case opcode::OP_EvalFieldVariable: + case opcode::OP_CreateLocalVariable: + case opcode::OP_SetLevelFieldVariableField: + case opcode::OP_EvalSelfFieldVariable: + case opcode::OP_EvalNewLocalArrayRefCached0: + case opcode::OP_SetAnimFieldVariableField: + case opcode::OP_SafeCreateVariableFieldCached: + case opcode::OP_SetNewLocalVariableFieldCached0: + case opcode::OP_EvalFieldVariableRef: + case opcode::OP_EvalLevelFieldVariable: + case opcode::OP_EvalAnimFieldVariableRef: + case opcode::OP_GetAnimation: + case opcode::OP_unk_133: + case opcode::OP_unk_135: + case opcode::OP_unk_136: + case opcode::OP_unk_138: + case opcode::OP_EvalNewLocalArrayRefCached0_Precompiled: + case opcode::OP_SetNewLocalVariableFieldCached0_Precompiled: + case opcode::OP_CreateLocalVariable_Precompiled: + case opcode::OP_SafeCreateVariableFieldCached_Precompiled: + case opcode::OP_unk_166: + return 9; + case opcode::OP_GetVector: + return 13; + case opcode::OP_waittillmatch2: + case opcode::OP_ClearVariableField: + case opcode::OP_EvalNewLocalVariableRefCached0: + case opcode::OP_unk_140: + case opcode::OP_unk_141: + case opcode::OP_unk_142: + case opcode::OP_unk_143: + case opcode::OP_unk_144: + case opcode::OP_breakpoint: + case opcode::OP_assignmentBreakpoint: + case opcode::OP_manualAndAssignmentBreakpoint: + default: throw error("couldn't resolve instruction size for " + std::to_string(id)); - // } + } } } // namespace xsk::gsc::iw9 diff --git a/src/iw9/xsk/iw9.hpp b/src/iw9/xsk/iw9.hpp index 8f8da792..ad6ff8b0 100644 --- a/src/iw9/xsk/iw9.hpp +++ b/src/iw9/xsk/iw9.hpp @@ -8,6 +8,7 @@ #include "utils/xsk/utils.hpp" #include "disassembler.hpp" +#include "decompiler.hpp" #include "resolver.hpp" #include "context.hpp" @@ -18,173 +19,173 @@ constexpr std::uint32_t max_string_id = 0; enum class opcode : std::uint8_t { - unk_000 = 0x00, // size 1 OP_CastFieldObject - unk_001 = 0x01, // size 2 OP_SetLocalVariableFieldCached - unk_002 = 0x02, // size 1 OP_plus - unk_003 = 0x03, // size 2 OP_RemoveLocalVariables - unk_004 = 0x04, // size 9, script 8 (hash?) OP_EvalSelfFieldVariableRef - unk_005 = 0x05, // size 6, stack 8 + 8 OP_ScriptFarMethodChildThreadCall - unk_006 = 0x06, // size 1 OP_GetGameRef - unk_007 = 0x07, // size 9, script 8 (hash?) OP_EvalAnimFieldVariable - unk_008 = 0x08, // size 9, script 8 (hash?) OP_EvalLevelFieldVariableRef - unk_009 = 0x09, // size 1 OP_GetThisthread - unk_010 = 0x0A, // size 1 OP_greater - unk_011 = 0x0B, // size 3 OP_waittillmatch - unk_012 = 0x0C, // size 1 OP_shift_right - unk_013 = 0x0D, // size 1 OP_dec - unk_014 = 0x0E, // size 3 OP_JumpOnTrue - unk_015 = 0x0F, // size 1 OP_bit_or - unk_016 = 0x10, // size 1 OP_equality - unk_017 = 0x11, // size 1 OP_ClearLocalVariableFieldCached0 - unk_018 = 0x12, // size 1 OP_notify - unk_019 = 0x13, // size 13 OP_GetVector - unk_020 = 0x14, // size 2 OP_ScriptMethodChildThreadCallPointer - unk_021 = 0x15, // size 1 OP_PreScriptCall - unk_022 = 0x16, // size 2 OP_GetByte - unk_023 = 0x17, // size 6, stack 8 + 8 OP_ScriptFarThreadCall - unk_024 = 0x18, // size 9, script 8 (hash?) OP_SetSelfFieldVariableField - unk_025 = 0x19, // size 3 OP_JumpOnFalseExpr - unk_026 = 0x1A, // size 1 OP_GetUndefined - unk_027 = 0x1B, // size 3 OP_jumpback - unk_028 = 0x1C, // size 3 OP_JumpOnTrueExpr - unk_029 = 0x1D, // size 4, stack string OP_CallBuiltin - unk_030 = 0x1E, // size 1 OP_SetLocalVariableFieldCached0 - unk_031 = 0x1F, // size 9, script 8 (hash?) OP_ClearFieldVariable - unk_032 = 0x20, // size 1 OP_GetLevel - unk_033 = 0x21, // size 1 OP_size - unk_034 = 0x22, // size 2 OP_SafeSetWaittillVariableFieldCached - unk_035 = 0x23, // size 1 OP_AddArray - unk_036 = 0x24, // size 1 OP_endon - unk_037 = 0x25, // size 9, script 8 (hash?) OP_EvalFieldVariable - unk_038 = 0x26, // size 1 OP_shift_left - unk_039 = 0x27, // size 1 OP_EvalLocalArrayRefCached0 - unk_040 = 0x28, // size 1 OP_Return - unk_041 = 0x29, // size 9 OP_CreateLocalVariable - unk_042 = 0x2A, // size 1 OP_SafeSetVariableFieldCached0 - unk_043 = 0x2B, // size 3, stack string OP_GetBuiltinFunction - unk_044 = 0x2C, // size 2 OP_CallBuiltinMethodPointer - unk_045 = 0x2D, // size 1 OP_GetSelfObject - unk_046 = 0x2E, // size 1 OP_GetGame - unk_047 = 0x2F, // size 9, script 8 (hash?) OP_SetLevelFieldVariableField - unk_048 = 0x30, // size 1 OP_EvalArray - unk_049 = 0x31, // size 1 OP_GetSelf - unk_050 = 0x32, // size 1 OP_End - unk_051 = 0x33, // size 9, script 8 (hash?) OP_EvalSelfFieldVariable - unk_052 = 0x34, // size 1 OP_less_equal - unk_053 = 0x35, // size 1 OP_EvalLocalVariableCached0 - unk_054 = 0x36, // size 1 OP_EvalLocalVariableCached1 - unk_055 = 0x37, // size 1 OP_EvalLocalVariableCached2 - unk_056 = 0x38, // size 1 OP_EvalLocalVariableCached3 - unk_057 = 0x39, // size 1 OP_EvalLocalVariableCached4 - unk_058 = 0x3A, // size 1 OP_EvalLocalVariableCached5 - unk_059 = 0x3B, // size 2 OP_EvalLocalVariableCached - unk_060 = 0x3C, // size 9 OP_EvalNewLocalArrayRefCached0 - unk_061 = 0x3D, // size 2 OP_ScriptChildThreadCallPointer - unk_062 = 0x3E, // size 2 OP_EvalLocalVariableObjectCached - unk_063 = 0x3F, // size 5 OP_GetInteger - unk_064 = 0x40, // size 1 OP_ScriptMethodCallPointer - unk_065 = 0x41, // size 1 OP_checkclearparams - unk_066 = 0x42, // size 9, script 8 (hash?) OP_SetAnimFieldVariableField - unk_067 = 0x43, // missing OP_waittillmatch2 - unk_068 = 0x44, // size 1 OP_minus - unk_069 = 0x45, // size 3 OP_GetNegUnsignedShort - unk_070 = 0x46, // size 2 OP_GetNegByte - unk_071 = 0x47, // size 9 OP_SafeCreateVariableFieldCached - unk_072 = 0x48, // size 1 OP_greater_equal - unk_073 = 0x49, // size 1 OP_vector - unk_074 = 0x4A, // size 3, stack string OP_GetBuiltinMethod - unk_075 = 0x4B, // size 3 + 8 * count, stack strings OP_endswitch - unk_076 = 0x4C, // size 1 OP_ClearArray - unk_077 = 0x4D, // size 1 OP_DecTop - unk_078 = 0x4E, // size 1 OP_CastBool - unk_079 = 0x4F, // size 1 OP_EvalArrayRef - unk_080 = 0x50, // size 9 OP_SetNewLocalVariableFieldCached0 - unk_081 = 0x51, // size 1 OP_GetZero - unk_082 = 0x52, // size 1 OP_wait - unk_083 = 0x53, // size 1 OP_waittill - unk_084 = 0x54, // size 5, stack string OP_GetIString - unk_085 = 0x55, // size 5, stack 8 + 8 OP_ScriptFarFunctionCall - unk_086 = 0x56, // size 1 OP_GetAnimObject - unk_087 = 0x57, // size 2, stack string OP_GetAnimTree - unk_088 = 0x58, // size 2 OP_EvalLocalArrayCached - unk_089 = 0x59, // size 1 OP_mod - unk_090 = 0x5A, // size 6, stack 8 + 8 OP_ScriptFarMethodThreadCall - unk_091 = 0x5B, // size 3 OP_GetUnsignedShort - unk_092 = 0x5C, // size 1 OP_clearparams - unk_093 = 0x5D, // size 2 OP_ScriptMethodThreadCallPointer - unk_094 = 0x5E, // size 1 OP_ScriptFunctionCallPointer - unk_095 = 0x5F, // size 1 OP_EmptyArray - unk_096 = 0x60, // size 2 OP_SafeSetVariableFieldCached - unk_097 = 0x61, // missing OP_ClearVariableField - unk_098 = 0x62, // size 9, script 8 (hash?) OP_EvalFieldVariableRef - unk_099 = 0x63, // missing OP_EvalNewLocalVariableRefCached0 - unk_100 = 0x64, // size 5 OP_GetFloat - unk_101 = 0x65, // size 2 OP_EvalLocalVariableRefCached - unk_102 = 0x66, // size 3 OP_JumpOnFalse - unk_103 = 0x67, // size 1 OP_BoolComplement - unk_104 = 0x68, // size 2 OP_ScriptThreadCallPointer - unk_105 = 0x69, // size 1 OP_less - unk_106 = 0x6A, // size 1 OP_BoolNot - unk_107 = 0x6B, // size 1 OP_waittillFrameEnd - unk_108 = 0x6C, // size 1 OP_waitframe - unk_109 = 0x6D, // size 5, stack string OP_GetString - unk_110 = 0x6E, // size 9, script 8 (hash?) OP_EvalLevelFieldVariable - unk_111 = 0x6F, // size 1 OP_GetLevelObject - unk_112 = 0x70, // size 1 OP_inc - unk_113 = 0x71, // size 4, stack string (hash) OP_CallBuiltinMethod - unk_114 = 0x72, // size 1 OP_GetAnim - unk_115 = 0x73, // size 5 OP_switch - unk_116 = 0x74, // size 1 OP_SetVariableField - unk_117 = 0x75, // size 1 OP_divide - unk_118 = 0x76, // size 6, stack 8 + 8 OP_ScriptFarChildThreadCall - unk_119 = 0x77, // size 1 OP_multiply - unk_120 = 0x78, // size 2 OP_ClearLocalVariableFieldCached - unk_121 = 0x79, // size 9, script 8 (hash?) OP_EvalAnimFieldVariableRef - unk_122 = 0x7A, // size 2 OP_EvalLocalArrayRefCached - unk_123 = 0x7B, // size 1 OP_EvalLocalVariableRefCached0 - unk_124 = 0x7C, // size 1 OP_bit_and - unk_125 = 0x7D, // size ?, stack string * 2 OP_GetAnimation - unk_126 = 0x7E, // size 5, stack 8 + 8 OP_GetFarFunction - unk_127 = 0x7F, // size 2 OP_CallBuiltinPointer - unk_128 = 0x80, // size 5 OP_jump - unk_129 = 0x81, // size 1 OP_voidCodepos - unk_130 = 0x82, // size 5, stack 8 + 8 OP_ScriptFarMethodCall - unk_131 = 0x83, // size 1 OP_inequality - unk_132 = 0x84, // size 1 OP_bit_ex_or - unk_133 = 0x85, // size 9 - unk_134 = 0x86, // size 5 - unk_135 = 0x87, // size 9 - unk_136 = 0x88, // size 9 - unk_137 = 0x89, // size 5 - unk_138 = 0x8A, // size 9 - unk_139 = 0x8B, - unk_140 = 0x8C, - unk_141 = 0x8D, - unk_142 = 0x8E, - unk_143 = 0x8F, - unk_144 = 0x90, - unk_145 = 0x91, // size 6 OP_prof_begin - unk_146 = 0x92, // size 2 OP_prof_end - unk_147 = 0x93, // OP_breakpoint - unk_148 = 0x94, // OP_assignmentBreakpoint - unk_149 = 0x95, // OP_manualAndAssignmentBreakpoint - unk_150 = 0x96, // size 1 OP_BoolNotAfterAnd - unk_151 = 0x97, // size 2 + 8 * count (params?) OP_FormalParams - unk_152 = 0x98, // size 1 OP_IsDefined - unk_153 = 0x99, // size 1 OP_IsTrue - unk_154 = 0x9A, // size 5, stack 4 OP_NativeGetFarFunction - unk_155 = 0x9B, // size 5, stack 4 OP_NativeFarFunctionCall - unk_156 = 0x9C, // size 5, stack 4 OP_NativeFarMethodCall - unk_157 = 0x9D, // size 6, stack 4 OP_NativeFarFunctionThreadCall - unk_158 = 0x9E, // size 6, stack 4 OP_NativeFarMethodThreadCall - unk_159 = 0x9F, // size 6, stack 4 OP_NativeFarFunctionChildThreadCall - unk_160 = 0xA0, // size 6, stack 4 OP_NativeFarMethodChildThreadCall - unk_161 = 0xA1, // size 9 OP_EvalNewLocalArrayRefCached0_Precompiled - unk_162 = 0xA2, // size 9 OP_SetNewLocalVariableFieldCached0_Precompiled - unk_163 = 0xA3, // size 9 OP_CreateLocalVariable_Precompiled - unk_164 = 0xA4, // size 9 OP_SafeCreateVariableFieldCached_Precompiled - unk_165 = 0xA5, // size 2 + 8 * count (params?) OP_FormalParams_Precompiled - unk_166 = 0xA6, // size 9, stack 8 + OP_CastFieldObject = 0x00, + OP_SetLocalVariableFieldCached = 0x01, + OP_plus = 0x02, + OP_RemoveLocalVariables = 0x03, + OP_EvalSelfFieldVariableRef = 0x04, + OP_ScriptFarMethodChildThreadCall = 0x05, + OP_GetGameRef = 0x06, + OP_EvalAnimFieldVariable = 0x07, + OP_EvalLevelFieldVariableRef = 0x08, + OP_GetThisthread = 0x09, + OP_greater = 0x0A, + OP_waittillmatch = 0x0B, + OP_shift_right = 0x0C, + OP_dec = 0x0D, + OP_JumpOnTrue = 0x0E, + OP_bit_or = 0x0F, + OP_equality = 0x10, + OP_ClearLocalVariableFieldCached0 = 0x11, + OP_notify = 0x12, + OP_GetVector = 0x13, + OP_ScriptMethodChildThreadCallPointer = 0x14, + OP_PreScriptCall = 0x15, + OP_GetByte = 0x16, + OP_ScriptFarThreadCall = 0x17, + OP_SetSelfFieldVariableField = 0x18, + OP_JumpOnFalseExpr = 0x19, + OP_GetUndefined = 0x1A, + OP_jumpback = 0x1B, + OP_JumpOnTrueExpr = 0x1C, + OP_CallBuiltin = 0x1D, + OP_SetLocalVariableFieldCached0 = 0x1E, + OP_ClearFieldVariable = 0x1F, + OP_GetLevel = 0x20, + OP_size = 0x21, + OP_SafeSetWaittillVariableFieldCached = 0x22, + OP_AddArray = 0x23, + OP_endon = 0x24, + OP_EvalFieldVariable = 0x25, + OP_shift_left = 0x26, + OP_EvalLocalArrayRefCached0 = 0x27, + OP_Return = 0x28, + OP_CreateLocalVariable = 0x29, + OP_SafeSetVariableFieldCached0 = 0x2A, + OP_GetBuiltinFunction = 0x2B, + OP_CallBuiltinMethodPointer = 0x2C, + OP_GetSelfObject = 0x2D, + OP_GetGame = 0x2E, + OP_SetLevelFieldVariableField = 0x2F, + OP_EvalArray = 0x30, + OP_GetSelf = 0x31, + OP_End = 0x32, + OP_EvalSelfFieldVariable = 0x33, + OP_less_equal = 0x34, + OP_EvalLocalVariableCached0 = 0x35, + OP_EvalLocalVariableCached1 = 0x36, + OP_EvalLocalVariableCached2 = 0x37, + OP_EvalLocalVariableCached3 = 0x38, + OP_EvalLocalVariableCached4 = 0x39, + OP_EvalLocalVariableCached5 = 0x3A, + OP_EvalLocalVariableCached = 0x3B, + OP_EvalNewLocalArrayRefCached0 = 0x3C, + OP_ScriptChildThreadCallPointer = 0x3D, + OP_EvalLocalVariableObjectCached = 0x3E, + OP_GetInteger = 0x3F, + OP_ScriptMethodCallPointer = 0x40, + OP_checkclearparams = 0x41, + OP_SetAnimFieldVariableField = 0x42, + OP_waittillmatch2 = 0x43, + OP_minus = 0x44, + OP_GetNegUnsignedShort = 0x45, + OP_GetNegByte = 0x46, + OP_SafeCreateVariableFieldCached = 0x47, + OP_greater_equal = 0x48, + OP_vector = 0x49, + OP_GetBuiltinMethod = 0x4A, + OP_endswitch = 0x4B, + OP_ClearArray = 0x4C, + OP_DecTop = 0x4D, + OP_CastBool = 0x4E, + OP_EvalArrayRef = 0x4F, + OP_SetNewLocalVariableFieldCached0 = 0x50, + OP_GetZero = 0x51, + OP_wait = 0x52, + OP_waittill = 0x53, + OP_GetIString = 0x54, + OP_ScriptFarFunctionCall = 0x55, + OP_GetAnimObject = 0x56, + OP_GetAnimTree = 0x57, + OP_EvalLocalArrayCached = 0x58, + OP_mod = 0x59, + OP_ScriptFarMethodThreadCall = 0x5A, + OP_GetUnsignedShort = 0x5B, + OP_clearparams = 0x5C, + OP_ScriptMethodThreadCallPointer = 0x5D, + OP_ScriptFunctionCallPointer = 0x5E, + OP_EmptyArray = 0x5F, + OP_SafeSetVariableFieldCached = 0x60, + OP_ClearVariableField = 0x61, + OP_EvalFieldVariableRef = 0x62, + OP_EvalNewLocalVariableRefCached0 = 0x63, + OP_GetFloat = 0x64, + OP_EvalLocalVariableRefCached = 0x65, + OP_JumpOnFalse = 0x66, + OP_BoolComplement = 0x67, + OP_ScriptThreadCallPointer = 0x68, + OP_less = 0x69, + OP_BoolNot = 0x6A, + OP_waittillFrameEnd = 0x6B, + OP_waitframe = 0x6C, + OP_GetString = 0x6D, + OP_EvalLevelFieldVariable = 0x6E, + OP_GetLevelObject = 0x6F, + OP_inc = 0x70, + OP_CallBuiltinMethod = 0x71, + OP_GetAnim = 0x72, + OP_switch = 0x73, + OP_SetVariableField = 0x74, + OP_divide = 0x75, + OP_ScriptFarChildThreadCall = 0x76, + OP_multiply = 0x77, + OP_ClearLocalVariableFieldCached = 0x78, + OP_EvalAnimFieldVariableRef = 0x79, + OP_EvalLocalArrayRefCached = 0x7A, + OP_EvalLocalVariableRefCached0 = 0x7B, + OP_bit_and = 0x7C, + OP_GetAnimation = 0x7D, + OP_GetFarFunction = 0x7E, + OP_CallBuiltinPointer = 0x7F, + OP_jump = 0x80, + OP_voidCodepos = 0x81, + OP_ScriptFarMethodCall = 0x82, + OP_inequality = 0x83, + OP_bit_ex_or = 0x84, + OP_unk_133 = 0x85, // size 9 + OP_unk_134 = 0x86, // size 5 + OP_unk_135 = 0x87, // size 9 + OP_unk_136 = 0x88, // size 9 + OP_unk_137 = 0x89, // size 5 + OP_unk_138 = 0x8A, // size 9 + OP_unk_139 = 0x8B, + OP_unk_140 = 0x8C, + OP_unk_141 = 0x8D, + OP_unk_142 = 0x8E, + OP_unk_143 = 0x8F, + OP_unk_144 = 0x90, + OP_prof_begin = 0x91, + OP_prof_end = 0x92, + OP_breakpoint = 0x93, + OP_assignmentBreakpoint = 0x94, + OP_manualAndAssignmentBreakpoint = 0x95, + OP_BoolNotAfterAnd = 0x96, + OP_FormalParams = 0x97, + OP_IsDefined = 0x98, + OP_IsTrue = 0x99, + OP_NativeGetFarFunction = 0x9A, + OP_NativeFarFunctionCall = 0x9B, + OP_NativeFarMethodCall = 0x9C, + OP_NativeFarFunctionThreadCall = 0x9D, + OP_NativeFarMethodThreadCall = 0x9E, + OP_NativeFarFunctionChildThreadCall = 0x9F, + OP_NativeFarMethodChildThreadCall = 0xA0, + OP_EvalNewLocalArrayRefCached0_Precompiled = 0xA1, + OP_SetNewLocalVariableFieldCached0_Precompiled = 0xA2, + OP_CreateLocalVariable_Precompiled = 0xA3, + OP_SafeCreateVariableFieldCached_Precompiled = 0xA4, + OP_FormalParams_Precompiled = 0xA5, + OP_unk_166 = 0xA6, // size 9, stack 8 OP_count = 0xA7, }; diff --git a/src/iw9/xsk/resolver.cpp b/src/iw9/xsk/resolver.cpp index 281505ba..492d3023 100644 --- a/src/iw9/xsk/resolver.cpp +++ b/src/iw9/xsk/resolver.cpp @@ -297,173 +297,173 @@ auto resolver::fs_to_game_path(const std::filesystem::path& file) -> std::filesy const std::array, 167> opcode_list {{ - { 0x00, "unk_000" }, - { 0x01, "unk_001" }, - { 0x02, "unk_002" }, - { 0x03, "unk_003" }, - { 0x04, "unk_004" }, - { 0x05, "unk_005" }, - { 0x06, "unk_006" }, - { 0x07, "unk_007" }, - { 0x08, "unk_008" }, - { 0x09, "unk_009" }, - { 0x0A, "unk_010" }, - { 0x0B, "unk_011" }, - { 0x0C, "unk_012" }, - { 0x0D, "unk_013" }, - { 0x0E, "unk_014" }, - { 0x0F, "unk_015" }, - { 0x10, "unk_016" }, - { 0x11, "unk_017" }, - { 0x12, "unk_018" }, - { 0x13, "unk_019" }, - { 0x14, "unk_020" }, - { 0x15, "unk_021" }, - { 0x16, "unk_022" }, - { 0x17, "unk_023" }, - { 0x18, "unk_024" }, - { 0x19, "unk_025" }, - { 0x1A, "unk_026" }, - { 0x1B, "unk_027" }, - { 0x1C, "unk_028" }, - { 0x1D, "unk_029" }, - { 0x1E, "unk_030" }, - { 0x1F, "unk_031" }, - { 0x20, "unk_032" }, - { 0x21, "unk_033" }, - { 0x22, "unk_034" }, - { 0x23, "unk_035" }, - { 0x24, "unk_036" }, - { 0x25, "unk_037" }, - { 0x26, "unk_038" }, - { 0x27, "unk_039" }, - { 0x28, "unk_040" }, - { 0x29, "unk_041" }, - { 0x2A, "unk_042" }, - { 0x2B, "unk_043" }, - { 0x2C, "unk_044" }, - { 0x2D, "unk_045" }, - { 0x2E, "unk_046" }, - { 0x2F, "unk_047" }, - { 0x30, "unk_048" }, - { 0x31, "unk_049" }, - { 0x32, "unk_050" }, - { 0x33, "unk_051" }, - { 0x34, "unk_052" }, - { 0x35, "unk_053" }, - { 0x36, "unk_054" }, - { 0x37, "unk_055" }, - { 0x38, "unk_056" }, - { 0x39, "unk_057" }, - { 0x3A, "unk_058" }, - { 0x3B, "unk_059" }, - { 0x3C, "unk_060" }, - { 0x3D, "unk_061" }, - { 0x3E, "unk_062" }, - { 0x3F, "unk_063" }, - { 0x40, "unk_064" }, - { 0x41, "unk_065" }, - { 0x42, "unk_066" }, - { 0x43, "unk_067" }, - { 0x44, "unk_068" }, - { 0x45, "unk_069" }, - { 0x46, "unk_070" }, - { 0x47, "unk_071" }, - { 0x48, "unk_072" }, - { 0x49, "unk_073" }, - { 0x4A, "unk_074" }, - { 0x4B, "unk_075" }, - { 0x4C, "unk_076" }, - { 0x4D, "unk_077" }, - { 0x4E, "unk_078" }, - { 0x4F, "unk_079" }, - { 0x50, "unk_080" }, - { 0x51, "unk_081" }, - { 0x52, "unk_082" }, - { 0x53, "unk_083" }, - { 0x54, "unk_084" }, - { 0x55, "unk_085" }, - { 0x56, "unk_086" }, - { 0x57, "unk_087" }, - { 0x58, "unk_088" }, - { 0x59, "unk_089" }, - { 0x5A, "unk_090" }, - { 0x5B, "unk_091" }, - { 0x5C, "unk_092" }, - { 0x5D, "unk_093" }, - { 0x5E, "unk_094" }, - { 0x5F, "unk_095" }, - { 0x60, "unk_096" }, - { 0x61, "unk_097" }, - { 0x62, "unk_098" }, - { 0x63, "unk_099" }, - { 0x64, "unk_100" }, - { 0x65, "unk_101" }, - { 0x66, "unk_102" }, - { 0x67, "unk_103" }, - { 0x68, "unk_104" }, - { 0x69, "unk_105" }, - { 0x6A, "unk_106" }, - { 0x6B, "unk_107" }, - { 0x6C, "unk_108" }, - { 0x6D, "unk_109" }, - { 0x6E, "unk_110" }, - { 0x6F, "unk_111" }, - { 0x70, "unk_112" }, - { 0x71, "unk_113" }, - { 0x72, "unk_114" }, - { 0x73, "unk_115" }, - { 0x74, "unk_116" }, - { 0x75, "unk_117" }, - { 0x76, "unk_118" }, - { 0x77, "unk_119" }, - { 0x78, "unk_120" }, - { 0x79, "unk_121" }, - { 0x7A, "unk_122" }, - { 0x7B, "unk_123" }, - { 0x7C, "unk_124" }, - { 0x7D, "unk_125" }, - { 0x7E, "unk_126" }, - { 0x7F, "unk_127" }, - { 0x80, "unk_128" }, - { 0x81, "unk_129" }, - { 0x82, "unk_130" }, - { 0x83, "unk_131" }, - { 0x84, "unk_132" }, - { 0x85, "unk_133" }, - { 0x86, "unk_134" }, - { 0x87, "unk_135" }, - { 0x88, "unk_136" }, - { 0x89, "unk_137" }, - { 0x8A, "unk_138" }, - { 0x8B, "unk_139" }, - { 0x8C, "unk_140" }, - { 0x8D, "unk_141" }, - { 0x8E, "unk_142" }, - { 0x8F, "unk_143" }, - { 0x90, "unk_144" }, - { 0x91, "unk_145" }, - { 0x92, "unk_146" }, - { 0x93, "unk_147" }, - { 0x94, "unk_148" }, - { 0x95, "unk_149" }, - { 0x96, "unk_150" }, - { 0x97, "unk_151" }, - { 0x98, "unk_152" }, - { 0x99, "unk_153" }, - { 0x9A, "unk_154" }, - { 0x9B, "unk_155" }, - { 0x9C, "unk_156" }, - { 0x9D, "unk_157" }, - { 0x9E, "unk_158" }, - { 0x9F, "unk_159" }, - { 0xA0, "unk_160" }, - { 0xA1, "unk_161" }, - { 0xA2, "unk_162" }, - { 0xA3, "unk_163" }, - { 0xA4, "unk_164" }, - { 0xA5, "unk_165" }, - { 0xA6, "unk_166" }, + { 0x00, "OP_CastFieldObject" }, + { 0x01, "OP_SetLocalVariableFieldCached" }, + { 0x02, "OP_plus" }, + { 0x03, "OP_RemoveLocalVariables" }, + { 0x04, "OP_EvalSelfFieldVariableRef" }, + { 0x05, "OP_ScriptFarMethodChildThreadCall" }, + { 0x06, "OP_GetGameRef" }, + { 0x07, "OP_EvalAnimFieldVariable" }, + { 0x08, "OP_EvalLevelFieldVariableRef" }, + { 0x09, "OP_GetThisthread" }, + { 0x0A, "OP_greater" }, + { 0x0B, "OP_waittillmatch" }, + { 0x0C, "OP_shift_right" }, + { 0x0D, "OP_dec" }, + { 0x0E, "OP_JumpOnTrue" }, + { 0x0F, "OP_bit_or" }, + { 0x10, "OP_equality" }, + { 0x11, "OP_ClearLocalVariableFieldCached0" }, + { 0x12, "OP_notify" }, + { 0x13, "OP_GetVector" }, + { 0x14, "OP_ScriptMethodChildThreadCallPointer" }, + { 0x15, "OP_PreScriptCall" }, + { 0x16, "OP_GetByte" }, + { 0x17, "OP_ScriptFarThreadCall" }, + { 0x18, "OP_SetSelfFieldVariableField" }, + { 0x19, "OP_JumpOnFalseExpr" }, + { 0x1A, "OP_GetUndefined" }, + { 0x1B, "OP_jumpback" }, + { 0x1C, "OP_JumpOnTrueExpr" }, + { 0x1D, "OP_CallBuiltin" }, + { 0x1E, "OP_SetLocalVariableFieldCached0" }, + { 0x1F, "OP_ClearFieldVariable" }, + { 0x20, "OP_GetLevel" }, + { 0x21, "OP_size" }, + { 0x22, "OP_SafeSetWaittillVariableFieldCached" }, + { 0x23, "OP_AddArray" }, + { 0x24, "OP_endon" }, + { 0x25, "OP_EvalFieldVariable" }, + { 0x26, "OP_shift_left" }, + { 0x27, "OP_EvalLocalArrayRefCached0" }, + { 0x28, "OP_Return" }, + { 0x29, "OP_CreateLocalVariable" }, + { 0x2A, "OP_SafeSetVariableFieldCached0" }, + { 0x2B, "OP_GetBuiltinFunction" }, + { 0x2C, "OP_CallBuiltinMethodPointer" }, + { 0x2D, "OP_GetSelfObject" }, + { 0x2E, "OP_GetGame" }, + { 0x2F, "OP_SetLevelFieldVariableField" }, + { 0x30, "OP_EvalArray" }, + { 0x31, "OP_GetSelf" }, + { 0x32, "OP_End" }, + { 0x33, "OP_EvalSelfFieldVariable" }, + { 0x34, "OP_less_equal" }, + { 0x35, "OP_EvalLocalVariableCached0" }, + { 0x36, "OP_EvalLocalVariableCached1" }, + { 0x37, "OP_EvalLocalVariableCached2" }, + { 0x38, "OP_EvalLocalVariableCached3" }, + { 0x39, "OP_EvalLocalVariableCached4" }, + { 0x3A, "OP_EvalLocalVariableCached5" }, + { 0x3B, "OP_EvalLocalVariableCached" }, + { 0x3C, "OP_EvalNewLocalArrayRefCached0" }, + { 0x3D, "OP_ScriptChildThreadCallPointer" }, + { 0x3E, "OP_EvalLocalVariableObjectCached" }, + { 0x3F, "OP_GetInteger" }, + { 0x40, "OP_ScriptMethodCallPointer" }, + { 0x41, "OP_checkclearparams" }, + { 0x42, "OP_SetAnimFieldVariableField" }, + { 0x43, "OP_waittillmatch2" }, + { 0x44, "OP_minus" }, + { 0x45, "OP_GetNegUnsignedShort" }, + { 0x46, "OP_GetNegByte" }, + { 0x47, "OP_SafeCreateVariableFieldCached" }, + { 0x48, "OP_greater_equal" }, + { 0x49, "OP_vector" }, + { 0x4A, "OP_GetBuiltinMethod" }, + { 0x4B, "OP_endswitch" }, + { 0x4C, "OP_ClearArray" }, + { 0x4D, "OP_DecTop" }, + { 0x4E, "OP_CastBool" }, + { 0x4F, "OP_EvalArrayRef" }, + { 0x50, "OP_SetNewLocalVariableFieldCached0" }, + { 0x51, "OP_GetZero" }, + { 0x52, "OP_wait" }, + { 0x53, "OP_waittill" }, + { 0x54, "OP_GetIString" }, + { 0x55, "OP_ScriptFarFunctionCall" }, + { 0x56, "OP_GetAnimObject" }, + { 0x57, "OP_GetAnimTree" }, + { 0x58, "OP_EvalLocalArrayCached" }, + { 0x59, "OP_mod" }, + { 0x5A, "OP_ScriptFarMethodThreadCall" }, + { 0x5B, "OP_GetUnsignedShort" }, + { 0x5C, "OP_clearparams" }, + { 0x5D, "OP_ScriptMethodThreadCallPointer" }, + { 0x5E, "OP_ScriptFunctionCallPointer" }, + { 0x5F, "OP_EmptyArray" }, + { 0x60, "OP_SafeSetVariableFieldCached" }, + { 0x61, "OP_ClearVariableField" }, + { 0x62, "OP_EvalFieldVariableRef" }, + { 0x63, "OP_EvalNewLocalVariableRefCached0" }, + { 0x64, "OP_GetFloat" }, + { 0x65, "OP_EvalLocalVariableRefCached" }, + { 0x66, "OP_JumpOnFalse" }, + { 0x67, "OP_BoolComplement" }, + { 0x68, "OP_ScriptThreadCallPointer" }, + { 0x69, "OP_less" }, + { 0x6A, "OP_BoolNot" }, + { 0x6B, "OP_waittillFrameEnd" }, + { 0x6C, "OP_waitframe" }, + { 0x6D, "OP_GetString" }, + { 0x6E, "OP_EvalLevelFieldVariable" }, + { 0x6F, "OP_GetLevelObject" }, + { 0x70, "OP_inc" }, + { 0x71, "OP_CallBuiltinMethod" }, + { 0x72, "OP_GetAnim" }, + { 0x73, "OP_switch" }, + { 0x74, "OP_SetVariableField" }, + { 0x75, "OP_divide" }, + { 0x76, "OP_ScriptFarChildThreadCall" }, + { 0x77, "OP_multiply" }, + { 0x78, "OP_ClearLocalVariableFieldCached" }, + { 0x79, "OP_EvalAnimFieldVariableRef" }, + { 0x7A, "OP_EvalLocalArrayRefCached" }, + { 0x7B, "OP_EvalLocalVariableRefCached0" }, + { 0x7C, "OP_bit_and" }, + { 0x7D, "OP_GetAnimation" }, + { 0x7E, "OP_GetFarFunction" }, + { 0x7F, "OP_CallBuiltinPointer" }, + { 0x80, "OP_jump" }, + { 0x81, "OP_voidCodepos" }, + { 0x82, "OP_ScriptFarMethodCall" }, + { 0x83, "OP_inequality" }, + { 0x84, "OP_bit_ex_or" }, + { 0x85, "OP_unk_133" }, + { 0x86, "OP_unk_134" }, + { 0x87, "OP_unk_135" }, + { 0x88, "OP_unk_136" }, + { 0x89, "OP_unk_137" }, + { 0x8A, "OP_unk_138" }, + { 0x8B, "OP_unk_139" }, + { 0x8C, "OP_unk_140" }, + { 0x8D, "OP_unk_141" }, + { 0x8E, "OP_unk_142" }, + { 0x8F, "OP_unk_143" }, + { 0x90, "OP_unk_144" }, + { 0x91, "OP_prof_begin" }, + { 0x92, "OP_prof_end" }, + { 0x93, "OP_breakpoint" }, + { 0x94, "OP_assignmentBreakpoint" }, + { 0x95, "OP_manualAndAssignmentBreakpoint" }, + { 0x96, "OP_BoolNotAfterAnd" }, + { 0x97, "OP_FormalParams" }, + { 0x98, "OP_IsDefined" }, + { 0x99, "OP_IsTrue" }, + { 0x9A, "OP_NativeGetFarFunction" }, + { 0x9B, "OP_NativeFarFunctionCall" }, + { 0x9C, "OP_NativeFarMethodCall" }, + { 0x9D, "OP_NativeFarFunctionThreadCall" }, + { 0x9E, "OP_NativeFarMethodThreadCall" }, + { 0x9F, "OP_NativeFarFunctionChildThreadCall" }, + { 0xA0, "OP_NativeFarMethodChildThreadCall" }, + { 0xA1, "OP_EvalNewLocalArrayRefCached0_Precompiled" }, + { 0xA2, "OP_SetNewLocalVariableFieldCached0_Precompiled" }, + { 0xA3, "OP_CreateLocalVariable_Precompiled" }, + { 0xA4, "OP_SafeCreateVariableFieldCached_Precompiled" }, + { 0xA5, "OP_FormalParams_Precompiled" }, + { 0xA6, "OP_unk_166" }, }}; const std::array, 0> function_list