blackops2 implementation

This commit is contained in:
xensik
2022-02-18 19:07:37 +01:00
parent c9c5e7c259
commit 2f402a10cc
35 changed files with 28817 additions and 4 deletions

View File

@ -0,0 +1,24 @@
// 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
{
struct block
{
using ptr = std::unique_ptr<block>;
std::string loc_end;
std::string loc_break;
std::string loc_continue;
abort_t abort;
bool is_dev;
block() : is_dev(false), abort(abort_t::abort_none) {}
};
} // namespace xsk::arc

View File

@ -0,0 +1,22 @@
// 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 assembler
{
public:
using ptr = std::unique_ptr<assembler>;
virtual ~assembler() = default;
virtual auto output() -> std::vector<std::uint8_t> = 0;
virtual void assemble(const std::string& file, std::vector<std::uint8_t>& data) = 0;
virtual void assemble(const std::string& file, assembly::ptr& data) = 0;
};
} // namespace xsk::arc

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.
#pragma once
namespace xsk::arc
{
class compiler
{
public:
using ptr = std::unique_ptr<compiler>;
virtual ~compiler() = default;
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

View File

@ -0,0 +1,21 @@
// 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 decompiler
{
public:
using ptr = std::unique_ptr<decompiler>;
virtual ~decompiler() = default;
virtual auto output() -> std::vector<std::uint8_t> = 0;
virtual void decompile(const std::string& file, const assembly::ptr& data) = 0;
};
} // namespace xsk::arc

View File

@ -0,0 +1,22 @@
// 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 disassembler
{
public:
using ptr = std::unique_ptr<disassembler>;
virtual ~disassembler() = default;
virtual auto output() -> assembly::ptr = 0;
virtual auto output_data() -> std::vector<std::uint8_t> = 0;
virtual void disassemble(const std::string& file, std::vector<std::uint8_t>& data) = 0;
};
} // namespace xsk::arc

View File

@ -0,0 +1,46 @@
// 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 error : public std::runtime_error
{
public:
error(const std::string& what)
: std::runtime_error("[ERROR]: "s + what) {}
};
class asm_error : public std::runtime_error
{
public:
asm_error(const std::string& what)
: std::runtime_error("[ERROR]:assembler: "s + what) {}
};
class disasm_error : public std::runtime_error
{
public:
disasm_error(const std::string& what)
: std::runtime_error("[ERROR]:disassembler: "s + what) {}
};
class comp_error : public std::runtime_error
{
public:
comp_error(const location& loc, const std::string& what)
: std::runtime_error("[ERROR]:compiler:" + loc.print() + ": " + what) {}
};
class decomp_error : public std::runtime_error
{
public:
decomp_error(const std::string& what)
: std::runtime_error("[ERROR]:decompiler: "s + what) {}
};
} // namespace xsk::arc

View File

@ -0,0 +1,229 @@
// 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
{
/// A point in a source file.
class position
{
public:
/// Type for file name.
typedef const std::string filename_type;
/// Type for line and column numbers.
typedef int counter_type;
/// Construct a position.
explicit position(filename_type *f = nullptr, counter_type l = 1, counter_type c = 1)
: filename(f), line(l), column(c) {}
/// Initialization.
void initialize(filename_type *fn = nullptr, counter_type l = 1, counter_type c = 1)
{
filename = fn;
line = l;
column = c;
}
/** \name Line and Column related manipulators
** \{ */
/// (line related) Advance to the COUNT next lines.
void lines(counter_type count = 1)
{
if (count)
{
column = 1;
line = add_(line, count, 1);
}
}
/// (column related) Advance to the COUNT next columns.
void columns(counter_type count = 1)
{
column = add_(column, count, 1);
}
/** \} */
/// File name to which this position refers.
filename_type *filename;
/// Current line number.
counter_type line;
/// Current column number.
counter_type column;
private:
/// Compute max (min, lhs+rhs).
static counter_type add_(counter_type lhs, counter_type rhs, counter_type min)
{
return lhs + rhs < min ? min : lhs + rhs;
}
};
/// Add \a width columns, in place.
inline position& operator+=(position &res, position::counter_type width)
{
res.columns(width);
return res;
}
/// Add \a width columns.
inline position operator+(position res, position::counter_type width)
{
return res += width;
}
/// Subtract \a width columns, in place.
inline position& operator-=(position &res, position::counter_type width)
{
return res += -width;
}
/// Subtract \a width columns.
inline position operator-(position res, position::counter_type width)
{
return res -= width;
}
/** \brief Intercept output stream redirection.
** \param ostr the destination output stream
** \param pos a reference to the position to redirect
*/
template <typename YYChar>
std::basic_ostream<YYChar>& operator<<(std::basic_ostream<YYChar> &ostr, const position &pos)
{
if (pos.filename)
ostr << *pos.filename << ':';
return ostr << pos.line << '.' << pos.column;
}
/// Two points in a source file.
class location
{
public:
/// Type for file name.
typedef position::filename_type filename_type;
/// Type for line and column numbers.
typedef position::counter_type counter_type;
/// Construct a location from \a b to \a e.
location(const position &b, const position &e)
: begin(b), end(e) {}
/// Construct a 0-width location in \a p.
explicit location(const position &p = position())
: begin(p), end(p) {}
/// Construct a 0-width location in \a f, \a l, \a c.
explicit location(filename_type *f, counter_type l = 1, counter_type c = 1)
: begin(f, l, c), end(f, l, c) {}
/// Initialization.
void initialize(filename_type *f = nullptr, counter_type l = 1, counter_type c = 1)
{
begin.initialize(f, l, c);
end = begin;
}
/** \name Line and Column related manipulators
** \{ */
public:
/// Reset initial location to final location.
void step()
{
begin = end;
}
/// Extend the current location to the COUNT next columns.
void columns(counter_type count = 1)
{
end += count;
}
/// Extend the current location to the COUNT next lines.
void lines(counter_type count = 1)
{
end.lines(count);
}
/** \} */
public:
auto print() const -> std::string
{
return *begin.filename + ":" + std::to_string(begin.line) + ":" + std::to_string(begin.column);
}
auto label() const -> std::string
{
return utils::string::va("loc_%X", begin.line);
}
public:
/// Beginning of the located region.
position begin;
/// End of the located region.
position end;
};
/// Join two locations, in place.
inline location& operator+=(location &res, const location &end)
{
res.end = end.end;
return res;
}
/// Join two locations.
inline location operator+(location res, const location &end)
{
return res += end;
}
/// Add \a width columns to the end position, in place.
inline location& operator+=(location &res, location::counter_type width)
{
res.columns(width);
return res;
}
/// Add \a width columns to the end position.
inline location operator+(location res, location::counter_type width)
{
return res += width;
}
/// Subtract \a width columns to the end position, in place.
inline location& operator-=(location &res, location::counter_type width)
{
return res += -width;
}
/// Subtract \a width columns to the end position.
inline location operator-(location res, location::counter_type width)
{
return res -= width;
}
/** \brief Intercept output stream redirection.
** \param ostr the destination output stream
** \param loc a reference to the location to redirect
**
** Avoid duplicate information.
*/
template <typename YYChar>
std::basic_ostream<YYChar>& operator<<(std::basic_ostream<YYChar> &ostr, const location &loc)
{
location::counter_type end_col = 0 < loc.end.column ? loc.end.column - 1 : 0;
ostr << loc.begin;
if (loc.end.filename && (!loc.begin.filename || *loc.begin.filename != *loc.end.filename))
ostr << '-' << loc.end.filename << ':' << loc.end.line << '.' << end_col;
else if (loc.begin.line < loc.end.line)
ostr << '-' << loc.end.line << '.' << end_col;
else if (loc.begin.column < end_col)
ostr << '-' << end_col;
return ostr;
}
} // namespace xsk::arc

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

179
src/utils/xsk/arc/types.hpp Normal file
View File

@ -0,0 +1,179 @@
// 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
{
enum class build
{
dev,
prod,
};
enum class abort_t
{
abort_none = 0,
abort_continue = 1,
abort_break = 2,
abort_return = 3,
};
struct include_t
{
std::string name;
std::vector<std::string> funcs;
include_t(const std::string& name, const std::vector<std::string>& funcs) : name(name), funcs(funcs) {}
};
struct animtree_t
{
std::string name;
bool loaded;
};
struct instruction
{
using ptr = std::unique_ptr<instruction>;
std::uint32_t index;
std::uint32_t size;
std::uint8_t opcode;
std::vector<std::string> data;
instruction() : index(0), size(0), opcode(0xFF) {}
};
struct function
{
using ptr = std::unique_ptr<function>;
std::uint32_t index;
std::uint32_t size;
std::uint8_t params;
std::uint8_t flags;
std::string name;
std::vector<instruction::ptr> instructions;
std::unordered_map<std::uint32_t, std::string> labels;
function() : index(0), size(0), params(0), flags(0) {}
};
struct animation_ref
{
using ptr = std::shared_ptr<animation_ref>;
std::string name;
std::uint32_t ref;
};
struct animtree_ref
{
using ptr = std::shared_ptr<animtree_ref>;
std::string name;
std::vector<std::uint32_t> refs;
std::vector<animation_ref> anims;
};
enum class string_type : std::uint8_t
{
literal = 0,
canonical = 1,
};
struct string_ref
{
using ptr = std::shared_ptr<string_ref>;
std::string name;
std::uint8_t type;
std::vector<std::uint32_t> refs;
};
enum class export_flags : std::uint8_t
{
none = 0x00,
vis_public = 0x01,
vis_autoexec = 0x02,
vis_private = 0x04,
unk1 = 0x08, // never seen
unk2 = 0x10, // inside dev /##/ ?
varargs_may = 0x20, // T7, T8, T9
};
struct export_ref
{
using ptr = std::shared_ptr<export_ref>;
std::uint32_t checksum;
std::uint32_t offset;
std::string name;
std::string space;
std::uint8_t params;
std::uint8_t flags;
std::uint32_t size;
};
enum class import_flags : std::uint8_t
{
none = 0,
func_reference = 1,
func_call = 2,
func_call_thread = 3,
meth_call = 4,
meth_call_thread = 5,
developer = 0x10,
unk = 0x20, // T7, T8, T9
};
struct import_ref
{
using ptr = std::shared_ptr<import_ref>;
std::string space;
std::string name;
std::uint8_t params;
std::uint8_t flags;
std::vector<std::uint32_t> refs;
};
struct header
{
std::uint64_t magic;
std::uint32_t source_crc;
std::uint32_t include_offset;
std::uint32_t animtree_offset;
std::uint32_t cseg_offset;
std::uint32_t stringtablefixup_offset;
std::uint32_t exports_offset;
std::uint32_t imports_offset;
std::uint32_t fixup_offset;
std::uint32_t profile_offset;
std::uint32_t cseg_size;
std::uint16_t name;
std::uint16_t stringtablefixup_count;
std::uint16_t exports_count;
std::uint16_t imports_count;
std::uint16_t fixup_count;
std::uint16_t profile_count;
std::uint8_t include_count;
std::uint8_t animtree_count;
std::uint8_t flags;
// char[1] pad;
};
struct assembly
{
using ptr = std::unique_ptr<assembly>;
std::vector<function::ptr> functions;
std::vector<std::string> includes;
std::vector<animtree_ref> animtrees;
};
} // namespace xsk::arc

View File

@ -131,7 +131,7 @@ auto node::precedence() -> std::uint8_t
case kind::expr_shift_right: return 8;
case kind::expr_add: return 9;
case kind::expr_sub: return 9;
case kind::expr_mul: return 10;
case kind::expr_mul: return 10;
case kind::expr_div: return 10;
case kind::expr_mod: return 10;
default: return 0;

View File

@ -24,3 +24,16 @@
#include "gsc/interfaces/disassembler.hpp"
#include "gsc/interfaces/compiler.hpp"
#include "gsc/interfaces/decompiler.hpp"
// ARC Types
#include "arc/location.hpp"
#include "arc/types.hpp"
#include "arc/block.hpp"
#include "arc/nodetree.hpp"
// ARC Interfaces
#include "arc/interfaces/exception.hpp"
#include "arc/interfaces/assembler.hpp"
#include "arc/interfaces/disassembler.hpp"
#include "arc/interfaces/compiler.hpp"
#include "arc/interfaces/decompiler.hpp"