context wrapper & t6 bug fixing

This commit is contained in:
xensik 2022-02-21 16:08:55 +01:00
parent 6980506e88
commit 9b7eb28b84
18 changed files with 309 additions and 145 deletions

View File

@ -185,6 +185,7 @@ void assembler::assemble_function(const function::ptr& func)
{ {
func->index = script_->pos(); func->index = script_->pos();
func->size = 0; func->size = 0;
labels_.clear();
for (const auto& inst : func->instructions) 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); const auto& itr = func->labels.find(old_idx);
if (itr != labels_.end()) if (itr != func->labels.end())
{ {
labels_.insert({ inst->index, itr->second }); 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_GetAnim:
case opcode::OP_GetGameRef: case opcode::OP_GetGameRef:
case opcode::OP_CreateLocalVariable: case opcode::OP_CreateLocalVariable:
case opcode::OP_RemoveLocalVariables:
case opcode::OP_EvalArray: case opcode::OP_EvalArray:
case opcode::OP_EvalLocalArrayRefCached:
case opcode::OP_EvalArrayRef: case opcode::OP_EvalArrayRef:
case opcode::OP_ClearArray: case opcode::OP_ClearArray:
case opcode::OP_EmptyArray: case opcode::OP_EmptyArray:
@ -364,7 +363,9 @@ void assembler::assemble_instruction(const instruction::ptr& inst)
case opcode::OP_SafeCreateLocalVariables: case opcode::OP_SafeCreateLocalVariables:
assemble_localvars(inst); assemble_localvars(inst);
break; break;
case opcode::OP_RemoveLocalVariables:
case opcode::OP_EvalLocalVariableCached: case opcode::OP_EvalLocalVariableCached:
case opcode::OP_EvalLocalArrayRefCached:
case opcode::OP_SafeSetWaittillVariableFieldCached: case opcode::OP_SafeSetWaittillVariableFieldCached:
case opcode::OP_EvalLocalVariableRefCached: case opcode::OP_EvalLocalVariableRefCached:
script_->write<std::uint8_t>(static_cast<std::uint8_t>(inst->opcode)); 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_GetAnim:
case opcode::OP_GetGameRef: case opcode::OP_GetGameRef:
case opcode::OP_CreateLocalVariable: case opcode::OP_CreateLocalVariable:
case opcode::OP_RemoveLocalVariables:
case opcode::OP_EvalArray: case opcode::OP_EvalArray:
case opcode::OP_EvalLocalArrayRefCached:
case opcode::OP_EvalArrayRef: case opcode::OP_EvalArrayRef:
case opcode::OP_ClearArray: case opcode::OP_ClearArray:
case opcode::OP_EmptyArray: case opcode::OP_EmptyArray:
@ -649,7 +648,9 @@ void assembler::align_instruction(const instruction::ptr& inst)
} }
} }
break; break;
case opcode::OP_RemoveLocalVariables:
case opcode::OP_EvalLocalVariableCached: case opcode::OP_EvalLocalVariableCached:
case opcode::OP_EvalLocalArrayRefCached:
case opcode::OP_SafeSetWaittillVariableFieldCached: case opcode::OP_SafeSetWaittillVariableFieldCached:
case opcode::OP_EvalLocalVariableRefCached: case opcode::OP_EvalLocalVariableRefCached:
script_->seek(1); script_->seek(1);

View File

@ -40,23 +40,21 @@ void compiler::compile(const std::string& file, std::vector<std::uint8_t>& data)
{ {
filename_ = file; filename_ = file;
auto prog = parse_buffer(filename_, data); auto prog = parse_buffer(filename_, reinterpret_cast<char*>(data.data()), data.size());
compile_program(prog); 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); ast::program::ptr result(nullptr);
resolver::set_reader(read_callback_); lexer lexer(mode_, file, data, size);
lexer lexer(mode_, file, reinterpret_cast<char*>(data.data()), data.size());
parser parser(lexer, result); 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 compiler::parse_file(const std::string& file) -> ast::program::ptr
{ {
auto buffer = read_callback_(file); auto data = resolver::file_data(file);
auto result = parse_buffer(file, buffer); auto result = parse_buffer(file, std::get<1>(data), std::get<2>(data));
return result; return result;
} }
@ -113,7 +111,7 @@ void compiler::emit_include(const ast::include::ptr& include)
{ {
if (entry == path) 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_break_ = false;
can_continue_ = false; can_continue_ = false;
local_stack_.clear(); local_stack_.clear();
break_loc_ = ""; blocks_.clear();
continue_loc_ = "";
abort_ = abort_t::abort_none;
process_thread(thread); process_thread(thread);
blocks_.push_back(block());
emit_expr_parameters(thread->params); emit_expr_parameters(thread->params);
emit_stmt_list(thread->stmt); emit_stmt_list(thread->stmt);
if (abort_ == abort_t::abort_none) if (blocks_.back().abort == abort_t::abort_none)
emit_opcode(opcode::OP_End); emit_opcode(opcode::OP_End);
blocks_.pop_back();
function_->size = index_ - function_->index; function_->size = index_ - function_->index;
assembly_->functions.push_back(std::move(function_)); 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); 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); emit_stmt(stmt->stmt);
blocks_.pop_back();
insert_label(end_loc); 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); 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); emit_stmt(stmt->stmt_if);
blocks_.pop_back();
emit_opcode(opcode::OP_Jump, end_loc); emit_opcode(opcode::OP_Jump, end_loc);
insert_label(else_loc); insert_label(else_loc);
auto& root = blocks_.back();
blocks_.push_back(block(root.loc_break, root.loc_continue));
emit_stmt(stmt->stmt_else); emit_stmt(stmt->stmt_else);
blocks_.pop_back();
insert_label(end_loc); insert_label(end_loc);
} }
void compiler::emit_stmt_while(const ast::stmt_while::ptr& stmt) 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_break = can_break_;
auto old_continue = can_continue_; auto old_continue = can_continue_;
can_break_ = true; can_break_ = true;
can_continue_ = true; can_continue_ = true;
break_loc_ = create_label(); auto break_loc = create_label();
continue_loc_ = insert_label(); auto continue_loc = insert_label();
auto begin_loc = continue_loc_; auto begin_loc = continue_loc;
if (stmt->test == ast::kind::expr_not) if (stmt->test == ast::kind::expr_not)
{ {
emit_expr(stmt->test.as_not->rvalue); emit_expr(stmt->test.as_not->rvalue);
emit_opcode(opcode::OP_JumpOnTrue, break_loc_); emit_opcode(opcode::OP_JumpOnTrue, break_loc);
} }
else else
{ {
emit_expr(stmt->test); 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_stmt(stmt->stmt);
emit_opcode(opcode::OP_Jump, begin_loc); blocks_.pop_back();
insert_label(break_loc_);
emit_opcode(opcode::OP_Jump, continue_loc);
insert_label(break_loc);
can_break_ = old_break; can_break_ = old_break;
can_continue_ = old_continue; 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) 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_break = can_break_;
auto old_continue = can_continue_; auto old_continue = can_continue_;
can_break_ = true; can_break_ = true;
can_continue_ = true; can_continue_ = true;
break_loc_ = create_label(); auto break_loc = create_label();
continue_loc_ = create_label(); auto continue_loc = create_label();
auto begin_loc = insert_label(); auto begin_loc = insert_label();
blocks_.push_back(block(break_loc, continue_loc));
emit_stmt(stmt->stmt); emit_stmt(stmt->stmt);
blocks_.pop_back();
insert_label(continue_loc_); insert_label(continue_loc);
if (stmt->test == ast::kind::expr_not) if (stmt->test == ast::kind::expr_not)
{ {
emit_expr(stmt->test.as_not->rvalue); emit_expr(stmt->test.as_not->rvalue);
emit_opcode(opcode::OP_JumpOnTrue, break_loc_); emit_opcode(opcode::OP_JumpOnTrue, break_loc);
} }
else else
{ {
emit_expr(stmt->test); 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); emit_opcode(opcode::OP_Jump, begin_loc);
insert_label(break_loc_); insert_label(break_loc);
can_break_ = old_break; can_break_ = old_break;
can_continue_ = old_continue; 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) 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_break = can_break_;
auto old_continue = can_continue_; auto old_continue = can_continue_;
emit_stmt(stmt->init); emit_stmt(stmt->init);
break_loc_ = create_label(); auto break_loc = create_label();
continue_loc_ = create_label(); auto continue_loc = create_label();
auto begin_loc = insert_label(); auto begin_loc = insert_label();
@ -608,34 +609,30 @@ void compiler::emit_stmt_for(const ast::stmt_for::ptr& stmt)
if (!const_cond) if (!const_cond)
{ {
emit_expr(stmt->test); emit_expr(stmt->test);
emit_opcode(opcode::OP_JumpOnFalse, break_loc_); emit_opcode(opcode::OP_JumpOnFalse, break_loc);
} }
can_break_ = true; can_break_ = true;
can_continue_ = true; can_continue_ = true;
blocks_.push_back(block(break_loc, continue_loc));
emit_stmt(stmt->stmt); emit_stmt(stmt->stmt);
blocks_.pop_back();
can_break_ = false; can_break_ = false;
can_continue_ = false; can_continue_ = false;
insert_label(continue_loc_); insert_label(continue_loc);
emit_stmt(stmt->iter); emit_stmt(stmt->iter);
emit_opcode(opcode::OP_Jump, begin_loc); emit_opcode(opcode::OP_Jump, begin_loc);
insert_label(break_loc_); insert_label(break_loc);
can_break_ = old_break; can_break_ = old_break;
can_continue_ = old_continue; 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) 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_break = can_break_;
auto old_continue = can_continue_; 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_opcode(opcode::OP_FirstArrayKey);
emit_expr_variable_ref(stmt->key_expr, true); emit_expr_variable_ref(stmt->key_expr, true);
break_loc_ = create_label(); auto break_loc = create_label();
continue_loc_ = create_label(); auto continue_loc = create_label();
auto begin_loc = insert_label(); auto begin_loc = insert_label();
emit_expr_variable(stmt->key_expr); emit_expr_variable(stmt->key_expr);
emit_opcode(opcode::OP_IsDefined); emit_opcode(opcode::OP_IsDefined);
emit_opcode(opcode::OP_JumpOnFalse, break_loc_); emit_opcode(opcode::OP_JumpOnFalse, break_loc);
can_break_ = true; can_break_ = true;
can_continue_ = 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_EvalLocalVariableCached, variable_access(stmt->array.as_identifier));
emit_opcode(opcode::OP_EvalArray); emit_opcode(opcode::OP_EvalArray);
emit_expr_variable_ref(stmt->value_expr, true); emit_expr_variable_ref(stmt->value_expr, true);
blocks_.push_back(block(break_loc, continue_loc));
emit_stmt(stmt->stmt); emit_stmt(stmt->stmt);
blocks_.pop_back();
can_break_ = false; can_break_ = false;
can_continue_ = false; can_continue_ = false;
insert_label(continue_loc_); insert_label(continue_loc);
emit_expr_variable(stmt->key_expr); emit_expr_variable(stmt->key_expr);
emit_expr_variable(stmt->array); emit_expr_variable(stmt->array);
emit_opcode(opcode::OP_NextArrayKey); emit_opcode(opcode::OP_NextArrayKey);
emit_expr_variable_ref(stmt->key_expr, true); emit_expr_variable_ref(stmt->key_expr, true);
emit_opcode(opcode::OP_Jump, begin_loc); emit_opcode(opcode::OP_Jump, begin_loc);
insert_label(break_loc_); insert_label(break_loc);
can_break_ = old_break; can_break_ = old_break;
can_continue_ = old_continue; 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) 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_; auto old_break = can_break_;
can_break_ = false; can_break_ = false;
auto jmptable_loc = create_label(); auto jmptable_loc = create_label();
break_loc_ = create_label(); auto break_loc = create_label();
emit_expr(stmt->test); emit_expr(stmt->test);
emit_opcode(opcode::OP_Switch, jmptable_loc); emit_opcode(opcode::OP_Switch, jmptable_loc);
can_break_ = true; can_break_ = true;
blocks_.push_back(block(break_loc, blocks_.back().loc_continue));
std::vector<std::string> data; std::vector<std::string> data;
data.push_back(utils::string::va("%d", stmt->stmt->list.size())); 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"); 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); emit_stmt_list(case_->stmt);
blocks_.pop_back();
} }
else if (entry == ast::kind::stmt_default) 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("default");
data.push_back(loc); data.push_back(loc);
has_default = true; has_default = true;
auto& paren = blocks_.back();
blocks_.push_back(block(paren.loc_break, paren.loc_continue));
emit_stmt_list(entry.as_default->stmt); emit_stmt_list(entry.as_default->stmt);
blocks_.pop_back();
} }
else else
{ {
@ -751,13 +755,13 @@ void compiler::emit_stmt_switch(const ast::stmt_switch::ptr& stmt)
} }
} }
blocks_.pop_back();
insert_label(jmptable_loc); insert_label(jmptable_loc);
emit_opcode(opcode::OP_EndSwitch, data); emit_opcode(opcode::OP_EndSwitch, data);
insert_label(break_loc_); insert_label(break_loc);
can_break_ = old_break; can_break_ = old_break;
break_loc_ = old_break_loc;
abort_ = old_abort;
} }
void compiler::emit_stmt_case(const ast::stmt_case::ptr& stmt) 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) 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"); throw comp_error(stmt->loc(), "illegal break statement");
abort_ = abort_t::abort_break; blocks_.back().abort = abort_t::abort_break;
emit_opcode(opcode::OP_Jump, break_loc_); emit_opcode(opcode::OP_Jump, blocks_.back().loc_break);
} }
void compiler::emit_stmt_continue(const ast::stmt_continue::ptr& stmt) 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"); throw comp_error(stmt->loc(), "illegal continue statement");
abort_ = abort_t::abort_continue; blocks_.back().abort = abort_t::abort_continue;
emit_opcode(opcode::OP_Jump, continue_loc_); emit_opcode(opcode::OP_Jump, blocks_.back().loc_continue);
} }
void compiler::emit_stmt_return(const ast::stmt_return::ptr& stmt) void compiler::emit_stmt_return(const ast::stmt_return::ptr& stmt)
{ {
if (abort_ == abort_t::abort_none) if (blocks_.back().abort == abort_t::abort_none)
abort_ = abort_t::abort_return; blocks_.back().abort = abort_t::abort_return;
if (stmt->expr != ast::kind::null) 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) void compiler::emit_expr_call_pointer(const ast::expr_pointer::ptr& expr)
{ {
emit_opcode(opcode::OP_PreScriptCall);
emit_expr_arguments(expr->args); emit_expr_arguments(expr->args);
emit_expr(expr->func); 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) 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_arguments(expr->args);
emit_expr(obj); emit_expr(obj);
emit_expr(expr->func); emit_expr(expr->func);
@ -1571,14 +1577,11 @@ void compiler::emit_expr_array_ref(const ast::expr_array::ptr& expr, bool set)
break; break;
case ast::kind::expr_array: case ast::kind::expr_array:
case ast::kind::expr_field: case ast::kind::expr_field:
case ast::kind::expr_identifier:
emit_expr_variable_ref(expr->obj, false); emit_expr_variable_ref(expr->obj, false);
emit_opcode(opcode::OP_EvalArrayRef); emit_opcode(opcode::OP_EvalArrayRef);
if (set) emit_opcode(opcode::OP_SetVariableField); if (set) emit_opcode(opcode::OP_SetVariableField);
break; 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_call:
case ast::kind::expr_method: case ast::kind::expr_method:
default: default:

View File

@ -12,7 +12,6 @@ enum class opcode : std::uint8_t;
class compiler : public arc::compiler class compiler : public arc::compiler
{ {
build mode_;
std::string filename_; std::string filename_;
assembly::ptr assembly_; assembly::ptr assembly_;
function::ptr function_; function::ptr function_;
@ -24,23 +23,20 @@ class compiler : public arc::compiler
std::vector<include_t> includes_; std::vector<include_t> includes_;
std::vector<animtree_t> animtrees_; std::vector<animtree_t> animtrees_;
std::unordered_map<std::string, ast::expr> constants_; std::unordered_map<std::string, ast::expr> constants_;
std::function<std::vector<std::uint8_t>(const std::string&)> read_callback_; std::vector<block> blocks_;
abort_t abort_;
std::string break_loc_;
std::string continue_loc_;
bool can_break_; bool can_break_;
bool can_continue_; bool can_continue_;
bool developer_thread_; bool developer_thread_;
build mode_;
public: public:
compiler(build mode) : mode_(mode) {}
auto output() -> assembly::ptr; auto output() -> assembly::ptr;
auto output_data() -> std::vector<std::uint8_t>; auto output_data() -> std::vector<std::uint8_t>;
void compile(const std::string& file, std::vector<std::uint8_t>& data); 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: 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; auto parse_file(const std::string& file) -> ast::program::ptr;
void compile_program(const ast::program::ptr& program); void compile_program(const ast::program::ptr& program);
void emit_include(const ast::include::ptr& include); void emit_include(const ast::include::ptr& include);
@ -163,7 +159,6 @@ private:
auto map_known_includes(const std::string& include) -> bool; auto map_known_includes(const std::string& include) -> bool;
utils::byte_buffer::ptr output_; utils::byte_buffer::ptr output_;
void print_function(const function::ptr& func); void print_function(const function::ptr& func);
void print_instruction(const instruction::ptr& inst); void print_instruction(const instruction::ptr& inst);

23
src/t6/xsk/context.cpp Normal file
View 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
View 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

View File

@ -248,6 +248,8 @@ void disassembler::disassemble_function(const function::ptr& func)
} }
} }
void disassembler::disassemble_instruction(const instruction::ptr& inst) void disassembler::disassemble_instruction(const instruction::ptr& inst)
{ {
switch (opcode(inst->opcode)) switch (opcode(inst->opcode))
@ -264,9 +266,7 @@ void disassembler::disassemble_instruction(const instruction::ptr& inst)
case opcode::OP_GetAnim: case opcode::OP_GetAnim:
case opcode::OP_GetGameRef: case opcode::OP_GetGameRef:
case opcode::OP_CreateLocalVariable: case opcode::OP_CreateLocalVariable:
case opcode::OP_RemoveLocalVariables:
case opcode::OP_EvalArray: case opcode::OP_EvalArray:
case opcode::OP_EvalLocalArrayRefCached:
case opcode::OP_EvalArrayRef: case opcode::OP_EvalArrayRef:
case opcode::OP_ClearArray: case opcode::OP_ClearArray:
case opcode::OP_EmptyArray: 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>())); inst->data.push_back(utils::string::va("%i", script_->read<std::int32_t>()));
break; break;
case opcode::OP_GetFloat: case opcode::OP_GetFloat:
{
inst->size += script_->align(4); inst->size += script_->align(4);
auto val = script_->read<float>(); inst->data.push_back(utils::string::float_string(script_->read<float>()));
inst->data.push_back(utils::string::va("%g%s", val, val == int(val) ? ".0" : ""));
}
break; break;
case opcode::OP_GetVector: case opcode::OP_GetVector:
inst->size += script_->align(4); inst->size += script_->align(4);
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::va("%g", script_->read<float>())); inst->data.push_back(utils::string::float_string(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>()));
break; break;
case opcode::OP_GetString: case opcode::OP_GetString:
case opcode::OP_GetIString: case opcode::OP_GetIString:
@ -383,7 +380,9 @@ void disassembler::disassemble_instruction(const instruction::ptr& inst)
case opcode::OP_SafeCreateLocalVariables: case opcode::OP_SafeCreateLocalVariables:
disassemble_localvars(inst); disassemble_localvars(inst);
break; break;
case opcode::OP_RemoveLocalVariables:
case opcode::OP_EvalLocalVariableCached: case opcode::OP_EvalLocalVariableCached:
case opcode::OP_EvalLocalArrayRefCached:
case opcode::OP_SafeSetWaittillVariableFieldCached: case opcode::OP_SafeSetWaittillVariableFieldCached:
case opcode::OP_EvalLocalVariableRefCached: case opcode::OP_EvalLocalVariableRefCached:
inst->data.push_back(utils::string::va("%i", script_->read<std::uint8_t>())); inst->data.push_back(utils::string::va("%i", script_->read<std::uint8_t>()));

View File

@ -12,6 +12,18 @@ namespace xsk::arc::t6
std::unordered_map<std::uint8_t, std::string_view> opcode_map; 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::string_view, std::uint8_t> opcode_map_rev;
std::unordered_map<std::uint32_t, std::string_view> dvar_map; 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 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; 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 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); 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 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; 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> auto resolver::file_data(const std::string& name) -> std::tuple<const std::string*, char*, size_t>
{ {
const auto& itr = files.find(name); 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 + "'"); 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 std::set<std::string> paths
{ {
"aitype", "aitype",

View File

@ -11,6 +11,8 @@ namespace xsk::arc::t6
class resolver class resolver
{ {
public: 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_id(const std::string& name) -> std::uint8_t;
static auto opcode_name(std::uint8_t id) -> std::string; static auto opcode_name(std::uint8_t id) -> std::string;
static auto dvar_name(std::uint32_t id) -> std::string; static auto dvar_name(std::uint32_t id) -> std::string;

View File

@ -25,9 +25,7 @@ auto opcode_size(std::uint8_t id) -> std::uint32_t
case opcode::OP_GetAnim: case opcode::OP_GetAnim:
case opcode::OP_GetGameRef: case opcode::OP_GetGameRef:
case opcode::OP_CreateLocalVariable: case opcode::OP_CreateLocalVariable:
case opcode::OP_RemoveLocalVariables:
case opcode::OP_EvalArray: case opcode::OP_EvalArray:
case opcode::OP_EvalLocalArrayRefCached:
case opcode::OP_EvalArrayRef: case opcode::OP_EvalArrayRef:
case opcode::OP_ClearArray: case opcode::OP_ClearArray:
case opcode::OP_EmptyArray: 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_GetByte:
case opcode::OP_GetNegByte: case opcode::OP_GetNegByte:
case opcode::OP_SafeCreateLocalVariables: case opcode::OP_SafeCreateLocalVariables:
case opcode::OP_RemoveLocalVariables:
case opcode::OP_EvalLocalVariableCached: case opcode::OP_EvalLocalVariableCached:
case opcode::OP_EvalLocalArrayRefCached:
case opcode::OP_SafeSetWaittillVariableFieldCached: case opcode::OP_SafeSetWaittillVariableFieldCached:
case opcode::OP_EvalLocalVariableRefCached: case opcode::OP_EvalLocalVariableRefCached:
case opcode::OP_ScriptFunctionCallPointer: case opcode::OP_ScriptFunctionCallPointer:

View File

@ -9,9 +9,10 @@
#include "assembler.hpp" #include "assembler.hpp"
#include "disassembler.hpp" #include "disassembler.hpp"
#include "decompiler.hpp"
#include "compiler.hpp" #include "compiler.hpp"
#include "decompiler.hpp"
#include "resolver.hpp" #include "resolver.hpp"
#include "context.hpp"
namespace xsk::arc::t6 namespace xsk::arc::t6
{ {

View File

@ -452,25 +452,22 @@ void init()
namespace arc namespace arc
{ {
std::map<game, assembler::ptr> assemblers; std::map<game, context::ptr> contexts;
std::map<game, disassembler::ptr> disassemblers;
std::map<game, compiler::ptr> compilers;
std::map<game, decompiler::ptr> decompilers;
std::map<mode, std::function<void(game game, const std::filesystem::path& file)>> funcs; std::map<mode, std::function<void(game game, const std::filesystem::path& file)>> funcs;
void assemble_file(game game, const std::filesystem::path& file) void assemble_file(game game, const std::filesystem::path& file)
{ {
try try
{ {
const auto& assembler = assemblers[game]; auto& assembler = contexts[game]->assembler();
auto data = utils::file::read(file.string()); auto data = utils::file::read(file.string());
auto path = t6::resolver::fs_to_game_path(file); auto path = t6::resolver::fs_to_game_path(file);
auto next = path.extension() == ".gscasm" ? path.replace_extension(".gsc") : path.replace_extension(".csc"); 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"; std::cout << "assembled " << path.replace_extension() << "\n";
} }
catch (const std::exception& e) catch (const std::exception& e)
@ -483,15 +480,15 @@ void disassemble_file(game game, const std::filesystem::path& file)
{ {
try try
{ {
const auto& disassembler = disassemblers[game]; auto& disassembler = contexts[game]->disassembler();
auto data = utils::file::read(file.string()); auto data = utils::file::read(file.string());
auto path = t6::resolver::fs_to_game_path(file); auto path = t6::resolver::fs_to_game_path(file);
auto next = path.extension() == ".gsc" ? path.replace_extension(".gscasm") : path.replace_extension(".cscasm"); 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"; std::cout << "disassembled " << path.replace_extension() << "\n";
} }
catch (const std::exception& e) catch (const std::exception& e)
@ -504,20 +501,19 @@ void compile_file(game game, const std::filesystem::path& file)
{ {
try try
{ {
const auto& assembler = assemblers[game]; auto& assembler = contexts[game]->assembler();
const auto& compiler = compilers[game]; auto& compiler = contexts[game]->compiler();
auto data = utils::file::read(file.string()); auto data = utils::file::read(file.string());
auto path = t6::resolver::fs_to_game_path(file); 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"; std::cout << "compiled " << path.replace_extension() << "\n";
} }
catch (const std::exception& e) catch (const std::exception& e)
@ -530,19 +526,19 @@ void decompile_file(game game, const std::filesystem::path& file)
{ {
try try
{ {
const auto& disassembler = disassemblers[game]; auto& disassembler = contexts[game]->disassembler();
const auto& decompiler = decompilers[game]; auto& decompiler = contexts[game]->decompiler();
auto data = utils::file::read(file.string()); auto data = utils::file::read(file.string());
auto path = t6::resolver::fs_to_game_path(file); 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"; std::cout << "decompiled " << path.replace_extension() << "\n";
} }
catch (const std::exception& e) catch (const std::exception& e)
@ -553,10 +549,9 @@ void decompile_file(game game, const std::filesystem::path& file)
void init() void init()
{ {
assemblers[game::T6] = std::make_unique<t6::assembler>(); contexts[game::T6] = std::make_unique<t6::context>();
disassemblers[game::T6] = std::make_unique<t6::disassembler>(); contexts[game::T6]->init(build::prod, utils::file::read);
compilers[game::T6] = std::make_unique<t6::compiler>(build::prod);
decompilers[game::T6] = std::make_unique<t6::decompiler>();
funcs[mode::ASM] = assemble_file; funcs[mode::ASM] = assemble_file;
funcs[mode::DISASM] = disassemble_file; funcs[mode::DISASM] = disassemble_file;
funcs[mode::COMP] = compile_file; funcs[mode::COMP] = compile_file;

View File

@ -19,6 +19,8 @@ struct block
bool is_dev; bool is_dev;
block() : is_dev(false), abort(abort_t::abort_none) {} 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 } // namespace xsk::arc

View File

@ -17,7 +17,6 @@ public:
virtual auto output() -> assembly::ptr = 0; virtual auto output() -> assembly::ptr = 0;
virtual auto output_data() -> std::vector<std::uint8_t> = 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 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 } // namespace xsk::arc

View 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

View File

@ -8,10 +8,12 @@
namespace xsk::arc namespace xsk::arc
{ {
using read_cb_type = std::function<std::vector<std::uint8_t>(const std::string&)>;
enum class build enum class build
{ {
dev,
prod, prod,
dev,
}; };
enum class abort_t enum class abort_t

View File

@ -37,3 +37,4 @@
#include "arc/interfaces/disassembler.hpp" #include "arc/interfaces/disassembler.hpp"
#include "arc/interfaces/compiler.hpp" #include "arc/interfaces/compiler.hpp"
#include "arc/interfaces/decompiler.hpp" #include "arc/interfaces/decompiler.hpp"
#include "arc/interfaces/context.hpp"

View File

@ -227,4 +227,86 @@ auto string::parse_code(std::string& line) -> std::vector<std::string>
return data; 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 } // namespace xsk::utils

View File

@ -37,6 +37,7 @@ public:
static auto split(std::string& str, char delimiter) -> std::vector<std::string>; 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 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 parse_code(std::string& line) -> std::vector<std::string>;
static auto float_string(float value) -> std::string;
}; };
} // namespace xsk::utils } // namespace xsk::utils