iw8 build

This commit is contained in:
xensik
2021-05-08 19:18:20 +02:00
committed by xensik
parent 8ced7a8c85
commit 564c46cdb2
142 changed files with 97064 additions and 3 deletions

6
src/iw8/stdafx.cpp Normal file
View File

@ -0,0 +1,6 @@
// 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"

38
src/iw8/stdafx.hpp Normal file
View File

@ -0,0 +1,38 @@
// 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.
#pragma once
// Warnings
#ifdef _WIN32
#pragma warning(disable:4244)
#pragma warning(disable:4267)
#pragma warning(disable:4005)
#pragma warning(disable:4065)
#define _CRT_SECURE_NO_WARNINGS
#endif
// C/C++
#include <regex>
#include <string>
#include <vector>
#include <memory>
#include <algorithm>
#include <filesystem>
#include <functional>
#include <stdexcept>
#include <map>
#include <stack>
#include <array>
#include <iostream>
#include <sstream>
#include <fstream>
#include <unordered_map>
#include <stdio.h>
// Ext
using namespace std::literals;
#include "xsk/iw8.hpp"

682
src/iw8/xsk/assembler.cpp Normal file
View File

@ -0,0 +1,682 @@
// 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 assembler::output_script() -> std::vector<std::uint8_t>
{
std::vector<std::uint8_t> script;
if(script_ == nullptr) return script;
script.resize(script_->pos());
memcpy(script.data(), script_->buffer().data(), script.size());
return script;
}
auto assembler::output_stack() -> std::vector<std::uint8_t>
{
std::vector<std::uint8_t> stack;
if(stack_ == nullptr) return stack;
stack.resize(stack_->pos());
memcpy(stack.data(), stack_->buffer().data(), stack.size());
return stack;
}
void assembler::assemble(const std::string& file, std::vector<std::uint8_t>& data)
{
std::vector<std::string> assembly = utils::string::clean_buffer_lines(data);
std::vector<gsc::function_ptr> functions;
gsc::function_ptr func = nullptr;
std::uint32_t index = 1;
std::uint16_t switchnum = 0;
for (auto& line : assembly)
{
if (line == "" || line.substr(0, 2) == "//")
{
continue;
}
else if (line.substr(0, 4) == "sub_")
{
func = std::make_unique<gsc::function>();
func->index = index;
func->name = line.substr(4);
}
else if (line.substr(0, 4) == "end_")
{
if (func != nullptr)
{
func->size = index - func->index;
functions.push_back(std::move(func));
}
}
else if (line.substr(0, 4) == "loc_")
{
func->labels[index] = line;
}
else
{
auto data = utils::string::parse_code(line);
if (switchnum)
{
if (data[0] == "case" || data[0] == "default")
{
for (auto& entry : data)
{
func->instructions.back()->data.push_back(entry);
}
switchnum--;
continue;
}
throw gsc::asm_error("invalid instruction inside endswitch \""s + line + "\"!");
}
else
{
auto inst = std::make_unique<gsc::instruction>();
inst->index = index;
inst->opcode = static_cast<std::uint8_t>(resolver::opcode_id(data[0]));
inst->size = opcode_size(inst->opcode);
data.erase(data.begin());
inst->data = std::move(data);
if (opcode(inst->opcode) == opcode::OP_endswitch)
{
switchnum = static_cast<std::uint16_t>(std::stoi(inst->data[0]));
inst->size += 7 * switchnum;
}
index += inst->size;
func->instructions.push_back(std::move(inst));
}
}
}
this->assemble(file, functions);
}
void assembler::assemble(const std::string& file, std::vector<gsc::function_ptr>& functions)
{
script_ = std::make_unique<utils::byte_buffer>(0x100000);
stack_ = std::make_unique<utils::byte_buffer>(0x100000);
filename_ = file;
functions_ = std::move(functions);
script_->write<std::uint8_t>(static_cast<std::uint8_t>(opcode::OP_End));
for (const auto& func : functions_)
{
this->assemble_function(func);
}
}
void assembler::assemble_function(const gsc::function_ptr& func)
{
labels_ = func->labels;
stack_->write<std::uint32_t>(func->size);
func->id = func->name.substr(0, 3) == "_ID" ? std::stoi(func->name.substr(3)) : resolver::token_id(func->name);
stack_->write<std::uint32_t>(func->id);
if (func->id == 0)
{
stack_->write_c_string(func->name);
}
for (const auto& inst : func->instructions)
{
this->assemble_instruction(inst);
}
}
void assembler::assemble_instruction(const gsc::instruction_ptr& inst)
{
switch (opcode(inst->opcode))
{
case opcode::OP_CastFieldObject:
case opcode::OP_plus:
case opcode::OP_GetGameRef:
case opcode::OP_GetThisthread:
case opcode::OP_greater:
case opcode::OP_shift_right:
case opcode::OP_dec:
case opcode::OP_bit_or:
case opcode::OP_equality:
case opcode::OP_ClearLocalVariableFieldCached0:
case opcode::OP_notify:
case opcode::OP_PreScriptCall:
case opcode::OP_GetUndefined:
case opcode::OP_SetLocalVariableFieldCached0:
case opcode::OP_GetLevel:
case opcode::OP_size:
case opcode::OP_AddArray:
case opcode::OP_endon:
case opcode::OP_shift_left:
case opcode::OP_EvalLocalArrayRefCached0:
case opcode::OP_Return:
case opcode::OP_SafeSetVariableFieldCached0:
case opcode::OP_GetSelfObject:
case opcode::OP_GetGame:
case opcode::OP_EvalArray:
case opcode::OP_GetSelf:
case opcode::OP_End:
case opcode::OP_less_equal:
case opcode::OP_EvalLocalVariableCached0:
case opcode::OP_EvalLocalVariableCached1:
case opcode::OP_EvalLocalVariableCached2:
case opcode::OP_EvalLocalVariableCached3:
case opcode::OP_EvalLocalVariableCached4:
case opcode::OP_EvalLocalVariableCached5:
case opcode::OP_ScriptMethodCallPointer:
case opcode::OP_checkclearparams:
case opcode::OP_waittillmatch2:
case opcode::OP_minus:
case opcode::OP_greater_equal:
case opcode::OP_vector:
case opcode::OP_ClearArray:
case opcode::OP_DecTop:
case opcode::OP_CastBool:
case opcode::OP_EvalArrayRef:
case opcode::OP_GetZero:
case opcode::OP_wait:
case opcode::OP_waittill:
case opcode::OP_GetAnimObject:
case opcode::OP_mod:
case opcode::OP_clearparams:
case opcode::OP_ScriptFunctionCallPointer:
case opcode::OP_EmptyArray:
case opcode::OP_ClearVariableField:
case opcode::OP_EvalNewLocalVariableRefCached0:
case opcode::OP_BoolComplement:
case opcode::OP_less:
case opcode::OP_BoolNot:
case opcode::OP_waittillFrameEnd:
case opcode::OP_waitframe:
case opcode::OP_GetLevelObject:
case opcode::OP_inc:
case opcode::OP_GetAnim:
case opcode::OP_SetVariableField:
case opcode::OP_divide:
case opcode::OP_multiply:
case opcode::OP_EvalLocalVariableRefCached0:
case opcode::OP_bit_and:
case opcode::OP_voidCodepos:
case opcode::OP_inequality:
case opcode::OP_bit_ex_or:
/*
case opcode::OP_NOP:
case opcode::OP_abort:
case opcode::OP_object:
case opcode::OP_thread_object:
case opcode::OP_EvalLocalVariable:
case opcode::OP_EvalLocalVariableRef:
case opcode::OP_breakpoint:
case opcode::OP_assignmentBreakpoint:
case opcode::OP_manualAndAssignmentBreakpoint:
*/
case opcode::OP_BoolNotAfterAnd:
case opcode::OP_IsDefined:
case opcode::OP_IsTrue:
script_->write<std::uint8_t>(static_cast<std::uint8_t>(inst->opcode));
break;
case opcode::OP_GetByte:
script_->write<std::uint8_t>(static_cast<std::uint8_t>(inst->opcode));
script_->write<std::uint8_t>(static_cast<std::uint8_t>(std::stoi(inst->data[0])));
break;
case opcode::OP_GetNegByte:
script_->write<std::uint8_t>(static_cast<std::uint8_t>(inst->opcode));
script_->write<std::int8_t>(static_cast<std::int8_t>(std::stoi(inst->data[0])));
break;
case opcode::OP_GetUnsignedShort:
script_->write<std::uint8_t>(static_cast<std::uint8_t>(inst->opcode));
script_->write<std::uint16_t>(static_cast<std::uint16_t>(std::stoi(inst->data[0])));
break;
case opcode::OP_GetNegUnsignedShort:
script_->write<std::uint8_t>(static_cast<std::uint8_t>(inst->opcode));
script_->write<std::int16_t>(static_cast<std::int16_t>(std::stoi(inst->data[0])));
case opcode::OP_GetInteger:
script_->write<std::uint8_t>(static_cast<std::uint8_t>(inst->opcode));
script_->write<std::int32_t>(std::stoi(inst->data[0]));
break;
case opcode::OP_GetFloat:
script_->write<std::uint8_t>(static_cast<std::uint8_t>(inst->opcode));
script_->write<float>(std::stof(inst->data[0]));
break;
case opcode::OP_GetVector:
script_->write<std::uint8_t>(static_cast<std::uint8_t>(inst->opcode));
script_->write<float>(std::stof(inst->data[0]));
script_->write<float>(std::stof(inst->data[1]));
script_->write<float>(std::stof(inst->data[2]));
break;
case opcode::OP_GetString:
case opcode::OP_GetIString:
script_->write<std::uint8_t>(static_cast<std::uint8_t>(inst->opcode));
script_->write<std::uint32_t>(0);
stack_->write_c_string(utils::string::to_code(inst->data[0]));
break;
case opcode::OP_GetAnimation:
script_->write<std::uint8_t>(static_cast<std::uint8_t>(inst->opcode));
script_->write<std::uint32_t>(0);
script_->write<std::uint32_t>(0);
stack_->write_c_string(utils::string::unquote(inst->data[0]));
stack_->write_c_string(utils::string::unquote(inst->data[1]));
break;
case opcode::OP_GetAnimTree:
script_->write<std::uint8_t>(static_cast<std::uint8_t>(inst->opcode));
script_->write<std::uint8_t>(0);
stack_->write_c_string(utils::string::unquote(inst->data[0]));
break;
case opcode::OP_waittillmatch:
script_->write<std::uint8_t>(static_cast<std::uint8_t>(inst->opcode));
script_->write<std::uint16_t>(0);
break;
case opcode::OP_SetNewLocalVariableFieldCached0:
case opcode::OP_EvalNewLocalArrayRefCached0:
case opcode::OP_SafeCreateVariableFieldCached:
case opcode::OP_ClearLocalVariableFieldCached:
case opcode::OP_SetLocalVariableFieldCached:
case opcode::OP_RemoveLocalVariables:
case opcode::OP_EvalLocalVariableRefCached:
case opcode::OP_EvalLocalArrayRefCached:
case opcode::OP_SafeSetVariableFieldCached:
case opcode::OP_EvalLocalVariableCached:
case opcode::OP_SafeSetWaittillVariableFieldCached:
case opcode::OP_CreateLocalVariable:
case opcode::OP_EvalLocalVariableObjectCached:
case opcode::OP_EvalLocalArrayCached:
script_->write<std::uint8_t>(static_cast<std::uint8_t>(inst->opcode));
script_->write<std::uint8_t>(static_cast<std::uint8_t>(std::stoi(inst->data[0])));
break;
case opcode::OP_EvalSelfFieldVariable:
case opcode::OP_SetLevelFieldVariableField:
case opcode::OP_ClearFieldVariable:
case opcode::OP_EvalFieldVariable:
case opcode::OP_EvalFieldVariableRef:
case opcode::OP_EvalLevelFieldVariable:
case opcode::OP_SetAnimFieldVariableField:
case opcode::OP_SetSelfFieldVariableField:
case opcode::OP_EvalAnimFieldVariableRef:
case opcode::OP_EvalLevelFieldVariableRef:
case opcode::OP_EvalAnimFieldVariable:
case opcode::OP_EvalSelfFieldVariableRef:
this->assemble_field_variable(inst);
break;
case opcode::OP_CallBuiltinPointer:
case opcode::OP_CallBuiltinMethodPointer:
case opcode::OP_ScriptThreadCallPointer:
case opcode::OP_ScriptChildThreadCallPointer:
case opcode::OP_ScriptMethodThreadCallPointer:
case opcode::OP_ScriptMethodChildThreadCallPointer:
script_->write<std::uint8_t>(static_cast<std::uint8_t>(inst->opcode));
script_->write<std::uint8_t>(static_cast<std::uint8_t>(std::stoi(inst->data[0])));
break;
case opcode::OP_GetLocalFunction:
case opcode::OP_ScriptLocalFunctionCall2:
case opcode::OP_ScriptLocalFunctionCall:
case opcode::OP_ScriptLocalMethodCall:
this->assemble_local_call(inst, false);
break;
case opcode::OP_ScriptLocalThreadCall:
case opcode::OP_ScriptLocalChildThreadCall:
case opcode::OP_ScriptLocalMethodThreadCall:
case opcode::OP_ScriptLocalMethodChildThreadCall:
this->assemble_local_call(inst, true);
break;
case opcode::OP_GetFarFunction:
case opcode::OP_ScriptFarFunctionCall2:
case opcode::OP_ScriptFarFunctionCall:
case opcode::OP_ScriptFarMethodCall:
this->assemble_far_call(inst, false);
break;
case opcode::OP_ScriptFarThreadCall:
case opcode::OP_ScriptFarChildThreadCall:
case opcode::OP_ScriptFarMethodThreadCall:
case opcode::OP_ScriptFarMethodChildThreadCall:
this->assemble_far_call(inst, true);
break;
case opcode::OP_CallBuiltin:
this->assemble_builtin_call(inst, false, true);
break;
case opcode::OP_CallBuiltinMethod:
this->assemble_builtin_call(inst, true, true);
break;
case opcode::OP_GetBuiltinFunction:
case opcode::OP_CallBuiltin0:
case opcode::OP_CallBuiltin1:
case opcode::OP_CallBuiltin2:
case opcode::OP_CallBuiltin3:
case opcode::OP_CallBuiltin4:
case opcode::OP_CallBuiltin5:
this->assemble_builtin_call(inst, false, false);
break;
case opcode::OP_GetBuiltinMethod:
case opcode::OP_CallBuiltinMethod0:
case opcode::OP_CallBuiltinMethod1:
case opcode::OP_CallBuiltinMethod2:
case opcode::OP_CallBuiltinMethod3:
case opcode::OP_CallBuiltinMethod4:
case opcode::OP_CallBuiltinMethod5:
this->assemble_builtin_call(inst, true, false);
break;
case opcode::OP_JumpOnFalseExpr:
case opcode::OP_JumpOnTrueExpr:
case opcode::OP_JumpOnFalse:
case opcode::OP_JumpOnTrue:
this->assemble_jump(inst, true, false);
break;
case opcode::OP_jumpback:
this->assemble_jump(inst, false, true);
break;
case opcode::OP_jump:
this->assemble_jump(inst, false, false);
break;
case opcode::OP_switch:
this->assemble_switch(inst);
break;
case opcode::OP_endswitch:
this->assemble_end_switch(inst);
break;
/*
case opcode::OP_prof_begin:
script_->write<std::uint32_t>(0); // TODO: skipped data
script_->write<std::uint8_t>(0);
break;
case opcode::OP_prof_end:
script_->write<std::uint8_t>(0); // TODO: skipped data
break;
case opcode::OP_EvalNewLocalArrayRefCached0_Precompiled:
case opcode::OP_SetNewLocalVariableFieldCached0_Precompiled:
case opcode::OP_CreateLocalVariable_Precompiled:
case opcode::OP_SafeCreateVariableFieldCached_Precompiled:
script_->write<std::uint8_t>(static_cast<std::uint8_t>(inst->opcode));
script_->write<std::uint8_t>(static_cast<std::uint8_t>(std::stoi(inst->data[0])));
break;
*/
case opcode::OP_FormalParams:
// case opcode::OP_FormalParams_Precompiled:
this->assemble_formal_params(inst);
break;
/*
case opcode::OP_NativeGetLocalFunction:
case opcode::OP_NativeLocalFunctionCall:
case opcode::OP_NativeLocalFunctionCall2:
case opcode::OP_NativeLocalMethodCall:
this->assemble_local_call(inst, false);
break;
case opcode::OP_NativeGetFarFunction:
case opcode::OP_NativeFarFunctionCall:
case opcode::OP_NativeFarFunctionCall2:
case opcode::OP_NativeFarMethodCall:
this->assemble_far_call(inst, false);
break;
case opcode::OP_NativeLocalFunctionThreadCall:
case opcode::OP_NativeLocalMethodThreadCall:
case opcode::OP_NativeLocalFunctionChildThreadCall:
case opcode::OP_NativeLocalMethodChildThreadCall:
this->assemble_local_call(inst, true);
break;
case opcode::OP_NativeFarFunctionThreadCall:
case opcode::OP_NativeFarMethodThreadCall:
case opcode::OP_NativeFarFunctionChildThreadCall:
case opcode::OP_NativeFarMethodChildThreadCall:
this->assemble_far_call(inst, true);
break;
*/
default:
throw gsc::asm_error(utils::string::va("Unhandled opcode 0x%X at index '%04X'!", inst->opcode, inst->index));
}
}
void assembler::assemble_builtin_call(const gsc::instruction_ptr& inst, bool method, bool arg_num)
{
script_->write<std::uint8_t>(static_cast<std::uint8_t>(inst->opcode));
std::uint16_t id = 0;
if (arg_num)
{
script_->write<std::uint8_t>(static_cast<std::uint8_t>(std::stoi(inst->data[0])));
if (method)
id = inst->data[1].substr(0, 3) == "_ID" ? std::stoi(inst->data[1].substr(3)) : resolver::method_id(inst->data[1]);
else
id = inst->data[1].substr(0, 3) == "_ID" ? std::stoi(inst->data[1].substr(3)) : resolver::function_id(inst->data[1]);
}
else
{
if (method)
id = inst->data[0].substr(0, 3) == "_ID" ? std::stoi(inst->data[0].substr(3)) : resolver::method_id(inst->data[0]);
else
id = inst->data[0].substr(0, 3) == "_ID" ? std::stoi(inst->data[0].substr(3)) : resolver::function_id(inst->data[0]);
}
script_->write<std::uint16_t>(id);
}
void assembler::assemble_local_call(const gsc::instruction_ptr& inst, bool thread)
{
script_->write<std::uint8_t>(static_cast<std::uint8_t>(inst->opcode));
std::int32_t addr = this->resolve_function(inst->data[0]);
std::int32_t offset = addr - inst->index - 1;
this->assemble_offset(offset);
if (thread)
{
script_->write<std::uint8_t>(static_cast<std::uint8_t>(std::stoi(inst->data[1])));
}
}
void assembler::assemble_far_call(const gsc::instruction_ptr& inst, bool thread)
{
script_->write<std::uint8_t>(static_cast<std::uint8_t>(inst->opcode));
script_->write<std::uint8_t>(0);
script_->write<std::uint16_t>(0);
std::uint32_t file_id = 0;
std::uint32_t func_id = 0;
if (thread)
{
script_->write<std::uint8_t>(static_cast<std::uint8_t>(std::stoi(inst->data[0])));
file_id = inst->data[1].substr(0, 3) == "_ID" ? std::stoi(inst->data[1].substr(3)) : resolver::file_id(inst->data[1]);
func_id = inst->data[2].substr(0, 3) == "_ID" ? std::stoi(inst->data[2].substr(3)) : resolver::token_id(inst->data[2]);
}
else
{
file_id = inst->data[0].substr(0, 3) == "_ID" ? std::stoi(inst->data[0].substr(3)) : resolver::file_id(inst->data[0]);
func_id = inst->data[1].substr(0, 3) == "_ID" ? std::stoi(inst->data[1].substr(3)) : resolver::token_id(inst->data[1]);
}
stack_->write<std::uint32_t>(file_id);
if (file_id == 0) stack_->write_c_string(thread ? inst->data[1] : inst->data[0]);
stack_->write<std::uint32_t>(func_id);
if (func_id == 0) stack_->write_c_string(thread ? inst->data[2] : inst->data[1]);
}
void assembler::assemble_jump(const gsc::instruction_ptr& inst, bool expr, bool back)
{
script_->write<std::uint8_t>(static_cast<std::uint8_t>(inst->opcode));
std::int32_t addr = this->resolve_label(inst->data[0]);
if (expr)
{
script_->write<std::int16_t>(addr - inst->index - 3);
}
else if (back)
{
script_->write<std::int16_t>((inst->index + 3) - addr);
}
else
{
script_->write<std::int32_t>(addr - inst->index - 5);
}
}
void assembler::assemble_field_variable(const gsc::instruction_ptr& inst)
{
script_->write<std::uint8_t>(static_cast<std::uint8_t>(inst->opcode));
std::uint32_t field_id = 0;
if (inst->data[0].substr(0, 3) == "_ID")
{
field_id = std::stoi(inst->data[0].substr(3));
}
else
{
field_id = resolver::token_id(inst->data[0]);
if (field_id == 0)
{
field_id = 0xFFFF;
}
}
script_->write<std::uint32_t>(field_id);
if (field_id > 0x13160) // 0xE2C0 or 0x13160
{
stack_->write<std::uint32_t>(0);
stack_->write_c_string(inst->data[0]);
}
}
void assembler::assemble_formal_params(const gsc::instruction_ptr& inst)
{
script_->write<std::uint8_t>(static_cast<std::uint8_t>(inst->opcode));
auto size = std::stoi(inst->data[0]);
script_->write<std::uint8_t>(static_cast<std::uint8_t>(size));
for(auto i = 1; i <= size; i++)
{
script_->write<std::uint8_t>(static_cast<std::uint8_t>(std::stoi(inst->data[i])));
}
}
void assembler::assemble_switch(const gsc::instruction_ptr& inst)
{
script_->write<std::uint8_t>(static_cast<std::uint8_t>(inst->opcode));
std::int32_t addr = this->resolve_label(inst->data[0]);
script_->write<std::int32_t>(addr - inst->index - 4);
}
void assembler::assemble_end_switch(const gsc::instruction_ptr& inst)
{
script_->write<std::uint8_t>(static_cast<std::uint8_t>(inst->opcode));
std::uint16_t casenum = 0;
if (utils::string::is_number(inst->data[0]))
{
casenum = std::stoi(inst->data[0]);
}
else
{
throw gsc::asm_error("invalid endswitch number!");
}
script_->write<std::uint16_t>(casenum);
std::uint32_t internal_index = inst->index + 3;
for (std::uint16_t i = 0; i < casenum; i++)
{
if (inst->data[1 + (3 * i)] == "case")
{
if (utils::string::is_number(inst->data[1 + (3 * i) + 1]))
{
script_->write<uint32_t>((std::stoi(inst->data[1 + (3 * i) + 1]) & 0xFFFFFF) + 0x800000);
}
else
{
script_->write<uint32_t>(i + 1);
stack_->write_c_string(utils::string::unquote(inst->data[1 + (3 * i) + 1]));
}
internal_index += 4;
std::int32_t addr = this->resolve_label(inst->data[1 + (3 * i) + 2]);
this->assemble_offset(addr - internal_index);
internal_index += 3;
}
else if (inst->data[1 + (3 * i)] == "default")
{
script_->write<uint32_t>(0);
stack_->write_c_string("\x01");
internal_index += 4;
std::int32_t addr = this->resolve_label(inst->data[1 + (3 * i) + 1]);
this->assemble_offset(addr - internal_index);
internal_index += 3;
}
}
}
void assembler::assemble_offset(std::int32_t offset)
{
std::array<std::uint8_t, 4> bytes = {};
offset = (offset << 8) >> 8;
*reinterpret_cast<std::int32_t*>(bytes.data()) = offset;
script_->write<std::uint8_t>(bytes[0]);
script_->write<std::uint8_t>(bytes[1]);
script_->write<std::uint8_t>(bytes[2]);
}
auto assembler::resolve_function(const std::string& name) -> std::uint32_t
{
auto temp = name.substr(0, 4) == "sub_" ? name.substr(4) : name;
for (const auto& func : functions_)
{
if (func->name == temp)
{
return func->index;
}
}
throw gsc::asm_error("Couldn't resolve local function address of '" + temp + "'!");
}
auto assembler::resolve_label(const std::string& name) -> std::uint32_t
{
for (auto& func : labels_)
{
if (func.second == name)
{
return func.first;
}
}
throw gsc::asm_error("Couldn't resolve label address of '" + name + "'!");
}
} // namespace xsk::gsc::iw8

41
src/iw8/xsk/assembler.hpp Normal file
View File

@ -0,0 +1,41 @@
// 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.
#pragma once
namespace xsk::gsc::iw8
{
class assembler : public gsc::assembler
{
std::string filename_;
utils::byte_buffer_ptr script_;
utils::byte_buffer_ptr stack_;
std::vector<gsc::function_ptr> functions_;
std::unordered_map<std::uint32_t, std::string> labels_;
public:
auto output_script() -> std::vector<std::uint8_t>;
auto output_stack() -> std::vector<std::uint8_t>;
void assemble(const std::string& file, std::vector<std::uint8_t>& data);
void assemble(const std::string& file, std::vector<gsc::function_ptr>& functions);
private:
void assemble_function(const gsc::function_ptr& func);
void assemble_instruction(const gsc::instruction_ptr& inst);
void assemble_builtin_call(const gsc::instruction_ptr& inst, bool method, bool arg_num);
void assemble_local_call(const gsc::instruction_ptr& inst, bool thread);
void assemble_far_call(const gsc::instruction_ptr& inst, bool thread);
void assemble_jump(const gsc::instruction_ptr& inst, bool expr, bool back);
void assemble_field_variable(const gsc::instruction_ptr& inst);
void assemble_formal_params(const gsc::instruction_ptr& inst);
void assemble_switch(const gsc::instruction_ptr& inst);
void assemble_end_switch(const gsc::instruction_ptr& inst);
void assemble_offset(std::int32_t offset);
auto resolve_function(const std::string& name) -> std::uint32_t;
auto resolve_label(const std::string& name) -> std::uint32_t;
};
} // namespace xsk::gsc::iw8

2453
src/iw8/xsk/compiler.cpp Normal file

File diff suppressed because it is too large Load Diff

152
src/iw8/xsk/compiler.hpp Normal file
View File

@ -0,0 +1,152 @@
// 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.
#pragma once
namespace xsk::gsc::iw8
{
enum class opcode : std::uint8_t;
class compiler : public gsc::compiler
{
std::string filename_;
std::vector<gsc::function_ptr> assembly_;
gsc::function_ptr function_;
std::uint32_t index_;
std::uint32_t label_idx_;
std::uint8_t stack_idx_;
std::vector<std::string> local_stack_;
std::vector<std::string> local_functions_;
std::vector<include_t> includes_;
std::vector<animtree_t> animtrees_;
std::unordered_map<std::string, gsc::expr_ptr> constants_;
std::function<std::vector<std::uint8_t>(const std::string&)> callback_readf_;
std::vector<gsc::context*> break_ctxs_;
std::vector<gsc::context*> continue_ctxs_;
bool can_break_;
bool can_continue_;
public:
auto output() -> std::vector<gsc::function_ptr>;
void compile(const std::string& file, std::vector<std::uint8_t>& data);
void set_readf_callback(std::function<std::vector<std::uint8_t>(const std::string&)> func);
private:
auto parse_buffer(const std::string& file, std::vector<std::uint8_t>& data) -> gsc::program_ptr;
auto parse_file(const std::string& file) -> gsc::program_ptr;
void compile_program(const gsc::program_ptr& program);
void emit_include(const gsc::include_ptr& include);
void emit_define(const gsc::define_ptr& define);
void emit_usingtree(const gsc::usingtree_ptr& animtree);
void emit_constant(const gsc::constant_ptr& constant);
void emit_thread(const gsc::thread_ptr& thread);
void emit_parameters(const gsc::context_ptr& ctx, const gsc::parameters_ptr& params);
void emit_stmt(const gsc::context_ptr& ctx, const gsc::stmt_ptr& stmt, bool last);
void emit_stmt_list(const gsc::context_ptr& ctx, const gsc::stmt_list_ptr& stmt, bool last);
void emit_stmt_call(const gsc::context_ptr& ctx, const gsc::stmt_call_ptr& stmt);
void emit_stmt_assign(const gsc::context_ptr& ctx, const gsc::stmt_assign_ptr& stmt);
void emit_stmt_endon(const gsc::context_ptr& ctx, const gsc::stmt_endon_ptr& stmt);
void emit_stmt_notify(const gsc::context_ptr& ctx, const gsc::stmt_notify_ptr& stmt);
void emit_stmt_wait(const gsc::context_ptr& ctx, const gsc::stmt_wait_ptr& stmt);
void emit_stmt_waittill(const gsc::context_ptr& ctx, const gsc::stmt_waittill_ptr& stmt);
void emit_stmt_waittillmatch(const gsc::context_ptr& ctx, const gsc::stmt_waittillmatch_ptr& stmt);
void emit_stmt_waittillframeend(const gsc::context_ptr& ctx, const gsc::stmt_waittillframeend_ptr& stmt);
void emit_stmt_waitframe(const gsc::context_ptr& ctx, const gsc::stmt_waitframe_ptr& stmt);
void emit_stmt_if(const gsc::context_ptr& ctx, const gsc::stmt_if_ptr& stmt, bool last);
void emit_stmt_ifelse(const gsc::context_ptr& ctx, const gsc::stmt_ifelse_ptr& stmt, bool last);
void emit_stmt_while(const gsc::context_ptr& ctx, const gsc::stmt_while_ptr& stmt);
void emit_stmt_for(const gsc::context_ptr& ctx, const gsc::stmt_for_ptr& stmt);
void emit_stmt_foreach(const gsc::context_ptr& ctx, const gsc::stmt_foreach_ptr& stmt);
void emit_stmt_switch(const gsc::context_ptr& ctx, const gsc::stmt_switch_ptr& stmt);
void emit_stmt_case(const gsc::context_ptr& ctx, const gsc::stmt_case_ptr& stmt);
void emit_stmt_default(const gsc::context_ptr& ctx, const gsc::stmt_default_ptr& stmt);
void emit_stmt_break(const gsc::context_ptr& ctx, const gsc::stmt_break_ptr& stmt);
void emit_stmt_continue(const gsc::context_ptr& ctx, const gsc::stmt_continue_ptr& stmt);
void emit_stmt_return(const gsc::context_ptr& ctx, const gsc::stmt_return_ptr& stmt);
void emit_expr(const gsc::context_ptr& ctx, const gsc::expr_ptr& expr);
void emit_expr_assign(const gsc::context_ptr& ctx, const gsc::expr_assign_ptr& expr);
void emit_expr_ternary(const gsc::context_ptr& ctx, const gsc::expr_ternary_ptr& expr);
void emit_expr_binary(const gsc::context_ptr& ctx, const gsc::expr_binary_ptr& expr);
void emit_expr_isdefined(const gsc::context_ptr& ctx, const gsc::expr_arguments_ptr& expr);
void emit_expr_istrue(const gsc::context_ptr& ctx, const gsc::expr_arguments_ptr& expr);
void emit_expr_bool_not_after_and(const gsc::context_ptr& ctx, const gsc::expr_ptr& expr);
void emit_expr_and(const gsc::context_ptr& ctx, const gsc::expr_and_ptr& expr);
void emit_expr_or(const gsc::context_ptr& ctx, const gsc::expr_or_ptr& expr);
void emit_expr_complement(const gsc::context_ptr& ctx, const gsc::expr_complement_ptr& expr);
void emit_expr_not(const gsc::context_ptr& ctx, const gsc::expr_not_ptr& expr);
void emit_expr_call(const gsc::context_ptr& ctx, const gsc::expr_call_ptr& expr);
void emit_expr_call_pointer(const gsc::context_ptr& ctx, const gsc::expr_call_ptr& expr);
void emit_expr_call_pointer_type(const gsc::context_ptr& ctx, int args, bool builtin, bool method, bool thread, bool child);
void emit_expr_call_function(const gsc::context_ptr& ctx, const gsc::expr_call_ptr& expr);
void emit_expr_call_function_builtin(const gsc::context_ptr& ctx, const std::string& func, int args, bool method);
void emit_expr_call_function_local(const gsc::context_ptr& ctx, const std::string& func, int args, bool method, bool thread, bool child);
void emit_expr_call_function_far(const gsc::context_ptr& ctx, const std::string& file, const std::string& func, int args, bool method, bool thread, bool child);
void emit_expr_arguments(const gsc::context_ptr& ctx, const gsc::expr_arguments_ptr& arg_list);
void emit_expr_function(const gsc::context_ptr& ctx, const gsc::expr_function_ptr& node);
void emit_expr_clear_variable(const gsc::context_ptr& ctx, const gsc::expr_ptr& lvalue);
void emit_expr_add_array(const gsc::context_ptr& ctx, const gsc::expr_add_array_ptr& expr);
void emit_expr_size(const gsc::context_ptr& ctx, const gsc::expr_size_ptr& expr);
void emit_variable_ref(const gsc::context_ptr& ctx, const gsc::expr_ptr& expr, bool set);
void emit_array_variable_ref(const gsc::context_ptr& ctx, const gsc::expr_array_ptr& expr, bool set);
void emit_field_variable_ref(const gsc::context_ptr& ctx, const gsc::expr_field_ptr& expr, bool set);
void emit_local_variable_ref(const gsc::context_ptr& ctx, const gsc::name_ptr& expr, bool set);
void emit_variable(const gsc::context_ptr& ctx, const gsc::expr_ptr& expr);
void emit_array_variable(const gsc::context_ptr& ctx, const gsc::expr_array_ptr& expr);
void emit_field_variable(const gsc::context_ptr& ctx, const gsc::expr_field_ptr& expr);
void emit_local_variable(const gsc::context_ptr& ctx, const gsc::name_ptr& expr);
void emit_clear_local_variable(const gsc::context_ptr& ctx, const gsc::name_ptr& expr);
void emit_create_local_vars(const gsc::context_ptr& ctx);
void emit_remove_local_vars(const gsc::context_ptr& ctx);
void emit_object(const gsc::context_ptr& ctx, const gsc::expr_ptr& expr);
void emit_animtree(const gsc::context_ptr& ctx, const gsc::animtree_ptr& animtree);
void emit_animation(const gsc::context_ptr& ctx, const gsc::animation_ptr& animation);
void emit_istring(const gsc::context_ptr& ctx, const gsc::istring_ptr& str);
void emit_string(const gsc::context_ptr& ctx, const gsc::string_ptr& str);
void emit_color(const gsc::context_ptr& ctx, const gsc::color_ptr& color);
void emit_vector(const gsc::context_ptr& ctx, const gsc::vector_ptr& vec);
void emit_float(const gsc::context_ptr& ctx, const gsc::float_ptr& num);
void emit_integer(const gsc::context_ptr& ctx, const gsc::integer_ptr& num);
void emit_false(const gsc::context_ptr& ctx, const gsc::false_ptr& expr);
void emit_true(const gsc::context_ptr& ctx, const gsc::true_ptr& expr);
void emit_opcode(const gsc::context_ptr& ctx, opcode op);
void emit_opcode(const gsc::context_ptr& ctx, opcode op, const std::string& data);
void emit_opcode(const gsc::context_ptr& ctx, opcode op, const std::vector<std::string>& data);
void process_thread(const gsc::context_ptr& ctx, const gsc::thread_ptr& thread);
void process_parameters(const gsc::context_ptr& ctx, const gsc::parameters_ptr& params);
void process_stmt(const gsc::context_ptr& ctx, const gsc::stmt_ptr& stmt);
void process_stmt_list(const gsc::context_ptr& ctx, const gsc::stmt_list_ptr& stmt);
void process_expr(const gsc::context_ptr& ctx, const gsc::expr_ptr& expr);
void process_stmt_waittill(const gsc::context_ptr& ctx, const gsc::stmt_waittill_ptr& stmt);
void process_stmt_if(const gsc::context_ptr& ctx, const gsc::stmt_if_ptr& stmt);
void process_stmt_ifelse(const gsc::context_ptr& ctx, const gsc::stmt_ifelse_ptr& stmt);
void process_stmt_while(const gsc::context_ptr& ctx, const gsc::stmt_while_ptr& stmt);
void process_stmt_for(const gsc::context_ptr& ctx, const gsc::stmt_for_ptr& stmt);
void process_stmt_foreach(const gsc::context_ptr& ctx, const gsc::stmt_foreach_ptr& stmt);
void process_stmt_switch(const gsc::context_ptr& ctx, const gsc::stmt_switch_ptr& stmt);
void process_stmt_break(const gsc::context_ptr& ctx, const gsc::stmt_break_ptr& stmt);
void process_stmt_continue(const gsc::context_ptr& ctx, const gsc::stmt_continue_ptr& stmt);
void process_stmt_return(const gsc::context_ptr& ctx, const gsc::stmt_return_ptr& stmt);
void register_variable(const gsc::context_ptr& ctx, const std::string& name);
void initialize_variable(const gsc::context_ptr& ctx, const gsc::name_ptr& name);
void create_variable(const gsc::context_ptr& ctx, const gsc::name_ptr& name);
auto variable_stack_index(const gsc::context_ptr& ctx, const gsc::name_ptr& name) -> std::uint8_t;
auto variable_create_index(const gsc::context_ptr& ctx, const gsc::name_ptr& name) -> std::string;
auto variable_access_index(const gsc::context_ptr& ctx, const gsc::name_ptr& name) -> std::string;
auto variable_initialized(const gsc::context_ptr& ctx, const gsc::name_ptr& name) -> bool;
auto is_include_call(const std::string& name, std::string& file) -> bool;
auto is_local_call(const std::string& name) -> bool;
auto is_builtin_call(const std::string& name) -> bool;
auto is_builtin_func(const std::string& name) -> bool;
auto is_builtin_method(const std::string& name) -> bool;
auto is_constant_condition(const gsc::expr_ptr& expr) -> bool;
auto create_label() -> std::string;
auto insert_label() -> std::string;
void insert_label(const std::string& label);
auto map_known_includes(const std::string& include) -> bool;
};
} // namespace xsk::gsc::iw8

3386
src/iw8/xsk/decompiler.cpp Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,95 @@
// 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.
#pragma once
namespace xsk::gsc::iw8
{
class decompiler : public gsc::decompiler
{
std::string filename_;
std::unique_ptr<utils::byte_buffer> output_;
gsc::program_ptr program_;
gsc::thread_ptr func_;
std::unordered_map<std::uint32_t, std::string> labels_;
std::vector<std::string> expr_labels_;
std::vector<std::string> tern_labels_;
std::stack<gsc::node_ptr> stack_;
std::vector<gsc::context> blocks_;
public:
auto output() -> std::vector<std::uint8_t>;
void decompile(const std::string& file, std::vector<gsc::function_ptr>& functions);
private:
void decompile_function(const gsc::function_ptr& func);
void decompile_statements(const gsc::function_ptr& func);
void decompile_expr();
void decompile_ternary();
void decompile_block(const gsc::stmt_list_ptr& block);
void decompile_search_infinite(const gsc::stmt_list_ptr& block);
void decompile_search_loop(const gsc::stmt_list_ptr& block);
void decompile_search_switch(const gsc::stmt_list_ptr& block);
void decompile_search_ifelse(const gsc::stmt_list_ptr& block);
void decompile_break_continue(const gsc::stmt_list_ptr& block);
void decompile_if(const gsc::stmt_list_ptr& block, std::uint32_t start, std::uint32_t end);
void decompile_ifelse(const gsc::stmt_list_ptr& block, std::uint32_t start, std::uint32_t end);
void decompile_last_ifelse(const gsc::stmt_list_ptr& block, std::uint32_t start, std::uint32_t end);
void decompile_infinite(const gsc::stmt_list_ptr& block, std::uint32_t start, std::uint32_t end);
void decompile_loop(const gsc::stmt_list_ptr& block, std::uint32_t start, std::uint32_t end);
void decompile_while(const gsc::stmt_list_ptr& block, std::uint32_t start, std::uint32_t end);
void decompile_for(const gsc::stmt_list_ptr& block, std::uint32_t start, std::uint32_t end);
void decompile_foreach(const gsc::stmt_list_ptr& block, std::uint32_t start, std::uint32_t end);
void decompile_switch(const gsc::stmt_list_ptr& block, std::uint32_t start);
auto find_location_reference(const gsc::stmt_list_ptr& block, std::uint32_t start, std::uint32_t end, const std::string& location) -> bool;
auto find_location_index(const gsc::stmt_list_ptr& block, const std::string& location) -> std::uint32_t;
auto last_location_index(const gsc::stmt_list_ptr& block, std::uint32_t index) -> bool;
void process_stack(const gsc::thread_ptr& thread);
void process_parameters(const gsc::context_ptr& ctx, const gsc::parameters_ptr& params);
void process_stmt(const gsc::context_ptr& ctx, const gsc::stmt_ptr& stmt);
void process_stmt_list(const gsc::context_ptr& ctx, const gsc::stmt_list_ptr& stmt);
void process_stmt_call(const gsc::context_ptr& ctx, const gsc::stmt_call_ptr& stmt);
void process_stmt_assign(const gsc::context_ptr& ctx, const gsc::stmt_assign_ptr& stmt);
void process_stmt_endon(const gsc::context_ptr& ctx, const gsc::stmt_endon_ptr& stmt);
void process_stmt_notify(const gsc::context_ptr& ctx, const gsc::stmt_notify_ptr& stmt);
void process_stmt_wait(const gsc::context_ptr& ctx, const gsc::stmt_wait_ptr& stmt);
void process_stmt_waittill(const gsc::context_ptr& ctx, const gsc::stmt_waittill_ptr& stmt);
void process_stmt_waittillmatch(const gsc::context_ptr& ctx, const gsc::stmt_waittillmatch_ptr& stmt);
void process_stmt_waittillframeend(const gsc::context_ptr& ctx, const gsc::stmt_waittillframeend_ptr& stmt);
void process_stmt_if(const gsc::context_ptr& ctx, const gsc::stmt_if_ptr& stmt);
void process_stmt_ifelse(const gsc::context_ptr& ctx, const gsc::stmt_ifelse_ptr& stmt);
void process_stmt_while(const gsc::context_ptr& ctx, const gsc::stmt_while_ptr& stmt);
void process_stmt_for(const gsc::context_ptr& ctx, const gsc::stmt_for_ptr& stmt);
void process_stmt_foreach(const gsc::context_ptr& ctx, const gsc::stmt_foreach_ptr& stmt);
void process_stmt_switch(const gsc::context_ptr& ctx, const gsc::stmt_switch_ptr& stmt);
void process_stmt_cases(const gsc::context_ptr& ctx, const gsc::stmt_list_ptr& stmt);
void process_stmt_break(const gsc::context_ptr& ctx, const gsc::stmt_break_ptr& stmt);
void process_stmt_return(const gsc::context_ptr& ctx, const gsc::stmt_return_ptr& stmt);
void process_expr(const gsc::context_ptr& ctx, gsc::expr_ptr& expr);
void process_expr_assign(const gsc::context_ptr& ctx, gsc::expr_assign_ptr& expr);
void process_expr_ternary(const gsc::context_ptr& ctx, const gsc::expr_ternary_ptr& expr);
void process_expr_binary(const gsc::context_ptr& ctx, const gsc::expr_binary_ptr& expr);
void process_expr_and(const gsc::context_ptr& ctx, const gsc::expr_and_ptr& expr);
void process_expr_or(const gsc::context_ptr& ctx, const gsc::expr_or_ptr& expr);
void process_expr_complement(const gsc::context_ptr& ctx, const gsc::expr_complement_ptr& expr);
void process_expr_not(const gsc::context_ptr& ctx, const gsc::expr_not_ptr& expr);
void process_expr_call(const gsc::context_ptr& ctx, const gsc::expr_call_ptr& expr);
void process_expr_call_pointer(const gsc::context_ptr& ctx, const gsc::expr_call_ptr& expr);
void process_expr_call_function(const gsc::context_ptr& ctx, const gsc::expr_call_ptr& expr);
void process_expr_arguments(const gsc::context_ptr& ctx, const gsc::expr_arguments_ptr& arg_list);
void process_expr_function(const gsc::context_ptr& ctx, const gsc::expr_function_ptr& node);
void process_expr_add_array(const gsc::context_ptr& ctx, const gsc::expr_add_array_ptr& expr);
void process_expr_size(const gsc::context_ptr& ctx, const gsc::expr_size_ptr& expr);
void process_array_variable(const gsc::context_ptr& ctx, const gsc::expr_array_ptr& expr);
void process_field_variable(const gsc::context_ptr& ctx, const gsc::expr_field_ptr& expr);
void process_local_variable(const gsc::context_ptr& ctx, const gsc::name_ptr& expr);
void process_vector(const gsc::context_ptr& ctx, const gsc::vector_ptr& vec);
void process_var_create(const gsc::context_ptr& ctx, gsc::expr_ptr& expr, bool fromstmt = false);
void process_var_access(const gsc::context_ptr& ctx, gsc::expr_ptr& expr);
void process_var_remove(const gsc::context_ptr& ctx, const gsc::asm_remove_ptr& expr);
};
} // namespace xsk::gsc::iw8

View File

@ -0,0 +1,644 @@
// 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 disassembler::output() -> std::vector<gsc::function_ptr>
{
return std::move(functions_);
}
auto disassembler::output_data() -> std::vector<std::uint8_t>
{
output_ = std::make_unique<utils::byte_buffer>(0x100000);
output_->write_string("// IW8 PC GSCASM\n");
output_->write_string("// Disassembled by https://github.com/xensik/gsc-tool\n");
for (auto& func : functions_)
{
this->print_function(func);
}
std::vector<std::uint8_t> output;
output.resize(output_->pos());
memcpy(output.data(), output_->buffer().data(), output.size());
return output;
}
void disassembler::disassemble(const std::string& file, std::vector<std::uint8_t>& script, std::vector<std::uint8_t>& stack)
{
filename_ = file;
script_ = std::make_unique<utils::byte_buffer>(script);
stack_ = std::make_unique<utils::byte_buffer>(stack);
functions_.clear();
script_->seek(1);
while (stack_->is_avail() && script_->is_avail())
{
functions_.push_back(std::make_unique<gsc::function>());
auto& func = functions_.back();
func->index = static_cast<std::uint32_t>(script_->pos());
func->size = stack_->read<std::uint32_t>();
func->id = stack_->read<std::uint32_t>();
func->name = "sub_"s + (func->id == 0 ? stack_->read_c_string() : resolver::token_name(func->id));
this->dissasemble_function(func);
func->labels = labels_;
labels_.clear();
}
this->resolve_local_functions();
}
void disassembler::dissasemble_function(const gsc::function_ptr& func)
{
auto size = func->size;
while (size > 0)
{
func->instructions.push_back(std::make_unique<gsc::instruction>());
auto& inst = func->instructions.back();
inst->index = static_cast<std::uint32_t>(script_->pos());
inst->opcode = script_->read<std::uint8_t>();
inst->size = opcode_size(inst->opcode);
this->dissasemble_instruction(inst);
size -= inst->size;
}
}
void disassembler::dissasemble_instruction(const gsc::instruction_ptr& inst)
{
switch (opcode(inst->opcode))
{
case opcode::OP_CastFieldObject:
case opcode::OP_plus:
case opcode::OP_GetGameRef:
case opcode::OP_GetThisthread:
case opcode::OP_greater:
case opcode::OP_shift_right:
case opcode::OP_dec:
case opcode::OP_bit_or:
case opcode::OP_equality:
case opcode::OP_ClearLocalVariableFieldCached0:
case opcode::OP_notify:
case opcode::OP_PreScriptCall:
case opcode::OP_GetUndefined:
case opcode::OP_SetLocalVariableFieldCached0:
case opcode::OP_GetLevel:
case opcode::OP_size:
case opcode::OP_AddArray:
case opcode::OP_endon:
case opcode::OP_shift_left:
case opcode::OP_EvalLocalArrayRefCached0:
case opcode::OP_Return:
case opcode::OP_SafeSetVariableFieldCached0:
case opcode::OP_GetSelfObject:
case opcode::OP_GetGame:
case opcode::OP_EvalArray:
case opcode::OP_GetSelf:
case opcode::OP_End:
case opcode::OP_less_equal:
case opcode::OP_EvalLocalVariableCached0:
case opcode::OP_EvalLocalVariableCached1:
case opcode::OP_EvalLocalVariableCached2:
case opcode::OP_EvalLocalVariableCached3:
case opcode::OP_EvalLocalVariableCached4:
case opcode::OP_EvalLocalVariableCached5:
case opcode::OP_ScriptMethodCallPointer:
case opcode::OP_checkclearparams:
case opcode::OP_waittillmatch2:
case opcode::OP_minus:
case opcode::OP_greater_equal:
case opcode::OP_vector:
case opcode::OP_ClearArray:
case opcode::OP_DecTop:
case opcode::OP_CastBool:
case opcode::OP_EvalArrayRef:
case opcode::OP_GetZero:
case opcode::OP_wait:
case opcode::OP_waittill:
case opcode::OP_GetAnimObject:
case opcode::OP_mod:
case opcode::OP_clearparams:
case opcode::OP_ScriptFunctionCallPointer:
case opcode::OP_EmptyArray:
case opcode::OP_ClearVariableField:
case opcode::OP_EvalNewLocalVariableRefCached0:
case opcode::OP_BoolComplement:
case opcode::OP_less:
case opcode::OP_BoolNot:
case opcode::OP_waittillFrameEnd:
case opcode::OP_waitframe:
case opcode::OP_GetLevelObject:
case opcode::OP_inc:
case opcode::OP_GetAnim:
case opcode::OP_SetVariableField:
case opcode::OP_divide:
case opcode::OP_multiply:
case opcode::OP_EvalLocalVariableRefCached0:
case opcode::OP_bit_and:
case opcode::OP_voidCodepos:
case opcode::OP_inequality:
case opcode::OP_bit_ex_or:
// case opcode::OP_NOP:
// case opcode::OP_abort:
// case opcode::OP_object:
// case opcode::OP_thread_object:
case opcode::OP_EvalLocalVariable:
case opcode::OP_EvalLocalVariableRef:
// case opcode::OP_breakpoint:
// case opcode::OP_assignmentBreakpoint:
// case opcode::OP_manualAndAssignmentBreakpoint:
case opcode::OP_BoolNotAfterAnd:
case opcode::OP_IsDefined:
case opcode::OP_IsTrue:
break;
case opcode::OP_GetByte:
case opcode::OP_GetNegByte:
inst->data.push_back(utils::string::va("%i", script_->read<std::uint8_t>()));
break;
case opcode::OP_GetUnsignedShort:
case opcode::OP_GetNegUnsignedShort:
inst->data.push_back(utils::string::va("%i", script_->read<std::uint16_t>()));
break;
case opcode::OP_GetInteger:
inst->data.push_back(utils::string::va("%i", script_->read<std::int32_t>()));
break;
case opcode::OP_GetFloat:
{
auto val = script_->read<float>();
inst->data.push_back(utils::string::va("%g%s", val, val == int(val) ? ".0" : ""));
}
break;
case opcode::OP_GetVector:
inst->data.push_back(utils::string::va("%g", script_->read<float>()));
inst->data.push_back(utils::string::va("%g", script_->read<float>()));
inst->data.push_back(utils::string::va("%g", script_->read<float>()));
break;
case opcode::OP_GetString:
case opcode::OP_GetIString:
script_->seek(4);
inst->data.push_back(utils::string::to_literal(stack_->read_c_string()));
break;
case opcode::OP_GetAnimation:
script_->seek(8);
inst->data.push_back(utils::string::quote(stack_->read_c_string().data(), false));
inst->data.push_back(utils::string::quote(stack_->read_c_string().data(), false));
break;
case opcode::OP_GetAnimTree:
script_->seek(1);
inst->data.push_back(utils::string::quote(stack_->read_c_string().data(), false));
break;
case opcode::OP_waittillmatch:
inst->data.push_back(utils::string::va("%i", script_->read<std::uint16_t>()));
break;
case opcode::OP_SetNewLocalVariableFieldCached0:
case opcode::OP_EvalNewLocalArrayRefCached0:
case opcode::OP_SafeCreateVariableFieldCached:
case opcode::OP_ClearLocalVariableFieldCached:
case opcode::OP_SetLocalVariableFieldCached:
case opcode::OP_RemoveLocalVariables:
case opcode::OP_EvalLocalVariableRefCached:
case opcode::OP_EvalLocalArrayRefCached:
case opcode::OP_SafeSetVariableFieldCached:
case opcode::OP_EvalLocalVariableCached:
case opcode::OP_SafeSetWaittillVariableFieldCached:
case opcode::OP_CreateLocalVariable:
case opcode::OP_EvalLocalVariableObjectCached:
case opcode::OP_EvalLocalArrayCached:
inst->data.push_back(utils::string::va("%i", script_->read<std::uint8_t>()));
break;
case opcode::OP_EvalSelfFieldVariable:
case opcode::OP_SetLevelFieldVariableField:
case opcode::OP_ClearFieldVariable:
case opcode::OP_EvalFieldVariable:
case opcode::OP_EvalFieldVariableRef:
case opcode::OP_EvalLevelFieldVariable:
case opcode::OP_SetAnimFieldVariableField:
case opcode::OP_SetSelfFieldVariableField:
case opcode::OP_EvalAnimFieldVariableRef:
case opcode::OP_EvalLevelFieldVariableRef:
case opcode::OP_EvalAnimFieldVariable:
case opcode::OP_EvalSelfFieldVariableRef:
this->disassemble_field_variable(inst);
break;
case opcode::OP_CallBuiltinPointer:
case opcode::OP_CallBuiltinMethodPointer:
case opcode::OP_ScriptThreadCallPointer:
case opcode::OP_ScriptChildThreadCallPointer:
case opcode::OP_ScriptMethodThreadCallPointer:
case opcode::OP_ScriptMethodChildThreadCallPointer:
inst->data.push_back(utils::string::va("%i", script_->read<std::uint8_t>()));
break;
case opcode::OP_GetLocalFunction:
case opcode::OP_ScriptLocalFunctionCall2:
case opcode::OP_ScriptLocalFunctionCall:
case opcode::OP_ScriptLocalMethodCall:
this->disassemble_local_call(inst, false);
break;
case opcode::OP_ScriptLocalThreadCall:
case opcode::OP_ScriptLocalChildThreadCall:
case opcode::OP_ScriptLocalMethodThreadCall:
case opcode::OP_ScriptLocalMethodChildThreadCall:
this->disassemble_local_call(inst, true);
break;
case opcode::OP_GetFarFunction:
case opcode::OP_ScriptFarFunctionCall2:
case opcode::OP_ScriptFarFunctionCall:
case opcode::OP_ScriptFarMethodCall:
this->disassemble_far_call(inst, false);
break;
case opcode::OP_ScriptFarThreadCall:
case opcode::OP_ScriptFarChildThreadCall:
case opcode::OP_ScriptFarMethodThreadCall:
case opcode::OP_ScriptFarMethodChildThreadCall:
this->disassemble_far_call(inst, true);
break;
case opcode::OP_CallBuiltin:
this->disassemble_builtin_call(inst, false, true);
break;
case opcode::OP_CallBuiltinMethod:
this->disassemble_builtin_call(inst, true, true);
break;
case opcode::OP_GetBuiltinFunction:
case opcode::OP_CallBuiltin0:
case opcode::OP_CallBuiltin1:
case opcode::OP_CallBuiltin2:
case opcode::OP_CallBuiltin3:
case opcode::OP_CallBuiltin4:
case opcode::OP_CallBuiltin5:
this->disassemble_builtin_call(inst, false, false);
break;
case opcode::OP_GetBuiltinMethod:
case opcode::OP_CallBuiltinMethod0:
case opcode::OP_CallBuiltinMethod1:
case opcode::OP_CallBuiltinMethod2:
case opcode::OP_CallBuiltinMethod3:
case opcode::OP_CallBuiltinMethod4:
case opcode::OP_CallBuiltinMethod5:
this->disassemble_builtin_call(inst, true, false);
break;
case opcode::OP_JumpOnFalse:
case opcode::OP_JumpOnTrue:
case opcode::OP_JumpOnFalseExpr:
case opcode::OP_JumpOnTrueExpr:
this->disassemble_jump(inst, true, false);
break;
case opcode::OP_jumpback:
this->disassemble_jump(inst, false, true);
break;
case opcode::OP_jump:
this->disassemble_jump(inst, false, false);
break;
case opcode::OP_switch:
this->disassemble_switch(inst);
break;
case opcode::OP_endswitch:
this->disassemble_end_switch(inst);
break;
/*
case opcode::OP_prof_begin:
script_->seek(5); // TODO: skipped data
break;
case opcode::OP_prof_end:
script_->seek(1); // TODO: skipped data
break;
case opcode::OP_EvalNewLocalArrayRefCached0_Precompiled:
case opcode::OP_SetNewLocalVariableFieldCached0_Precompiled:
case opcode::OP_CreateLocalVariable_Precompiled:
case opcode::OP_SafeCreateVariableFieldCached_Precompiled:
inst->data.push_back(utils::string::va("%i", script_->read<std::uint8_t>()));
break;
*/
case opcode::OP_FormalParams:
case opcode::OP_FormalParams_Precompiled:
this->disassemble_formal_params(inst);
break;
/* case opcode::OP_NativeGetLocalFunction:
case opcode::OP_NativeLocalFunctionCall:
case opcode::OP_NativeLocalFunctionCall2:
case opcode::OP_NativeLocalMethodCall:
this->disassemble_local_call(inst, false);
break;
case opcode::OP_NativeGetFarFunction:
case opcode::OP_NativeFarFunctionCall:
case opcode::OP_NativeFarFunctionCall2:
case opcode::OP_NativeFarMethodCall:
this->disassemble_far_call(inst, false);
break;
case opcode::OP_NativeLocalFunctionThreadCall:
case opcode::OP_NativeLocalMethodThreadCall:
case opcode::OP_NativeLocalFunctionChildThreadCall:
case opcode::OP_NativeLocalMethodChildThreadCall:
this->disassemble_local_call(inst, true);
break;
case opcode::OP_NativeFarFunctionThreadCall:
case opcode::OP_NativeFarMethodThreadCall:
case opcode::OP_NativeFarFunctionChildThreadCall:
case opcode::OP_NativeFarMethodChildThreadCall:
this->disassemble_far_call(inst, true);
break;
*/
default:
throw gsc::disasm_error(utils::string::va("Unhandled opcode 0x%X at index '%04X'!", inst->opcode, inst->index));
}
}
void disassembler::disassemble_builtin_call(const gsc::instruction_ptr& inst, bool method, bool arg_num)
{
if (arg_num)
{
inst->data.push_back(utils::string::va("%i", script_->read<std::uint8_t>()));
}
if (method)
{
inst->data.push_back(resolver::method_name(script_->read<std::uint16_t>()));
}
else
{
inst->data.push_back(resolver::function_name(script_->read<std::uint16_t>()));
}
}
void disassembler::disassemble_local_call(const gsc::instruction_ptr& inst, bool thread)
{
std::int32_t offset = this->disassemble_offset();
inst->data.push_back(utils::string::va("%X", offset + inst->index + 1));
if (thread)
{
inst->data.push_back(utils::string::va("%i", script_->read<std::uint8_t>()));
}
}
void disassembler::disassemble_far_call(const gsc::instruction_ptr& inst, bool thread)
{
script_->seek(3);
if (thread)
{
inst->data.push_back(utils::string::va("%i", script_->read<std::uint8_t>()));
}
auto file_id = stack_->read<std::uint32_t>();
auto file_name = file_id == 0 ? stack_->read_c_string() : resolver::file_name(file_id);
auto func_id = stack_->read<std::uint32_t>();
auto func_name = func_id == 0 ? stack_->read_c_string() : resolver::token_name(func_id);
inst->data.push_back(file_name != "" ? file_name : utils::string::va("_ID%i", file_id));
inst->data.push_back(func_name != "" ? func_name : utils::string::va("_ID%i", func_id));
}
void disassembler::disassemble_jump(const gsc::instruction_ptr& inst, bool expr, bool back)
{
std::int32_t addr;
std::string label;
if (expr)
{
addr = inst->index + 3 + script_->read<std::int16_t>();
label = utils::string::va("loc_%X", addr);
inst->data.push_back(label);
}
else if (back)
{
addr = inst->index + 3 - script_->read<std::uint16_t>();
label = utils::string::va("loc_%X", addr);
inst->data.push_back(label);
}
else
{
addr = inst->index + 5 + script_->read<std::int32_t>();
label = utils::string::va("loc_%X", addr);
inst->data.push_back(label);
}
labels_.insert({addr, label});
}
void disassembler::disassemble_field_variable(const gsc::instruction_ptr& inst)
{
std::uint32_t field_id = script_->read<std::uint32_t>();
std::string field_name;
if(field_id > 0x13160) // 0xE2C0 or 0x13160
{
auto temp = stack_->read<std::uint32_t>();
field_name = temp == 0 ? stack_->read_c_string() : std::to_string(temp);
}
else
{
field_name = resolver::token_name(field_id);
}
inst->data.push_back(field_name != "" ? field_name : utils::string::va("_ID%i", field_id));
}
void disassembler::disassemble_formal_params(const gsc::instruction_ptr& inst)
{
auto size = script_->read<std::uint8_t>();
inst->size += size;
inst->data.push_back(utils::string::va("%i", size));
while(size > 0)
{
inst->data.push_back(utils::string::va("%d", script_->read<std::uint8_t>()));
size--;
}
}
void disassembler::disassemble_switch(const gsc::instruction_ptr& inst)
{
std::int32_t addr = inst->index + 4 + script_->read<std::int32_t>();
std::string label = utils::string::va("loc_%X", addr);
inst->data.push_back(label);
labels_.insert({addr, label});
}
void disassembler::disassemble_end_switch(const gsc::instruction_ptr& inst)
{
std::uint16_t case_num = script_->read<std::uint16_t>();
inst->data.push_back(utils::string::va("%i", case_num));
std::uint32_t internal_index = inst->index + 3;
if (case_num)
{
for (auto i = case_num; i > 0; i--)
{
std::uint32_t case_label = script_->read<std::uint32_t>();
if (case_label < 0x80000 && case_label > 0)
{
inst->data.push_back("case");
inst->data.push_back(utils::string::quote(stack_->read_c_string(), false));
}
else if (case_label == 0)
{
inst->data.push_back("default");
stack_->read<std::uint16_t>();
}
else
{
inst->data.push_back("case");
inst->data.push_back(utils::string::va("%i", (case_label - 0x800000) & 0xFFFFFF));
}
inst->size += 4;
internal_index += 4;
auto addr = this->disassemble_offset() + internal_index;
std::string label = utils::string::va("loc_%X", addr);
inst->data.push_back(label);
labels_.insert({addr, label});
inst->size += 3;
internal_index += 3;
}
}
}
auto disassembler::disassemble_offset() -> std::int32_t
{
std::array<std::uint8_t, 4> bytes = {};
for (auto i = 0; i < 3; i++)
{
bytes[i] = script_->read<std::uint8_t>();
}
std::int32_t offset = *reinterpret_cast<std::int32_t*>(bytes.data());
offset = (offset << 8) >> 8;
return offset;
}
void disassembler::resolve_local_functions()
{
for (auto& func : functions_)
{
for (auto& inst : func->instructions)
{
switch (opcode(inst->opcode))
{
case opcode::OP_GetLocalFunction:
case opcode::OP_ScriptLocalFunctionCall:
case opcode::OP_ScriptLocalFunctionCall2:
case opcode::OP_ScriptLocalMethodCall:
case opcode::OP_ScriptLocalThreadCall:
case opcode::OP_ScriptLocalChildThreadCall:
case opcode::OP_ScriptLocalMethodThreadCall:
case opcode::OP_ScriptLocalMethodChildThreadCall:
inst->data.at(0) = this->resolve_function(inst->data[0]);
break;
default:
break;
}
}
}
}
auto disassembler::resolve_function(const std::string& index) -> std::string
{
if (utils::string::is_hex_number(index))
{
std::uint32_t idx = std::stoul(index, nullptr, 16);
for (auto& func : functions_)
{
if (func->index == idx)
{
return func->name;
}
}
throw gsc::disasm_error(utils::string::va("Couldn't resolve function name at index '0x%04X'!", idx));
}
throw gsc::disasm_error(utils::string::va("\"%s\" is not valid function address!", index.data()));
}
void disassembler::print_function(const gsc::function_ptr& func)
{
output_->write_string("\n");
output_->write_string(utils::string::va("%s\n", func->name.data()));
for (auto& inst : func->instructions)
{
const auto itr = func->labels.find(inst->index);
if (itr != func->labels.end())
{
output_->write_string(utils::string::va("\t%s\n", itr->second.data()));
}
this->print_instruction(inst);
}
output_->write_string("\n");
output_->write_string(utils::string::va("end_%s\n", func->name.substr(4).data()));
}
void disassembler::print_instruction(const gsc::instruction_ptr& inst)
{
switch (opcode(inst->opcode))
{
case opcode::OP_endswitch:
output_->write_string(utils::string::va("\t\t%s", resolver::opcode_name(inst->opcode).data()));
output_->write_string(utils::string::va(" %s\n", inst->data[0].data()));
{
std::uint32_t totalcase = std::stoul(inst->data[0]);
auto index = 0;
for (auto casenum = 0u; casenum < totalcase; casenum++)
{
if (inst->data[1 + index] == "case")
{
output_->write_string(utils::string::va("\t\t\t%s %s %s", inst->data[1 + index].data(), inst->data[1 + index + 1].data(), inst->data[1 + index + 2].data()));
index += 3;
}
else if (inst->data[1 + index] == "default")
{
output_->write_string(utils::string::va("\t\t\t%s %s", inst->data[1 + index].data(), inst->data[1 + index + 1].data()));
index += 2;
}
if (casenum != totalcase - 1)
{
output_->write_string("\n");
}
}
}
break;
default:
output_->write_string(utils::string::va("\t\t%s", resolver::opcode_name(inst->opcode).data()));
for (auto& d : inst->data)
{
output_->write_string(utils::string::va(" %s", d.data()));
}
break;
}
output_->write_string("\n");
}
} // namespace xsk::gsc::iw8

View File

@ -0,0 +1,43 @@
// 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.
#pragma once
namespace xsk::gsc::iw8
{
class disassembler : public gsc::disassembler
{
std::string filename_;
utils::byte_buffer_ptr script_;
utils::byte_buffer_ptr stack_;
utils::byte_buffer_ptr output_;
std::vector<gsc::function_ptr> functions_;
std::unordered_map<std::uint32_t, std::string> labels_;
public:
auto output() -> std::vector<gsc::function_ptr>;
auto output_data() -> std::vector<std::uint8_t>;
void disassemble(const std::string& file, std::vector<std::uint8_t>& script, std::vector<std::uint8_t>& stack);
private:
void dissasemble_function(const gsc::function_ptr& func);
void dissasemble_instruction(const gsc::instruction_ptr& inst);
void disassemble_builtin_call(const gsc::instruction_ptr& inst, bool method, bool arg_num);
void disassemble_local_call(const gsc::instruction_ptr& inst, bool thread);
void disassemble_far_call(const gsc::instruction_ptr& inst, bool thread);
void disassemble_jump(const gsc::instruction_ptr& inst, bool expr, bool back);
void disassemble_field_variable(const gsc::instruction_ptr& inst);
void disassemble_formal_params(const gsc::instruction_ptr& inst);
void disassemble_switch(const gsc::instruction_ptr& inst);
void disassemble_end_switch(const gsc::instruction_ptr& inst);
auto disassemble_offset() -> std::int32_t;
void resolve_local_functions();
auto resolve_function(const std::string& index) -> std::string;
void print_function(const gsc::function_ptr& func);
void print_instruction(const gsc::instruction_ptr& inst);
};
} // namespace xsk::gsc::iw8

229
src/iw8/xsk/iw8.cpp Normal file
View File

@ -0,0 +1,229 @@
// 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 opcode_size(std::uint8_t id) -> std::uint32_t
{
switch (opcode(id))
{
case opcode::OP_CastFieldObject:
case opcode::OP_plus:
case opcode::OP_GetGameRef:
case opcode::OP_GetThisthread:
case opcode::OP_greater:
case opcode::OP_shift_right:
case opcode::OP_dec:
case opcode::OP_bit_or:
case opcode::OP_equality:
case opcode::OP_ClearLocalVariableFieldCached0:
case opcode::OP_notify:
case opcode::OP_PreScriptCall:
case opcode::OP_GetUndefined:
case opcode::OP_SetLocalVariableFieldCached0:
case opcode::OP_GetLevel:
case opcode::OP_size:
case opcode::OP_AddArray:
case opcode::OP_endon:
case opcode::OP_shift_left:
case opcode::OP_EvalLocalArrayRefCached0:
case opcode::OP_Return:
case opcode::OP_SafeSetVariableFieldCached0:
case opcode::OP_GetSelfObject:
case opcode::OP_GetGame:
case opcode::OP_EvalArray:
case opcode::OP_GetSelf:
case opcode::OP_End:
case opcode::OP_less_equal:
case opcode::OP_EvalLocalVariableCached0:
case opcode::OP_EvalLocalVariableCached1:
case opcode::OP_EvalLocalVariableCached2:
case opcode::OP_EvalLocalVariableCached3:
case opcode::OP_EvalLocalVariableCached4:
case opcode::OP_EvalLocalVariableCached5:
case opcode::OP_ScriptMethodCallPointer:
case opcode::OP_checkclearparams:
case opcode::OP_waittillmatch2:
case opcode::OP_minus:
case opcode::OP_greater_equal:
case opcode::OP_vector:
case opcode::OP_ClearArray:
case opcode::OP_DecTop:
case opcode::OP_CastBool:
case opcode::OP_EvalArrayRef:
case opcode::OP_GetZero:
case opcode::OP_wait:
case opcode::OP_waittill:
case opcode::OP_GetAnimObject:
case opcode::OP_mod:
case opcode::OP_clearparams:
case opcode::OP_ScriptFunctionCallPointer:
case opcode::OP_EmptyArray:
case opcode::OP_ClearVariableField:
case opcode::OP_EvalNewLocalVariableRefCached0:
case opcode::OP_BoolComplement:
case opcode::OP_less:
case opcode::OP_BoolNot:
case opcode::OP_waittillFrameEnd:
case opcode::OP_waitframe:
case opcode::OP_GetLevelObject:
case opcode::OP_inc:
case opcode::OP_GetAnim:
case opcode::OP_SetVariableField:
case opcode::OP_divide:
case opcode::OP_multiply:
case opcode::OP_EvalLocalVariableRefCached0:
case opcode::OP_bit_and:
case opcode::OP_voidCodepos:
case opcode::OP_inequality:
case opcode::OP_bit_ex_or:
/*
case opcode::OP_NOP:
case opcode::OP_abort:
case opcode::OP_object:
case opcode::OP_thread_object:
case opcode::OP_EvalLocalVariable:
case opcode::OP_EvalLocalVariableRef:
case opcode::OP_breakpoint:
case opcode::OP_assignmentBreakpoint:
case opcode::OP_manualAndAssignmentBreakpoint:
*/
case opcode::OP_BoolNotAfterAnd:
case opcode::OP_IsDefined:
case opcode::OP_IsTrue:
return 1;
case opcode::OP_SetLocalVariableFieldCached:
case opcode::OP_RemoveLocalVariables:
case opcode::OP_ScriptMethodChildThreadCallPointer:
case opcode::OP_GetByte:
case opcode::OP_SafeSetWaittillVariableFieldCached:
case opcode::OP_CreateLocalVariable:
case opcode::OP_CallBuiltinMethodPointer:
case opcode::OP_EvalLocalVariableCached:
case opcode::OP_EvalNewLocalArrayRefCached0:
case opcode::OP_ScriptChildThreadCallPointer:
case opcode::OP_EvalLocalVariableObjectCached:
case opcode::OP_GetNegByte:
case opcode::OP_SafeCreateVariableFieldCached:
case opcode::OP_SetNewLocalVariableFieldCached0:
case opcode::OP_GetAnimTree:
case opcode::OP_EvalLocalArrayCached:
case opcode::OP_ScriptMethodThreadCallPointer:
case opcode::OP_SafeSetVariableFieldCached:
case opcode::OP_EvalLocalVariableRefCached:
case opcode::OP_ScriptThreadCallPointer:
case opcode::OP_ClearLocalVariableFieldCached:
case opcode::OP_EvalLocalArrayRefCached:
case opcode::OP_CallBuiltinPointer:
// case opcode::OP_prof_end:
case opcode::OP_FormalParams:
/*
case opcode::OP_EvalNewLocalArrayRefCached0_Precompiled:
case opcode::OP_SetNewLocalVariableFieldCached0_Precompiled:
case opcode::OP_CreateLocalVariable_Precompiled:
case opcode::OP_SafeCreateVariableFieldCached_Precompiled:
case opcode::OP_FormalParams_Precompiled:
*/
return 2;
case opcode::OP_waittillmatch:
case opcode::OP_JumpOnTrue:
case opcode::OP_JumpOnFalseExpr:
case opcode::OP_jumpback:
case opcode::OP_JumpOnTrueExpr:
case opcode::OP_CallBuiltin0:
case opcode::OP_CallBuiltin1:
case opcode::OP_CallBuiltin2:
case opcode::OP_CallBuiltin3:
case opcode::OP_CallBuiltin4:
case opcode::OP_CallBuiltin5:
case opcode::OP_GetBuiltinFunction:
case opcode::OP_GetNegUnsignedShort:
case opcode::OP_GetBuiltinMethod:
case opcode::OP_endswitch:
case opcode::OP_GetUnsignedShort:
case opcode::OP_JumpOnFalse:
case opcode::OP_CallBuiltinMethod0:
case opcode::OP_CallBuiltinMethod1:
case opcode::OP_CallBuiltinMethod2:
case opcode::OP_CallBuiltinMethod3:
case opcode::OP_CallBuiltinMethod4:
case opcode::OP_CallBuiltinMethod5:
return 3;
case opcode::OP_CallBuiltin:
case opcode::OP_ScriptLocalMethodCall:
case opcode::OP_ScriptLocalFunctionCall2:
case opcode::OP_ScriptFarFunctionCall:
case opcode::OP_ScriptFarFunctionCall2:
case opcode::OP_CallBuiltinMethod:
case opcode::OP_GetLocalFunction:
case opcode::OP_GetFarFunction:
case opcode::OP_ScriptFarMethodCall:
case opcode::OP_ScriptLocalFunctionCall:
/*
case opcode::OP_NativeGetLocalFunction:
case opcode::OP_NativeLocalFunctionCall:
case opcode::OP_NativeLocalFunctionCall2:
case opcode::OP_NativeLocalMethodCall:
case opcode::OP_NativeGetFarFunction:
case opcode::OP_NativeFarFunctionCall:
case opcode::OP_NativeFarFunctionCall2:
case opcode::OP_NativeFarMethodCall:
*/
return 4;
case opcode::OP_EvalSelfFieldVariableRef:
case opcode::OP_ScriptFarMethodChildThreadCall:
case opcode::OP_EvalAnimFieldVariable:
case opcode::OP_EvalLevelFieldVariableRef:
case opcode::OP_ScriptFarThreadCall:
case opcode::OP_SetSelfFieldVariableField:
case opcode::OP_ClearFieldVariable:
case opcode::OP_ScriptLocalMethodThreadCall:
case opcode::OP_EvalFieldVariable:
case opcode::OP_ScriptLocalChildThreadCall:
case opcode::OP_SetLevelFieldVariableField:
case opcode::OP_EvalSelfFieldVariable:
case opcode::OP_ScriptLocalThreadCall:
case opcode::OP_GetInteger:
case opcode::OP_SetAnimFieldVariableField:
case opcode::OP_GetIString:
case opcode::OP_ScriptFarMethodThreadCall:
case opcode::OP_EvalFieldVariableRef:
case opcode::OP_ScriptLocalMethodChildThreadCall:
case opcode::OP_GetFloat:
case opcode::OP_GetString:
case opcode::OP_EvalLevelFieldVariable:
case opcode::OP_switch:
case opcode::OP_ScriptFarChildThreadCall:
case opcode::OP_EvalAnimFieldVariableRef:
case opcode::OP_jump:
/*
case opcode::OP_NativeLocalFunctionThreadCall:
case opcode::OP_NativeLocalMethodThreadCall:
case opcode::OP_NativeLocalFunctionChildThreadCall:
case opcode::OP_NativeLocalMethodChildThreadCall:
case opcode::OP_NativeFarFunctionThreadCall:
case opcode::OP_NativeFarMethodThreadCall:
case opcode::OP_NativeFarFunctionChildThreadCall:
case opcode::OP_NativeFarMethodChildThreadCall:
*/
return 5;
/*
case opcode::OP_prof_begin:
return 6;
*/
case opcode::OP_GetAnimation:
return 9;
case opcode::OP_GetVector:
return 13;
default:
throw std::runtime_error("Couldn't resolve instruction size for " + std::to_string(id));
}
}
} // namespace xsk::gsc::iw8

216
src/iw8/xsk/iw8.hpp Normal file
View File

@ -0,0 +1,216 @@
// 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.
#pragma once
#include "utils/xsk/utils.hpp"
#include "assembler.hpp"
#include "disassembler.hpp"
#include "compiler.hpp"
#include "decompiler.hpp"
#include "resolver.hpp"
namespace xsk::gsc::iw8
{
enum class opcode : std::uint8_t
{
OP_CastFieldObject = 0x0,
OP_SetLocalVariableFieldCached = 0x1,
OP_plus = 0x2,
OP_RemoveLocalVariables = 0x3,
OP_EvalSelfFieldVariableRef = 0x4,
OP_ScriptFarMethodChildThreadCall = 0x5,
OP_GetGameRef = 0x6,
OP_EvalAnimFieldVariable = 0x7,
OP_EvalLevelFieldVariableRef = 0x8,
OP_GetThisthread = 0x9,
OP_greater = 0xA,
OP_waittillmatch = 0xB,
OP_shift_right = 0xC,
OP_dec = 0xD,
OP_JumpOnTrue = 0xE,
OP_bit_or = 0xF,
OP_equality = 0x10,
OP_ClearLocalVariableFieldCached0 = 0x11,
OP_notify = 0x12,
OP_GetVector = 0x13,
OP_ScriptMethodChildThreadCallPointer = 0x14,
OP_PreScriptCall = 0x15,
OP_GetByte = 0x16,
OP_ScriptFarThreadCall = 0x17,
OP_SetSelfFieldVariableField = 0x18,
OP_JumpOnFalseExpr = 0x19,
OP_GetUndefined = 0x1A,
OP_jumpback = 0x1B,
OP_JumpOnTrueExpr = 0x1C,
OP_CallBuiltin0 = 0x1D,
OP_CallBuiltin1 = 0x1E,
OP_CallBuiltin2 = 0x1F,
OP_CallBuiltin3 = 0x20,
OP_CallBuiltin4 = 0x21,
OP_CallBuiltin5 = 0x22,
OP_CallBuiltin = 0x23,
OP_SetLocalVariableFieldCached0 = 0x24,
OP_ClearFieldVariable = 0x25,
OP_GetLevel = 0x26,
OP_size = 0x27,
OP_SafeSetWaittillVariableFieldCached = 0x28,
OP_ScriptLocalMethodThreadCall = 0x29,
OP_AddArray = 0x2A,
OP_endon = 0x2B,
OP_EvalFieldVariable = 0x2C,
OP_shift_left = 0x2D,
OP_EvalLocalArrayRefCached0 = 0x2E,
OP_Return = 0x2F,
OP_CreateLocalVariable = 0x30,
OP_SafeSetVariableFieldCached0 = 0x31,
OP_GetBuiltinFunction = 0x32,
OP_ScriptLocalMethodCall = 0x33,
OP_CallBuiltinMethodPointer = 0x34,
OP_ScriptLocalChildThreadCall = 0x35,
OP_GetSelfObject = 0x36,
OP_GetGame = 0x37,
OP_SetLevelFieldVariableField = 0x38,
OP_EvalArray = 0x39,
OP_GetSelf = 0x3A,
OP_End = 0x3B,
OP_EvalSelfFieldVariable = 0x3C,
OP_less_equal = 0x3D,
OP_EvalLocalVariableCached0 = 0x3E,
OP_EvalLocalVariableCached1 = 0x3F,
OP_EvalLocalVariableCached2 = 0x40,
OP_EvalLocalVariableCached3 = 0x41,
OP_EvalLocalVariableCached4 = 0x42,
OP_EvalLocalVariableCached5 = 0x43,
OP_EvalLocalVariableCached = 0x44,
OP_EvalNewLocalArrayRefCached0 = 0x45,
OP_ScriptChildThreadCallPointer = 0x46,
OP_EvalLocalVariableObjectCached = 0x47,
OP_ScriptLocalThreadCall = 0x48,
OP_GetInteger = 0x49,
OP_ScriptMethodCallPointer = 0x4A,
OP_checkclearparams = 0x4B,
OP_SetAnimFieldVariableField = 0x4C,
OP_waittillmatch2 = 0x4D,
OP_minus = 0x4E,
OP_ScriptLocalFunctionCall2 = 0x4F,
OP_GetNegUnsignedShort = 0x50,
OP_GetNegByte = 0x51,
OP_SafeCreateVariableFieldCached = 0x52,
OP_greater_equal = 0x53,
OP_vector = 0x54,
OP_GetBuiltinMethod = 0x55,
OP_endswitch = 0x56,
OP_ClearArray = 0x57,
OP_DecTop = 0x58,
OP_CastBool = 0x59,
OP_EvalArrayRef = 0x5A,
OP_SetNewLocalVariableFieldCached0 = 0x5B,
OP_GetZero = 0x5C,
OP_wait = 0x5D,
OP_waittill = 0x5E,
OP_GetIString = 0x5F,
OP_ScriptFarFunctionCall = 0x60,
OP_GetAnimObject = 0x61,
OP_GetAnimTree = 0x62,
OP_EvalLocalArrayCached = 0x63,
OP_mod = 0x64,
OP_ScriptFarMethodThreadCall = 0x65,
OP_GetUnsignedShort = 0x66,
OP_clearparams = 0x67,
OP_ScriptMethodThreadCallPointer = 0x68,
OP_ScriptFunctionCallPointer = 0x69,
OP_EmptyArray = 0x6A,
OP_SafeSetVariableFieldCached = 0x6B,
OP_ClearVariableField = 0x6C,
OP_EvalFieldVariableRef = 0x6D,
OP_ScriptLocalMethodChildThreadCall = 0x6E,
OP_EvalNewLocalVariableRefCached0 = 0x6F,
OP_GetFloat = 0x70,
OP_EvalLocalVariableRefCached = 0x71,
OP_JumpOnFalse = 0x72,
OP_BoolComplement = 0x73,
OP_ScriptThreadCallPointer = 0x74,
OP_ScriptFarFunctionCall2 = 0x75,
OP_less = 0x76,
OP_BoolNot = 0x77,
OP_waittillFrameEnd = 0x78,
OP_waitframe = 0x79,
OP_GetString = 0x7A,
OP_EvalLevelFieldVariable = 0x7B,
OP_GetLevelObject = 0x7C,
OP_inc = 0x7D,
OP_CallBuiltinMethod0 = 0x7E,
OP_CallBuiltinMethod1 = 0x7F,
OP_CallBuiltinMethod2 = 0x80,
OP_CallBuiltinMethod3 = 0x81,
OP_CallBuiltinMethod4 = 0x82,
OP_CallBuiltinMethod5 = 0x83,
OP_CallBuiltinMethod = 0x84,
OP_GetAnim = 0x85,
OP_switch = 0x86,
OP_SetVariableField = 0x87,
OP_divide = 0x88,
OP_GetLocalFunction = 0x89,
OP_ScriptFarChildThreadCall = 0x8A,
OP_multiply = 0x8B,
OP_ClearLocalVariableFieldCached = 0x8C,
OP_EvalAnimFieldVariableRef = 0x8D,
OP_EvalLocalArrayRefCached = 0x8E,
OP_EvalLocalVariableRefCached0 = 0x8F,
OP_bit_and = 0x90,
OP_GetAnimation = 0x91,
OP_GetFarFunction = 0x92,
OP_CallBuiltinPointer = 0x93,
OP_jump = 0x94,
OP_voidCodepos = 0x95,
OP_ScriptFarMethodCall = 0x96,
OP_inequality = 0x97,
OP_ScriptLocalFunctionCall = 0x98,
OP_bit_ex_or = 0x99,
OP_NOP = 0x9A,
OP_abort = 0x9B,
OP_object = 0x9C,
OP_thread_object = 0x9D,
OP_EvalLocalVariable = 0x9E,
OP_EvalLocalVariableRef = 0x9F,
OP_prof_begin = 0xA0,
OP_prof_end = 0xA1,
OP_breakpoint = 0xA2,
OP_assignmentBreakpoint = 0xA3,
OP_manualAndAssignmentBreakpoint = 0xA4,
OP_BoolNotAfterAnd = 0xA5,
OP_FormalParams = 0xA6,
OP_IsDefined = 0xA7,
OP_IsTrue = 0xA8,
OP_NativeGetLocalFunction = 0xA9,
OP_NativeLocalFunctionCall = 0xAA,
OP_NativeLocalFunctionCall2 = 0xAB,
OP_NativeLocalMethodCall = 0xAC,
OP_NativeLocalFunctionThreadCall = 0xAD,
OP_NativeLocalMethodThreadCall = 0xAE,
OP_NativeLocalFunctionChildThreadCall = 0xAF,
OP_NativeLocalMethodChildThreadCall = 0xB0,
OP_NativeGetFarFunction = 0xB1,
OP_NativeFarFunctionCall = 0xB2,
OP_NativeFarFunctionCall2 = 0xB3,
OP_NativeFarMethodCall = 0xB4,
OP_NativeFarFunctionThreadCall = 0xB5,
OP_NativeFarMethodThreadCall = 0xB6,
OP_NativeFarFunctionChildThreadCall = 0xB7,
OP_NativeFarMethodChildThreadCall = 0xB8,
OP_EvalNewLocalArrayRefCached0_Precompiled = 0xB9,
OP_SetNewLocalVariableFieldCached0_Precompiled = 0xBA,
OP_CreateLocalVariable_Precompiled = 0xBB,
OP_SafeCreateVariableFieldCached_Precompiled = 0xBC,
OP_FormalParams_Precompiled = 0xBD,
OP_count = 0xBE,
};
auto opcode_size(std::uint8_t op) -> std::uint32_t;
} // namespace xsk::gsc::iw8

2882
src/iw8/xsk/lexer.cpp Normal file

File diff suppressed because it is too large Load Diff

708
src/iw8/xsk/lexer.hpp Normal file
View File

@ -0,0 +1,708 @@
#ifndef iw8_HEADER_H
#define iw8_HEADER_H 1
#define iw8_IN_HEADER 1
#line 5 "lexer.hpp"
#include "stdafx.hpp"
#include "iw8.hpp"
#include "parser.hpp"
using namespace xsk::gsc;
#line 11 "lexer.hpp"
#define YY_INT_ALIGNED short int
/* A lexical scanner generated by flex */
#define FLEX_SCANNER
#define YY_FLEX_MAJOR_VERSION 2
#define YY_FLEX_MINOR_VERSION 6
#define YY_FLEX_SUBMINOR_VERSION 4
#if YY_FLEX_SUBMINOR_VERSION > 0
#define FLEX_BETA
#endif
#ifdef yy_create_buffer
#define iw8__create_buffer_ALREADY_DEFINED
#else
#define yy_create_buffer iw8__create_buffer
#endif
#ifdef yy_delete_buffer
#define iw8__delete_buffer_ALREADY_DEFINED
#else
#define yy_delete_buffer iw8__delete_buffer
#endif
#ifdef yy_scan_buffer
#define iw8__scan_buffer_ALREADY_DEFINED
#else
#define yy_scan_buffer iw8__scan_buffer
#endif
#ifdef yy_scan_string
#define iw8__scan_string_ALREADY_DEFINED
#else
#define yy_scan_string iw8__scan_string
#endif
#ifdef yy_scan_bytes
#define iw8__scan_bytes_ALREADY_DEFINED
#else
#define yy_scan_bytes iw8__scan_bytes
#endif
#ifdef yy_init_buffer
#define iw8__init_buffer_ALREADY_DEFINED
#else
#define yy_init_buffer iw8__init_buffer
#endif
#ifdef yy_flush_buffer
#define iw8__flush_buffer_ALREADY_DEFINED
#else
#define yy_flush_buffer iw8__flush_buffer
#endif
#ifdef yy_load_buffer_state
#define iw8__load_buffer_state_ALREADY_DEFINED
#else
#define yy_load_buffer_state iw8__load_buffer_state
#endif
#ifdef yy_switch_to_buffer
#define iw8__switch_to_buffer_ALREADY_DEFINED
#else
#define yy_switch_to_buffer iw8__switch_to_buffer
#endif
#ifdef yypush_buffer_state
#define iw8_push_buffer_state_ALREADY_DEFINED
#else
#define yypush_buffer_state iw8_push_buffer_state
#endif
#ifdef yypop_buffer_state
#define iw8_pop_buffer_state_ALREADY_DEFINED
#else
#define yypop_buffer_state iw8_pop_buffer_state
#endif
#ifdef yyensure_buffer_stack
#define iw8_ensure_buffer_stack_ALREADY_DEFINED
#else
#define yyensure_buffer_stack iw8_ensure_buffer_stack
#endif
#ifdef yylex
#define iw8_lex_ALREADY_DEFINED
#else
#define yylex iw8_lex
#endif
#ifdef yyrestart
#define iw8_restart_ALREADY_DEFINED
#else
#define yyrestart iw8_restart
#endif
#ifdef yylex_init
#define iw8_lex_init_ALREADY_DEFINED
#else
#define yylex_init iw8_lex_init
#endif
#ifdef yylex_init_extra
#define iw8_lex_init_extra_ALREADY_DEFINED
#else
#define yylex_init_extra iw8_lex_init_extra
#endif
#ifdef yylex_destroy
#define iw8_lex_destroy_ALREADY_DEFINED
#else
#define yylex_destroy iw8_lex_destroy
#endif
#ifdef yyget_debug
#define iw8_get_debug_ALREADY_DEFINED
#else
#define yyget_debug iw8_get_debug
#endif
#ifdef yyset_debug
#define iw8_set_debug_ALREADY_DEFINED
#else
#define yyset_debug iw8_set_debug
#endif
#ifdef yyget_extra
#define iw8_get_extra_ALREADY_DEFINED
#else
#define yyget_extra iw8_get_extra
#endif
#ifdef yyset_extra
#define iw8_set_extra_ALREADY_DEFINED
#else
#define yyset_extra iw8_set_extra
#endif
#ifdef yyget_in
#define iw8_get_in_ALREADY_DEFINED
#else
#define yyget_in iw8_get_in
#endif
#ifdef yyset_in
#define iw8_set_in_ALREADY_DEFINED
#else
#define yyset_in iw8_set_in
#endif
#ifdef yyget_out
#define iw8_get_out_ALREADY_DEFINED
#else
#define yyget_out iw8_get_out
#endif
#ifdef yyset_out
#define iw8_set_out_ALREADY_DEFINED
#else
#define yyset_out iw8_set_out
#endif
#ifdef yyget_leng
#define iw8_get_leng_ALREADY_DEFINED
#else
#define yyget_leng iw8_get_leng
#endif
#ifdef yyget_text
#define iw8_get_text_ALREADY_DEFINED
#else
#define yyget_text iw8_get_text
#endif
#ifdef yyget_lineno
#define iw8_get_lineno_ALREADY_DEFINED
#else
#define yyget_lineno iw8_get_lineno
#endif
#ifdef yyset_lineno
#define iw8_set_lineno_ALREADY_DEFINED
#else
#define yyset_lineno iw8_set_lineno
#endif
#ifdef yyget_column
#define iw8_get_column_ALREADY_DEFINED
#else
#define yyget_column iw8_get_column
#endif
#ifdef yyset_column
#define iw8_set_column_ALREADY_DEFINED
#else
#define yyset_column iw8_set_column
#endif
#ifdef yywrap
#define iw8_wrap_ALREADY_DEFINED
#else
#define yywrap iw8_wrap
#endif
#ifdef yyalloc
#define iw8_alloc_ALREADY_DEFINED
#else
#define yyalloc iw8_alloc
#endif
#ifdef yyrealloc
#define iw8_realloc_ALREADY_DEFINED
#else
#define yyrealloc iw8_realloc
#endif
#ifdef yyfree
#define iw8_free_ALREADY_DEFINED
#else
#define yyfree iw8_free
#endif
/* First, we deal with platform-specific or compiler-specific issues. */
/* begin standard C headers. */
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>
/* end standard C headers. */
/* flex integer type definitions */
#ifndef FLEXINT_H
#define FLEXINT_H
/* C99 systems have <inttypes.h>. Non-C99 systems may or may not. */
#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h,
* if you want the limit (max/min) macros for int types.
*/
#ifndef __STDC_LIMIT_MACROS
#define __STDC_LIMIT_MACROS 1
#endif
#include <inttypes.h>
typedef int8_t flex_int8_t;
typedef uint8_t flex_uint8_t;
typedef int16_t flex_int16_t;
typedef uint16_t flex_uint16_t;
typedef int32_t flex_int32_t;
typedef uint32_t flex_uint32_t;
#else
typedef signed char flex_int8_t;
typedef short int flex_int16_t;
typedef int flex_int32_t;
typedef unsigned char flex_uint8_t;
typedef unsigned short int flex_uint16_t;
typedef unsigned int flex_uint32_t;
/* Limits of integral types. */
#ifndef INT8_MIN
#define INT8_MIN (-128)
#endif
#ifndef INT16_MIN
#define INT16_MIN (-32767-1)
#endif
#ifndef INT32_MIN
#define INT32_MIN (-2147483647-1)
#endif
#ifndef INT8_MAX
#define INT8_MAX (127)
#endif
#ifndef INT16_MAX
#define INT16_MAX (32767)
#endif
#ifndef INT32_MAX
#define INT32_MAX (2147483647)
#endif
#ifndef UINT8_MAX
#define UINT8_MAX (255U)
#endif
#ifndef UINT16_MAX
#define UINT16_MAX (65535U)
#endif
#ifndef UINT32_MAX
#define UINT32_MAX (4294967295U)
#endif
#ifndef SIZE_MAX
#define SIZE_MAX (~(size_t)0)
#endif
#endif /* ! C99 */
#endif /* ! FLEXINT_H */
/* begin standard C++ headers. */
/* TODO: this is always defined, so inline it */
#define yyconst const
#if defined(__GNUC__) && __GNUC__ >= 3
#define yynoreturn __attribute__((__noreturn__))
#else
#define yynoreturn
#endif
/* An opaque pointer. */
#ifndef YY_TYPEDEF_YY_SCANNER_T
#define YY_TYPEDEF_YY_SCANNER_T
typedef void* yyscan_t;
#endif
/* For convenience, these vars (plus the bison vars far below)
are macros in the reentrant scanner. */
#define yyin yyg->yyin_r
#define yyout yyg->yyout_r
#define yyextra yyg->yyextra_r
#define yyleng yyg->yyleng_r
#define yytext yyg->yytext_r
#define yylineno (YY_CURRENT_BUFFER_LVALUE->yy_bs_lineno)
#define yycolumn (YY_CURRENT_BUFFER_LVALUE->yy_bs_column)
#define yy_flex_debug yyg->yy_flex_debug_r
/* Size of default input buffer. */
#ifndef YY_BUF_SIZE
#ifdef __ia64__
/* On IA-64, the buffer size is 16k, not 8k.
* Moreover, YY_BUF_SIZE is 2*YY_READ_BUF_SIZE in the general case.
* Ditto for the __ia64__ case accordingly.
*/
#define YY_BUF_SIZE 32768
#else
#define YY_BUF_SIZE 16384
#endif /* __ia64__ */
#endif
#ifndef YY_TYPEDEF_YY_BUFFER_STATE
#define YY_TYPEDEF_YY_BUFFER_STATE
typedef struct yy_buffer_state *YY_BUFFER_STATE;
#endif
#ifndef YY_TYPEDEF_YY_SIZE_T
#define YY_TYPEDEF_YY_SIZE_T
typedef size_t yy_size_t;
#endif
#ifndef YY_STRUCT_YY_BUFFER_STATE
#define YY_STRUCT_YY_BUFFER_STATE
struct yy_buffer_state
{
FILE *yy_input_file;
char *yy_ch_buf; /* input buffer */
char *yy_buf_pos; /* current position in input buffer */
/* Size of input buffer in bytes, not including room for EOB
* characters.
*/
int yy_buf_size;
/* Number of characters read into yy_ch_buf, not including EOB
* characters.
*/
int yy_n_chars;
/* Whether we "own" the buffer - i.e., we know we created it,
* and can realloc() it to grow it, and should free() it to
* delete it.
*/
int yy_is_our_buffer;
/* Whether this is an "interactive" input source; if so, and
* if we're using stdio for input, then we want to use getc()
* instead of fread(), to make sure we stop fetching input after
* each newline.
*/
int yy_is_interactive;
/* Whether we're considered to be at the beginning of a line.
* If so, '^' rules will be active on the next match, otherwise
* not.
*/
int yy_at_bol;
int yy_bs_lineno; /**< The line count. */
int yy_bs_column; /**< The column count. */
/* Whether to try to fill the input buffer when we reach the
* end of it.
*/
int yy_fill_buffer;
int yy_buffer_status;
};
#endif /* !YY_STRUCT_YY_BUFFER_STATE */
void yyrestart ( FILE *input_file , yyscan_t yyscanner );
void yy_switch_to_buffer ( YY_BUFFER_STATE new_buffer , yyscan_t yyscanner );
YY_BUFFER_STATE yy_create_buffer ( FILE *file, int size , yyscan_t yyscanner );
void yy_delete_buffer ( YY_BUFFER_STATE b , yyscan_t yyscanner );
void yy_flush_buffer ( YY_BUFFER_STATE b , yyscan_t yyscanner );
void yypush_buffer_state ( YY_BUFFER_STATE new_buffer , yyscan_t yyscanner );
void yypop_buffer_state ( yyscan_t yyscanner );
YY_BUFFER_STATE yy_scan_buffer ( char *base, yy_size_t size , yyscan_t yyscanner );
YY_BUFFER_STATE yy_scan_string ( const char *yy_str , yyscan_t yyscanner );
YY_BUFFER_STATE yy_scan_bytes ( const char *bytes, int len , yyscan_t yyscanner );
void *yyalloc ( yy_size_t , yyscan_t yyscanner );
void *yyrealloc ( void *, yy_size_t , yyscan_t yyscanner );
void yyfree ( void * , yyscan_t yyscanner );
/* Begin user sect3 */
#define iw8_wrap(yyscanner) (/*CONSTCOND*/1)
#define YY_SKIP_YYWRAP
#define yytext_ptr yytext_r
#ifdef YY_HEADER_EXPORT_START_CONDITIONS
#define INITIAL 0
#define COMMENT_BLOCK_STATE 1
#define DEVELOPER_BLOCK_STATE 2
#endif
#ifndef YY_NO_UNISTD_H
/* Special case for "unistd.h", since it is non-ANSI. We include it way
* down here because we want the user's section 1 to have been scanned first.
* The user has a chance to override it with an option.
*/
#include <unistd.h>
#endif
#ifndef YY_EXTRA_TYPE
#define YY_EXTRA_TYPE void *
#endif
int yylex_init (yyscan_t* scanner);
int yylex_init_extra ( YY_EXTRA_TYPE user_defined, yyscan_t* scanner);
/* Accessor methods to globals.
These are made visible to non-reentrant scanners for convenience. */
int yylex_destroy ( yyscan_t yyscanner );
int yyget_debug ( yyscan_t yyscanner );
void yyset_debug ( int debug_flag , yyscan_t yyscanner );
YY_EXTRA_TYPE yyget_extra ( yyscan_t yyscanner );
void yyset_extra ( YY_EXTRA_TYPE user_defined , yyscan_t yyscanner );
FILE *yyget_in ( yyscan_t yyscanner );
void yyset_in ( FILE * _in_str , yyscan_t yyscanner );
FILE *yyget_out ( yyscan_t yyscanner );
void yyset_out ( FILE * _out_str , yyscan_t yyscanner );
int yyget_leng ( yyscan_t yyscanner );
char *yyget_text ( yyscan_t yyscanner );
int yyget_lineno ( yyscan_t yyscanner );
void yyset_lineno ( int _line_number , yyscan_t yyscanner );
int yyget_column ( yyscan_t yyscanner );
void yyset_column ( int _column_no , yyscan_t yyscanner );
/* Macros after this point can all be overridden by user definitions in
* section 1.
*/
#ifndef YY_SKIP_YYWRAP
#ifdef __cplusplus
extern "C" int yywrap ( yyscan_t yyscanner );
#else
extern int yywrap ( yyscan_t yyscanner );
#endif
#endif
#ifndef yytext_ptr
static void yy_flex_strncpy ( char *, const char *, int , yyscan_t yyscanner);
#endif
#ifdef YY_NEED_STRLEN
static int yy_flex_strlen ( const char * , yyscan_t yyscanner);
#endif
#ifndef YY_NO_INPUT
#endif
/* Amount of stuff to slurp up with each read. */
#ifndef YY_READ_BUF_SIZE
#ifdef __ia64__
/* On IA-64, the buffer size is 16k, not 8k */
#define YY_READ_BUF_SIZE 16384
#else
#define YY_READ_BUF_SIZE 8192
#endif /* __ia64__ */
#endif
/* Number of entries by which start-condition stack grows. */
#ifndef YY_START_STACK_INCR
#define YY_START_STACK_INCR 25
#endif
/* Default declaration of generated scanner - a define so the user can
* easily add parameters.
*/
#ifndef YY_DECL
#define YY_DECL_IS_OURS 1
extern int yylex (yyscan_t yyscanner);
#define YY_DECL int yylex (yyscan_t yyscanner)
#endif /* !YY_DECL */
/* yy_get_previous_state - get the state just before the EOB char was reached */
#undef YY_NEW_FILE
#undef YY_FLUSH_BUFFER
#undef yy_set_bol
#undef yy_new_buffer
#undef yy_set_interactive
#undef YY_DO_BEFORE_ACTION
#ifdef YY_DECL_IS_OURS
#undef YY_DECL_IS_OURS
#undef YY_DECL
#endif
#ifndef iw8__create_buffer_ALREADY_DEFINED
#undef yy_create_buffer
#endif
#ifndef iw8__delete_buffer_ALREADY_DEFINED
#undef yy_delete_buffer
#endif
#ifndef iw8__scan_buffer_ALREADY_DEFINED
#undef yy_scan_buffer
#endif
#ifndef iw8__scan_string_ALREADY_DEFINED
#undef yy_scan_string
#endif
#ifndef iw8__scan_bytes_ALREADY_DEFINED
#undef yy_scan_bytes
#endif
#ifndef iw8__init_buffer_ALREADY_DEFINED
#undef yy_init_buffer
#endif
#ifndef iw8__flush_buffer_ALREADY_DEFINED
#undef yy_flush_buffer
#endif
#ifndef iw8__load_buffer_state_ALREADY_DEFINED
#undef yy_load_buffer_state
#endif
#ifndef iw8__switch_to_buffer_ALREADY_DEFINED
#undef yy_switch_to_buffer
#endif
#ifndef iw8_push_buffer_state_ALREADY_DEFINED
#undef yypush_buffer_state
#endif
#ifndef iw8_pop_buffer_state_ALREADY_DEFINED
#undef yypop_buffer_state
#endif
#ifndef iw8_ensure_buffer_stack_ALREADY_DEFINED
#undef yyensure_buffer_stack
#endif
#ifndef iw8_lex_ALREADY_DEFINED
#undef yylex
#endif
#ifndef iw8_restart_ALREADY_DEFINED
#undef yyrestart
#endif
#ifndef iw8_lex_init_ALREADY_DEFINED
#undef yylex_init
#endif
#ifndef iw8_lex_init_extra_ALREADY_DEFINED
#undef yylex_init_extra
#endif
#ifndef iw8_lex_destroy_ALREADY_DEFINED
#undef yylex_destroy
#endif
#ifndef iw8_get_debug_ALREADY_DEFINED
#undef yyget_debug
#endif
#ifndef iw8_set_debug_ALREADY_DEFINED
#undef yyset_debug
#endif
#ifndef iw8_get_extra_ALREADY_DEFINED
#undef yyget_extra
#endif
#ifndef iw8_set_extra_ALREADY_DEFINED
#undef yyset_extra
#endif
#ifndef iw8_get_in_ALREADY_DEFINED
#undef yyget_in
#endif
#ifndef iw8_set_in_ALREADY_DEFINED
#undef yyset_in
#endif
#ifndef iw8_get_out_ALREADY_DEFINED
#undef yyget_out
#endif
#ifndef iw8_set_out_ALREADY_DEFINED
#undef yyset_out
#endif
#ifndef iw8_get_leng_ALREADY_DEFINED
#undef yyget_leng
#endif
#ifndef iw8_get_text_ALREADY_DEFINED
#undef yyget_text
#endif
#ifndef iw8_get_lineno_ALREADY_DEFINED
#undef yyget_lineno
#endif
#ifndef iw8_set_lineno_ALREADY_DEFINED
#undef yyset_lineno
#endif
#ifndef iw8_get_column_ALREADY_DEFINED
#undef yyget_column
#endif
#ifndef iw8_set_column_ALREADY_DEFINED
#undef yyset_column
#endif
#ifndef iw8_wrap_ALREADY_DEFINED
#undef yywrap
#endif
#ifndef iw8_get_lval_ALREADY_DEFINED
#undef yyget_lval
#endif
#ifndef iw8_set_lval_ALREADY_DEFINED
#undef yyset_lval
#endif
#ifndef iw8_get_lloc_ALREADY_DEFINED
#undef yyget_lloc
#endif
#ifndef iw8_set_lloc_ALREADY_DEFINED
#undef yyset_lloc
#endif
#ifndef iw8_alloc_ALREADY_DEFINED
#undef yyalloc
#endif
#ifndef iw8_realloc_ALREADY_DEFINED
#undef yyrealloc
#endif
#ifndef iw8_free_ALREADY_DEFINED
#undef yyfree
#endif
#ifndef iw8_text_ALREADY_DEFINED
#undef yytext
#endif
#ifndef iw8_leng_ALREADY_DEFINED
#undef yyleng
#endif
#ifndef iw8_in_ALREADY_DEFINED
#undef yyin
#endif
#ifndef iw8_out_ALREADY_DEFINED
#undef yyout
#endif
#ifndef iw8__flex_debug_ALREADY_DEFINED
#undef yy_flex_debug
#endif
#ifndef iw8_lineno_ALREADY_DEFINED
#undef yylineno
#endif
#ifndef iw8_tables_fload_ALREADY_DEFINED
#undef yytables_fload
#endif
#ifndef iw8_tables_destroy_ALREADY_DEFINED
#undef yytables_destroy
#endif
#ifndef iw8_TABLES_NAME_ALREADY_DEFINED
#undef yyTABLES_NAME
#endif
#line 155 "lexer.lpp"
#line 706 "lexer.hpp"
#undef iw8_IN_HEADER
#endif /* iw8_HEADER_H */

4116
src/iw8/xsk/parser.cpp Normal file

File diff suppressed because it is too large Load Diff

4918
src/iw8/xsk/parser.hpp Normal file

File diff suppressed because it is too large Load Diff

75544
src/iw8/xsk/resolver.cpp Normal file

File diff suppressed because it is too large Load Diff

33
src/iw8/xsk/resolver.hpp Normal file
View File

@ -0,0 +1,33 @@
// 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.
#pragma once
namespace xsk::gsc::iw8
{
class resolver
{
public:
static auto opcode_id(const std::string& name) -> std::uint8_t;
static auto opcode_name(std::uint8_t id) -> std::string;
static auto function_id(const std::string& name) -> std::uint16_t;
static auto function_name(std::uint16_t id) -> std::string;
static auto method_id(const std::string& name) -> std::uint16_t;
static auto method_name(std::uint16_t id) -> std::string;
static auto file_id(const std::string& name) -> std::uint32_t;
static auto file_name(std::uint32_t id) -> std::string;
static auto token_id(const std::string& name) -> std::uint32_t;
static auto token_name(std::uint32_t id) -> std::string;
static auto find_function(const std::string& name) -> bool;
static auto find_method(const std::string& name) -> bool;
};
} // namespace xsk::gsc::iw8

View File

@ -8,6 +8,7 @@
#include "iw5/xsk/iw5.hpp"
#include "iw6/xsk/iw6.hpp"
#include "iw7/xsk/iw7.hpp"
#include "iw8/xsk/iw8.hpp"
#include "s1/xsk/s1.hpp"
#include "s2/xsk/s2.hpp"
#include "h1/xsk/h1.hpp"
@ -17,7 +18,7 @@ namespace xsk::gsc
{
enum class mode { __, ASM, DISASM, COMP, DECOMP };
enum class game { __, IW5, IW6, IW7, S1, S2, H1, H2 };
enum class game { __, IW5, IW6, IW7, IW8, S1, S2, H1, H2 };
std::map<std::string, mode> modes =
{
@ -32,6 +33,7 @@ std::map<std::string, game> games =
{ "-iw5", game::IW5 },
{ "-iw6", game::IW6 },
{ "-iw7", game::IW7 },
{ "-iw8", game::IW8 },
{ "-s1", game::S1 },
{ "-s2", game::S2 },
{ "-h1", game::H1 },
@ -71,6 +73,7 @@ auto choose_resolver_file_name(uint32_t id, game& game) -> std::string
case game::IW5: return iw5::resolver::file_name(static_cast<std::uint16_t>(id));
case game::IW6: return iw6::resolver::file_name(static_cast<std::uint16_t>(id));
case game::IW7: return iw7::resolver::file_name(id);
case game::IW8: return iw8::resolver::file_name(id);
case game::S1: return s1::resolver::file_name(static_cast<std::uint16_t>(id));
case game::S2: return s2::resolver::file_name(static_cast<std::uint16_t>(id));
case game::H1: return h1::resolver::file_name(static_cast<std::uint16_t>(id));
@ -417,6 +420,11 @@ std::uint32_t main(std::uint32_t argc, char** argv)
iw7::assembler assembler;
assemble_file(assembler, file, zonetool);
}
else if (game == game::IW8)
{
iw8::assembler assembler;
assemble_file(assembler, file, zonetool);
}
else if (game == game::S1)
{
s1::assembler assembler;
@ -455,6 +463,11 @@ std::uint32_t main(std::uint32_t argc, char** argv)
iw7::disassembler disassembler;
disassemble_file(disassembler, file, game, zonetool);
}
else if (game == game::IW8)
{
iw8::disassembler disassembler;
disassemble_file(disassembler, file, game, zonetool);
}
else if (game == game::S1)
{
s1::disassembler disassembler;
@ -496,6 +509,12 @@ std::uint32_t main(std::uint32_t argc, char** argv)
iw7::compiler compiler;
compile_file(assembler, compiler, file ,zonetool);
}
else if (game == game::IW8)
{
iw8::assembler assembler;
iw8::compiler compiler;
compile_file(assembler, compiler, file ,zonetool);
}
else if (game == game::S1)
{
s1::assembler assembler;
@ -541,6 +560,12 @@ std::uint32_t main(std::uint32_t argc, char** argv)
iw7::decompiler decompiler;
decompile_file(disassembler, decompiler, file, game, zonetool);
}
else if (game == game::IW8)
{
iw8::disassembler disassembler;
iw8::decompiler decompiler;
decompile_file(disassembler, decompiler, file, game, zonetool);
}
else if (game == game::S1)
{
s1::disassembler disassembler;