context wrapper & t6 bug fixing
This commit is contained in:
parent
6980506e88
commit
9b7eb28b84
@ -185,6 +185,7 @@ void assembler::assemble_function(const function::ptr& func)
|
||||
{
|
||||
func->index = script_->pos();
|
||||
func->size = 0;
|
||||
labels_.clear();
|
||||
|
||||
for (const auto& inst : func->instructions)
|
||||
{
|
||||
@ -197,7 +198,7 @@ void assembler::assemble_function(const function::ptr& func)
|
||||
|
||||
const auto& itr = func->labels.find(old_idx);
|
||||
|
||||
if (itr != labels_.end())
|
||||
if (itr != func->labels.end())
|
||||
{
|
||||
labels_.insert({ inst->index, itr->second });
|
||||
}
|
||||
@ -235,9 +236,7 @@ void assembler::assemble_instruction(const instruction::ptr& inst)
|
||||
case opcode::OP_GetAnim:
|
||||
case opcode::OP_GetGameRef:
|
||||
case opcode::OP_CreateLocalVariable:
|
||||
case opcode::OP_RemoveLocalVariables:
|
||||
case opcode::OP_EvalArray:
|
||||
case opcode::OP_EvalLocalArrayRefCached:
|
||||
case opcode::OP_EvalArrayRef:
|
||||
case opcode::OP_ClearArray:
|
||||
case opcode::OP_EmptyArray:
|
||||
@ -364,7 +363,9 @@ void assembler::assemble_instruction(const instruction::ptr& inst)
|
||||
case opcode::OP_SafeCreateLocalVariables:
|
||||
assemble_localvars(inst);
|
||||
break;
|
||||
case opcode::OP_RemoveLocalVariables:
|
||||
case opcode::OP_EvalLocalVariableCached:
|
||||
case opcode::OP_EvalLocalArrayRefCached:
|
||||
case opcode::OP_SafeSetWaittillVariableFieldCached:
|
||||
case opcode::OP_EvalLocalVariableRefCached:
|
||||
script_->write<std::uint8_t>(static_cast<std::uint8_t>(inst->opcode));
|
||||
@ -523,9 +524,7 @@ void assembler::align_instruction(const instruction::ptr& inst)
|
||||
case opcode::OP_GetAnim:
|
||||
case opcode::OP_GetGameRef:
|
||||
case opcode::OP_CreateLocalVariable:
|
||||
case opcode::OP_RemoveLocalVariables:
|
||||
case opcode::OP_EvalArray:
|
||||
case opcode::OP_EvalLocalArrayRefCached:
|
||||
case opcode::OP_EvalArrayRef:
|
||||
case opcode::OP_ClearArray:
|
||||
case opcode::OP_EmptyArray:
|
||||
@ -649,7 +648,9 @@ void assembler::align_instruction(const instruction::ptr& inst)
|
||||
}
|
||||
}
|
||||
break;
|
||||
case opcode::OP_RemoveLocalVariables:
|
||||
case opcode::OP_EvalLocalVariableCached:
|
||||
case opcode::OP_EvalLocalArrayRefCached:
|
||||
case opcode::OP_SafeSetWaittillVariableFieldCached:
|
||||
case opcode::OP_EvalLocalVariableRefCached:
|
||||
script_->seek(1);
|
||||
|
@ -40,23 +40,21 @@ void compiler::compile(const std::string& file, std::vector<std::uint8_t>& data)
|
||||
{
|
||||
filename_ = file;
|
||||
|
||||
auto prog = parse_buffer(filename_, data);
|
||||
auto prog = parse_buffer(filename_, reinterpret_cast<char*>(data.data()), data.size());
|
||||
|
||||
compile_program(prog);
|
||||
}
|
||||
|
||||
void compiler::read_callback(std::function<std::vector<std::uint8_t>(const std::string&)> func)
|
||||
void compiler::mode(build mode)
|
||||
{
|
||||
read_callback_ = func;
|
||||
mode_ = mode;
|
||||
}
|
||||
|
||||
auto compiler::parse_buffer(const std::string& file, std::vector<std::uint8_t>& data) -> ast::program::ptr
|
||||
auto compiler::parse_buffer(const std::string& file, char* data, size_t size) -> ast::program::ptr
|
||||
{
|
||||
ast::program::ptr result(nullptr);
|
||||
|
||||
resolver::set_reader(read_callback_);
|
||||
|
||||
lexer lexer(mode_, file, reinterpret_cast<char*>(data.data()), data.size());
|
||||
lexer lexer(mode_, file, data, size);
|
||||
|
||||
parser parser(lexer, result);
|
||||
|
||||
@ -70,8 +68,8 @@ auto compiler::parse_buffer(const std::string& file, std::vector<std::uint8_t>&
|
||||
|
||||
auto compiler::parse_file(const std::string& file) -> ast::program::ptr
|
||||
{
|
||||
auto buffer = read_callback_(file);
|
||||
auto result = parse_buffer(file, buffer);
|
||||
auto data = resolver::file_data(file);
|
||||
auto result = parse_buffer(file, std::get<1>(data), std::get<2>(data));
|
||||
|
||||
return result;
|
||||
}
|
||||
@ -113,7 +111,7 @@ void compiler::emit_include(const ast::include::ptr& include)
|
||||
{
|
||||
if (entry == path)
|
||||
{
|
||||
throw comp_error(include->loc(), "error duplicated include file '" + path + "'.");
|
||||
throw comp_error(include->loc(), "duplicated include file '" + path + "'.");
|
||||
}
|
||||
}
|
||||
|
||||
@ -213,18 +211,20 @@ void compiler::emit_decl_thread(const ast::decl_thread::ptr& thread)
|
||||
can_break_ = false;
|
||||
can_continue_ = false;
|
||||
local_stack_.clear();
|
||||
break_loc_ = "";
|
||||
continue_loc_ = "";
|
||||
abort_ = abort_t::abort_none;
|
||||
blocks_.clear();
|
||||
|
||||
process_thread(thread);
|
||||
|
||||
blocks_.push_back(block());
|
||||
|
||||
emit_expr_parameters(thread->params);
|
||||
emit_stmt_list(thread->stmt);
|
||||
|
||||
if (abort_ == abort_t::abort_none)
|
||||
if (blocks_.back().abort == abort_t::abort_none)
|
||||
emit_opcode(opcode::OP_End);
|
||||
|
||||
blocks_.pop_back();
|
||||
|
||||
function_->size = index_ - function_->index;
|
||||
assembly_->functions.push_back(std::move(function_));
|
||||
}
|
||||
@ -479,8 +479,13 @@ void compiler::emit_stmt_if(const ast::stmt_if::ptr& stmt)
|
||||
emit_opcode(opcode::OP_JumpOnFalse, end_loc);
|
||||
}
|
||||
|
||||
auto& paren = blocks_.back();
|
||||
blocks_.push_back(block(paren.loc_break, paren.loc_continue));
|
||||
|
||||
emit_stmt(stmt->stmt);
|
||||
|
||||
blocks_.pop_back();
|
||||
|
||||
insert_label(end_loc);
|
||||
}
|
||||
|
||||
@ -500,106 +505,102 @@ void compiler::emit_stmt_ifelse(const ast::stmt_ifelse::ptr& stmt)
|
||||
emit_opcode(opcode::OP_JumpOnFalse, else_loc);
|
||||
}
|
||||
|
||||
auto& paren = blocks_.back();
|
||||
blocks_.push_back(block(paren.loc_break, paren.loc_continue));
|
||||
emit_stmt(stmt->stmt_if);
|
||||
blocks_.pop_back();
|
||||
|
||||
emit_opcode(opcode::OP_Jump, end_loc);
|
||||
|
||||
insert_label(else_loc);
|
||||
|
||||
auto& root = blocks_.back();
|
||||
blocks_.push_back(block(root.loc_break, root.loc_continue));
|
||||
emit_stmt(stmt->stmt_else);
|
||||
blocks_.pop_back();
|
||||
|
||||
insert_label(end_loc);
|
||||
}
|
||||
|
||||
void compiler::emit_stmt_while(const ast::stmt_while::ptr& stmt)
|
||||
{
|
||||
auto old_abort = abort_;
|
||||
auto old_break_loc = break_loc_;
|
||||
auto old_continue_loc = continue_loc_;
|
||||
auto old_break = can_break_;
|
||||
auto old_continue = can_continue_;
|
||||
|
||||
can_break_ = true;
|
||||
can_continue_ = true;
|
||||
break_loc_ = create_label();
|
||||
continue_loc_ = insert_label();
|
||||
auto break_loc = create_label();
|
||||
auto continue_loc = insert_label();
|
||||
|
||||
auto begin_loc = continue_loc_;
|
||||
auto begin_loc = continue_loc;
|
||||
|
||||
if (stmt->test == ast::kind::expr_not)
|
||||
{
|
||||
emit_expr(stmt->test.as_not->rvalue);
|
||||
emit_opcode(opcode::OP_JumpOnTrue, break_loc_);
|
||||
emit_opcode(opcode::OP_JumpOnTrue, break_loc);
|
||||
}
|
||||
else
|
||||
{
|
||||
emit_expr(stmt->test);
|
||||
emit_opcode(opcode::OP_JumpOnFalse, break_loc_);
|
||||
emit_opcode(opcode::OP_JumpOnFalse, break_loc);
|
||||
}
|
||||
|
||||
blocks_.push_back(block(break_loc, continue_loc));
|
||||
emit_stmt(stmt->stmt);
|
||||
emit_opcode(opcode::OP_Jump, begin_loc);
|
||||
insert_label(break_loc_);
|
||||
blocks_.pop_back();
|
||||
|
||||
emit_opcode(opcode::OP_Jump, continue_loc);
|
||||
insert_label(break_loc);
|
||||
|
||||
can_break_ = old_break;
|
||||
can_continue_ = old_continue;
|
||||
break_loc_ = old_break_loc;
|
||||
continue_loc_ = old_continue_loc;
|
||||
abort_ = old_abort;
|
||||
}
|
||||
|
||||
void compiler::emit_stmt_dowhile(const ast::stmt_dowhile::ptr& stmt)
|
||||
{
|
||||
auto old_abort = abort_;
|
||||
auto old_break_loc = break_loc_;
|
||||
auto old_continue_loc = continue_loc_;
|
||||
auto old_break = can_break_;
|
||||
auto old_continue = can_continue_;
|
||||
|
||||
can_break_ = true;
|
||||
can_continue_ = true;
|
||||
break_loc_ = create_label();
|
||||
continue_loc_ = create_label();
|
||||
auto break_loc = create_label();
|
||||
auto continue_loc = create_label();
|
||||
|
||||
auto begin_loc = insert_label();
|
||||
|
||||
blocks_.push_back(block(break_loc, continue_loc));
|
||||
emit_stmt(stmt->stmt);
|
||||
blocks_.pop_back();
|
||||
|
||||
insert_label(continue_loc_);
|
||||
insert_label(continue_loc);
|
||||
|
||||
if (stmt->test == ast::kind::expr_not)
|
||||
{
|
||||
emit_expr(stmt->test.as_not->rvalue);
|
||||
emit_opcode(opcode::OP_JumpOnTrue, break_loc_);
|
||||
emit_opcode(opcode::OP_JumpOnTrue, break_loc);
|
||||
}
|
||||
else
|
||||
{
|
||||
emit_expr(stmt->test);
|
||||
emit_opcode(opcode::OP_JumpOnFalse, break_loc_);
|
||||
emit_opcode(opcode::OP_JumpOnFalse, break_loc);
|
||||
}
|
||||
|
||||
emit_opcode(opcode::OP_Jump, begin_loc);
|
||||
insert_label(break_loc_);
|
||||
insert_label(break_loc);
|
||||
|
||||
can_break_ = old_break;
|
||||
can_continue_ = old_continue;
|
||||
break_loc_ = old_break_loc;
|
||||
continue_loc_ = old_continue_loc;
|
||||
abort_ = old_abort;
|
||||
}
|
||||
|
||||
void compiler::emit_stmt_for(const ast::stmt_for::ptr& stmt)
|
||||
{
|
||||
auto old_abort = abort_;
|
||||
auto old_break_loc = break_loc_;
|
||||
auto old_continue_loc = continue_loc_;
|
||||
auto old_break = can_break_;
|
||||
auto old_continue = can_continue_;
|
||||
|
||||
emit_stmt(stmt->init);
|
||||
|
||||
break_loc_ = create_label();
|
||||
continue_loc_ = create_label();
|
||||
auto break_loc = create_label();
|
||||
auto continue_loc = create_label();
|
||||
|
||||
auto begin_loc = insert_label();
|
||||
|
||||
@ -608,34 +609,30 @@ void compiler::emit_stmt_for(const ast::stmt_for::ptr& stmt)
|
||||
if (!const_cond)
|
||||
{
|
||||
emit_expr(stmt->test);
|
||||
emit_opcode(opcode::OP_JumpOnFalse, break_loc_);
|
||||
emit_opcode(opcode::OP_JumpOnFalse, break_loc);
|
||||
}
|
||||
|
||||
can_break_ = true;
|
||||
can_continue_ = true;
|
||||
|
||||
blocks_.push_back(block(break_loc, continue_loc));
|
||||
emit_stmt(stmt->stmt);
|
||||
blocks_.pop_back();
|
||||
|
||||
can_break_ = false;
|
||||
can_continue_ = false;
|
||||
|
||||
insert_label(continue_loc_);
|
||||
insert_label(continue_loc);
|
||||
emit_stmt(stmt->iter);
|
||||
emit_opcode(opcode::OP_Jump, begin_loc);
|
||||
insert_label(break_loc_);
|
||||
insert_label(break_loc);
|
||||
|
||||
can_break_ = old_break;
|
||||
can_continue_ = old_continue;
|
||||
break_loc_ = old_break_loc;
|
||||
continue_loc_ = old_continue_loc;
|
||||
abort_ = old_abort;
|
||||
}
|
||||
|
||||
void compiler::emit_stmt_foreach(const ast::stmt_foreach::ptr& stmt)
|
||||
{
|
||||
auto old_abort = abort_;
|
||||
auto old_break_loc = break_loc_;
|
||||
auto old_continue_loc = continue_loc_;
|
||||
auto old_break = can_break_;
|
||||
auto old_continue = can_continue_;
|
||||
|
||||
@ -645,14 +642,14 @@ void compiler::emit_stmt_foreach(const ast::stmt_foreach::ptr& stmt)
|
||||
emit_opcode(opcode::OP_FirstArrayKey);
|
||||
emit_expr_variable_ref(stmt->key_expr, true);
|
||||
|
||||
break_loc_ = create_label();
|
||||
continue_loc_ = create_label();
|
||||
auto break_loc = create_label();
|
||||
auto continue_loc = create_label();
|
||||
|
||||
auto begin_loc = insert_label();
|
||||
|
||||
emit_expr_variable(stmt->key_expr);
|
||||
emit_opcode(opcode::OP_IsDefined);
|
||||
emit_opcode(opcode::OP_JumpOnFalse, break_loc_);
|
||||
emit_opcode(opcode::OP_JumpOnFalse, break_loc);
|
||||
|
||||
can_break_ = true;
|
||||
can_continue_ = true;
|
||||
@ -661,44 +658,44 @@ void compiler::emit_stmt_foreach(const ast::stmt_foreach::ptr& stmt)
|
||||
emit_opcode(opcode::OP_EvalLocalVariableCached, variable_access(stmt->array.as_identifier));
|
||||
emit_opcode(opcode::OP_EvalArray);
|
||||
emit_expr_variable_ref(stmt->value_expr, true);
|
||||
|
||||
blocks_.push_back(block(break_loc, continue_loc));
|
||||
emit_stmt(stmt->stmt);
|
||||
blocks_.pop_back();
|
||||
|
||||
can_break_ = false;
|
||||
can_continue_ = false;
|
||||
|
||||
insert_label(continue_loc_);
|
||||
insert_label(continue_loc);
|
||||
|
||||
emit_expr_variable(stmt->key_expr);
|
||||
emit_expr_variable(stmt->array);
|
||||
emit_opcode(opcode::OP_NextArrayKey);
|
||||
emit_expr_variable_ref(stmt->key_expr, true);
|
||||
emit_opcode(opcode::OP_Jump, begin_loc);
|
||||
insert_label(break_loc_);
|
||||
insert_label(break_loc);
|
||||
|
||||
can_break_ = old_break;
|
||||
can_continue_ = old_continue;
|
||||
break_loc_ = old_break_loc;
|
||||
continue_loc_ = old_continue_loc;
|
||||
abort_ = old_abort;
|
||||
}
|
||||
|
||||
void compiler::emit_stmt_switch(const ast::stmt_switch::ptr& stmt)
|
||||
{
|
||||
auto old_abort = abort_;
|
||||
auto old_break_loc = break_loc_;
|
||||
auto old_break = can_break_;
|
||||
|
||||
can_break_ = false;
|
||||
|
||||
auto jmptable_loc = create_label();
|
||||
|
||||
break_loc_ = create_label();
|
||||
auto break_loc = create_label();
|
||||
|
||||
emit_expr(stmt->test);
|
||||
emit_opcode(opcode::OP_Switch, jmptable_loc);
|
||||
|
||||
can_break_ = true;
|
||||
|
||||
blocks_.push_back(block(break_loc, blocks_.back().loc_continue));
|
||||
|
||||
std::vector<std::string> data;
|
||||
data.push_back(utils::string::va("%d", stmt->stmt->list.size()));
|
||||
|
||||
@ -735,7 +732,10 @@ void compiler::emit_stmt_switch(const ast::stmt_switch::ptr& stmt)
|
||||
throw comp_error(stmt->loc(), "case type must be int or string");
|
||||
}
|
||||
|
||||
auto& paren = blocks_.back();
|
||||
blocks_.push_back(block(paren.loc_break, paren.loc_continue));
|
||||
emit_stmt_list(case_->stmt);
|
||||
blocks_.pop_back();
|
||||
}
|
||||
else if (entry == ast::kind::stmt_default)
|
||||
{
|
||||
@ -743,7 +743,11 @@ void compiler::emit_stmt_switch(const ast::stmt_switch::ptr& stmt)
|
||||
data.push_back("default");
|
||||
data.push_back(loc);
|
||||
has_default = true;
|
||||
|
||||
auto& paren = blocks_.back();
|
||||
blocks_.push_back(block(paren.loc_break, paren.loc_continue));
|
||||
emit_stmt_list(entry.as_default->stmt);
|
||||
blocks_.pop_back();
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -751,13 +755,13 @@ void compiler::emit_stmt_switch(const ast::stmt_switch::ptr& stmt)
|
||||
}
|
||||
}
|
||||
|
||||
blocks_.pop_back();
|
||||
|
||||
insert_label(jmptable_loc);
|
||||
emit_opcode(opcode::OP_EndSwitch, data);
|
||||
insert_label(break_loc_);
|
||||
insert_label(break_loc);
|
||||
|
||||
can_break_ = old_break;
|
||||
break_loc_ = old_break_loc;
|
||||
abort_ = old_abort;
|
||||
}
|
||||
|
||||
void compiler::emit_stmt_case(const ast::stmt_case::ptr& stmt)
|
||||
@ -772,26 +776,26 @@ void compiler::emit_stmt_default(const ast::stmt_default::ptr& stmt)
|
||||
|
||||
void compiler::emit_stmt_break(const ast::stmt_break::ptr& stmt)
|
||||
{
|
||||
if (!can_break_ || abort_ != abort_t::abort_none || break_loc_ == "")
|
||||
if (!can_break_ || blocks_.back().abort != abort_t::abort_none || blocks_.back().loc_break == "")
|
||||
throw comp_error(stmt->loc(), "illegal break statement");
|
||||
|
||||
abort_ = abort_t::abort_break;
|
||||
emit_opcode(opcode::OP_Jump, break_loc_);
|
||||
blocks_.back().abort = abort_t::abort_break;
|
||||
emit_opcode(opcode::OP_Jump, blocks_.back().loc_break);
|
||||
}
|
||||
|
||||
void compiler::emit_stmt_continue(const ast::stmt_continue::ptr& stmt)
|
||||
{
|
||||
if (!can_continue_ || abort_ != abort_t::abort_none || continue_loc_ == "")
|
||||
if (!can_continue_ || blocks_.back().abort != abort_t::abort_none || blocks_.back().loc_continue == "")
|
||||
throw comp_error(stmt->loc(), "illegal continue statement");
|
||||
|
||||
abort_ = abort_t::abort_continue;
|
||||
emit_opcode(opcode::OP_Jump, continue_loc_);
|
||||
blocks_.back().abort = abort_t::abort_continue;
|
||||
emit_opcode(opcode::OP_Jump, blocks_.back().loc_continue);
|
||||
}
|
||||
|
||||
void compiler::emit_stmt_return(const ast::stmt_return::ptr& stmt)
|
||||
{
|
||||
if (abort_ == abort_t::abort_none)
|
||||
abort_ = abort_t::abort_return;
|
||||
if (blocks_.back().abort == abort_t::abort_none)
|
||||
blocks_.back().abort = abort_t::abort_return;
|
||||
|
||||
if (stmt->expr != ast::kind::null)
|
||||
{
|
||||
@ -1222,6 +1226,7 @@ void compiler::emit_expr_call(const ast::expr_call::ptr& expr)
|
||||
|
||||
void compiler::emit_expr_call_pointer(const ast::expr_pointer::ptr& expr)
|
||||
{
|
||||
emit_opcode(opcode::OP_PreScriptCall);
|
||||
emit_expr_arguments(expr->args);
|
||||
emit_expr(expr->func);
|
||||
|
||||
@ -1296,6 +1301,7 @@ void compiler::emit_expr_method(const ast::expr_method::ptr& expr)
|
||||
|
||||
void compiler::emit_expr_method_pointer(const ast::expr_pointer::ptr& expr, const ast::expr& obj)
|
||||
{
|
||||
emit_opcode(opcode::OP_PreScriptCall);
|
||||
emit_expr_arguments(expr->args);
|
||||
emit_expr(obj);
|
||||
emit_expr(expr->func);
|
||||
@ -1571,14 +1577,11 @@ void compiler::emit_expr_array_ref(const ast::expr_array::ptr& expr, bool set)
|
||||
break;
|
||||
case ast::kind::expr_array:
|
||||
case ast::kind::expr_field:
|
||||
case ast::kind::expr_identifier:
|
||||
emit_expr_variable_ref(expr->obj, false);
|
||||
emit_opcode(opcode::OP_EvalArrayRef);
|
||||
if (set) emit_opcode(opcode::OP_SetVariableField);
|
||||
break;
|
||||
case ast::kind::expr_identifier:
|
||||
emit_opcode(opcode::OP_EvalLocalArrayRefCached, variable_access(expr->obj.as_identifier));
|
||||
if (set) emit_opcode(opcode::OP_SetVariableField);
|
||||
break;
|
||||
case ast::kind::expr_call:
|
||||
case ast::kind::expr_method:
|
||||
default:
|
||||
|
@ -12,7 +12,6 @@ enum class opcode : std::uint8_t;
|
||||
|
||||
class compiler : public arc::compiler
|
||||
{
|
||||
build mode_;
|
||||
std::string filename_;
|
||||
assembly::ptr assembly_;
|
||||
function::ptr function_;
|
||||
@ -24,23 +23,20 @@ class compiler : public arc::compiler
|
||||
std::vector<include_t> includes_;
|
||||
std::vector<animtree_t> animtrees_;
|
||||
std::unordered_map<std::string, ast::expr> constants_;
|
||||
std::function<std::vector<std::uint8_t>(const std::string&)> read_callback_;
|
||||
abort_t abort_;
|
||||
std::string break_loc_;
|
||||
std::string continue_loc_;
|
||||
std::vector<block> blocks_;
|
||||
bool can_break_;
|
||||
bool can_continue_;
|
||||
bool developer_thread_;
|
||||
build mode_;
|
||||
|
||||
public:
|
||||
compiler(build mode) : mode_(mode) {}
|
||||
auto output() -> assembly::ptr;
|
||||
auto output_data() -> std::vector<std::uint8_t>;
|
||||
void compile(const std::string& file, std::vector<std::uint8_t>& data);
|
||||
void read_callback(std::function<std::vector<std::uint8_t>(const std::string&)> func);
|
||||
void mode(build mode);
|
||||
|
||||
private:
|
||||
auto parse_buffer(const std::string& file, std::vector<std::uint8_t>& data) -> ast::program::ptr;
|
||||
auto parse_buffer(const std::string& file, char* data, size_t size) -> ast::program::ptr;
|
||||
auto parse_file(const std::string& file) -> ast::program::ptr;
|
||||
void compile_program(const ast::program::ptr& program);
|
||||
void emit_include(const ast::include::ptr& include);
|
||||
@ -163,7 +159,6 @@ private:
|
||||
|
||||
auto map_known_includes(const std::string& include) -> bool;
|
||||
|
||||
|
||||
utils::byte_buffer::ptr output_;
|
||||
void print_function(const function::ptr& func);
|
||||
void print_instruction(const instruction::ptr& inst);
|
||||
|
23
src/t6/xsk/context.cpp
Normal file
23
src/t6/xsk/context.cpp
Normal file
@ -0,0 +1,23 @@
|
||||
// Copyright 2022 xensik. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a GNU GPLv3 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
#include "stdafx.hpp"
|
||||
#include "t6.hpp"
|
||||
|
||||
namespace xsk::arc::t6
|
||||
{
|
||||
|
||||
void context::init(build mode, read_cb_type callback)
|
||||
{
|
||||
compiler_.mode(mode);
|
||||
resolver::init(callback);
|
||||
}
|
||||
|
||||
void context::cleanup()
|
||||
{
|
||||
resolver::cleanup();
|
||||
}
|
||||
|
||||
} // namespace xsk::arc::t6
|
28
src/t6/xsk/context.hpp
Normal file
28
src/t6/xsk/context.hpp
Normal file
@ -0,0 +1,28 @@
|
||||
// Copyright 2022 xensik. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a GNU GPLv3 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace xsk::arc::t6
|
||||
{
|
||||
|
||||
class context : public arc::context
|
||||
{
|
||||
t6::assembler assembler_;
|
||||
t6::disassembler disassembler_;
|
||||
t6::compiler compiler_;
|
||||
t6::decompiler decompiler_;
|
||||
|
||||
public:
|
||||
void init(build mode, read_cb_type callback);
|
||||
void cleanup();
|
||||
|
||||
auto assembler() -> arc::assembler& { return assembler_; }
|
||||
auto disassembler() -> arc::disassembler& { return disassembler_; }
|
||||
auto compiler() -> arc::compiler& { return compiler_; }
|
||||
auto decompiler() -> arc::decompiler& { return decompiler_; }
|
||||
};
|
||||
|
||||
} // namespace xsk::arc::t6
|
@ -248,6 +248,8 @@ void disassembler::disassemble_function(const function::ptr& func)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void disassembler::disassemble_instruction(const instruction::ptr& inst)
|
||||
{
|
||||
switch (opcode(inst->opcode))
|
||||
@ -264,9 +266,7 @@ void disassembler::disassemble_instruction(const instruction::ptr& inst)
|
||||
case opcode::OP_GetAnim:
|
||||
case opcode::OP_GetGameRef:
|
||||
case opcode::OP_CreateLocalVariable:
|
||||
case opcode::OP_RemoveLocalVariables:
|
||||
case opcode::OP_EvalArray:
|
||||
case opcode::OP_EvalLocalArrayRefCached:
|
||||
case opcode::OP_EvalArrayRef:
|
||||
case opcode::OP_ClearArray:
|
||||
case opcode::OP_EmptyArray:
|
||||
@ -351,17 +351,14 @@ void disassembler::disassemble_instruction(const instruction::ptr& inst)
|
||||
inst->data.push_back(utils::string::va("%i", script_->read<std::int32_t>()));
|
||||
break;
|
||||
case opcode::OP_GetFloat:
|
||||
{
|
||||
inst->size += script_->align(4);
|
||||
auto val = script_->read<float>();
|
||||
inst->data.push_back(utils::string::va("%g%s", val, val == int(val) ? ".0" : ""));
|
||||
}
|
||||
inst->data.push_back(utils::string::float_string(script_->read<float>()));
|
||||
break;
|
||||
case opcode::OP_GetVector:
|
||||
inst->size += script_->align(4);
|
||||
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>()));
|
||||
inst->data.push_back(utils::string::float_string(script_->read<float>()));
|
||||
inst->data.push_back(utils::string::float_string(script_->read<float>()));
|
||||
inst->data.push_back(utils::string::float_string(script_->read<float>()));
|
||||
break;
|
||||
case opcode::OP_GetString:
|
||||
case opcode::OP_GetIString:
|
||||
@ -383,7 +380,9 @@ void disassembler::disassemble_instruction(const instruction::ptr& inst)
|
||||
case opcode::OP_SafeCreateLocalVariables:
|
||||
disassemble_localvars(inst);
|
||||
break;
|
||||
case opcode::OP_RemoveLocalVariables:
|
||||
case opcode::OP_EvalLocalVariableCached:
|
||||
case opcode::OP_EvalLocalArrayRefCached:
|
||||
case opcode::OP_SafeSetWaittillVariableFieldCached:
|
||||
case opcode::OP_EvalLocalVariableRefCached:
|
||||
inst->data.push_back(utils::string::va("%i", script_->read<std::uint8_t>()));
|
||||
|
@ -12,6 +12,18 @@ namespace xsk::arc::t6
|
||||
std::unordered_map<std::uint8_t, std::string_view> opcode_map;
|
||||
std::unordered_map<std::string_view, std::uint8_t> opcode_map_rev;
|
||||
std::unordered_map<std::uint32_t, std::string_view> dvar_map;
|
||||
std::unordered_map<std::string, std::vector<std::uint8_t>> files;
|
||||
std::function<std::vector<std::uint8_t>(const std::string&)> read_callback = nullptr;
|
||||
|
||||
void resolver::init(read_cb_type callback)
|
||||
{
|
||||
read_callback = callback;
|
||||
}
|
||||
|
||||
void resolver::cleanup()
|
||||
{
|
||||
files.clear();
|
||||
}
|
||||
|
||||
auto resolver::opcode_id(const std::string& name) -> std::uint8_t
|
||||
{
|
||||
@ -22,7 +34,7 @@ auto resolver::opcode_id(const std::string& name) -> std::uint8_t
|
||||
return itr->second;
|
||||
}
|
||||
|
||||
throw gsc::error(utils::string::va("Couldn't resolve opcode id for name '%s'!", name.data()));
|
||||
throw error(utils::string::va("Couldn't resolve opcode id for name '%s'!", name.data()));
|
||||
}
|
||||
|
||||
auto resolver::opcode_name(std::uint8_t id) -> std::string
|
||||
@ -34,7 +46,7 @@ auto resolver::opcode_name(std::uint8_t id) -> std::string
|
||||
return std::string(itr->second);
|
||||
}
|
||||
|
||||
throw gsc::error(utils::string::va("Couldn't resolve opcode name for id '0x%hhX'!", id));
|
||||
throw error(utils::string::va("Couldn't resolve opcode name for id '0x%hhX'!", id));
|
||||
}
|
||||
|
||||
auto resolver::dvar_name(std::uint32_t id) -> std::string
|
||||
@ -67,9 +79,6 @@ auto resolver::make_token(std::string_view str) -> std::string
|
||||
return data;
|
||||
}
|
||||
|
||||
std::function<std::vector<std::uint8_t>(const std::string&)> read_callback = nullptr;
|
||||
std::unordered_map<std::string, std::vector<std::uint8_t>> files;
|
||||
|
||||
auto resolver::file_data(const std::string& name) -> std::tuple<const std::string*, char*, size_t>
|
||||
{
|
||||
const auto& itr = files.find(name);
|
||||
@ -91,11 +100,6 @@ auto resolver::file_data(const std::string& name) -> std::tuple<const std::strin
|
||||
throw error("couldn't open gsc file '" + name + "'");
|
||||
}
|
||||
|
||||
void resolver::set_reader(std::function<std::vector<std::uint8_t>(const std::string&)> callback)
|
||||
{
|
||||
read_callback = callback;
|
||||
}
|
||||
|
||||
std::set<std::string> paths
|
||||
{
|
||||
"aitype",
|
||||
|
@ -11,6 +11,8 @@ namespace xsk::arc::t6
|
||||
class resolver
|
||||
{
|
||||
public:
|
||||
static void init(read_cb_type callback);
|
||||
static void cleanup();
|
||||
static auto opcode_id(const std::string& name) -> std::uint8_t;
|
||||
static auto opcode_name(std::uint8_t id) -> std::string;
|
||||
static auto dvar_name(std::uint32_t id) -> std::string;
|
||||
|
@ -25,9 +25,7 @@ auto opcode_size(std::uint8_t id) -> std::uint32_t
|
||||
case opcode::OP_GetAnim:
|
||||
case opcode::OP_GetGameRef:
|
||||
case opcode::OP_CreateLocalVariable:
|
||||
case opcode::OP_RemoveLocalVariables:
|
||||
case opcode::OP_EvalArray:
|
||||
case opcode::OP_EvalLocalArrayRefCached:
|
||||
case opcode::OP_EvalArrayRef:
|
||||
case opcode::OP_ClearArray:
|
||||
case opcode::OP_EmptyArray:
|
||||
@ -102,7 +100,9 @@ auto opcode_size(std::uint8_t id) -> std::uint32_t
|
||||
case opcode::OP_GetByte:
|
||||
case opcode::OP_GetNegByte:
|
||||
case opcode::OP_SafeCreateLocalVariables:
|
||||
case opcode::OP_RemoveLocalVariables:
|
||||
case opcode::OP_EvalLocalVariableCached:
|
||||
case opcode::OP_EvalLocalArrayRefCached:
|
||||
case opcode::OP_SafeSetWaittillVariableFieldCached:
|
||||
case opcode::OP_EvalLocalVariableRefCached:
|
||||
case opcode::OP_ScriptFunctionCallPointer:
|
||||
|
@ -9,9 +9,10 @@
|
||||
|
||||
#include "assembler.hpp"
|
||||
#include "disassembler.hpp"
|
||||
#include "decompiler.hpp"
|
||||
#include "compiler.hpp"
|
||||
#include "decompiler.hpp"
|
||||
#include "resolver.hpp"
|
||||
#include "context.hpp"
|
||||
|
||||
namespace xsk::arc::t6
|
||||
{
|
||||
|
@ -452,25 +452,22 @@ void init()
|
||||
namespace arc
|
||||
{
|
||||
|
||||
std::map<game, assembler::ptr> assemblers;
|
||||
std::map<game, disassembler::ptr> disassemblers;
|
||||
std::map<game, compiler::ptr> compilers;
|
||||
std::map<game, decompiler::ptr> decompilers;
|
||||
std::map<game, context::ptr> contexts;
|
||||
std::map<mode, std::function<void(game game, const std::filesystem::path& file)>> funcs;
|
||||
|
||||
void assemble_file(game game, const std::filesystem::path& file)
|
||||
{
|
||||
try
|
||||
{
|
||||
const auto& assembler = assemblers[game];
|
||||
auto& assembler = contexts[game]->assembler();
|
||||
|
||||
auto data = utils::file::read(file.string());
|
||||
auto path = t6::resolver::fs_to_game_path(file);
|
||||
auto next = path.extension() == ".gscasm" ? path.replace_extension(".gsc") : path.replace_extension(".csc");
|
||||
|
||||
assembler->assemble(next.string(), data);
|
||||
assembler.assemble(next.string(), data);
|
||||
|
||||
utils::file::save((std::filesystem::path("assembled/t6") / next).string(), assembler->output());
|
||||
utils::file::save((std::filesystem::path("assembled/t6") / next).string(), assembler.output());
|
||||
std::cout << "assembled " << path.replace_extension() << "\n";
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
@ -483,15 +480,15 @@ void disassemble_file(game game, const std::filesystem::path& file)
|
||||
{
|
||||
try
|
||||
{
|
||||
const auto& disassembler = disassemblers[game];
|
||||
auto& disassembler = contexts[game]->disassembler();
|
||||
|
||||
auto data = utils::file::read(file.string());
|
||||
auto path = t6::resolver::fs_to_game_path(file);
|
||||
auto next = path.extension() == ".gsc" ? path.replace_extension(".gscasm") : path.replace_extension(".cscasm");
|
||||
|
||||
disassembler->disassemble(file.string(), data);
|
||||
disassembler.disassemble(file.string(), data);
|
||||
|
||||
utils::file::save((std::filesystem::path("disassembled/t6") / next).string(), disassembler->output_data());
|
||||
utils::file::save((std::filesystem::path("disassembled/t6") / next).string(), disassembler.output_data());
|
||||
std::cout << "disassembled " << path.replace_extension() << "\n";
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
@ -504,20 +501,19 @@ void compile_file(game game, const std::filesystem::path& file)
|
||||
{
|
||||
try
|
||||
{
|
||||
const auto& assembler = assemblers[game];
|
||||
const auto& compiler = compilers[game];
|
||||
auto& assembler = contexts[game]->assembler();
|
||||
auto& compiler = contexts[game]->compiler();
|
||||
|
||||
auto data = utils::file::read(file.string());
|
||||
auto path = t6::resolver::fs_to_game_path(file);
|
||||
|
||||
compiler->read_callback(utils::file::read);
|
||||
compiler->compile(file.string(), data);
|
||||
compiler.compile(file.string(), data);
|
||||
|
||||
auto assembly = compiler->output();
|
||||
auto assembly = compiler.output();
|
||||
|
||||
assembler->assemble(path.string(), assembly);
|
||||
assembler.assemble(path.string(), assembly);
|
||||
|
||||
utils::file::save((std::filesystem::path("compiled/t6") / path).string(), assembler->output());
|
||||
utils::file::save((std::filesystem::path("compiled/t6") / path).string(), assembler.output());
|
||||
std::cout << "compiled " << path.replace_extension() << "\n";
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
@ -530,19 +526,19 @@ void decompile_file(game game, const std::filesystem::path& file)
|
||||
{
|
||||
try
|
||||
{
|
||||
const auto& disassembler = disassemblers[game];
|
||||
const auto& decompiler = decompilers[game];
|
||||
auto& disassembler = contexts[game]->disassembler();
|
||||
auto& decompiler = contexts[game]->decompiler();
|
||||
|
||||
auto data = utils::file::read(file.string());
|
||||
auto path = t6::resolver::fs_to_game_path(file);
|
||||
|
||||
disassembler->disassemble(file.string(), data);
|
||||
disassembler.disassemble(file.string(), data);
|
||||
|
||||
auto output = disassembler->output();
|
||||
auto output = disassembler.output();
|
||||
|
||||
decompiler->decompile(file.string(), output);
|
||||
decompiler.decompile(file.string(), output);
|
||||
|
||||
utils::file::save((std::filesystem::path("decompiled/t6") / path).string(), decompiler->output());
|
||||
utils::file::save((std::filesystem::path("decompiled/t6") / path).string(), decompiler.output());
|
||||
std::cout << "decompiled " << path.replace_extension() << "\n";
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
@ -553,10 +549,9 @@ void decompile_file(game game, const std::filesystem::path& file)
|
||||
|
||||
void init()
|
||||
{
|
||||
assemblers[game::T6] = std::make_unique<t6::assembler>();
|
||||
disassemblers[game::T6] = std::make_unique<t6::disassembler>();
|
||||
compilers[game::T6] = std::make_unique<t6::compiler>(build::prod);
|
||||
decompilers[game::T6] = std::make_unique<t6::decompiler>();
|
||||
contexts[game::T6] = std::make_unique<t6::context>();
|
||||
contexts[game::T6]->init(build::prod, utils::file::read);
|
||||
|
||||
funcs[mode::ASM] = assemble_file;
|
||||
funcs[mode::DISASM] = disassemble_file;
|
||||
funcs[mode::COMP] = compile_file;
|
||||
|
@ -19,6 +19,8 @@ struct block
|
||||
bool is_dev;
|
||||
|
||||
block() : is_dev(false), abort(abort_t::abort_none) {}
|
||||
block(const std::string& lbreak, const std::string& lcont)
|
||||
: is_dev(false), abort(abort_t::abort_none), loc_break(lbreak), loc_continue(lcont) {}
|
||||
};
|
||||
|
||||
} // namespace xsk::arc
|
||||
|
@ -17,7 +17,6 @@ public:
|
||||
virtual auto output() -> assembly::ptr = 0;
|
||||
virtual auto output_data() -> std::vector<std::uint8_t> = 0;
|
||||
virtual void compile(const std::string& file, std::vector<std::uint8_t>& data) = 0;
|
||||
virtual void read_callback(std::function<std::vector<std::uint8_t>(const std::string&)> func) = 0;
|
||||
};
|
||||
|
||||
} // namespace xsk::arc
|
||||
|
26
src/utils/xsk/arc/interfaces/context.hpp
Normal file
26
src/utils/xsk/arc/interfaces/context.hpp
Normal file
@ -0,0 +1,26 @@
|
||||
// Copyright 2022 xensik. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a GNU GPLv3 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace xsk::arc
|
||||
{
|
||||
|
||||
class context
|
||||
{
|
||||
public:
|
||||
using ptr = std::unique_ptr<context>;
|
||||
|
||||
virtual ~context() = default;
|
||||
virtual void init(build mode, read_cb_type callback) = 0;
|
||||
virtual void cleanup() = 0;
|
||||
|
||||
virtual auto assembler() -> assembler& = 0;
|
||||
virtual auto disassembler() -> disassembler& = 0;
|
||||
virtual auto compiler() -> compiler& = 0;
|
||||
virtual auto decompiler() -> decompiler& = 0;
|
||||
};
|
||||
|
||||
} // namespace xsk::arc
|
@ -8,10 +8,12 @@
|
||||
namespace xsk::arc
|
||||
{
|
||||
|
||||
using read_cb_type = std::function<std::vector<std::uint8_t>(const std::string&)>;
|
||||
|
||||
enum class build
|
||||
{
|
||||
dev,
|
||||
prod,
|
||||
dev,
|
||||
};
|
||||
|
||||
enum class abort_t
|
||||
|
@ -37,3 +37,4 @@
|
||||
#include "arc/interfaces/disassembler.hpp"
|
||||
#include "arc/interfaces/compiler.hpp"
|
||||
#include "arc/interfaces/decompiler.hpp"
|
||||
#include "arc/interfaces/context.hpp"
|
||||
|
@ -227,4 +227,86 @@ auto string::parse_code(std::string& line) -> std::vector<std::string>
|
||||
return data;
|
||||
}
|
||||
|
||||
auto string::float_string(float value) -> std::string
|
||||
{
|
||||
enum flags_t : std::uint8_t { none = 0, negative = 1, integer = 2, has_exp = 4, exp_neg = 8 };
|
||||
|
||||
auto str = utils::string::va("%g", value);
|
||||
|
||||
auto flags = integer | (str[0] == '-' ? negative : none);
|
||||
|
||||
for (auto i = 1; i < str.size(); i++)
|
||||
{
|
||||
if (str[i] == '-') flags |= exp_neg;
|
||||
else if (str[i] == 'e') flags |= has_exp;
|
||||
else if ( str[i] == '.') flags &= ~integer;
|
||||
}
|
||||
|
||||
if (!(flags & has_exp))
|
||||
return str += (flags & integer) ? ".0" : "";
|
||||
|
||||
std::string p_int;
|
||||
std::string p_dec;
|
||||
std::string p_exp;
|
||||
|
||||
if(flags & integer)
|
||||
{
|
||||
auto i = (flags & negative) ? 1 : 0;
|
||||
|
||||
while (str[i] != 'e')
|
||||
p_int.push_back(str[i++]);
|
||||
|
||||
i += 2;
|
||||
|
||||
while (i < str.size())
|
||||
p_exp.push_back(str[i++]);
|
||||
|
||||
auto offset = std::stoi(p_exp);
|
||||
|
||||
if ((flags & exp_neg))
|
||||
offset -= p_int.size();
|
||||
|
||||
while (offset--)
|
||||
{
|
||||
if((flags & exp_neg))
|
||||
p_int.insert(p_int.begin(), '0');
|
||||
else
|
||||
p_int.push_back('0');
|
||||
}
|
||||
|
||||
return ((flags & negative) ? "-" : "") + ((flags & exp_neg) ? "0." + p_int : p_int + ".0");
|
||||
}
|
||||
else
|
||||
{
|
||||
auto i = (flags & negative) ? 1 : 0;
|
||||
|
||||
while (str[i] != '.')
|
||||
p_int.push_back(str[i++]);
|
||||
|
||||
i++;
|
||||
|
||||
while (str[i] != 'e')
|
||||
p_dec.push_back(str[i++]);
|
||||
|
||||
i += 2;
|
||||
|
||||
while (i < str.size())
|
||||
p_exp.push_back(str[i++]);
|
||||
|
||||
auto offset = std::stoi(p_exp);
|
||||
|
||||
offset -= (flags & exp_neg) ? p_int.size() : p_dec.size();
|
||||
|
||||
while (offset--)
|
||||
{
|
||||
if(flags & exp_neg)
|
||||
p_int.insert(p_int.begin(), '0');
|
||||
else
|
||||
p_dec.push_back('0');
|
||||
}
|
||||
|
||||
return ((flags & negative) ? "-" : "") + ((flags & exp_neg) ? "0." + p_int + p_dec : p_int + p_dec + ".0");
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace xsk::utils
|
||||
|
@ -37,6 +37,7 @@ public:
|
||||
static auto split(std::string& str, char delimiter) -> std::vector<std::string>;
|
||||
static auto clean_buffer_lines(std::vector<std::uint8_t>& buffer) -> std::vector<std::string>;
|
||||
static auto parse_code(std::string& line) -> std::vector<std::string>;
|
||||
static auto float_string(float value) -> std::string;
|
||||
};
|
||||
|
||||
} // namespace xsk::utils
|
||||
|
Loading…
Reference in New Issue
Block a user