// Copyright 2021 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 "iw8.hpp" namespace xsk::gsc::iw8 { auto decompiler::output() -> std::vector { std::vector output; auto data = std::make_unique(0x100000); data->write_string("// IW8 PC GSC\n// 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& functions) { filename_ = file; program_ = std::make_unique(); for (auto& func : functions) { auto name = std::make_unique(func->name.substr(4)); auto params = std::make_unique(); auto block = std::make_unique(); func_ = std::make_unique(std::move(name),std::move(params),std::move(block)); labels_ = func->labels; expr_labels_.clear(); stack_ = std::stack(); this->decompile_function(func); this->process_stack(func_); program_->definitions.push_back(gsc::define_ptr(std::move(func_))); } } void decompiler::decompile_function(const gsc::function_ptr& func) { this->decompile_statements(func); if(stack_.size() > 0) { throw gsc::decomp_error("stack not emty at function end"); } auto& block = func_->block; gsc::context ctx; ctx.loc_end = utils::string::va("loc_%X", block->stmts.back().as_node->loc.begin.line); // remove last return block->stmts.pop_back(); // hotfix empty else block at func end if(block->stmts.size() > 0 && block->stmts.back().as_node->type == gsc::node_t::asm_jump) { if(block->stmts.back().as_jump->value == ctx.loc_end) block->stmts.pop_back(); } blocks_.push_back(ctx); this->decompile_block(block); blocks_.pop_back(); } void decompiler::decompile_statements(const gsc::function_ptr& func) { std::uint32_t last_null_loc = 0; bool in_waittill = false; for (auto& inst : func->instructions) { auto loc = gsc::location(&filename_, inst->index); const auto itr = func->labels.find(inst->index); if (itr != func->labels.end()) { for(auto& entry : expr_labels_) { if(entry == itr->second) { decompile_expr(); } } for(auto& entry : tern_labels_) { if(entry == itr->second) { decompile_ternary(); } } } switch (opcode(inst->opcode)) { case opcode::OP_End: { auto stmt = gsc::stmt_ptr(std::make_unique(loc, std::make_unique())); func_->block->stmts.push_back(std::move(stmt)); } break; case opcode::OP_Return: { auto expr = std::move(stack_.top()); stack_.pop(); auto stmt = gsc::stmt_ptr(std::make_unique(expr->loc, std::move(expr))); func_->block->stmts.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 = gsc::expr_ptr(std::make_unique(loc, inst->data[0])); auto y = gsc::expr_ptr(std::make_unique(loc, inst->data[1])); auto z = gsc::expr_ptr(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 tree = utils::string::unquote(inst->data[0]); if(tree != "") { auto treename = std::make_unique(loc, inst->data[0]); auto animtree = std::make_unique(loc, std::move(treename)); program_->definitions.push_back(gsc::define_ptr(std::move(animtree))); } auto node = std::make_unique(loc, utils::string::unquote(inst->data[1])); stack_.push(std::move(node)); } break; case opcode::OP_GetAnimTree: { auto tree = utils::string::unquote(inst->data[0]); if(tree != "") { auto treename = std::make_unique(loc, inst->data[0]); auto animtree = std::make_unique(loc, std::move(treename)); program_->definitions.push_back(gsc::define_ptr(std::move(animtree))); } 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 file = std::make_unique(loc); auto func = std::make_unique(loc, inst->data[0]); auto stmt = std::make_unique(loc, std::move(file), std::move(func)); stack_.push(std::move(stmt)); } break; case opcode::OP_GetLocalFunction: { auto file = std::make_unique(loc); auto func = std::make_unique(loc, inst->data[0].substr(4)); auto stmt = std::make_unique(loc, std::move(file), std::move(func)); stack_.push(std::move(stmt)); } break; case opcode::OP_GetFarFunction: { auto file = std::make_unique(loc, utils::string::backslash(inst->data[0])); auto func = std::make_unique(loc, inst->data[1]); auto stmt = std::make_unique(loc, std::move(file), std::move(func)); stack_.push(std::move(stmt)); }; break; case opcode::OP_CreateLocalVariable: { if(in_waittill) { auto expr = std::make_unique(loc, inst->data[0]); stack_.push(std::move(expr)); } else { auto stmt = std::make_unique(loc, inst->data[0]); func_->block->stmts.push_back(gsc::stmt_ptr(std::move(stmt))); } } break; case opcode::OP_RemoveLocalVariables: { auto stmt = std::make_unique(loc, inst->data[0]); func_->block->stmts.push_back(gsc::stmt_ptr(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 = gsc::expr_ptr(std::move(stack_.top())); stack_.pop(); auto obj = gsc::expr_ptr(std::make_unique(loc, inst->data[0])); auto node = std::make_unique(key.as_node->loc, std::move(obj), std::move(key)); stack_.push(std::move(node)); } break; case opcode::OP_EvalArray: { auto obj = gsc::expr_ptr(std::move(stack_.top())); stack_.pop(); auto key = gsc::expr_ptr(std::move(stack_.top())); stack_.pop(); auto node = std::make_unique(key.as_node->loc, std::move(obj), std::move(key)); stack_.push(std::move(node)); } break; case opcode::OP_EvalNewLocalArrayRefCached0: { auto key = gsc::expr_ptr(std::move(stack_.top())); stack_.pop(); auto obj = gsc::expr_ptr(std::make_unique(loc, inst->data[0])); auto node = std::make_unique(key.as_node->loc, std::move(obj), std::move(key)); stack_.push(std::move(node)); } break; case opcode::OP_EvalLocalArrayRefCached0: { auto key = gsc::expr_ptr(std::move(stack_.top())); stack_.pop(); auto obj = gsc::expr_ptr(std::make_unique(loc, "0")); auto node = std::make_unique(key.as_node->loc, std::move(obj), std::move(key)); stack_.push(std::move(node)); } break; case opcode::OP_EvalLocalArrayRefCached: { auto key = gsc::expr_ptr(std::move(stack_.top())); stack_.pop(); auto obj = gsc::expr_ptr(std::make_unique(loc, inst->data[0])); auto node = std::make_unique(key.as_node->loc, std::move(obj), std::move(key)); stack_.push(std::move(node)); } break; case opcode::OP_EvalArrayRef: { auto obj = gsc::expr_ptr(std::move(stack_.top())); stack_.pop(); auto key = gsc::expr_ptr(std::move(stack_.top())); stack_.pop(); auto node = std::make_unique(key.as_node->loc, std::move(obj), std::move(key)); stack_.push(std::move(node)); } break; case opcode::OP_ClearArray: { auto obj = gsc::expr_ptr(std::move(stack_.top())); stack_.pop(); auto key = gsc::expr_ptr(std::move(stack_.top())); stack_.pop(); loc = key.as_node->loc; auto lvalue = gsc::expr_ptr(std::make_unique(loc, std::move(obj), std::move(key))); auto rvalue = gsc::expr_ptr(std::make_unique(loc)); auto expr = std::make_unique(loc, std::move(lvalue), std::move(rvalue)); auto stmt = gsc::stmt_ptr(std::make_unique(loc, std::move(expr))); func_->block->stmts.push_back(std::move(stmt)); } break; case opcode::OP_AddArray: { auto var = std::move(stack_.top()); stack_.pop(); auto array = std::move(stack_.top()); stack_.pop(); if (array->type == gsc::node_t::data_empty_array) { auto args = std::make_unique(loc); args->list.push_back(std::move(var)); auto expr = std::make_unique(array->loc, std::move(args)); stack_.push(std::move(expr)); } else if (array->type == gsc::node_t::expr_add_array) { (*(gsc::expr_add_array_ptr*)&array)->args->list.push_back(std::move(var)); stack_.push(std::move(array)); } else { throw gsc::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_ScriptLocalFunctionCall2: { auto args = std::make_unique(loc); auto name = std::make_unique(loc, inst->data[0].substr(4)); auto file = std::make_unique(loc); auto func = gsc::expr_call_type_ptr(std::make_unique(loc, std::move(file), std::move(name), std::move(args))); auto obj = gsc::expr_ptr(std::make_unique()); auto expr = std::make_unique(loc, false, false, std::move(obj) ,std::move(func)); stack_.push(std::move(expr)); } break; case opcode::OP_ScriptLocalFunctionCall: { auto args = std::make_unique(loc); auto name = std::make_unique(loc, inst->data[0].substr(4)); auto file = std::make_unique(loc); auto var = std::move(stack_.top()); stack_.pop(); loc = var->loc; while(var->type != gsc::node_t::asm_prescriptcall) { args->list.push_back(std::move(var)); var = std::move(stack_.top()); stack_.pop(); loc = var->loc; } auto func = gsc::expr_call_type_ptr(std::make_unique(loc, std::move(file), std::move(name), std::move(args))); auto obj = gsc::expr_ptr(std::make_unique()); auto expr = std::make_unique(loc, false, false, std::move(obj) ,std::move(func)); stack_.push(std::move(expr)); } break; case opcode::OP_ScriptLocalMethodCall: { auto obj = gsc::expr_ptr(std::move(stack_.top())); stack_.pop(); loc = obj.as_node->loc; auto args = std::make_unique(loc); auto name = std::make_unique(loc, inst->data[0].substr(4)); auto file = std::make_unique(loc); auto var = std::move(stack_.top()); stack_.pop(); loc = var->loc; while(var->type != gsc::node_t::asm_prescriptcall) { args->list.push_back(std::move(var)); var = std::move(stack_.top()); stack_.pop(); loc = var->loc; } auto func = gsc::expr_call_type_ptr(std::make_unique(loc, std::move(file), std::move(name), std::move(args))); auto expr = std::make_unique(loc, false, false, std::move(obj) ,std::move(func)); stack_.push(std::move(expr)); } break; case opcode::OP_ScriptLocalThreadCall: { auto args = std::make_unique(loc); auto name = std::make_unique(loc, inst->data[0].substr(4)); auto file = std::make_unique(loc); auto argnum = std::stoul(inst->data[1]); for (size_t i = argnum; i > 0; i--) { auto var = std::move(stack_.top()); stack_.pop(); loc = var->loc; args->list.push_back(std::move(var)); } auto func = gsc::expr_call_type_ptr(std::make_unique(loc, std::move(file), std::move(name), std::move(args))); auto obj = gsc::expr_ptr(std::make_unique()); auto expr = std::make_unique(loc, true, false, std::move(obj) ,std::move(func)); stack_.push(std::move(expr)); } break; case opcode::OP_ScriptLocalChildThreadCall: { auto args = std::make_unique(loc); auto name = std::make_unique(loc, inst->data[0].substr(4)); auto file = std::make_unique(loc); auto argnum = std::stoul(inst->data[1]); for (size_t i = argnum; i > 0; i--) { auto var = std::move(stack_.top()); stack_.pop(); loc = var->loc; args->list.push_back(std::move(var)); } auto func = gsc::expr_call_type_ptr(std::make_unique(loc, std::move(file), std::move(name), std::move(args))); auto obj = gsc::expr_ptr(std::make_unique()); auto expr = std::make_unique(loc, false, true, std::move(obj) ,std::move(func)); stack_.push(std::move(expr)); } break; case opcode::OP_ScriptLocalMethodThreadCall: { auto obj = gsc::expr_ptr(std::move(stack_.top())); stack_.pop(); loc = obj.as_node->loc; auto args = std::make_unique(loc); auto name = std::make_unique(loc, inst->data[0].substr(4)); auto file = std::make_unique(loc); auto argnum = std::stoul(inst->data[1]); for (size_t i = argnum; i > 0; i--) { auto var = std::move(stack_.top()); stack_.pop(); loc = var->loc; args->list.push_back(std::move(var)); } auto func = gsc::expr_call_type_ptr(std::make_unique(loc, std::move(file), std::move(name), std::move(args))); auto expr = std::make_unique(loc, true, false, std::move(obj) ,std::move(func)); stack_.push(std::move(expr)); } break; case opcode::OP_ScriptLocalMethodChildThreadCall: { auto obj = gsc::expr_ptr(std::move(stack_.top())); stack_.pop(); loc = obj.as_node->loc; auto args = std::make_unique(loc); auto name = std::make_unique(loc, inst->data[0].substr(4)); auto file = std::make_unique(loc); auto argnum = std::stoul(inst->data[1]); for (size_t i = argnum; i > 0; i--) { auto var = std::move(stack_.top()); stack_.pop(); loc = var->loc; args->list.push_back(std::move(var)); } auto func = gsc::expr_call_type_ptr(std::make_unique(loc, std::move(file), std::move(name), std::move(args))); auto expr = std::make_unique(loc, false, true, std::move(obj) ,std::move(func)); stack_.push(std::move(expr)); } break; case opcode::OP_ScriptFarFunctionCall2: { auto args = std::make_unique(loc); auto name = std::make_unique(loc, inst->data[1]); auto file = std::make_unique(loc, utils::string::backslash(inst->data[0])); auto func = gsc::expr_call_type_ptr(std::make_unique(loc, std::move(file), std::move(name), std::move(args))); auto obj = gsc::expr_ptr(std::make_unique()); auto expr = std::make_unique(loc, false, false, std::move(obj) ,std::move(func)); stack_.push(std::move(expr)); } break; case opcode::OP_ScriptFarFunctionCall: { auto args = std::make_unique(loc); auto name = std::make_unique(loc, inst->data[1]); auto file = std::make_unique(loc, utils::string::backslash(inst->data[0])); auto var = std::move(stack_.top()); stack_.pop(); loc = var->loc; while(var->type != gsc::node_t::asm_prescriptcall) { args->list.push_back(std::move(var)); var = std::move(stack_.top()); stack_.pop(); loc = var->loc; } auto func = gsc::expr_call_type_ptr(std::make_unique(loc, std::move(file), std::move(name), std::move(args))); auto obj = gsc::expr_ptr(std::make_unique()); auto expr = std::make_unique(loc, false, false, std::move(obj) ,std::move(func)); stack_.push(std::move(expr)); } break; case opcode::OP_ScriptFarMethodCall: { auto obj = gsc::expr_ptr(std::move(stack_.top())); stack_.pop(); loc = obj.as_node->loc; auto args = std::make_unique(loc); auto name = std::make_unique(loc, inst->data[1]); auto file = std::make_unique(loc, utils::string::backslash(inst->data[0])); auto var = std::move(stack_.top()); stack_.pop(); loc = var->loc; while(var->type != gsc::node_t::asm_prescriptcall) { args->list.push_back(std::move(var)); var = std::move(stack_.top()); stack_.pop(); loc = var->loc; } auto func = gsc::expr_call_type_ptr(std::make_unique(loc, std::move(file), std::move(name), std::move(args))); auto expr = std::make_unique(loc, false, false, std::move(obj) ,std::move(func)); stack_.push(std::move(expr)); } break; case opcode::OP_ScriptFarThreadCall: { auto args = std::make_unique(loc); auto name = std::make_unique(loc, inst->data[2]); auto file = std::make_unique(loc, utils::string::backslash(inst->data[1])); auto argnum = std::stoul(inst->data[0]); for (size_t i = argnum; i > 0; i--) { auto var = std::move(stack_.top()); stack_.pop(); loc = var->loc; args->list.push_back(std::move(var)); } auto func = gsc::expr_call_type_ptr(std::make_unique(loc, std::move(file), std::move(name), std::move(args))); auto obj = gsc::expr_ptr(std::make_unique()); auto expr = std::make_unique(loc, true, false, std::move(obj) ,std::move(func)); stack_.push(std::move(expr)); } break; case opcode::OP_ScriptFarChildThreadCall: { auto args = std::make_unique(loc); auto name = std::make_unique(loc, inst->data[2]); auto file = std::make_unique(loc, utils::string::backslash(inst->data[1])); auto argnum = std::stoul(inst->data[0]); for (size_t i = argnum; i > 0; i--) { auto var = std::move(stack_.top()); stack_.pop(); loc = var->loc; args->list.push_back(std::move(var)); } auto func = gsc::expr_call_type_ptr(std::make_unique(loc, std::move(file), std::move(name), std::move(args))); auto obj = gsc::expr_ptr(std::make_unique()); auto expr = std::make_unique(loc, false, true, std::move(obj) ,std::move(func)); stack_.push(std::move(expr)); } break; case opcode::OP_ScriptFarMethodThreadCall: { auto obj = gsc::expr_ptr(std::move(stack_.top())); stack_.pop(); loc = obj.as_node->loc; auto args = std::make_unique(loc); auto name = std::make_unique(loc, inst->data[2]); auto file = std::make_unique(loc, utils::string::backslash(inst->data[1])); auto argnum = std::stoul(inst->data[0]); for (size_t i = argnum; i > 0; i--) { auto var = std::move(stack_.top()); stack_.pop(); loc = var->loc; args->list.push_back(std::move(var)); } auto func = gsc::expr_call_type_ptr(std::make_unique(loc, std::move(file), std::move(name), std::move(args))); auto expr = std::make_unique(loc, true, false, std::move(obj) ,std::move(func)); stack_.push(std::move(expr)); } break; case opcode::OP_ScriptFarMethodChildThreadCall: { auto obj = gsc::expr_ptr(std::move(stack_.top())); stack_.pop(); loc = obj.as_node->loc; auto args = std::make_unique(loc); auto name = std::make_unique(loc, inst->data[2]); auto file = std::make_unique(loc, utils::string::backslash(inst->data[1])); auto argnum = std::stoul(inst->data[0]); for (size_t i = argnum; i > 0; i--) { auto var = std::move(stack_.top()); stack_.pop(); loc = var->loc; args->list.push_back(std::move(var)); } auto func = gsc::expr_call_type_ptr(std::make_unique(loc, std::move(file), std::move(name), std::move(args))); auto expr = std::make_unique(loc, false, true, std::move(obj) ,std::move(func)); stack_.push(std::move(expr)); } break; case opcode::OP_ScriptFunctionCallPointer: { auto args = std::make_unique(loc); auto exprf = gsc::expr_ptr(std::move(stack_.top())); stack_.pop(); loc = exprf.as_node->loc; auto var = std::move(stack_.top()); stack_.pop(); loc = var->loc; while(var->type != gsc::node_t::asm_prescriptcall) { args->list.push_back(std::move(var)); var = std::move(stack_.top()); stack_.pop(); loc = var->loc; } auto func = gsc::expr_call_type_ptr(std::make_unique(loc, false, std::move(exprf), std::move(args))); auto obj = gsc::expr_ptr(std::make_unique()); auto expr = std::make_unique(loc, false, false, std::move(obj) ,std::move(func)); stack_.push(std::move(expr)); } break; case opcode::OP_ScriptMethodCallPointer: { auto exprf = gsc::expr_ptr(std::move(stack_.top())); stack_.pop(); auto obj = gsc::expr_ptr(std::move(stack_.top())); stack_.pop(); loc = obj.as_node->loc; auto args = std::make_unique(loc); auto var = std::move(stack_.top()); stack_.pop(); loc = var->loc; while(var->type != gsc::node_t::asm_prescriptcall) { args->list.push_back(std::move(var)); var = std::move(stack_.top()); stack_.pop(); loc = var->loc; } auto func = gsc::expr_call_type_ptr(std::make_unique(loc, false, std::move(exprf), std::move(args))); auto expr = std::make_unique(loc, false, false, std::move(obj) ,std::move(func)); stack_.push(std::move(expr)); } break; case opcode::OP_ScriptThreadCallPointer: { auto args = std::make_unique(loc); auto exprf = gsc::expr_ptr(std::move(stack_.top())); stack_.pop(); loc = exprf.as_node->loc; auto argnum = std::stoul(inst->data[0]); for (size_t i = argnum; i > 0; i--) { auto var = std::move(stack_.top()); stack_.pop(); loc = var->loc; args->list.push_back(std::move(var)); } auto func = gsc::expr_call_type_ptr(std::make_unique(loc, false, std::move(exprf), std::move(args))); auto obj = gsc::expr_ptr(std::make_unique()); auto expr = std::make_unique(loc, true, false, std::move(obj) ,std::move(func)); stack_.push(std::move(expr)); } break; case opcode::OP_ScriptChildThreadCallPointer: { auto args = std::make_unique(loc); auto exprf = gsc::expr_ptr(std::move(stack_.top())); stack_.pop(); loc = exprf.as_node->loc; auto argnum = std::stoul(inst->data[0]); for (size_t i = argnum; i > 0; i--) { auto var = std::move(stack_.top()); stack_.pop(); loc = var->loc; args->list.push_back(std::move(var)); } auto func = gsc::expr_call_type_ptr(std::make_unique(loc, false, std::move(exprf), std::move(args))); auto obj = gsc::expr_ptr(std::make_unique()); auto expr = std::make_unique(loc, false, true, std::move(obj) ,std::move(func)); stack_.push(std::move(expr)); } break; case opcode::OP_ScriptMethodThreadCallPointer: { auto args = std::make_unique(loc); auto exprf = gsc::expr_ptr(std::move(stack_.top())); stack_.pop(); auto obj = gsc::expr_ptr(std::move(stack_.top())); stack_.pop(); loc = obj.as_node->loc; auto argnum = std::stoul(inst->data[0]); for (size_t i = argnum; i > 0; i--) { auto var = std::move(stack_.top()); stack_.pop(); loc = var->loc; args->list.push_back(std::move(var)); } auto func = gsc::expr_call_type_ptr(std::make_unique(loc, false, std::move(exprf), std::move(args))); auto expr = std::make_unique(loc, true, false, std::move(obj) ,std::move(func)); stack_.push(std::move(expr)); } break; case opcode::OP_ScriptMethodChildThreadCallPointer: { auto args = std::make_unique(loc); auto exprf = gsc::expr_ptr(std::move(stack_.top())); stack_.pop(); auto obj = gsc::expr_ptr(std::move(stack_.top())); stack_.pop(); loc = obj.as_node->loc; auto argnum = std::stoul(inst->data[0]); for (size_t i = argnum; i > 0; i--) { auto var = std::move(stack_.top()); stack_.pop(); loc = var->loc; args->list.push_back(std::move(var)); } auto func = gsc::expr_call_type_ptr(std::make_unique(loc, false, std::move(exprf), std::move(args))); auto expr = std::make_unique(loc, false, true, std::move(obj) ,std::move(func)); stack_.push(std::move(expr)); } break; case opcode::OP_CallBuiltinPointer: { auto args = std::make_unique(loc); auto exprf = gsc::expr_ptr(std::move(stack_.top())); stack_.pop(); loc = exprf.as_node->loc; auto argnum = std::stoul(inst->data[0]); for (size_t i = argnum; i > 0; i--) { auto var = std::move(stack_.top()); stack_.pop(); loc = var->loc; args->list.push_back(std::move(var)); } auto obj = gsc::expr_ptr(std::make_unique()); auto func = gsc::expr_call_type_ptr(std::make_unique(loc, true, std::move(exprf), std::move(args))); auto expr = std::make_unique(loc, false, false, std::move(obj) ,std::move(func)); stack_.push(std::move(expr)); } break; case opcode::OP_CallBuiltinMethodPointer: { auto args = std::make_unique(loc); auto exprf = gsc::expr_ptr(std::move(stack_.top())); stack_.pop(); auto obj = gsc::expr_ptr(std::move(stack_.top())); stack_.pop(); loc = obj.as_node->loc; auto argnum = std::stoul(inst->data[0]); for (size_t i = argnum; i > 0; i--) { auto var = std::move(stack_.top()); stack_.pop(); loc = var->loc; args->list.push_back(std::move(var)); } auto func = gsc::expr_call_type_ptr(std::make_unique(loc, true, std::move(exprf), std::move(args))); auto expr = std::make_unique(loc, false, false, std::move(obj) ,std::move(func)); stack_.push(std::move(expr)); } break; case opcode::OP_CallBuiltin0: { auto obj = gsc::expr_ptr(std::make_unique()); auto args = std::make_unique(loc); auto name = std::make_unique(loc, inst->data[0]); auto file = std::make_unique(loc); auto func = gsc::expr_call_type_ptr(std::make_unique(loc, std::move(file), std::move(name), std::move(args))); auto expr = std::make_unique(loc, false, false, std::move(obj) ,std::move(func)); stack_.push(std::move(expr)); } break; case opcode::OP_CallBuiltin1: { auto obj = gsc::expr_ptr(std::make_unique()); auto args = std::make_unique(loc); auto name = std::make_unique(loc, inst->data[0]); auto file = std::make_unique(loc); for (size_t i = 1; i > 0; i--) { auto var = std::move(stack_.top()); stack_.pop(); loc = var->loc; args->list.push_back(std::move(var)); } auto func = gsc::expr_call_type_ptr(std::make_unique(loc, std::move(file), std::move(name), std::move(args))); auto expr = std::make_unique(loc, false, false, std::move(obj) ,std::move(func)); stack_.push(std::move(expr)); } break; case opcode::OP_CallBuiltin2: { auto obj = gsc::expr_ptr(std::make_unique()); auto args = std::make_unique(loc); auto name = std::make_unique(loc, inst->data[0]); auto file = std::make_unique(loc); for (size_t i = 2; i > 0; i--) { auto var = std::move(stack_.top()); stack_.pop(); loc = var->loc; args->list.push_back(std::move(var)); } auto func = gsc::expr_call_type_ptr(std::make_unique(loc, std::move(file), std::move(name), std::move(args))); auto expr = std::make_unique(loc, false, false, std::move(obj) ,std::move(func)); stack_.push(std::move(expr)); } break; case opcode::OP_CallBuiltin3: { auto obj = gsc::expr_ptr(std::make_unique()); auto args = std::make_unique(loc); auto name = std::make_unique(loc, inst->data[0]); auto file = std::make_unique(loc); for (size_t i = 3; i > 0; i--) { auto var = std::move(stack_.top()); stack_.pop(); loc = var->loc; args->list.push_back(std::move(var)); } auto func = gsc::expr_call_type_ptr(std::make_unique(loc, std::move(file), std::move(name), std::move(args))); auto expr = std::make_unique(loc, false, false, std::move(obj) ,std::move(func)); stack_.push(std::move(expr)); } break; case opcode::OP_CallBuiltin4: { auto obj = gsc::expr_ptr(std::make_unique()); auto args = std::make_unique(loc); auto name = std::make_unique(loc, inst->data[0]); auto file = std::make_unique(loc); for (size_t i = 4; i > 0; i--) { auto var = std::move(stack_.top()); stack_.pop(); loc = var->loc; args->list.push_back(std::move(var)); } auto func = gsc::expr_call_type_ptr(std::make_unique(loc, std::move(file), std::move(name), std::move(args))); auto expr = std::make_unique(loc, false, false, std::move(obj) ,std::move(func)); stack_.push(std::move(expr)); } break; case opcode::OP_CallBuiltin5: { auto obj = gsc::expr_ptr(std::make_unique()); auto args = std::make_unique(loc); auto name = std::make_unique(loc, inst->data[0]); auto file = std::make_unique(loc); for (size_t i = 5; i > 0; i--) { auto var = std::move(stack_.top()); stack_.pop(); loc = var->loc; args->list.push_back(std::move(var)); } auto func = gsc::expr_call_type_ptr(std::make_unique(loc, std::move(file), std::move(name), std::move(args))); auto expr = std::make_unique(loc, false, false, std::move(obj) ,std::move(func)); stack_.push(std::move(expr)); } break; case opcode::OP_CallBuiltin: { auto obj = gsc::expr_ptr(std::make_unique()); auto args = std::make_unique(loc); auto name = std::make_unique(loc, inst->data[1]); auto file = std::make_unique(loc); auto argnum = std::stoul(inst->data[0]); for (size_t i = argnum; i > 0; i--) { auto var = std::move(stack_.top()); stack_.pop(); loc = var->loc; args->list.push_back(std::move(var)); } auto func = gsc::expr_call_type_ptr(std::make_unique(loc, std::move(file), std::move(name), std::move(args))); auto expr = std::make_unique(loc, false, false, std::move(obj) ,std::move(func)); stack_.push(std::move(expr)); } break; case opcode::OP_CallBuiltinMethod0: { auto obj = gsc::expr_ptr(std::move(stack_.top())); stack_.pop(); loc = obj.as_node->loc; auto args = std::make_unique(loc); auto name = std::make_unique(loc, inst->data[0]); auto file = std::make_unique(loc); auto func = gsc::expr_call_type_ptr(std::make_unique(loc, std::move(file), std::move(name), std::move(args))); auto expr = std::make_unique(loc, false, false, std::move(obj) ,std::move(func)); stack_.push(std::move(expr)); } break; case opcode::OP_CallBuiltinMethod1: { auto obj = gsc::expr_ptr(std::move(stack_.top())); stack_.pop(); auto args = std::make_unique(loc); auto name = std::make_unique(loc, inst->data[0]); auto file = std::make_unique(loc); for (size_t i = 1; i > 0; i--) { auto var = std::move(stack_.top()); stack_.pop(); loc = var->loc; args->list.push_back(std::move(var)); } auto func = gsc::expr_call_type_ptr(std::make_unique(loc, std::move(file), std::move(name), std::move(args))); auto expr = std::make_unique(loc, false, false, std::move(obj) ,std::move(func)); stack_.push(std::move(expr)); } break; case opcode::OP_CallBuiltinMethod2: { auto obj = gsc::expr_ptr(std::move(stack_.top())); stack_.pop(); auto args = std::make_unique(loc); auto name = std::make_unique(loc, inst->data[0]); auto file = std::make_unique(loc); for (size_t i = 2; i > 0; i--) { auto var = std::move(stack_.top()); stack_.pop(); loc = var->loc; args->list.push_back(std::move(var)); } auto func = gsc::expr_call_type_ptr(std::make_unique(loc, std::move(file), std::move(name), std::move(args))); auto expr = std::make_unique(loc, false, false, std::move(obj) ,std::move(func)); stack_.push(std::move(expr)); } break; case opcode::OP_CallBuiltinMethod3: { auto obj = gsc::expr_ptr(std::move(stack_.top())); stack_.pop(); auto args = std::make_unique(loc); auto name = std::make_unique(loc, inst->data[0]); auto file = std::make_unique(loc); for (size_t i = 3; i > 0; i--) { auto var = std::move(stack_.top()); stack_.pop(); loc = var->loc; args->list.push_back(std::move(var)); } auto func = gsc::expr_call_type_ptr(std::make_unique(loc, std::move(file), std::move(name), std::move(args))); auto expr = std::make_unique(loc, false, false, std::move(obj) ,std::move(func)); stack_.push(std::move(expr)); } break; case opcode::OP_CallBuiltinMethod4: { auto obj = gsc::expr_ptr(std::move(stack_.top())); stack_.pop(); auto args = std::make_unique(loc); auto name = std::make_unique(loc, inst->data[0]); auto file = std::make_unique(loc); for (size_t i = 4; i > 0; i--) { auto var = std::move(stack_.top()); stack_.pop(); loc = var->loc; args->list.push_back(std::move(var)); } auto func = gsc::expr_call_type_ptr(std::make_unique(loc, std::move(file), std::move(name), std::move(args))); auto expr = std::make_unique(loc, false, false, std::move(obj) ,std::move(func)); stack_.push(std::move(expr)); } break; case opcode::OP_CallBuiltinMethod5: { auto obj = gsc::expr_ptr(std::move(stack_.top())); stack_.pop(); auto args = std::make_unique(loc); auto name = std::make_unique(loc, inst->data[0]); auto file = std::make_unique(loc); for (size_t i = 5; i > 0; i--) { auto var = std::move(stack_.top()); stack_.pop(); loc = var->loc; args->list.push_back(std::move(var)); } auto func = gsc::expr_call_type_ptr(std::make_unique(loc, std::move(file), std::move(name), std::move(args))); auto expr = std::make_unique(loc, false, false, std::move(obj) ,std::move(func)); stack_.push(std::move(expr)); } break; case opcode::OP_CallBuiltinMethod: { auto obj = gsc::expr_ptr(std::move(stack_.top())); stack_.pop(); loc = obj.as_node->loc; auto args = std::make_unique(loc); auto name = std::make_unique(loc, inst->data[1]); auto file = std::make_unique(loc); auto argnum = std::stoul(inst->data[0]); for (size_t i = argnum; i > 0; i--) { auto var = std::move(stack_.top()); stack_.pop(); loc = var->loc; args->list.push_back(std::move(var)); } auto func = gsc::expr_call_type_ptr(std::make_unique(loc, std::move(file), std::move(name), std::move(args))); auto expr = std::make_unique(loc, false, false, std::move(obj) ,std::move(func)); stack_.push(std::move(expr)); } break; case opcode::OP_DecTop: { auto expr = std::move(stack_.top()); stack_.pop(); loc = expr->loc; auto stmt = std::make_unique(loc, std::move(*(gsc::expr_call_ptr*)&expr)); func_->block->stmts.push_back(gsc::stmt_ptr(std::move(stmt))); } break; case opcode::OP_inc: { auto lvalue = gsc::expr_ptr(std::move(stack_.top())); stack_.pop(); loc = lvalue.as_node->loc; auto expr = std::make_unique(loc, std::move(lvalue)); stack_.push(std::move(expr)); } break; case opcode::OP_dec: { auto lvalue = gsc::expr_ptr(std::move(stack_.top())); stack_.pop(); loc = lvalue.as_node->loc; auto expr = std::make_unique(loc, std::move(lvalue)); stack_.push(std::move(expr)); } break; case opcode::OP_bit_or: { auto rvalue = gsc::expr_ptr(std::move(stack_.top())); stack_.pop(); auto lvalue = gsc::expr_ptr(std::move(stack_.top())); stack_.pop(); loc = lvalue.as_node->loc; auto expr = std::make_unique(loc, std::move(lvalue), std::move(rvalue)); stack_.push(std::move(expr)); } break; case opcode::OP_bit_ex_or: { auto rvalue = gsc::expr_ptr(std::move(stack_.top())); stack_.pop(); auto lvalue = gsc::expr_ptr(std::move(stack_.top())); stack_.pop(); loc = lvalue.as_node->loc; auto expr = std::make_unique(loc, std::move(lvalue), std::move(rvalue)); stack_.push(std::move(expr)); } break; case opcode::OP_bit_and: { auto rvalue = gsc::expr_ptr(std::move(stack_.top())); stack_.pop(); auto lvalue = gsc::expr_ptr(std::move(stack_.top())); stack_.pop(); loc = lvalue.as_node->loc; auto expr = std::make_unique(loc, std::move(lvalue), std::move(rvalue)); stack_.push(std::move(expr)); } break; case opcode::OP_equality: { auto rvalue = gsc::expr_ptr(std::move(stack_.top())); stack_.pop(); auto lvalue = gsc::expr_ptr(std::move(stack_.top())); stack_.pop(); loc = lvalue.as_node->loc; auto expr = std::make_unique(loc, std::move(lvalue), std::move(rvalue)); stack_.push(std::move(expr)); } break; case opcode::OP_inequality: { auto rvalue = gsc::expr_ptr(std::move(stack_.top())); stack_.pop(); auto lvalue = gsc::expr_ptr(std::move(stack_.top())); stack_.pop(); loc = lvalue.as_node->loc; auto expr = std::make_unique(loc, std::move(lvalue), std::move(rvalue)); stack_.push(std::move(expr)); } break; case opcode::OP_less: { auto rvalue = gsc::expr_ptr(std::move(stack_.top())); stack_.pop(); auto lvalue = gsc::expr_ptr(std::move(stack_.top())); stack_.pop(); loc = lvalue.as_node->loc; auto expr = std::make_unique(loc, std::move(lvalue), std::move(rvalue)); stack_.push(std::move(expr)); } break; case opcode::OP_greater: { auto rvalue = gsc::expr_ptr(std::move(stack_.top())); stack_.pop(); auto lvalue = gsc::expr_ptr(std::move(stack_.top())); stack_.pop(); loc = lvalue.as_node->loc; auto expr = std::make_unique(loc, std::move(lvalue), std::move(rvalue)); stack_.push(std::move(expr)); } break; case opcode::OP_less_equal: { auto rvalue = gsc::expr_ptr(std::move(stack_.top())); stack_.pop(); auto lvalue = gsc::expr_ptr(std::move(stack_.top())); stack_.pop(); loc = lvalue.as_node->loc; auto expr = std::make_unique(loc, std::move(lvalue), std::move(rvalue)); stack_.push(std::move(expr)); } break; case opcode::OP_greater_equal: { auto rvalue = gsc::expr_ptr(std::move(stack_.top())); stack_.pop(); auto lvalue = gsc::expr_ptr(std::move(stack_.top())); stack_.pop(); loc = lvalue.as_node->loc; auto expr = std::make_unique(loc, std::move(lvalue), std::move(rvalue)); stack_.push(std::move(expr)); } break; case opcode::OP_shift_left: { auto rvalue = gsc::expr_ptr(std::move(stack_.top())); stack_.pop(); auto lvalue = gsc::expr_ptr(std::move(stack_.top())); stack_.pop(); loc = lvalue.as_node->loc; auto expr = std::make_unique(loc, std::move(lvalue), std::move(rvalue)); stack_.push(std::move(expr)); } break; case opcode::OP_shift_right: { auto rvalue = gsc::expr_ptr(std::move(stack_.top())); stack_.pop(); auto lvalue = gsc::expr_ptr(std::move(stack_.top())); stack_.pop(); loc = lvalue.as_node->loc; auto expr = std::make_unique(loc, std::move(lvalue), std::move(rvalue)); stack_.push(std::move(expr)); } break; case opcode::OP_plus: { auto rvalue = gsc::expr_ptr(std::move(stack_.top())); stack_.pop(); auto lvalue = gsc::expr_ptr(std::move(stack_.top())); stack_.pop(); loc = lvalue.as_node->loc; auto expr = std::make_unique(loc, std::move(lvalue), std::move(rvalue)); stack_.push(std::move(expr)); } break; case opcode::OP_minus: { auto rvalue = gsc::expr_ptr(std::move(stack_.top())); stack_.pop(); auto lvalue = gsc::expr_ptr(std::move(stack_.top())); stack_.pop(); loc = lvalue.as_node->loc; auto expr = std::make_unique(loc, std::move(lvalue), std::move(rvalue)); stack_.push(std::move(expr)); } break; case opcode::OP_multiply: { auto rvalue = gsc::expr_ptr(std::move(stack_.top())); stack_.pop(); auto lvalue = gsc::expr_ptr(std::move(stack_.top())); stack_.pop(); loc = lvalue.as_node->loc; auto expr = std::make_unique(loc, std::move(lvalue), std::move(rvalue)); stack_.push(std::move(expr)); } break; case opcode::OP_divide: { auto rvalue = gsc::expr_ptr(std::move(stack_.top())); stack_.pop(); auto lvalue = gsc::expr_ptr(std::move(stack_.top())); stack_.pop(); loc = lvalue.as_node->loc; auto expr = std::make_unique(loc, std::move(lvalue), std::move(rvalue)); stack_.push(std::move(expr)); } break; case opcode::OP_mod: { auto rvalue = gsc::expr_ptr(std::move(stack_.top())); stack_.pop(); auto lvalue = gsc::expr_ptr(std::move(stack_.top())); stack_.pop(); loc = lvalue.as_node->loc; auto expr = std::make_unique(loc, std::move(lvalue), std::move(rvalue)); stack_.push(std::move(expr)); } break; case opcode::OP_wait: { auto expr = std::move(stack_.top()); stack_.pop(); loc = expr->loc; auto stmt = std::make_unique(loc, std::move(expr)); func_->block->stmts.push_back(gsc::stmt_ptr(std::move(stmt))); } break; case opcode::OP_waittillFrameEnd: { auto stmt = gsc::stmt_ptr(std::make_unique(loc)); func_->block->stmts.push_back(std::move(stmt)); } break; case opcode::OP_waitframe: { auto stmt = gsc::stmt_ptr(std::make_unique(loc)); func_->block->stmts.push_back(std::move(stmt)); } break; case opcode::OP_waittill: { auto obj = gsc::expr_ptr(std::move(stack_.top())); stack_.pop(); auto nstr = gsc::expr_ptr(std::move(stack_.top())); stack_.pop(); loc = nstr.as_node->loc; auto args = std::make_unique(loc); auto stmt = std::make_unique(loc, std::move(obj) , std::move(nstr), std::move(args)); stack_.push(std::move(stmt)); in_waittill = true; } break; case opcode::OP_waittillmatch: { auto obj = gsc::expr_ptr(std::move(stack_.top())); stack_.pop(); auto expr = gsc::expr_ptr(std::move(stack_.top())); stack_.pop(); loc = expr.as_node->loc; gsc::expr_arguments_ptr args = std::make_unique(); args->loc = loc; auto argnum = std::stoul(inst->data[0]); for (auto i = 0u; i < argnum; i++) { auto node = std::move(stack_.top()); stack_.pop(); args->loc = node->loc; args->list.push_back(std::move(node)); } loc = args->loc; auto stmt = std::make_unique(loc, std::move(obj), std::move(expr), std::move(args)); stack_.push(std::move(stmt)); } break; case opcode::OP_clearparams: { auto args = std::make_unique(loc); auto var = std::move(stack_.top()); stack_.pop(); while(var->type != gsc::node_t::stmt_waittill && var->type != gsc::node_t::stmt_waittillmatch) { args->list.push_back(std::move(var)); var = std::move(stack_.top()); stack_.pop(); } if(var->type == gsc::node_t::stmt_waittill) { std::reverse(args->list.begin(), args->list.end()); (*(gsc::stmt_waittill_ptr*)&var)->args = std::move(args); in_waittill = false; } func_->block->stmts.push_back(gsc::stmt_ptr(std::move(var))); } break; case opcode::OP_checkclearparams: break; case opcode::OP_notify: { auto obj = gsc::expr_ptr(std::move(stack_.top())); stack_.pop(); auto nstr = gsc::expr_ptr(std::move(stack_.top())); stack_.pop(); auto args = std::make_unique(loc); auto var = std::move(stack_.top()); stack_.pop(); loc = var->loc; while(var->type != gsc::node_t::asm_voidcodepos) { args->list.push_back(std::move(var)); var = std::move(stack_.top()); stack_.pop(); loc = var->loc; } auto stmt = std::make_unique(loc, std::move(obj) , std::move(nstr), std::move(args)); func_->block->stmts.push_back(gsc::stmt_ptr(std::move(stmt))); } break; case opcode::OP_endon: { auto obj = gsc::expr_ptr(std::move(stack_.top())); stack_.pop(); auto nstr = gsc::expr_ptr(std::move(stack_.top())); stack_.pop(); loc = nstr.as_node->loc; auto stmt = std::make_unique(loc, std::move(obj) , std::move(nstr)); func_->block->stmts.push_back(gsc::stmt_ptr(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 = gsc::expr_ptr(std::move(stack_.top())); stack_.pop(); auto y = gsc::expr_ptr(std::move(stack_.top())); stack_.pop(); auto z = gsc::expr_ptr(std::move(stack_.top())); stack_.pop(); loc = z.as_node->loc; auto expr = std::make_unique(loc, std::move(x), std::move(y), std::move(z)); stack_.push(std::move(expr)); } break; case opcode::OP_size: { auto lvalue = gsc::expr_ptr(std::move(stack_.top())); stack_.pop(); loc = lvalue.as_node->loc; auto expr = std::make_unique(loc, std::move(lvalue)); stack_.push(std::move(expr)); } break; case opcode::OP_EvalLevelFieldVariable: { auto obj = gsc::expr_ptr(std::make_unique(loc)); auto field = std::make_unique(loc, inst->data[0]); auto stmt = std::make_unique(loc, std::move(obj), std::move(field)); stack_.push(std::move(stmt)); } break; case opcode::OP_EvalAnimFieldVariable: { auto obj = gsc::expr_ptr(std::make_unique(loc)); auto field = std::make_unique(loc, inst->data[0]); auto stmt = std::make_unique(loc, std::move(obj), std::move(field)); stack_.push(std::move(stmt)); } break; case opcode::OP_EvalSelfFieldVariable: { auto obj = gsc::expr_ptr(std::make_unique(loc)); auto field = std::make_unique(loc, inst->data[0]); auto stmt = std::make_unique(loc, std::move(obj), std::move(field)); stack_.push(std::move(stmt)); } break; case opcode::OP_EvalFieldVariable: { auto obj = gsc::expr_ptr(std::move(stack_.top())); stack_.pop(); loc = obj.as_node->loc; auto field = std::make_unique(loc, inst->data[0]); auto stmt = std::make_unique(loc, std::move(obj), std::move(field)); stack_.push(std::move(stmt)); } break; case opcode::OP_EvalLevelFieldVariableRef: { auto obj = gsc::expr_ptr(std::make_unique(loc)); auto field = std::make_unique(loc, inst->data[0]); auto stmt = std::make_unique(loc, std::move(obj), std::move(field)); stack_.push(std::move(stmt)); } break; case opcode::OP_EvalAnimFieldVariableRef: { auto obj = gsc::expr_ptr(std::make_unique(loc)); auto field = std::make_unique(loc, inst->data[0]); auto stmt = std::make_unique(loc, std::move(obj), std::move(field)); stack_.push(std::move(stmt)); } break; case opcode::OP_EvalSelfFieldVariableRef: { auto obj = gsc::expr_ptr(std::make_unique(loc)); auto field = std::make_unique(loc, inst->data[0]); auto stmt = std::make_unique(loc, std::move(obj), std::move(field)); stack_.push(std::move(stmt)); } break; case opcode::OP_EvalFieldVariableRef: { auto obj = gsc::expr_ptr(std::move(stack_.top())); stack_.pop(); loc = obj.as_node->loc; auto field = std::make_unique(loc, inst->data[0]); auto stmt = std::make_unique(loc, std::move(obj), std::move(field)); stack_.push(std::move(stmt)); } break; case opcode::OP_ClearFieldVariable: { auto obj = gsc::expr_ptr(std::move(stack_.top())); stack_.pop(); loc = obj.as_node->loc; auto field = std::make_unique(loc, inst->data[0]); auto expr = gsc::expr_ptr(std::make_unique(loc, std::move(obj), std::move(field))); auto undef = gsc::expr_ptr(std::make_unique(loc)); auto e = std::make_unique(loc, std::move(expr), std::move(undef)); func_->block->stmts.push_back(gsc::stmt_ptr(std::make_unique(loc, std::move(e)))); } break; case opcode::OP_SafeCreateVariableFieldCached: { func_->params->list.push_back(std::make_unique(loc, "var_" + inst->data[0])); } break; case opcode::OP_SafeSetWaittillVariableFieldCached: { if(stack_.top()->type != gsc::node_t::asm_create) { auto node = std::make_unique(loc, inst->data[0]); stack_.push(std::move(node)); } } 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 = gsc::expr_ptr(std::make_unique(loc)); auto field = std::make_unique(loc, inst->data[0]); auto lvalue = gsc::expr_ptr(std::make_unique(loc, std::move(obj), std::move(field))); auto rvalue = gsc::expr_ptr(std::move(stack_.top())); stack_.pop(); loc = rvalue.as_node->loc; auto e = std::make_unique(loc,std::move(lvalue), std::move(rvalue)); auto stmt = std::make_unique(loc, std::move(e)); func_->block->stmts.push_back(gsc::stmt_ptr(std::move(stmt))); } break; case opcode::OP_SetVariableField: { auto lvalue = gsc::expr_ptr(std::move(stack_.top())); stack_.pop(); loc = lvalue.as_node->loc; if(lvalue.as_node->type == gsc::node_t::expr_increment) { auto stmt = std::make_unique(loc, std::move(lvalue.as_increment)); func_->block->stmts.push_back(gsc::stmt_ptr(std::move(stmt))); } else if(lvalue.as_node->type == gsc::node_t::expr_decrement) { auto stmt = std::make_unique(loc, std::move(lvalue.as_decrement)); func_->block->stmts.push_back(gsc::stmt_ptr(std::move(stmt))); } else { auto rvalue = gsc::expr_ptr(std::move(stack_.top())); stack_.pop(); loc = rvalue.as_node->loc; auto e = std::make_unique(loc, std::move(lvalue), std::move(rvalue)); auto stmt = std::make_unique(loc, std::move(e)); func_->block->stmts.push_back(gsc::stmt_ptr(std::move(stmt))); } } break; case opcode::OP_SetAnimFieldVariableField: { auto obj = gsc::expr_ptr(std::make_unique(loc)); auto field = std::make_unique(loc, inst->data[0]); auto lvalue = gsc::expr_ptr(std::make_unique(loc, std::move(obj), std::move(field))); auto rvalue = gsc::expr_ptr(std::move(stack_.top())); stack_.pop(); loc = rvalue.as_node->loc; auto e = std::make_unique(loc, std::move(lvalue), std::move(rvalue)); auto stmt = std::make_unique(loc, std::move(e)); func_->block->stmts.push_back(gsc::stmt_ptr(std::move(stmt))); } break; case opcode::OP_SetSelfFieldVariableField: { auto obj = gsc::expr_ptr(std::make_unique(loc)); auto field = std::make_unique(loc, inst->data[0]); auto lvalue = gsc::expr_ptr(std::make_unique(loc, std::move(obj), std::move(field))); auto rvalue = gsc::expr_ptr(std::move(stack_.top())); stack_.pop(); loc = rvalue.as_node->loc; auto e = std::make_unique(loc, std::move(lvalue), std::move(rvalue)); auto stmt = std::make_unique(loc, std::move(e)); func_->block->stmts.push_back(gsc::stmt_ptr(std::move(stmt))); } break; case opcode::OP_SetLocalVariableFieldCached0: { auto lvalue = gsc::expr_ptr(std::make_unique(loc, "0")); auto rvalue = gsc::expr_ptr(std::move(stack_.top())); stack_.pop(); loc = rvalue.as_node->loc; auto e = std::make_unique(loc, std::move(lvalue), std::move(rvalue)); auto stmt = std::make_unique(loc, std::move(e)); func_->block->stmts.push_back(gsc::stmt_ptr(std::move(stmt))); } break; case opcode::OP_SetNewLocalVariableFieldCached0: { auto lvalue = gsc::expr_ptr(std::make_unique(loc, inst->data[0])); auto rvalue = gsc::expr_ptr(std::move(stack_.top())); stack_.pop(); loc = rvalue.as_node->loc; if(func_->block->stmts.size() > 0) { std::vector creates; while(func_->block->stmts.back().as_node->type == gsc::node_t::asm_create) { auto& entry = func_->block->stmts.back(); if(loc.begin.line < entry.as_node->loc.begin.line) { creates.push_back(entry.as_asm_create->index); func_->block->stmts.pop_back(); continue; } break; } std::reverse(creates.begin(), creates.end()); lvalue.as_asm_create->vars = creates; } auto e = std::make_unique(loc, std::move(lvalue), std::move(rvalue)); auto stmt = std::make_unique(loc, std::move(e)); func_->block->stmts.push_back(gsc::stmt_ptr(std::move(stmt))); } break; case opcode::OP_SetLocalVariableFieldCached: { auto lvalue = gsc::expr_ptr(std::make_unique(loc, inst->data[0])); auto rvalue = gsc::expr_ptr(std::move(stack_.top())); stack_.pop(); loc = rvalue.as_node->loc; auto e = std::make_unique(loc, std::move(lvalue), std::move(rvalue)); auto stmt = std::make_unique(loc, std::move(e)); func_->block->stmts.push_back(gsc::stmt_ptr(std::move(stmt))); } break; case opcode::OP_ClearLocalVariableFieldCached: { auto stmt = std::make_unique(loc, inst->data[0]); func_->block->stmts.push_back(gsc::stmt_ptr(std::move(stmt))); } break; case opcode::OP_ClearLocalVariableFieldCached0: { auto stmt = std::make_unique(loc,"0"); func_->block->stmts.push_back(gsc::stmt_ptr(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_CastFieldObject: case opcode::OP_CastBool: break; case opcode::OP_BoolNot: { auto lvalue = gsc::expr_ptr(std::move(stack_.top())); stack_.pop(); loc = lvalue.as_node->loc; auto expr = std::make_unique(loc, std::move(lvalue)); stack_.push(std::move(expr)); } break; case opcode::OP_BoolComplement: { auto lvalue = gsc::expr_ptr(std::move(stack_.top())); stack_.pop(); loc = lvalue.as_node->loc; auto expr = std::make_unique(loc, std::move(lvalue)); stack_.push(std::move(expr)); } break; case opcode::OP_switch: { auto expr = gsc::expr_ptr(std::move(stack_.top())); stack_.pop(); loc = expr.as_node->loc; auto sw = std::make_unique(loc, std::move(expr), inst->data[0]); func_->block->stmts.push_back(gsc::stmt_ptr(std::move(sw))); } break; case opcode::OP_endswitch: { auto count = inst->data[0]; inst->data.erase(inst->data.begin()); auto data = inst->data; auto end = std::make_unique(loc, data, count); func_->block->stmts.push_back(gsc::stmt_ptr(std::move(end))); } break; case opcode::OP_jump: { auto expr = std::make_unique(loc, inst->data[0]); func_->block->stmts.push_back(gsc::stmt_ptr(std::move(expr))); if(stack_.size() != 0) tern_labels_.push_back(inst->data[0]); } break; case opcode::OP_jumpback: { auto expr = std::make_unique(loc, inst->data[0]); func_->block->stmts.push_back(gsc::stmt_ptr(std::move(expr))); } break; case opcode::OP_JumpOnTrue: { auto lvalue = gsc::expr_ptr(std::move(stack_.top())); stack_.pop(); loc = lvalue.as_node->loc; auto e_not = gsc::expr_ptr(std::make_unique(loc, std::move(lvalue))); auto expr = std::make_unique(loc, std::move(e_not), inst->data[0]); func_->block->stmts.push_back(gsc::stmt_ptr(std::move(expr))); } break; case opcode::OP_JumpOnFalse: { auto lvalue = gsc::expr_ptr(std::move(stack_.top())); stack_.pop(); loc = lvalue.as_node->loc; auto expr = std::make_unique(loc, std::move(lvalue), inst->data[0]); func_->block->stmts.push_back(gsc::stmt_ptr(std::move(expr))); } break; case opcode::OP_JumpOnTrueExpr: { auto lvalue = gsc::expr_ptr(std::move(stack_.top())); stack_.pop(); loc = lvalue.as_node->loc; auto expr = std::make_unique(loc, std::move(lvalue), inst->data[0]); stack_.push(std::move(expr)); expr_labels_.push_back(inst->data[0]); } break; case opcode::OP_JumpOnFalseExpr: { auto lvalue = gsc::expr_ptr(std::move(stack_.top())); stack_.pop(); loc = lvalue.as_node->loc; auto expr = std::make_unique(loc, std::move(lvalue), inst->data[0]); stack_.push(std::move(expr)); 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 param = gsc::expr_ptr(std::move(stack_.top())); stack_.pop(); loc = param.as_node->loc; auto args = std::make_unique(loc); args->list.push_back(std::move(param)); auto name = std::make_unique(loc, "isdefined"); auto file = std::make_unique(loc); auto func = gsc::expr_call_type_ptr(std::make_unique(loc, std::move(file), std::move(name), std::move(args))); auto obj = gsc::expr_ptr(std::make_unique()); auto expr = std::make_unique(loc, false, false, std::move(obj) ,std::move(func)); stack_.push(std::move(expr)); } break; case opcode::OP_IsTrue: { auto param = gsc::expr_ptr(std::move(stack_.top())); stack_.pop(); loc = param.as_node->loc; auto args = std::make_unique(loc); args->list.push_back(std::move(param)); auto name = std::make_unique(loc, "istrue"); auto file = std::make_unique(loc); auto func = gsc::expr_call_type_ptr(std::make_unique(loc, std::move(file), std::move(name), std::move(args))); auto obj = gsc::expr_ptr(std::make_unique()); auto expr = std::make_unique(loc, false, false, std::move(obj) ,std::move(func)); stack_.push(std::move(expr)); } break; case opcode::OP_BoolNotAfterAnd: { auto lvalue = gsc::expr_ptr(std::move(stack_.top())); stack_.pop(); loc = lvalue.as_node->loc; auto expr = std::make_unique(loc, std::move(lvalue)); stack_.push(std::move(expr)); } break; default: throw gsc::decomp_error("unhandled opcode " + resolver::opcode_name(inst->opcode)); break; } } } void decompiler::decompile_expr() { auto expr = std::move(stack_.top()); stack_.pop(); auto jump_expr = std::move(stack_.top()); stack_.pop(); auto loc = jump_expr->loc; if(jump_expr->type == gsc::node_t::asm_jump_true_expr) { auto lvalue = std::move((*(gsc::asm_jump_true_expr_ptr*)&jump_expr)->expr); auto rvalue = gsc::expr_ptr(std::move(expr)); auto e = std::make_unique(loc, std::move(lvalue), std::move(rvalue)); stack_.push(std::move(e)); } else if(jump_expr->type == gsc::node_t::asm_jump_false_expr) { auto lvalue = std::move((*(gsc::asm_jump_false_expr_ptr*)&jump_expr)->expr); auto rvalue = gsc::expr_ptr(std::move(expr)); auto e = std::make_unique(loc, std::move(lvalue), std::move(rvalue)); stack_.push(std::move(e)); } else { throw gsc::decomp_error("TRIED TO DECOMPILE INVALID JUMP EXPR!"); } } void decompiler::decompile_ternary() { auto rvalue = std::move(stack_.top()); stack_.pop(); auto lvalue = std::move(stack_.top()); stack_.pop(); func_->block->stmts.pop_back(); auto stmt = std::move(func_->block->stmts.back()); func_->block->stmts.pop_back(); if(stmt.as_node->type == node_t::asm_jump_cond) { auto loc = stmt.as_cond->loc; auto e = std::make_unique(loc, std::move(stmt.as_cond->expr), std::move(lvalue), std::move(rvalue)); stack_.push(std::move(e)); } else { throw gsc::decomp_error("TRIED TO DECOMPILE INVALID TERNARY EXPR!"); } } void decompiler::decompile_block(const gsc::stmt_list_ptr& block) { this->decompile_search_infinite(block); this->decompile_search_loop(block); this->decompile_search_switch(block); this->decompile_search_ifelse(block); this->decompile_break_continue(block); } void decompiler::decompile_search_infinite(const gsc::stmt_list_ptr& block) { std::int32_t index = block->stmts.size() - 1; while(index >= 0) { if(block->stmts.at(index).as_node->type == gsc::node_t::asm_jump_back) { auto break_loc = last_location_index(block, index) ? blocks_.back().loc_end : utils::string::va("loc_%X", block->stmts.at(index+1).as_node->loc.begin.line); auto begin_loc = block->stmts.at(index).as_jump_back->value; auto start = find_location_index(block, begin_loc); if(block->stmts.at(start).as_node->type != gsc::node_t::asm_jump_cond) { decompile_infinite(block, start, index); index = start; } else if (block->stmts.at(start).as_cond->value != break_loc) { decompile_infinite(block, start, index); index = start; } } index--; } } void decompiler::decompile_search_loop(const gsc::stmt_list_ptr& block) { auto index = 0; while(index < block->stmts.size()) { auto& stmt = block->stmts.at(index); if(stmt.as_node->type == gsc::node_t::asm_jump_cond) { std::uint32_t end; if(stmt.as_cond->value == blocks_.back().loc_end) { end = block->stmts.size() - 1; } else { end = find_location_index(block, stmt.as_cond->value) - 1; } if(block->stmts.at(end).as_node->type == gsc::node_t::asm_jump_back && utils::string::va("loc_%X", block->stmts.at(index).as_node->loc.begin.line) == block->stmts.at(end).as_jump_back->value) { decompile_loop(block, index, end); index = 0; } } index++; } } void decompiler::decompile_search_switch(const gsc::stmt_list_ptr& block) { auto index = 0; while(index < block->stmts.size()) { if(block->stmts.at(index).as_node->type == gsc::node_t::asm_switch) { decompile_switch(block, index); } index++; } } void decompiler::decompile_search_ifelse(const gsc::stmt_list_ptr& block) { auto index = 0; while(index < block->stmts.size()) { auto& stmt = block->stmts.at(index); if(stmt.as_node->type == gsc::node_t::asm_jump_cond) { std::uint32_t end; if(stmt.as_cond->value == blocks_.back().loc_end) { end = block->stmts.size() - 1; } else { end = find_location_index(block, stmt.as_cond->value) - 1; } auto last_loc = blocks_.back().loc_end; if(block->stmts.at(end).as_node->type == gsc::node_t::asm_jump) { // if block is a loop check break, continue if(block->stmts.at(end).as_jump->value == blocks_.back().loc_continue) { // last if/else inside a loop still trigger this :( decompile_if(block, index, end); } else if(block->stmts.at(end).as_jump->value == blocks_.back().loc_break) { decompile_if(block, index, end); } else if(block->stmts.at(end).as_jump->value == blocks_.back().loc_end) { decompile_ifelse(block, index, end); } else if(block->stmts.at(end).as_jump->value == stmt.as_cond->value) { decompile_if(block, index, end); // if block, have a last empty else inside } else { decompile_ifelse(block, index, end); // TODO: if else block is empty, convert it to only if! } } else if(block->stmts.at(end).as_node->type == gsc::node_t::stmt_return && block->stmts.at(end).as_return->expr.as_node->type == gsc::node_t::null) { if(blocks_.back().loc_break != "" || blocks_.back().loc_continue != "") { decompile_if(block, index, end); // inside a loop cant be last } else if(end - index == 1) { decompile_if(block, index, end); // only one explicit return } else if(block->stmts.back().as_node->type != gsc::node_t::stmt_return) { decompile_if(block, index, end); // block end is not a last return } else if(blocks_.back().is_last && block->stmts.back().as_node->type != gsc::node_t::stmt_return) { decompile_if(block, index, end); // inside a last block but is not and inner last } else if(find_location_reference(block, end, block->stmts.size(), last_loc)) { decompile_if(block, index, end); // reference to func end after the if } else if(blocks_.size() > 1 && !blocks_.back().is_last) { decompile_if(block, index, end); // fake last ifelse } else { decompile_last_ifelse(block, index, end); // special case } } else { decompile_if(block, index, end); } } index++; } } void decompiler::decompile_break_continue(const gsc::stmt_list_ptr& block) { auto index = 0; while(index < block->stmts.size()) { if(block->stmts.at(index).as_node->type == gsc::node_t::asm_jump) { auto loc = block->stmts.at(index).as_node->loc; auto jump_loc = block->stmts.at(index).as_jump->value; if(jump_loc == blocks_.back().loc_continue) { block->stmts.erase(block->stmts.begin() + index); auto stmt = gsc::stmt_ptr(std::make_unique(loc)); block->stmts.insert(block->stmts.begin() + index, std::move(stmt)); } else if(jump_loc == blocks_.back().loc_break) { block->stmts.erase(block->stmts.begin() + index); auto stmt = gsc::stmt_ptr(std::make_unique(loc)); block->stmts.insert(block->stmts.begin() + index, std::move(stmt)); } } index++; } } void decompiler::decompile_if(const gsc::stmt_list_ptr& block, std::uint32_t begin, std::uint32_t end) { gsc::context ctx; ctx.loc_end = block->stmts.at(begin).as_cond->value; ctx.loc_break = blocks_.back().loc_break; ctx.loc_continue = blocks_.back().loc_continue; auto loc = block->stmts.at(begin).as_node->loc; auto expr = std::move(block->stmts.at(begin).as_cond->expr); block->stmts.erase(block->stmts.begin() + begin); // remove condition auto if_block = std::make_unique(loc); for(auto i = begin; i < end; i++) { if_block->stmts.push_back(std::move(block->stmts[begin])); block->stmts.erase(block->stmts.begin() + begin); } blocks_.push_back(ctx); decompile_block(if_block); blocks_.pop_back(); auto stmt = gsc::stmt_ptr(std::make_unique(loc, std::move(expr), gsc::stmt_ptr(std::move(if_block)))); block->stmts.insert(block->stmts.begin() + begin, std::move(stmt)); } void decompiler::decompile_ifelse(const gsc::stmt_list_ptr& block, std::uint32_t start, std::uint32_t end) { gsc::context ctx; ctx.loc_end = utils::string::va("loc_%X", block->stmts.at(end).as_node->loc.begin.line); ctx.loc_break = blocks_.back().loc_break; ctx.loc_continue = blocks_.back().loc_continue; auto loc = block->stmts.at(start).as_node->loc; auto expr = std::move(block->stmts.at(start).as_cond->expr); block->stmts.erase(block->stmts.begin() + start); // remove condition end = end - 1; auto if_block = std::make_unique(loc); for(auto i = start; i < end; i++) // skip the jump { if_block->stmts.push_back(std::move(block->stmts[start])); block->stmts.erase(block->stmts.begin() + start); } blocks_.push_back(ctx); decompile_block(if_block); blocks_.pop_back(); auto end_loc = block->stmts.at(start).as_jump->value; block->stmts.erase(block->stmts.begin() + start); // remove jump std::uint32_t end_index; if(end_loc == blocks_.back().loc_end) { end_index = block->stmts.size(); } else { end_index = find_location_index(block, end_loc); } gsc::context ctx2; ctx2.loc_end = end_loc; ctx2.loc_break = blocks_.back().loc_break; ctx2.loc_continue = blocks_.back().loc_continue; auto else_block = std::make_unique(loc); for(auto i = start; i < end_index; i++) { else_block->stmts.push_back(std::move(block->stmts[start])); block->stmts.erase(block->stmts.begin() + start); } blocks_.push_back(ctx2); decompile_block(else_block); blocks_.pop_back(); auto stmt = gsc::stmt_ptr(std::make_unique(loc, std::move(expr), gsc::stmt_ptr(std::move(if_block)), gsc::stmt_ptr(std::move(else_block)))); block->stmts.insert(block->stmts.begin() + start, std::move(stmt)); } void decompiler::decompile_last_ifelse(const gsc::stmt_list_ptr& block, std::uint32_t start, std::uint32_t end) { gsc::context ctx; ctx.is_last = true; auto inner_end = find_location_index(block, block->stmts.at(start).as_cond->value) - 1; ctx.loc_end = utils::string::va("loc_%X",block->stmts.at(inner_end).as_node->loc.begin.line); auto loc = block->stmts.at(start).as_node->loc; auto expr = std::move(block->stmts.at(start).as_cond->expr); block->stmts.erase(block->stmts.begin() + start); // remove condition end = end - 1; auto if_block = std::make_unique(loc); for(auto i = start; i < end; i++) { if_block->stmts.push_back(std::move(block->stmts[start])); block->stmts.erase(block->stmts.begin() + start); } block->stmts.erase(block->stmts.begin() + start); // remove if block return; blocks_.push_back(ctx); decompile_block(if_block); blocks_.pop_back(); if(start == block->stmts.size()) { auto stmt = gsc::stmt_ptr(std::make_unique(loc, std::move(expr), gsc::stmt_ptr(std::move(if_block)))); block->stmts.insert(block->stmts.begin() + start, std::move(stmt)); } else { gsc::context ctx2; ctx2.is_last = true; auto else_block = std::make_unique(loc); end = block->stmts.size(); ctx2.loc_end = utils::string::va("loc_%X", block->stmts.at(end - 1).as_node->loc.begin.line); // return is the block end for(auto i = start; i < end; i++) { else_block->stmts.push_back(std::move(block->stmts[start])); block->stmts.erase(block->stmts.begin() + start); } else_block->stmts.pop_back(); // remove else return; blocks_.push_back(ctx2); decompile_block(else_block); blocks_.pop_back(); auto stmt = gsc::stmt_ptr(std::make_unique(loc, std::move(expr), gsc::stmt_ptr(std::move(if_block)), gsc::stmt_ptr(std::move(else_block)))); block->stmts.insert(block->stmts.begin() + start, std::move(stmt)); } } void decompiler::decompile_infinite(const gsc::stmt_list_ptr& block, std::uint32_t start, std::uint32_t end) { gsc::context ctx; ctx.loc_break = last_location_index(block, end) ? blocks_.back().loc_end : utils::string::va("loc_%X", block->stmts.at(end+1).as_node->loc.begin.line); ctx.loc_end = utils::string::va("loc_%X", block->stmts.at(end).as_node->loc.begin.line); ctx.loc_continue = utils::string::va("loc_%X", block->stmts.at(end).as_node->loc.begin.line); auto loc = block->stmts.at(start).as_node->loc; block->stmts.erase(block->stmts.begin() + end); // remove jump back auto for_block = std::make_unique(loc); for(auto i = start; i < end; i++) { for_block->stmts.push_back(std::move(block->stmts[start])); block->stmts.erase(block->stmts.begin() + start); } blocks_.push_back(ctx); decompile_block(for_block); blocks_.pop_back(); auto pre_expr = gsc::stmt_ptr(std::make_unique()); auto expr = gsc::expr_ptr(std::make_unique()); auto post_expr = gsc::stmt_ptr(std::make_unique()); auto stmt = gsc::stmt_ptr(std::make_unique(loc, std::move(pre_expr), std::move(expr), std::move(post_expr), gsc::stmt_ptr(std::move(for_block)))); block->stmts.insert(block->stmts.begin() + start, std::move(stmt)); } void decompiler::decompile_loop(const gsc::stmt_list_ptr& block, std::uint32_t start, std::uint32_t end) { auto& last_stmt = block->stmts.at(end-1); if(last_stmt.as_node->type == gsc::node_t::stmt_assign) { if(last_stmt.as_assign->expr->type == gsc::node_t::expr_assign_equal) { auto& rval = last_stmt.as_assign->expr->rvalue; if(rval.as_node->type == gsc::node_t::expr_call) { if(rval.as_call->func.as_node->type == gsc::node_t::expr_call_function) { if(utils::string::to_lower(rval.as_call->func.as_func->name->value) == "getnextarraykey") { auto ref2 = utils::string::va("loc_%X", block->stmts.at(start).as_node->loc.begin.line); if(find_location_reference(block, 0, start, ref2)) { // begin is at condition, not pre-expr //decompile_while(block, start, end); //return; } else { decompile_foreach(block, start, end); return; } } } } } if(start > 0) // while at func start { auto index = 1; while(block->stmts.at(start - index).as_node->type == gsc::node_t::asm_create) { if(start - index > 0) index++; } if(block->stmts.at(start - index).as_node->type == gsc::node_t::stmt_assign) { auto ref = utils::string::va("loc_%X", block->stmts.at(end).as_node->loc.begin.line); auto ref2 = utils::string::va("loc_%X", block->stmts.at(start).as_node->loc.begin.line); 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, 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 gsc::stmt_list_ptr& block, std::uint32_t start, std::uint32_t end) { gsc::context ctx; ctx.loc_break = block->stmts.at(start).as_cond->value; ctx.loc_end = utils::string::va("loc_%X", block->stmts.at(end).as_node->loc.begin.line); ctx.loc_continue = utils::string::va("loc_%X",block->stmts.at(end).as_node->loc.begin.line); auto loc = block->stmts.at(start).as_node->loc; auto expr = std::move(block->stmts.at(start).as_cond->expr); block->stmts.erase(block->stmts.begin() + end); // remove jump back block->stmts.erase(block->stmts.begin() + start); // remove condition end = end - 1; auto while_block = std::make_unique(loc); for(auto i = start; i < end; i++) { while_block->stmts.push_back(std::move(block->stmts[start])); block->stmts.erase(block->stmts.begin() + start); } blocks_.push_back(ctx); decompile_block(while_block); blocks_.pop_back(); auto stmt = gsc::stmt_ptr(std::make_unique(loc, std::move(expr), gsc::stmt_ptr(std::move(while_block)))); block->stmts.insert(block->stmts.begin() + start, std::move(stmt)); } void decompiler::decompile_for(const gsc::stmt_list_ptr& block, std::uint32_t start, std::uint32_t end) { gsc::context ctx; ctx.loc_break = block->stmts.at(start).as_cond->value; ctx.loc_end = utils::string::va("loc_%X", block->stmts.at(end - 1).as_node->loc.begin.line); ctx.loc_continue = utils::string::va("loc_%X", block->stmts.at(end - 1).as_node->loc.begin.line); // remove emit local var_creates std::vector creates; while(block->stmts.at(start - 1).as_node->type == gsc::node_t::asm_create) { creates.push_back(block->stmts.at(start - 1).as_asm_create->index); block->stmts.erase(block->stmts.begin() + start - 1); start--; end--; } std::reverse(creates.begin(), creates.end()); auto loc = block->stmts.at(start - 1).as_node->loc; auto expr = std::move(block->stmts.at(start).as_cond->expr); auto pre_expr = gsc::stmt_ptr(std::make_unique()); pre_expr.as_list->stmts.push_back(std::move(block->stmts.at(start - 1))); pre_expr.as_list->is_expr = true; auto post_expr = gsc::stmt_ptr(std::make_unique()); post_expr.as_list->stmts.push_back(std::move(block->stmts.at(end - 1))); post_expr.as_list->is_expr = true; start = start - 1; end = end - 2; for(auto i = start; i < start + 2; i++) // remove prologue (pre-expr, condition) { block->stmts.erase(block->stmts.begin() + start); } end = end - 1; // set end in post-expr for(auto i = end; i < end + 2; i++) // remove epilogue (post-expr, jump back) { block->stmts.erase(block->stmts.begin() + end); } auto for_block = std::make_unique(loc); for(auto i = start; i < end; i++) { for_block->stmts.push_back(std::move(block->stmts[start])); block->stmts.erase(block->stmts.begin() + start); } blocks_.push_back(ctx); decompile_block(for_block); blocks_.pop_back(); auto stmt = gsc::stmt_ptr(std::make_unique(loc, std::move(pre_expr), std::move(expr), std::move(post_expr), gsc::stmt_ptr(std::move(for_block)))); stmt.as_for->vars = creates; block->stmts.insert(block->stmts.begin() + start, std::move(stmt)); } void decompiler::decompile_foreach(const gsc::stmt_list_ptr& block, std::uint32_t begin, std::uint32_t end) { gsc::context ctx; ctx.loc_break = block->stmts.at(begin).as_cond->value; ctx.loc_end = utils::string::va("loc_%X", block->stmts.at(end - 1).as_node->loc.begin.line); ctx.loc_continue = utils::string::va("loc_%X", block->stmts.at(end - 1).as_node->loc.begin.line); // remove local var_creates std::vector creates; while(block->stmts.at(begin - 1).as_node->type == gsc::node_t::asm_create) { creates.push_back(block->stmts.at(begin - 1).as_asm_create->index); block->stmts.erase(block->stmts.begin() + begin - 1); begin--; end--; } std::reverse(creates.begin(), creates.end()); auto loc = block->stmts.at(begin - 2).as_node->loc; auto pre_expr = gsc::stmt_ptr(std::make_unique()); pre_expr.as_list->stmts.push_back(std::move(block->stmts[begin-2])); pre_expr.as_list->stmts.push_back(std::move(block->stmts[begin-1])); auto stmt0 = std::move(block->stmts[begin+1]); begin = begin - 2; end = end - 4; for(auto i = begin; i < begin + 4; i++) // remove prologue ( array, elem, cond, elemRef) { block->stmts.erase(block->stmts.begin() + begin); } end = end - 1; // set end to post-expr for(auto i = end; i < end + 2; i++) // remove epilogue ( post-expr, jump back) { block->stmts.erase(block->stmts.begin() + end); } if(block->stmts.size() > end && block->stmts.at(end).as_node->type == gsc::node_t::asm_clear) { block->stmts.erase(block->stmts.begin() + end); } auto use_key = true; if(block->stmts.size() > end && block->stmts.at(end).as_node->type == gsc::node_t::asm_clear) { block->stmts.erase(block->stmts.begin() + end); use_key = false; } auto foreach_block = std::make_unique(loc); for(auto i = begin; i < end; i++) { foreach_block->stmts.push_back(std::move(block->stmts[begin])); block->stmts.erase(block->stmts.begin() + begin); } blocks_.push_back(ctx); decompile_block(foreach_block); blocks_.pop_back(); auto foreach_stmt = gsc::stmt_ptr(std::make_unique(loc, gsc::stmt_ptr(std::move(foreach_block)), use_key)); foreach_stmt.as_foreach->vars = creates; foreach_stmt.as_foreach->pre_expr = std::move(pre_expr); foreach_stmt.as_foreach->stmt0 = std::move(stmt0); block->stmts.insert(block->stmts.begin() + begin, std::move(foreach_stmt)); } void decompiler::decompile_switch(const gsc::stmt_list_ptr& block, std::uint32_t start) { gsc::context ctx; ctx.loc_continue = blocks_.back().loc_continue; ctx.loc_end = block->stmts.at(start).as_asm_switch->value; auto loc = block->stmts.at(start).as_node->loc; auto expr = std::move(block->stmts.at(start).as_asm_switch->expr); auto end_loc = block->stmts.at(start).as_asm_switch->value; auto end = find_location_index(block, end_loc); if(end == block->stmts.size() - 1) { ctx.loc_break = blocks_.back().loc_end; } else { ctx.loc_break = utils::string::va("loc_%X", block->stmts.at(end + 1).as_node->loc.begin.line); } // collect cases auto casenum = std::atol(block->stmts.at(end).as_asm_endswitch->count.data()); auto data = block->stmts.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(block, loc_str); auto loc_pos = gsc::location(&filename_, std::stol(loc_str.substr(4), 0, 16)); auto value = gsc::expr_ptr(std::make_unique(loc_pos, data.at(idx+1))); auto list = std::make_unique(loc); list->is_case = true; auto stmt = gsc::stmt_ptr(std::make_unique(loc_pos, std::move(value), std::move(list))); block->stmts.insert(block->stmts.begin() + loc_idx, std::move(stmt)); idx += 3; } else if(data.at(idx) == "default") { auto loc_str = data.at(idx+1); auto loc_idx = find_location_index(block, loc_str); auto loc_pos = gsc::location(&filename_, std::stol(loc_str.substr(4), 0, 16)); auto list = std::make_unique(loc); list->is_case = true; auto stmt = gsc::stmt_ptr(std::make_unique(loc_pos, std::move(list))); while(block->stmts.at(loc_idx).as_node->type == gsc::node_t::stmt_case) loc_idx++; block->stmts.insert(block->stmts.begin() + loc_idx, std::move(stmt)); idx += 2; } } end = find_location_index(block, end_loc) - 1; // update end; block->stmts.erase(block->stmts.begin() + start); // remove switch block->stmts.erase(block->stmts.begin() + end); // remove endswitch //decompile block auto sw_block = std::make_unique(loc); for(auto i = start; i < end; i++) { sw_block->stmts.push_back(std::move(block->stmts[start])); block->stmts.erase(block->stmts.begin() + start); } blocks_.push_back(ctx); decompile_block(sw_block); blocks_.pop_back(); auto stmt_list = std::make_unique(loc); gsc::stmt_ptr current_case = gsc::stmt_ptr(std::make_unique()); auto num = sw_block->stmts.size(); for(auto i = 0; i < num; i++) { auto& entry = sw_block->stmts[0]; if(entry.as_node->type == gsc::node_t::stmt_case || entry.as_node->type == gsc::node_t::stmt_default) { if(current_case.as_node->type != gsc::node_t::null) { stmt_list->stmts.push_back(std::move(current_case)); } current_case = std::move(sw_block->stmts[0]); sw_block->stmts.erase(sw_block->stmts.begin()); } else { if(current_case.as_node->type != gsc::node_t::null) { if(current_case.as_node->type == gsc::node_t::stmt_case) { current_case.as_case->stmt->stmts.push_back(std::move(sw_block->stmts[0])); sw_block->stmts.erase(sw_block->stmts.begin()); } else { current_case.as_default->stmt->stmts.push_back(std::move(sw_block->stmts[0])); sw_block->stmts.erase(sw_block->stmts.begin()); } } else { gsc::decomp_error("missing case before stmt inside switch!"); } } } if(current_case.as_node->type != gsc::node_t::null) { stmt_list->stmts.push_back(std::move(current_case)); } auto stmt = gsc::stmt_ptr(std::make_unique(loc, std::move(expr), std::move(stmt_list))); block->stmts.insert(block->stmts.begin() + start, std::move(stmt)); } auto decompiler::find_location_reference(const gsc::stmt_list_ptr& block, std::uint32_t start, std::uint32_t end, const std::string& location) -> bool { for(auto i = start; i < end; i++) { if(block->stmts.at(i).as_node->type == gsc::node_t::asm_jump_cond) { if(block->stmts.at(i).as_cond->value == location) return true; } else if(block->stmts.at(i).as_node->type == gsc::node_t::asm_jump) { if(block->stmts.at(i).as_jump->value == location) return true; } } return false; } auto decompiler::find_location_index(const gsc::stmt_list_ptr& block, const std::string& location) -> std::uint32_t { auto index = 0; if(location == blocks_.back().loc_end) return block->stmts.size(); for(auto& stmt : block->stmts) { if(stmt.as_node->loc.begin.line == std::stol(location.substr(4), 0, 16)) return index; index++; } throw gsc::decomp_error("LOCATION NOT FOUND! (" + location + ")"); } auto decompiler::last_location_index(const gsc::stmt_list_ptr& block, std::uint32_t index) -> bool { if(index == block->stmts.size() - 1) return true; return false; } void decompiler::process_stack(const gsc::thread_ptr& thread) { auto ctx = std::make_unique(); process_parameters(ctx, thread->params); process_stmt_list(ctx, thread->block); } void decompiler::process_parameters(const gsc::context_ptr& ctx, const gsc::parameters_ptr& params) { for(const auto& param : params->list) { ctx->local_vars.push_back({ param->value, static_cast(std::stoi(param->value.substr(4))), true }); ctx->local_vars_create_count++; } } void decompiler::process_stmt(const gsc::context_ptr& ctx, const gsc::stmt_ptr& stmt) { switch(stmt.as_node->type) { case gsc::node_t::stmt_list: process_stmt_list(ctx, stmt.as_list); break; case gsc::node_t::stmt_call: process_stmt_call(ctx, stmt.as_call); break; case gsc::node_t::stmt_assign: process_stmt_assign(ctx, stmt.as_assign); break; case gsc::node_t::stmt_endon: process_stmt_endon(ctx, stmt.as_endon); break; case gsc::node_t::stmt_notify: process_stmt_notify(ctx, stmt.as_notify); break; case gsc::node_t::stmt_wait: process_stmt_wait(ctx, stmt.as_wait); break; case gsc::node_t::stmt_waittill: process_stmt_waittill(ctx, stmt.as_waittill); break; case gsc::node_t::stmt_waittillmatch: process_stmt_waittillmatch(ctx, stmt.as_waittillmatch); break; case gsc::node_t::stmt_if: process_stmt_if(ctx, stmt.as_if); break; case gsc::node_t::stmt_ifelse: process_stmt_ifelse(ctx, stmt.as_ifelse); break; case gsc::node_t::stmt_while: process_stmt_while(ctx, stmt.as_while); break; case gsc::node_t::stmt_for: process_stmt_for(ctx, stmt.as_for); break; case gsc::node_t::stmt_foreach: process_stmt_foreach(ctx, stmt.as_foreach); break; case gsc::node_t::stmt_switch: process_stmt_switch(ctx, stmt.as_switch); break; case gsc::node_t::stmt_break: process_stmt_break(ctx, stmt.as_break); break; case gsc::node_t::stmt_return: process_stmt_return(ctx, stmt.as_return); break; case gsc::node_t::asm_remove: process_var_remove(ctx, stmt.as_asm_remove); break; case gsc::node_t::asm_create: { auto expr = gsc::expr_ptr(std::make_unique(stmt.as_asm_create->index)); process_var_create(ctx, expr, true); } break; default: break; } } void decompiler::process_stmt_list(const gsc::context_ptr& ctx, const gsc::stmt_list_ptr& stmt) { for (const auto& entry : stmt->stmts) { process_stmt(ctx, entry); } for(auto i = 0; i < stmt->stmts.size(); i++) { auto type = stmt->stmts.at(i).as_node->type; if(type == gsc::node_t::asm_create || type == gsc::node_t::asm_remove) { stmt->stmts.erase(stmt->stmts.begin() + i); i--; } } } void decompiler::process_stmt_call(const gsc::context_ptr& ctx, const gsc::stmt_call_ptr& stmt) { process_expr_call(ctx, stmt->expr); } void decompiler::process_stmt_assign(const gsc::context_ptr& ctx, const gsc::stmt_assign_ptr& stmt) { process_expr_assign(ctx, stmt->expr); } void decompiler::process_stmt_endon(const gsc::context_ptr& ctx, const gsc::stmt_endon_ptr& stmt) { process_expr(ctx, stmt->expr); process_expr(ctx, stmt->obj); } void decompiler::process_stmt_notify(const gsc::context_ptr& ctx, const gsc::stmt_notify_ptr& stmt) { process_expr_arguments(ctx, stmt->args); process_expr(ctx, stmt->expr); process_expr(ctx, stmt->obj); } void decompiler::process_stmt_wait(const gsc::context_ptr& ctx, const gsc::stmt_wait_ptr& stmt) { process_expr(ctx, stmt->expr); } void decompiler::process_stmt_waittill(const gsc::context_ptr& ctx, const gsc::stmt_waittill_ptr& stmt) { process_expr(ctx, stmt->expr); process_expr(ctx, stmt->obj); for(auto& arg : stmt->args->list) { process_expr(ctx, arg); } } void decompiler::process_stmt_waittillmatch(const gsc::context_ptr& ctx, const gsc::stmt_waittillmatch_ptr& stmt) { process_expr_arguments(ctx, stmt->args); process_expr(ctx, stmt->expr); process_expr(ctx, stmt->obj); } void decompiler::process_stmt_if(const gsc::context_ptr& ctx, const gsc::stmt_if_ptr& stmt) { process_expr(ctx, stmt->expr); stmt->ctx = std::make_unique(); ctx->transfer_decompiler(stmt->ctx); process_stmt(stmt->ctx, stmt->stmt); if(stmt->stmt.as_list->stmts.size() == 1 && !gsc::node::is_special_stmt(stmt->stmt.as_list->stmts.at(0))) { stmt->stmt = std::move(stmt->stmt.as_list->stmts.back()); } } void decompiler::process_stmt_ifelse(const gsc::context_ptr& ctx, const gsc::stmt_ifelse_ptr& stmt) { process_expr(ctx, stmt->expr); stmt->ctx_if = std::make_unique(); ctx->transfer_decompiler(stmt->ctx_if); process_stmt(stmt->ctx_if, stmt->stmt_if); stmt->ctx_else = std::make_unique(); ctx->transfer_decompiler(stmt->ctx_else); process_stmt(stmt->ctx_else, stmt->stmt_else); std::vector childs({stmt->ctx_if.get(), stmt->ctx_else.get()}); ctx->append(childs); if(stmt->stmt_if.as_list->stmts.size() == 1 && !gsc::node::is_special_stmt(stmt->stmt_if.as_list->stmts.at(0))) { stmt->stmt_if = std::move(stmt->stmt_if.as_list->stmts.back()); } if(stmt->stmt_else.as_list->stmts.size() == 1 && !gsc::node::is_special_stmt_noif(stmt->stmt_else.as_list->stmts.at(0))) { stmt->stmt_else = std::move(stmt->stmt_else.as_list->stmts.back()); } } void decompiler::process_stmt_while(const gsc::context_ptr& ctx, const gsc::stmt_while_ptr& stmt) { process_expr(ctx, stmt->expr); stmt->ctx = std::make_unique(); ctx->transfer_decompiler(stmt->ctx); process_stmt(stmt->ctx, stmt->stmt); std::vector childs({ stmt->ctx.get() }); if(stmt->expr.as_node->type == gsc::node_t::null) ctx->append_decompiler(stmt->ctx); if(stmt->stmt.as_list->stmts.size() == 1 && !gsc::node::is_special_stmt(stmt->stmt.as_list->stmts.at(0))) { stmt->stmt = std::move(stmt->stmt.as_list->stmts.back()); } } void decompiler::process_stmt_for(const gsc::context_ptr& ctx, const gsc::stmt_for_ptr& stmt) { process_stmt(ctx, stmt->pre_expr); for(auto& index : stmt->vars) { auto var = utils::string::va("var_%d", std::stoi(index)); ctx->local_vars.push_back({ var, static_cast(std::stoi(index)), true }); ctx->local_vars_create_count++; } stmt->ctx = std::make_unique(); ctx->transfer_decompiler(stmt->ctx); process_expr(ctx, stmt->expr); process_stmt(stmt->ctx, stmt->stmt); process_stmt(ctx, stmt->post_expr); if(stmt->expr.as_node->type == gsc::node_t::null) ctx->append_decompiler(stmt->ctx); if(stmt->stmt.as_list->stmts.size() == 1 && !gsc::node::is_special_stmt(stmt->stmt.as_list->stmts.at(0))) { stmt->stmt = std::move(stmt->stmt.as_list->stmts.back()); } } void decompiler::process_stmt_foreach(const gsc::context_ptr& ctx, const gsc::stmt_foreach_ptr& stmt) { process_stmt(ctx, stmt->pre_expr); for(auto& index : stmt->vars) { auto var1 = utils::string::va("var_%d", std::stoi(index)); ctx->local_vars.push_back({ var1, static_cast(std::stoi(index)), true }); ctx->local_vars_create_count++; } stmt->ctx = std::make_unique(); ctx->transfer_decompiler(stmt->ctx); process_stmt(stmt->ctx, stmt->stmt0); process_stmt(stmt->ctx, stmt->stmt); if(stmt->stmt.as_list->stmts.size() == 1 && !gsc::node::is_special_stmt(stmt->stmt.as_list->stmts.at(0))) { stmt->stmt = std::move(stmt->stmt.as_list->stmts.back()); } stmt->array_expr = std::move(stmt->pre_expr.as_list->stmts[0].as_assign->expr->rvalue); stmt->value_expr = std::move(stmt->stmt0.as_assign->expr->lvalue); stmt->key_expr = std::move(stmt->pre_expr.as_list->stmts[1].as_assign->expr->lvalue); } void decompiler::process_stmt_switch(const gsc::context_ptr& ctx, const gsc::stmt_switch_ptr& stmt) { process_expr(ctx, stmt->expr); stmt->ctx = std::make_unique(); ctx->transfer_decompiler(stmt->ctx); process_stmt_cases(stmt->ctx, stmt->stmt); ctx->append_decompiler(stmt->ctx, true); } void decompiler::process_stmt_cases(const gsc::context_ptr& ctx, const gsc::stmt_list_ptr& stmt) { std::vector childs; bool has_default = false; for(auto& entry : stmt->stmts) { if(entry.as_node->type == gsc::node_t::stmt_case) { entry.as_case->ctx = std::make_unique(); ctx->transfer_decompiler(entry.as_case->ctx); process_stmt_list(entry.as_case->ctx, entry.as_case->stmt); if(entry.as_case->ctx->abort == gsc::abort_t::abort_break) { childs.push_back(entry.as_case->ctx.get()); } } else if(entry.as_node->type == gsc::node_t::stmt_default) { has_default = true; entry.as_default->ctx = std::make_unique(); ctx->transfer_decompiler(entry.as_default->ctx); process_stmt_list(entry.as_default->ctx, entry.as_default->stmt); if(entry.as_default->ctx->abort == gsc::abort_t::abort_break) { childs.push_back(entry.as_default->ctx.get()); } } } if(has_default) { ctx->append(childs); } } void decompiler::process_stmt_break(const gsc::context_ptr& ctx, const gsc::stmt_break_ptr& stmt) { ctx->abort = gsc::abort_t::abort_break; } void decompiler::process_stmt_return(const gsc::context_ptr& ctx, const gsc::stmt_return_ptr& stmt) { if(stmt->expr.as_node->type == gsc::node_t::null) { return; } process_expr(ctx, stmt->expr); } void decompiler::process_expr(const gsc::context_ptr& ctx, gsc::expr_ptr& expr) { switch(expr.as_node->type) { case gsc::node_t::expr_increment: process_expr_assign(ctx, expr.as_assign); break; case gsc::node_t::expr_decrement: process_expr_assign(ctx, expr.as_assign); break; case gsc::node_t::expr_assign_equal: process_expr_assign(ctx, expr.as_assign); break; case gsc::node_t::expr_assign_add: process_expr_assign(ctx, expr.as_assign); break; case gsc::node_t::expr_assign_sub: process_expr_assign(ctx, expr.as_assign); break; case gsc::node_t::expr_assign_mult: process_expr_assign(ctx, expr.as_assign); break; case gsc::node_t::expr_assign_div: process_expr_assign(ctx, expr.as_assign); break; case gsc::node_t::expr_assign_mod: process_expr_assign(ctx, expr.as_assign); break; case gsc::node_t::expr_assign_shift_left: process_expr_assign(ctx, expr.as_assign); break; case gsc::node_t::expr_assign_shift_right: process_expr_assign(ctx, expr.as_assign); break; case gsc::node_t::expr_assign_bitwise_or: process_expr_assign(ctx, expr.as_assign); break; case gsc::node_t::expr_assign_bitwise_and: process_expr_assign(ctx, expr.as_assign); break; case gsc::node_t::expr_assign_bitwise_exor: process_expr_assign(ctx, expr.as_assign); break; case gsc::node_t::expr_ternary: process_expr_ternary(ctx, expr.as_ternary); break; case gsc::node_t::expr_and: process_expr_and(ctx, expr.as_and); break; case gsc::node_t::expr_or: process_expr_or(ctx, expr.as_or); break; case gsc::node_t::expr_equality: process_expr_binary(ctx, expr.as_binary); break; case gsc::node_t::expr_inequality: process_expr_binary(ctx, expr.as_binary); break; case gsc::node_t::expr_less: process_expr_binary(ctx, expr.as_binary); break; case gsc::node_t::expr_greater: process_expr_binary(ctx, expr.as_binary); break; case gsc::node_t::expr_less_equal: process_expr_binary(ctx, expr.as_binary); break; case gsc::node_t::expr_greater_equal: process_expr_binary(ctx, expr.as_binary); break; case gsc::node_t::expr_bitwise_or: process_expr_binary(ctx, expr.as_binary); break; case gsc::node_t::expr_bitwise_and: process_expr_binary(ctx, expr.as_binary); break; case gsc::node_t::expr_bitwise_exor: process_expr_binary(ctx, expr.as_binary); break; case gsc::node_t::expr_shift_left: process_expr_binary(ctx, expr.as_binary); break; case gsc::node_t::expr_shift_right: process_expr_binary(ctx, expr.as_binary); break; case gsc::node_t::expr_add: process_expr_binary(ctx, expr.as_binary); break; case gsc::node_t::expr_sub: process_expr_binary(ctx, expr.as_binary); break; case gsc::node_t::expr_mult: process_expr_binary(ctx, expr.as_binary); break; case gsc::node_t::expr_div: process_expr_binary(ctx, expr.as_binary); break; case gsc::node_t::expr_mod: process_expr_binary(ctx, expr.as_binary); break; case gsc::node_t::expr_complement: process_expr_complement(ctx, expr.as_complement); break; case gsc::node_t::expr_not: process_expr_not(ctx, expr.as_not); break; case gsc::node_t::expr_call: process_expr_call(ctx, expr.as_call); break; case gsc::node_t::expr_function: process_expr_function(ctx, expr.as_function); break; case gsc::node_t::expr_add_array: process_expr_add_array(ctx, expr.as_add_array); break; case gsc::node_t::expr_array: process_array_variable(ctx, expr.as_array); break; case gsc::node_t::expr_field: process_field_variable(ctx, expr.as_field); break; case gsc::node_t::expr_size: process_expr_size(ctx, expr.as_size); break; case gsc::node_t::data_name: process_local_variable(ctx, expr.as_name); break; case gsc::node_t::data_vector: process_vector(ctx, expr.as_vector); break; case gsc::node_t::asm_create: process_var_create(ctx, expr); break; case gsc::node_t::asm_access: process_var_access(ctx, expr); break; default: break; } } void decompiler::process_expr_assign(const gsc::context_ptr& ctx, gsc::expr_assign_ptr& expr) { if(expr->type == gsc::node_t::expr_increment) { process_expr(ctx, expr->lvalue); } else if(expr->type == gsc::node_t::expr_decrement) { process_expr(ctx, expr->lvalue); } else { process_expr(ctx, expr->rvalue); process_expr(ctx, expr->lvalue); if(expr->type == gsc::node_t::expr_assign_equal) { switch(expr->rvalue.as_node->type) { case gsc::node_t::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_mod->rvalue)); break; case gsc::node_t::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_mod->rvalue)); break; case gsc::node_t::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_mod->rvalue)); break; case gsc::node_t::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_mod->rvalue)); break; case gsc::node_t::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_mod->rvalue)); break; case gsc::node_t::expr_add: if(expr->lvalue == expr->rvalue.as_add->lvalue) expr = std::make_unique(std::move(expr->lvalue), std::move(expr->rvalue.as_mod->rvalue)); break; case gsc::node_t::expr_sub: if(expr->lvalue == expr->rvalue.as_sub->lvalue) expr = std::make_unique(std::move(expr->lvalue), std::move(expr->rvalue.as_mod->rvalue)); break; case gsc::node_t::expr_mult: if(expr->lvalue == expr->rvalue.as_mult->lvalue) expr = std::make_unique(std::move(expr->lvalue), std::move(expr->rvalue.as_mod->rvalue)); break; case gsc::node_t::expr_div: if(expr->lvalue == expr->rvalue.as_div->lvalue) expr = std::make_unique(std::move(expr->lvalue), std::move(expr->rvalue.as_mod->rvalue)); break; case gsc::node_t::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_ternary(const gsc::context_ptr& ctx, const gsc::expr_ternary_ptr& expr) { process_expr(ctx, expr->cond); process_expr(ctx, expr->lvalue); process_expr(ctx, expr->rvalue); } void decompiler::process_expr_binary(const gsc::context_ptr& ctx, const gsc::expr_binary_ptr& expr) { process_expr(ctx, expr->lvalue); process_expr(ctx, expr->rvalue); auto prec = expr->lvalue.as_node->precedence(); if(prec && prec < expr->precedence()) { expr->lvalue = expr_ptr(std::make_unique(std::move(expr->lvalue))); } prec = expr->rvalue.as_node->precedence(); if(prec && prec < expr->precedence() || (prec == expr->precedence() && expr->type == expr->rvalue.as_node->type)) { expr->rvalue = expr_ptr(std::make_unique(std::move(expr->rvalue))); } } void decompiler::process_expr_and(const gsc::context_ptr& ctx, const gsc::expr_and_ptr& expr) { process_expr(ctx, expr->lvalue); process_expr(ctx, expr->rvalue); auto prec = expr->lvalue.as_node->precedence(); if(prec && prec < expr->precedence()) { expr->lvalue = expr_ptr(std::make_unique(std::move(expr->lvalue))); } prec = expr->rvalue.as_node->precedence(); if(prec && prec < expr->precedence() || (prec == expr->precedence() && expr->type == expr->rvalue.as_node->type)) { expr->rvalue = expr_ptr(std::make_unique(std::move(expr->rvalue))); } } void decompiler::process_expr_or(const gsc::context_ptr& ctx, const gsc::expr_or_ptr& expr) { process_expr(ctx, expr->lvalue); process_expr(ctx, expr->rvalue); } void decompiler::process_expr_complement(const gsc::context_ptr& ctx, const gsc::expr_complement_ptr& expr) { process_expr(ctx, expr->rvalue); if(expr->rvalue.as_node->is_binary()) { expr->rvalue = expr_ptr(std::make_unique(std::move(expr->rvalue))); } } void decompiler::process_expr_not(const gsc::context_ptr& ctx, const gsc::expr_not_ptr& expr) { process_expr(ctx, expr->rvalue); if(expr->rvalue.as_node->is_binary()) { expr->rvalue = expr_ptr(std::make_unique(std::move(expr->rvalue))); } } void decompiler::process_expr_call(const gsc::context_ptr& ctx, const gsc::expr_call_ptr& expr) { if(expr->func.as_node->type == gsc::node_t::expr_call_pointer) { process_expr_call_pointer(ctx, expr); } else { process_expr_call_function(ctx, expr); } } void decompiler::process_expr_call_pointer(const gsc::context_ptr& ctx, const gsc::expr_call_ptr& expr) { process_expr_arguments(ctx, expr->func.as_pointer->args); if(expr->obj.as_node->type != gsc::node_t::null) process_expr(ctx, expr->obj); process_expr(ctx, expr->func.as_pointer->expr); } void decompiler::process_expr_call_function(const gsc::context_ptr& ctx, const gsc::expr_call_ptr& expr) { process_expr_arguments(ctx, expr->func.as_func->args); if(expr->obj.as_node->type != gsc::node_t::null) process_expr(ctx, expr->obj); } void decompiler::process_expr_arguments(const gsc::context_ptr& ctx, const gsc::expr_arguments_ptr& args) { for(auto i = args->list.size(); i > 0; i--) { process_expr(ctx, args->list.at(i - 1)); } } void decompiler::process_expr_function(const gsc::context_ptr& ctx, const gsc::expr_function_ptr& expr) { return; } void decompiler::process_expr_add_array(const gsc::context_ptr& ctx, const gsc::expr_add_array_ptr& expr) { for(auto& arg : expr->args->list) { process_expr(ctx, arg); } } void decompiler::process_expr_size(const gsc::context_ptr& ctx, const gsc::expr_size_ptr& expr) { process_expr(ctx, expr->obj); } void decompiler::process_array_variable(const gsc::context_ptr& ctx, const gsc::expr_array_ptr& expr) { process_expr(ctx, expr->key); process_expr(ctx, expr->obj); } void decompiler::process_field_variable(const gsc::context_ptr& ctx, const gsc::expr_field_ptr& expr) { process_expr(ctx, expr->obj); } void decompiler::process_local_variable(const gsc::context_ptr& ctx, const gsc::name_ptr& expr) { return; } void decompiler::process_vector(const gsc::context_ptr& ctx, const gsc::vector_ptr& vec) { process_expr(ctx, vec->z); process_expr(ctx, vec->y); process_expr(ctx, vec->x); } void decompiler::process_var_create(const gsc::context_ptr& ctx, gsc::expr_ptr& expr, bool fromstmt) { if(fromstmt) { auto var = utils::string::va("var_%d", std::stoi(expr.as_asm_create->index)); ctx->local_vars.push_back({ var, static_cast(std::stoi(expr.as_asm_create->index)), true }); ctx->local_vars_create_count++; } else { for(auto& entry : expr.as_asm_create->vars) { ctx->local_vars.push_back({ utils::string::va("var_%d", std::stoi(entry)), static_cast(std::stoi(entry)), true }); ctx->local_vars_create_count++; } auto var = utils::string::va("var_%d", std::stoi(expr.as_asm_create->index)); ctx->local_vars.push_back({ var, static_cast(std::stoi(expr.as_asm_create->index)), true }); ctx->local_vars_create_count++; expr = gsc::expr_ptr(std::make_unique(var)); } } void decompiler::process_var_access(const gsc::context_ptr& ctx, gsc::expr_ptr& expr) { if(ctx->local_vars.size() <= std::stoi(expr.as_asm_access->index)) { printf("WARNING: bad local var access\n"); } else { auto var = ctx->local_vars.at(ctx->local_vars.size() - 1 - std::stoi(expr.as_asm_access->index)).name; expr = gsc::expr_ptr(std::make_unique(var)); } } void decompiler::process_var_remove(const gsc::context_ptr& ctx, const gsc::asm_remove_ptr& expr) { ctx->local_vars_public_count = ctx->local_vars.size() - std::stoi(expr->index); } } // namespace xsk::gsc::iw8