refactor(arc): treyarch games & minor fixes (#119)
This commit is contained in:
parent
a8a62c2667
commit
07184a5d0f
2
.github/dependabot.yml
vendored
2
.github/dependabot.yml
vendored
@ -3,5 +3,5 @@ updates:
|
||||
- package-ecosystem: "gitsubmodule"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "daily"
|
||||
interval: "monthly"
|
||||
open-pull-requests-limit: 10
|
||||
|
2
.github/workflows/build.yml
vendored
2
.github/workflows/build.yml
vendored
@ -116,6 +116,8 @@ jobs:
|
||||
config: debug
|
||||
- configuration: release
|
||||
config: release
|
||||
- arch: x64
|
||||
platform: x64
|
||||
steps:
|
||||
- uses: rui314/setup-mold@staging
|
||||
- name: Check out files
|
||||
|
21
.gitignore
vendored
21
.gitignore
vendored
@ -156,23 +156,4 @@ decompiled/
|
||||
assembled/
|
||||
disassembled/
|
||||
|
||||
data/iw5_ps3/
|
||||
data/iw5_360/
|
||||
data/iw6_ps3/
|
||||
data/iw6_360/
|
||||
data/s1_ps3/
|
||||
data/s1_360/
|
||||
data/iw5/
|
||||
data/iw6/
|
||||
data/iw7/
|
||||
data/iw8/
|
||||
data/iw9/
|
||||
data/h1/
|
||||
data/h2/
|
||||
data/s1/
|
||||
data/s2/
|
||||
data/s4/
|
||||
data/t6/
|
||||
data/t7/
|
||||
data/t8/
|
||||
data/t9/
|
||||
data/*
|
||||
|
19
README.md
19
README.md
@ -18,23 +18,24 @@ A utility to compile & decompile IW engine game scripts.
|
||||
- **S4** *(Call of Duty: Vanguard)* `PC` `PS4` `PS5` `Xbox One` `Xbox Series X|S`
|
||||
- **H1** *(Call of Duty: Modern Warfare Remastered)* `PC` `PS4` `Xbox One`
|
||||
- **H2** *(Call of Duty: Modern Warfare 2 Campaign Remastered)* `PC` `PS4` `PS5` `Xbox One` `Xbox Series X|S`
|
||||
- **T6** *(Call of Duty: Black Ops II)* `PC`
|
||||
- **T7** *(Call of Duty: Black Ops III)* ***\*WIP\****
|
||||
- **T6** *(Call of Duty: Black Ops II)* `PC` `PS3` `Xbox 360` `Wii U`
|
||||
- **T7** *(Call of Duty: Black Ops III)* `PC` *(Decompiler)*
|
||||
- **T8** *(Call of Duty: Black Ops 4)* ***\*WIP\****
|
||||
- **T9** *(Call of Duty: Black Ops Cold War)* ***\*WIP\****
|
||||
|
||||
## Usage
|
||||
``./gsc-tool.exe <mode> <game> <path>``
|
||||
``./gsc-tool.exe <mode> <game> <system> <path>``
|
||||
|
||||
**modes**: `asm`, `disasm`, `comp`, `decomp`, `parse`
|
||||
**mode**: `asm`, `disasm`, `comp`, `decomp`, `parse`
|
||||
- *note:* zonetool files (*.cgsc*, *.cgsc.stack*) use: `zasm`, `zdisasm`, `zcomp`, `zdecomp` modes
|
||||
|
||||
**games**: `iw5`, `iw6`, `iw7`, `iw8`, `iw9`, `s1`, `s2`, `s4`, `h1`, `h2`, `t6`
|
||||
- *note:* PS3 & Xbox 360 use `iw5ps`, `iw5xb`, `iw6ps`, `iw6xb`, `s1ps`, `s1xb` games
|
||||
**game**: `iw5`, `iw6`, `iw7`, `iw8`, `iw9`, `s1`, `s2`, `s4`, `h1`, `h2`, `t6` `t7` `t8` `t9`
|
||||
|
||||
**paths**: `file` or `directory` (recursive process all files inside the directory)
|
||||
**system**: `pc`, `ps3`, `ps4`, `ps5`, `xb2` (*360*), `xb3` (*One*), `xb4` (*Series X|S*), `wiiu`
|
||||
|
||||
Example: ``./gsc-tool.exe comp iw5 ./data/iw5/my_fancy_script.gsc``
|
||||
**path**: `file` or `directory` (recursive process all files inside the directory)
|
||||
|
||||
Example: ``./gsc-tool.exe comp iw5 pc ./data/iw5/my_fancy_script.gsc``
|
||||
|
||||
| Mode |Description | Output |
|
||||
|:---------|:--------------------------|:------------|
|
||||
@ -62,7 +63,7 @@ note: for PS3 & Xbox 360 `.gscbin` files *(compressedLen, len, bytecodeLen)* are
|
||||
- treyarch (T6) format is a single buffer with gscobj data `.gsc` or `.csc`.
|
||||
|
||||
## Contribute
|
||||
If you like my work, feel free to contribute! Would allow me to spend more time adding new features & fixing bugs.
|
||||
If you like my work, consider sponsoring/donating! Would allow me to spend more time adding new features & fixing bugs.
|
||||
|
||||
BTC: bc1qky7x9kpjlt6nsvt7pckc3wwzk8rk9pgtnmw98u\
|
||||
ETH: 0x6261BBE1a33F6Fec4b722DbCe2c28B4CC02c9C7B\
|
||||
|
@ -1 +0,0 @@
|
||||
# GSC Syntax
|
10
gen/arc/Makefile
Normal file
10
gen/arc/Makefile
Normal file
@ -0,0 +1,10 @@
|
||||
generate: arc
|
||||
|
||||
clean:
|
||||
rm -rf ./parser.hpp
|
||||
rm -rf ./parser.cpp
|
||||
|
||||
arc: parser.ypp
|
||||
bison parser.ypp -Wcounterexamples
|
||||
mv parser.hpp ../../include/xsk/arc/
|
||||
mv parser.cpp ../../src/arc/
|
1328
gen/arc/parser.ypp
Normal file
1328
gen/arc/parser.ypp
Normal file
File diff suppressed because it is too large
Load Diff
48
include/xsk/arc/assembler.hpp
Normal file
48
include/xsk/arc/assembler.hpp
Normal file
@ -0,0 +1,48 @@
|
||||
// Copyright 2023 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 "xsk/utils/writer.hpp"
|
||||
#include "xsk/arc/common/types.hpp"
|
||||
|
||||
namespace xsk::arc
|
||||
{
|
||||
|
||||
class assembler
|
||||
{
|
||||
context const* ctx_;
|
||||
function const* func_;
|
||||
assembly const* assembly_;
|
||||
utils::writer script_;
|
||||
std::unordered_map<std::string, u16> strpool_;
|
||||
std::vector<export_ref> exports_;
|
||||
std::vector<import_ref> imports_;
|
||||
std::vector<string_ref> strings_;
|
||||
std::vector<animtree_ref> anims_;
|
||||
|
||||
public:
|
||||
assembler(context const* ctx);
|
||||
auto assemble(assembly const& data) -> buffer;
|
||||
|
||||
private:
|
||||
auto assemble_function(function& func) -> void;
|
||||
auto assemble_instruction(instruction const& inst) -> void;
|
||||
auto assemble_localvars(instruction const& inst) -> void;
|
||||
auto assemble_jump(instruction const& inst) -> void;
|
||||
auto assemble_switch(instruction const& inst) -> void;
|
||||
auto assemble_end_switch(instruction const& inst) -> void;
|
||||
auto process_string(std::string const& data) -> void;
|
||||
auto process_function(function const& func) -> void;
|
||||
auto process_instruction(instruction const& inst) -> void;
|
||||
auto align_instruction(instruction& inst) -> void;
|
||||
auto resolve_label(std::string const& name) -> i32;
|
||||
auto resolve_string(std::string const& name) -> u16;
|
||||
void add_stringref(std::string const& str, string_type type, u32 ref);
|
||||
void add_importref(std::vector<std::string> const& data, u32 ref);
|
||||
void add_animref(std::vector<std::string> const& data, u32 ref);
|
||||
};
|
||||
|
||||
} // namespace xsk::arc
|
@ -166,6 +166,11 @@ struct instruction
|
||||
u32 size;
|
||||
opcode opcode;
|
||||
std::vector<std::string> data;
|
||||
|
||||
static auto make() -> instruction::ptr
|
||||
{
|
||||
return std::unique_ptr<instruction>(new instruction);
|
||||
}
|
||||
};
|
||||
|
||||
struct function
|
||||
@ -180,6 +185,11 @@ struct function
|
||||
std::string space;
|
||||
std::vector<instruction::ptr> instructions;
|
||||
std::unordered_map<u32, std::string> labels;
|
||||
|
||||
static auto make() -> function::ptr
|
||||
{
|
||||
return std::unique_ptr<function>(new function);
|
||||
}
|
||||
};
|
||||
|
||||
struct assembly
|
||||
@ -188,21 +198,11 @@ struct assembly
|
||||
|
||||
std::vector<std::string> includes;
|
||||
std::vector<function::ptr> functions;
|
||||
|
||||
static auto make() -> assembly::ptr
|
||||
{
|
||||
return std::unique_ptr<assembly>(new assembly);
|
||||
}
|
||||
};
|
||||
|
||||
inline auto make_instruction() -> std::unique_ptr<instruction>
|
||||
{
|
||||
return std::unique_ptr<instruction>(new instruction);
|
||||
}
|
||||
|
||||
inline auto make_function() -> std::unique_ptr<function>
|
||||
{
|
||||
return std::unique_ptr<function>(new function);
|
||||
}
|
||||
|
||||
inline auto make_assembly() -> std::unique_ptr<assembly>
|
||||
{
|
||||
return std::unique_ptr<assembly>(new assembly);
|
||||
}
|
||||
|
||||
} // namespace xsk::arc
|
||||
|
@ -8,33 +8,32 @@
|
||||
namespace xsk::arc
|
||||
{
|
||||
|
||||
constexpr usize header_size_32 = 64;
|
||||
constexpr usize header_size_64 = 72;
|
||||
constexpr usize header_size_v1 = 64;
|
||||
constexpr usize header_size_v2 = 72;
|
||||
constexpr usize header_size_v3 = 0;
|
||||
|
||||
struct header
|
||||
enum class string_type : u8
|
||||
{
|
||||
u64 magic;
|
||||
u32 source_crc;
|
||||
u32 include_offset;
|
||||
u32 animtree_offset;
|
||||
u32 cseg_offset;
|
||||
u32 stringtablefixup_offset;
|
||||
u32 devblock_stringtablefixup_offset;
|
||||
u32 exports_offset;
|
||||
u32 imports_offset;
|
||||
u32 fixup_offset;
|
||||
u32 profile_offset;
|
||||
u32 cseg_size;
|
||||
u32 name;
|
||||
u16 stringtablefixup_count;
|
||||
u16 exports_count;
|
||||
u16 imports_count;
|
||||
u16 fixup_count;
|
||||
u16 profile_count;
|
||||
u16 devblock_stringtablefixup_count;
|
||||
u8 include_count;
|
||||
u8 animtree_count;
|
||||
u8 flags;
|
||||
literal = 0,
|
||||
canonical = 1,
|
||||
};
|
||||
|
||||
enum class param_type : u8
|
||||
{
|
||||
value = 0,
|
||||
reference = 1,
|
||||
vararg = 2,
|
||||
};
|
||||
|
||||
enum class export_flags : u8
|
||||
{
|
||||
export_none = 0x00,
|
||||
export_public = 0x01,
|
||||
export_autoexec = 0x02,
|
||||
export_private = 0x04,
|
||||
export_codecall = 0x08,
|
||||
export_private2 = 0x10,
|
||||
export_varargs = 0x20,
|
||||
};
|
||||
|
||||
enum class import_flags : u8
|
||||
@ -49,6 +48,58 @@ enum class import_flags : u8
|
||||
unk = 0x20, // T7, T8, T9
|
||||
};
|
||||
|
||||
struct header
|
||||
{
|
||||
u64 magic;
|
||||
u32 source_crc;
|
||||
u32 include_offset;
|
||||
u32 animtree_offset;
|
||||
u32 cseg_offset;
|
||||
u32 stringtablefixup_offset;
|
||||
u32 devblock_stringtablefixup_offset;
|
||||
u32 exports_offset;
|
||||
u32 imports_offset;
|
||||
u32 fixup_offset;
|
||||
u32 globalvar_offset;
|
||||
u32 profile_offset;
|
||||
u32 cseg_size;
|
||||
u32 name;
|
||||
u16 stringtablefixup_count;
|
||||
u16 exports_count;
|
||||
u16 imports_count;
|
||||
u16 fixup_count;
|
||||
u16 globalvar_count;
|
||||
u16 profile_count;
|
||||
u16 devblock_stringtablefixup_count;
|
||||
u8 include_count;
|
||||
u8 animtree_count;
|
||||
u8 flags;
|
||||
};
|
||||
|
||||
struct animation_ref
|
||||
{
|
||||
std::string name;
|
||||
u32 ref;
|
||||
};
|
||||
|
||||
struct animtree_ref
|
||||
{
|
||||
using ptr = std::shared_ptr<animtree_ref>;
|
||||
|
||||
std::string name;
|
||||
std::vector<u32> refs;
|
||||
std::vector<animation_ref> anims;
|
||||
};
|
||||
|
||||
struct string_ref
|
||||
{
|
||||
using ptr = std::shared_ptr<string_ref>;
|
||||
|
||||
std::string name;
|
||||
u8 type;
|
||||
std::vector<u32> refs;
|
||||
};
|
||||
|
||||
struct import_ref
|
||||
{
|
||||
using ptr = std::shared_ptr<import_ref>;
|
||||
@ -60,17 +111,6 @@ struct import_ref
|
||||
std::vector<u32> refs;
|
||||
};
|
||||
|
||||
enum class export_flags : u8
|
||||
{
|
||||
export_none = 0x00,
|
||||
export_public = 0x01,
|
||||
export_autoexec = 0x02,
|
||||
export_private = 0x04,
|
||||
export_codecall = 0x08,
|
||||
export_private2 = 0x10,
|
||||
export_varargs = 0x20,
|
||||
};
|
||||
|
||||
struct export_ref
|
||||
{
|
||||
using ptr = std::shared_ptr<export_ref>;
|
||||
@ -84,36 +124,4 @@ struct export_ref
|
||||
u8 flags;
|
||||
};
|
||||
|
||||
enum class string_type : u8
|
||||
{
|
||||
literal = 0,
|
||||
canonical = 1,
|
||||
};
|
||||
|
||||
struct string_ref
|
||||
{
|
||||
using ptr = std::shared_ptr<string_ref>;
|
||||
|
||||
std::string name;
|
||||
u8 type;
|
||||
std::vector<u32> refs;
|
||||
};
|
||||
|
||||
struct animation_ref
|
||||
{
|
||||
using ptr = std::shared_ptr<animation_ref>;
|
||||
|
||||
std::string name;
|
||||
u32 ref;
|
||||
};
|
||||
|
||||
struct animtree_ref
|
||||
{
|
||||
using ptr = std::shared_ptr<animtree_ref>;
|
||||
|
||||
std::string name;
|
||||
std::vector<u32> refs;
|
||||
std::vector<animation_ref> anims;
|
||||
};
|
||||
|
||||
} // namespace xsk::arc
|
||||
|
File diff suppressed because it is too large
Load Diff
21
include/xsk/arc/common/define.hpp
Normal file
21
include/xsk/arc/common/define.hpp
Normal file
@ -0,0 +1,21 @@
|
||||
// Copyright 2023 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 define
|
||||
{
|
||||
enum kind : u8 { PLAIN, BUILTIN, OBJECT, FUNCTION };
|
||||
|
||||
kind type;
|
||||
// bool vararg;
|
||||
std::vector<token> args;
|
||||
std::vector<token> exp;
|
||||
};
|
||||
|
||||
} // namespace xsk::arc
|
19
include/xsk/arc/common/directive.hpp
Normal file
19
include/xsk/arc/common/directive.hpp
Normal file
@ -0,0 +1,19 @@
|
||||
// Copyright 2023 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 directive
|
||||
{
|
||||
enum kind : u8 { IF, IFDEF, IFNDEF, ELIF, ELIFDEF, ELIFNDEF, ELSE, ENDIF, DEFINE, UNDEF, PRAGMA, WARNING, ERROR, LINE, INCLUDE, INLINE, INSERT, USINGTREE };
|
||||
|
||||
kind type;
|
||||
bool skip;
|
||||
};
|
||||
|
||||
} // namespace xsk::arc
|
23
include/xsk/arc/common/lookahead.hpp
Normal file
23
include/xsk/arc/common/lookahead.hpp
Normal file
@ -0,0 +1,23 @@
|
||||
// Copyright 2023 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 lookahead
|
||||
{
|
||||
char const* buffer_pos;
|
||||
usize available;
|
||||
char last_byte;
|
||||
char curr_byte;
|
||||
|
||||
lookahead(char const* data, usize size);
|
||||
auto advance() -> void;
|
||||
auto ended() { return available == 0; };
|
||||
};
|
||||
|
||||
} // namespace xsk::arc
|
33
include/xsk/arc/common/scope.hpp
Normal file
33
include/xsk/arc/common/scope.hpp
Normal file
@ -0,0 +1,33 @@
|
||||
// Copyright 2023 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 scope
|
||||
{
|
||||
using ptr = std::unique_ptr<scope>;
|
||||
|
||||
enum abort_type
|
||||
{
|
||||
abort_none = 0,
|
||||
abort_continue = 1,
|
||||
abort_break = 2,
|
||||
abort_return = 3,
|
||||
};
|
||||
|
||||
std::string end;
|
||||
std::string cnt;
|
||||
std::string brk;
|
||||
abort_type abort;
|
||||
bool is_dev;
|
||||
|
||||
scope() : abort(abort_type::abort_none), is_dev(false) {}
|
||||
scope(std::string const& brk, std::string const& cnt) : cnt{ cnt }, brk{ brk }, abort(abort_type::abort_none), is_dev(false) {}
|
||||
};
|
||||
|
||||
} // namespace xsk::arc
|
19
include/xsk/arc/common/space.hpp
Normal file
19
include/xsk/arc/common/space.hpp
Normal file
@ -0,0 +1,19 @@
|
||||
// Copyright 2023 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 spacing : u8
|
||||
{
|
||||
none = 0, // no space between tokens
|
||||
null = 1, // token just after new line
|
||||
back = 2, // token after space
|
||||
empty = 4, // token after new line + space
|
||||
};
|
||||
|
||||
} // namespace xsk::arc
|
43
include/xsk/arc/common/token.hpp
Normal file
43
include/xsk/arc/common/token.hpp
Normal file
@ -0,0 +1,43 @@
|
||||
// Copyright 2023 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 token
|
||||
{
|
||||
enum kind : u8
|
||||
{
|
||||
PLUS, MINUS, STAR, DIV, MOD, BITOR, BITAND, BITEXOR, SHL, SHR,
|
||||
ASSIGN, PLUSEQ, MINUSEQ, STAREQ, DIVEQ, MODEQ, BITOREQ, BITANDEQ, BITEXOREQ, SHLEQ, SHREQ,
|
||||
INC, DEC, GT, LT, GE, LE, NE, EQ, OR, AND, TILDE, BANG, QMARK, COLON, SHARP, COMMA, DOT,
|
||||
DOUBLEDOT, ELLIPSIS, SEMICOLON, DOUBLECOLON, LBRACKET, RBRACKET, LBRACE, RBRACE, LPAREN, RPAREN,
|
||||
|
||||
NAME, PATH, STRING, ISTRING, HASHSTR, INT, FLT,
|
||||
|
||||
DEVBEGIN, DEVEND, INLINE, INCLUDE, USINGTREE, ANIMTREE, AUTOEXEC, CODECALL, PRIVATE,
|
||||
ENDON, NOTIFY, WAIT, WAITTILL, WAITTILLMATCH, WAITTILLFRAMEEND, IF, ELSE, DO, WHILE,
|
||||
FOR, FOREACH, IN, SWITCH, CASE, DEFAULT, BREAK, CONTINUE, RETURN, PROFBEGIN, PROFEND,
|
||||
THREAD, TRUE, FALSE, UNDEFINED, SIZE, GAME, SELF, ANIM, LEVEL,
|
||||
CONST, ISDEFINED, VECTORSCALE, ANGLESTOUP, ANGLESTORIGHT, ANGLESTOFORWARD, ANGLECLAMP180,
|
||||
VECTORTOANGLES, ABS, GETTIME, GETDVAR, GETDVARINT, GETDVARFLOAT, GETDVARVECTOR, GETDVARCOLORRED,
|
||||
GETDVARCOLORGREEN, GETDVARCOLORBLUE, GETDVARCOLORALPHA, GETFIRSTARRAYKEY, GETNEXTARRAYKEY,
|
||||
|
||||
HASH, NEWLINE, EOS, DEFINED, MACROBEGIN, MACROEND, MACROARG, MACROVAOPT, MACROVAARGS, STRINGIZE, PASTE
|
||||
};
|
||||
|
||||
kind type;
|
||||
spacing space;
|
||||
location pos;
|
||||
std::string data;
|
||||
|
||||
token(kind type, spacing space, location pos) : type{ type }, space{ space }, pos{ pos }, data{} {}
|
||||
token(kind type, spacing space, location pos, std::string data) : type{ type }, space{ space }, pos{ pos }, data{ std::move(data) } {}
|
||||
auto to_string() -> std::string;
|
||||
};
|
||||
|
||||
} // namespace xsk::arc
|
@ -5,12 +5,18 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "asset.hpp"
|
||||
#include "assembly.hpp"
|
||||
#include "buffer.hpp"
|
||||
#include "location.hpp"
|
||||
#include "exception.hpp"
|
||||
#include "ast.hpp"
|
||||
#include "xsk/arc/common/asset.hpp"
|
||||
#include "xsk/arc/common/assembly.hpp"
|
||||
#include "xsk/arc/common/buffer.hpp"
|
||||
#include "xsk/arc/common/location.hpp"
|
||||
#include "xsk/arc/common/exception.hpp"
|
||||
#include "xsk/arc/common/lookahead.hpp"
|
||||
#include "xsk/arc/common/directive.hpp"
|
||||
#include "xsk/arc/common/scope.hpp"
|
||||
#include "xsk/arc/common/space.hpp"
|
||||
#include "xsk/arc/common/token.hpp"
|
||||
#include "xsk/arc/common/define.hpp"
|
||||
#include "xsk/arc/common/ast.hpp"
|
||||
|
||||
namespace xsk::arc
|
||||
{
|
||||
@ -37,7 +43,12 @@ enum class system : u8
|
||||
{
|
||||
pc,
|
||||
ps3,
|
||||
ps4,
|
||||
ps5,
|
||||
xb2,
|
||||
xb3,
|
||||
xb4,
|
||||
wiiu,
|
||||
};
|
||||
|
||||
enum class engine : u8
|
||||
@ -53,7 +64,18 @@ struct props
|
||||
enum values : u32
|
||||
{
|
||||
none = 0 << 0,
|
||||
version2 = 1 << 0,
|
||||
v2 = 1 << 0,
|
||||
v3 = 1 << 1,
|
||||
header64 = 1 << 2,
|
||||
header72 = 1 << 3,
|
||||
headerxx = 1 << 4,
|
||||
size64 = 1 << 5,
|
||||
hashids = 1 << 6,
|
||||
devstr = 1 << 7,
|
||||
spaces = 1 << 8,
|
||||
globals = 1 << 9,
|
||||
refvarg = 1 << 10,
|
||||
foreach = 1 << 11,
|
||||
};
|
||||
|
||||
props(values value) : value_(value) {}
|
||||
|
153
include/xsk/arc/compiler.hpp
Normal file
153
include/xsk/arc/compiler.hpp
Normal file
@ -0,0 +1,153 @@
|
||||
// Copyright 2023 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 "xsk/arc/common/types.hpp"
|
||||
|
||||
namespace xsk::arc
|
||||
{
|
||||
|
||||
class compiler
|
||||
{
|
||||
context* ctx_;
|
||||
assembly::ptr assembly_;
|
||||
function::ptr function_;
|
||||
std::vector<std::string> localfuncs_;
|
||||
std::vector<std::string> stackframe_;
|
||||
std::vector<scope> scopes_;
|
||||
std::unordered_map<std::string, expr const*> constants_;
|
||||
std::string animtree_;
|
||||
u32 index_;
|
||||
u32 label_idx_;
|
||||
bool can_break_;
|
||||
bool can_continue_;
|
||||
bool developer_thread_;
|
||||
|
||||
public:
|
||||
compiler(context* ctx);
|
||||
auto compile(program const& data) -> assembly::ptr;
|
||||
auto compile(std::string const& file, std::vector<u8>& data) -> assembly::ptr;
|
||||
|
||||
private:
|
||||
auto emit_program(program const& prog) -> void;
|
||||
auto emit_include(include const& inc) -> void;
|
||||
auto emit_decl(decl const& dec) -> void;
|
||||
auto emit_decl_usingtree(decl_usingtree const& animtree) -> void;
|
||||
auto emit_decl_function(decl_function const& func) -> void;
|
||||
auto emit_stmt(stmt const& stm) -> void;
|
||||
auto emit_stmt_list(stmt_list const& stm) -> void;
|
||||
auto emit_stmt_comp(stmt_comp const& stm) -> void;
|
||||
auto emit_stmt_dev(stmt_dev const& stm) -> void;
|
||||
auto emit_stmt_expr(stmt_expr const& stm) -> void;
|
||||
auto emit_stmt_endon(stmt_endon const& stm) -> void;
|
||||
auto emit_stmt_notify(stmt_notify const& stm) -> void;
|
||||
auto emit_stmt_wait(stmt_wait const& stm) -> void;
|
||||
auto emit_stmt_waittill(stmt_waittill const& stm) -> void;
|
||||
auto emit_stmt_waittillmatch(stmt_waittillmatch const& stm) -> void;
|
||||
auto emit_stmt_waittillframeend(stmt_waittillframeend const& stm) -> void;
|
||||
auto emit_stmt_if(stmt_if const& stm) -> void;
|
||||
auto emit_stmt_ifelse(stmt_ifelse const& stm) -> void;
|
||||
auto emit_stmt_while(stmt_while const& stm) -> void;
|
||||
auto emit_stmt_dowhile(stmt_dowhile const& stm) -> void;
|
||||
auto emit_stmt_for(stmt_for const& stm) -> void;
|
||||
auto emit_stmt_foreach(stmt_foreach const& stm) -> void;
|
||||
auto emit_stmt_switch(stmt_switch const& stm) -> void;
|
||||
auto emit_stmt_case(stmt_case const& stm) -> void;
|
||||
auto emit_stmt_default(stmt_default const& stm) -> void;
|
||||
auto emit_stmt_break(stmt_break const& stm) -> void;
|
||||
auto emit_stmt_continue(stmt_continue const& stm) -> void;
|
||||
auto emit_stmt_return(stmt_return const& stm) -> void;
|
||||
auto emit_stmt_breakpoint(stmt_breakpoint const& stm) -> void;
|
||||
auto emit_stmt_prof_begin(stmt_prof_begin const& stm) -> void;
|
||||
auto emit_stmt_prof_end(stmt_prof_end const& stm) -> void;
|
||||
auto emit_expr(expr const& exp) -> void;
|
||||
auto emit_expr_const(expr_const const& exp) -> void;
|
||||
auto emit_expr_assign(expr_assign const& exp) -> void;
|
||||
auto emit_expr_clear(expr const& exp) -> void;
|
||||
auto emit_expr_clear_local(expr_identifier const& exp) -> void;
|
||||
auto emit_expr_increment(expr_increment const& exp, bool is_stmt) -> void;
|
||||
auto emit_expr_decrement(expr_decrement const& exp, bool is_stmt) -> void;
|
||||
auto emit_expr_ternary(expr_ternary const& exp) -> void;
|
||||
auto emit_expr_binary(expr_binary const& exp) -> void;
|
||||
auto emit_expr_complement(expr_complement const& exp) -> void;
|
||||
auto emit_expr_negate(expr_negate const& exp) -> void;
|
||||
auto emit_expr_not(expr_not const& exp) -> void;
|
||||
auto emit_expr_call(expr_call const& exp, bool is_stmt) -> void;
|
||||
auto emit_expr_call_pointer(expr_pointer const& exp, bool is_stmt) -> void;
|
||||
auto emit_expr_call_function(expr_function const& exp, bool is_stmt) -> void;
|
||||
auto emit_expr_method(expr_method const& exp, bool is_stmt) -> void;
|
||||
auto emit_expr_method_pointer(expr_pointer const& exp, expr const& obj, bool is_stmt) -> void;
|
||||
auto emit_expr_method_function(expr_function const& exp, expr const& obj, bool is_stmt) -> void;
|
||||
auto emit_expr_parameters(expr_parameters const& exp) -> void;
|
||||
auto emit_expr_arguments(expr_arguments const& exp) -> void;
|
||||
auto emit_expr_isdefined(expr_isdefined const& exp) -> void;
|
||||
auto emit_expr_vectorscale(expr_vectorscale const& exp) -> void;
|
||||
auto emit_expr_anglestoup(expr_anglestoup const& exp) -> void;
|
||||
auto emit_expr_anglestoright(expr_anglestoright const& exp) -> void;
|
||||
auto emit_expr_anglestoforward(expr_anglestoforward const& exp) -> void;
|
||||
auto emit_expr_angleclamp180(expr_angleclamp180 const& exp) -> void;
|
||||
auto emit_expr_vectortoangles(expr_vectortoangles const& exp) -> void;
|
||||
auto emit_expr_abs(expr_abs const& exp) -> void;
|
||||
auto emit_expr_gettime(expr_gettime const& exp) -> void;
|
||||
auto emit_expr_getdvar(expr_getdvar const& exp) -> void;
|
||||
auto emit_expr_getdvarint(expr_getdvarint const& exp) -> void;
|
||||
auto emit_expr_getdvarfloat(expr_getdvarfloat const& exp) -> void;
|
||||
auto emit_expr_getdvarvector(expr_getdvarvector const& exp) -> void;
|
||||
auto emit_expr_getdvarcolorred(expr_getdvarcolorred const& exp) -> void;
|
||||
auto emit_expr_getdvarcolorgreen(expr_getdvarcolorgreen const& exp) -> void;
|
||||
auto emit_expr_getdvarcolorblue(expr_getdvarcolorblue const& exp) -> void;
|
||||
auto emit_expr_getdvarcoloralpha(expr_getdvarcoloralpha const& exp) -> void;
|
||||
auto emit_expr_getfirstarraykey(expr_getfirstarraykey const& exp) -> void;
|
||||
auto emit_expr_getnextarraykey(expr_getnextarraykey const& exp) -> void;
|
||||
auto emit_expr_reference(expr_reference const& exp) -> void;
|
||||
auto emit_expr_size(expr_size const& exp) -> void;
|
||||
auto emit_expr_variable_ref(expr const& exp, bool set) -> void;
|
||||
auto emit_expr_array_ref(expr_array const& exp, bool set) -> void;
|
||||
auto emit_expr_field_ref(expr_field const& exp, bool set) -> void;
|
||||
auto emit_expr_local_ref(expr_identifier const& exp, bool set) -> void;
|
||||
auto emit_expr_variable(expr const& exp) -> void;
|
||||
auto emit_expr_array(expr_array const& exp) -> void;
|
||||
auto emit_expr_field(expr_field const& exp) -> void;
|
||||
auto emit_expr_local(expr_identifier const& exp) -> void;
|
||||
auto emit_expr_object(expr const& exp) -> void;
|
||||
auto emit_expr_vector(expr_vector const& exp) -> void;
|
||||
auto emit_expr_animation(expr_animation const& exp) -> void;
|
||||
auto emit_expr_animtree(expr_animtree const& exp) -> void;
|
||||
auto emit_expr_istring(expr_istring const& exp) -> void;
|
||||
auto emit_expr_string(expr_string const& exp) -> void;
|
||||
auto emit_expr_hash(expr_hash const& exp) -> void;
|
||||
auto emit_expr_float(expr_float const& exp) -> void;
|
||||
auto emit_expr_integer(expr_integer const& exp) -> void;
|
||||
auto emit_expr_false(expr_false const& exp) -> void;
|
||||
auto emit_expr_true(expr_true const& exp) -> void;
|
||||
auto emit_opcode(opcode op) -> void;
|
||||
auto emit_opcode(opcode op, std::string const& data) -> void;
|
||||
auto emit_opcode(opcode op, std::vector<std::string> const& data) -> void;
|
||||
auto process_function(decl_function const& func) -> void;
|
||||
auto process_stmt(stmt const& stm) -> void;
|
||||
auto process_stmt_list(stmt_list const& stm) -> void;
|
||||
auto process_stmt_comp(stmt_comp const& stm) -> void;
|
||||
auto process_stmt_dev(stmt_dev const& stm) -> void;
|
||||
auto process_stmt_expr(stmt_expr const& stm) -> void;
|
||||
auto process_stmt_waittill(stmt_waittill const& stm) -> void;
|
||||
auto process_stmt_if(stmt_if const& stm) -> void;
|
||||
auto process_stmt_ifelse(stmt_ifelse const& stm) -> void;
|
||||
auto process_stmt_while(stmt_while const& stm) -> void;
|
||||
auto process_stmt_dowhile(stmt_dowhile const& stm) -> void;
|
||||
auto process_stmt_for(stmt_for const& stm) -> void;
|
||||
auto process_stmt_foreach(stmt_foreach const& stm) -> void;
|
||||
auto process_stmt_switch(stmt_switch const& stm) -> void;
|
||||
auto process_expr(expr const& exp) -> void;
|
||||
auto process_expr_parameters(expr_parameters const& exp) -> void;
|
||||
auto variable_register(expr_identifier const& exp) -> void;
|
||||
auto variable_access(expr_identifier const& exp) -> u8;
|
||||
auto is_constant_condition(expr const& exp) -> bool;
|
||||
auto insert_label(std::string const& label) -> void;
|
||||
auto insert_label() -> std::string;
|
||||
auto create_label() -> std::string;
|
||||
};
|
||||
|
||||
} // namespace xsk::arc
|
@ -5,10 +5,12 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common/types.hpp"
|
||||
#include "source.hpp"
|
||||
#include "disassembler.hpp"
|
||||
#include "decompiler.hpp"
|
||||
#include "xsk/arc/common/types.hpp"
|
||||
#include "xsk/arc/source.hpp"
|
||||
#include "xsk/arc/assembler.hpp"
|
||||
#include "xsk/arc/disassembler.hpp"
|
||||
#include "xsk/arc/compiler.hpp"
|
||||
#include "xsk/arc/decompiler.hpp"
|
||||
|
||||
namespace xsk::arc
|
||||
{
|
||||
@ -28,7 +30,9 @@ public:
|
||||
auto instance() const -> instance { return instance_; }
|
||||
auto magic() const -> u64 { return magic_; }
|
||||
auto source() -> source& { return source_; }
|
||||
auto assembler() -> assembler& { return assembler_; }
|
||||
auto disassembler() -> disassembler& { return disassembler_; }
|
||||
auto compiler() -> compiler& { return compiler_; }
|
||||
auto decompiler() -> decompiler& { return decompiler_; }
|
||||
|
||||
auto init(arc::build build, fs_callback callback) -> void;
|
||||
@ -36,14 +40,14 @@ public:
|
||||
auto engine_name() const -> std::string_view;
|
||||
|
||||
auto opcode_size(opcode op) const -> u32;
|
||||
auto opcode_id(opcode op) const -> u8;
|
||||
auto opcode_id(opcode op) const -> u16;
|
||||
auto opcode_name(opcode op) const -> std::string;
|
||||
auto opcode_enum(std::string const& name) const -> opcode;
|
||||
auto opcode_enum(u16 id) const -> opcode;
|
||||
auto dvar_id(std::string const& name) const -> u32;
|
||||
auto dvar_name(u32 id) const -> std::string;
|
||||
auto hash_id(std::string const& name) const -> u32;
|
||||
auto hash_name(u32 id) const -> std::string;
|
||||
auto make_token(std::string_view str) const -> std::string;
|
||||
auto load_header(std::string const& name) -> std::tuple<std::string const*, char const*, usize>;
|
||||
|
||||
protected:
|
||||
arc::props props_;
|
||||
@ -54,16 +58,18 @@ protected:
|
||||
arc::instance instance_;
|
||||
u64 magic_;
|
||||
arc::source source_;
|
||||
arc::assembler assembler_;
|
||||
arc::disassembler disassembler_;
|
||||
arc::compiler compiler_;
|
||||
arc::decompiler decompiler_;
|
||||
|
||||
fs_callback fs_callback_;
|
||||
std::unordered_map<opcode, std::string_view> opcode_map_;
|
||||
std::unordered_map<std::string_view, opcode> opcode_map_rev_;
|
||||
std::unordered_map<u16, opcode> code_map_;
|
||||
std::unordered_map<opcode, u8> code_map_rev_;
|
||||
std::unordered_map<u32, std::string_view> dvar_map_;
|
||||
std::unordered_map<opcode, u16> code_map_rev_;
|
||||
std::unordered_map<u32, std::string_view> hash_map_;
|
||||
std::unordered_map<std::string, std::vector<u8>> header_files_;
|
||||
};
|
||||
|
||||
} // namespace xsk::arc
|
||||
|
@ -5,7 +5,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common/types.hpp"
|
||||
#include "xsk/arc/common/types.hpp"
|
||||
|
||||
namespace xsk::arc
|
||||
{
|
||||
@ -20,6 +20,7 @@ class decompiler
|
||||
std::vector<std::string> expr_labels_;
|
||||
std::vector<std::string> tern_labels_;
|
||||
std::vector<std::string> locals_;
|
||||
std::vector<param_type> params_;
|
||||
std::stack<node::ptr> stack_;
|
||||
locjmp locs_;
|
||||
bool in_waittill_;
|
||||
@ -52,7 +53,7 @@ private:
|
||||
auto find_location_reference(stmt_list const& stm, usize begin, usize end, std::string const& loc) -> bool;
|
||||
auto find_location_index(stmt_list const& stm, std::string const& loc) -> usize;
|
||||
auto last_location_index(stmt_list const& stm, usize index) -> bool;
|
||||
auto lvalues_match(stmt_assign const& stm1, stmt_assign const& stm2) -> bool;
|
||||
auto lvalues_match(stmt_expr const& stm1, stmt_expr const& stm2) -> bool;
|
||||
auto resolve_label(std::string const& name) -> u32;
|
||||
auto process_function(decl_function& func) -> void;
|
||||
auto process_stmt(stmt& stm) -> void;
|
||||
@ -60,14 +61,12 @@ private:
|
||||
auto process_stmt_comp(stmt_comp& stm) -> void;
|
||||
auto process_stmt_dev(stmt_dev& stm) -> void;
|
||||
auto process_stmt_expr(stmt_expr& stm) -> void;
|
||||
auto process_stmt_call(stmt_call& stm) -> void;
|
||||
auto process_stmt_assign(stmt_assign& stm) -> void;
|
||||
auto process_stmt_endon(stmt_endon& stm) -> void;
|
||||
auto process_stmt_notify(stmt_notify& stm) -> void;
|
||||
auto process_stmt_realwait(stmt_realwait& stm) -> void;
|
||||
auto process_stmt_wait(stmt_wait& stm) -> void;
|
||||
auto process_stmt_waittill(stmt_waittill& stm) -> void;
|
||||
auto process_stmt_waittillmatch(stmt_waittillmatch& stm) -> void;
|
||||
auto process_stmt_waitrealtime(stmt_waitrealtime& stm) -> void;
|
||||
auto process_stmt_if(stmt_if& stm) -> void;
|
||||
auto process_stmt_ifelse(stmt_ifelse& stm) -> void;
|
||||
auto process_stmt_while(stmt_while& stm) -> void;
|
||||
@ -78,14 +77,12 @@ private:
|
||||
auto process_stmt_break(stmt_break& stm) -> void;
|
||||
auto process_stmt_continue(stmt_continue& stm) -> void;
|
||||
auto process_stmt_return(stmt_return& stm) -> void;
|
||||
auto process_expr(expr& exp) -> void;
|
||||
auto process_expr_assign(expr_assign::ptr& exp) -> void;
|
||||
auto process_expr(expr::ptr& exp) -> void;
|
||||
auto process_expr_increment(expr_increment& exp) -> void;
|
||||
auto process_expr_decrement(expr_decrement& exp) -> void;
|
||||
auto process_expr_assign(expr_assign::ptr& exp) -> void;
|
||||
auto process_expr_ternary(expr_ternary& exp) -> void;
|
||||
auto process_expr_binary(expr_binary& exp) -> void;
|
||||
auto process_expr_and(expr_and& exp) -> void;
|
||||
auto process_expr_or(expr_or& exp) -> void;
|
||||
auto process_expr_complement(expr_complement& exp) -> void;
|
||||
auto process_expr_not(expr_not& exp) -> void;
|
||||
auto process_expr_call(expr_call& exp) -> void;
|
||||
@ -93,8 +90,8 @@ private:
|
||||
auto process_expr_call_member(expr_member& exp) -> void;
|
||||
auto process_expr_call_pointer(expr_pointer& exp) -> void;
|
||||
auto process_expr_call_function(expr_function& exp) -> void;
|
||||
auto process_expr_method_pointer(expr_pointer& exp, expr& obj) -> void;
|
||||
auto process_expr_method_function(expr_function& exp, expr& obj) -> void;
|
||||
auto process_expr_method_pointer(expr_pointer& exp, expr::ptr& obj) -> void;
|
||||
auto process_expr_method_function(expr_function& exp, expr::ptr& obj) -> void;
|
||||
auto process_expr_parameters(expr_parameters& exp) -> void;
|
||||
auto process_expr_arguments(expr_arguments& exp) -> void;
|
||||
auto process_expr_size(expr_size& exp) -> void;
|
||||
|
@ -5,8 +5,8 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common/types.hpp"
|
||||
#include "xsk/utils/reader.hpp"
|
||||
#include "xsk/arc/common/types.hpp"
|
||||
|
||||
namespace xsk::arc
|
||||
{
|
||||
|
@ -12,13 +12,6 @@ namespace xsk::arc::t6
|
||||
{
|
||||
|
||||
constexpr usize code_count = 125;
|
||||
constexpr usize dvar_count = 3326;
|
||||
constexpr u64 header_magic = 0x06000A0D43534780;
|
||||
constexpr usize hash_count = 3326;
|
||||
|
||||
class context : public arc::context
|
||||
{
|
||||
public:
|
||||
context();
|
||||
};
|
||||
|
||||
} // namespace xsk::gsc::t6
|
||||
} // namespace xsk::arc::t6
|
||||
|
21
include/xsk/arc/engine/t6_pc.hpp
Normal file
21
include/xsk/arc/engine/t6_pc.hpp
Normal file
@ -0,0 +1,21 @@
|
||||
// Copyright 2023 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 "xsk/arc/engine/t6.hpp"
|
||||
|
||||
namespace xsk::arc::t6::pc
|
||||
{
|
||||
|
||||
constexpr u64 header_magic = 0x06000A0D43534780;
|
||||
|
||||
class context : public arc::context
|
||||
{
|
||||
public:
|
||||
context();
|
||||
};
|
||||
|
||||
} // namespace xsk::arc::t6::pc
|
21
include/xsk/arc/engine/t6_ps3.hpp
Normal file
21
include/xsk/arc/engine/t6_ps3.hpp
Normal file
@ -0,0 +1,21 @@
|
||||
// Copyright 2023 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 "xsk/arc/engine/t6.hpp"
|
||||
|
||||
namespace xsk::arc::t6::ps3
|
||||
{
|
||||
|
||||
constexpr u64 header_magic = 0x804753430D0A0006;
|
||||
|
||||
class context : public arc::context
|
||||
{
|
||||
public:
|
||||
context();
|
||||
};
|
||||
|
||||
} // namespace xsk::arc::t6::ps3
|
21
include/xsk/arc/engine/t6_wiiu.hpp
Normal file
21
include/xsk/arc/engine/t6_wiiu.hpp
Normal file
@ -0,0 +1,21 @@
|
||||
// Copyright 2023 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 "xsk/arc/engine/t6.hpp"
|
||||
|
||||
namespace xsk::arc::t6::wiiu
|
||||
{
|
||||
|
||||
constexpr u64 header_magic = 0x804753430D0A0006;
|
||||
|
||||
class context : public arc::context
|
||||
{
|
||||
public:
|
||||
context();
|
||||
};
|
||||
|
||||
} // namespace xsk::arc::t6::wiiu
|
21
include/xsk/arc/engine/t6_xb2.hpp
Normal file
21
include/xsk/arc/engine/t6_xb2.hpp
Normal file
@ -0,0 +1,21 @@
|
||||
// Copyright 2023 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 "xsk/arc/engine/t6.hpp"
|
||||
|
||||
namespace xsk::arc::t6::xb2
|
||||
{
|
||||
|
||||
constexpr u64 header_magic = 0x804753430D0A0006;
|
||||
|
||||
class context : public arc::context
|
||||
{
|
||||
public:
|
||||
context();
|
||||
};
|
||||
|
||||
} // namespace xsk::arc::t6::xb2
|
@ -11,9 +11,8 @@
|
||||
namespace xsk::arc::t7
|
||||
{
|
||||
|
||||
constexpr usize code_count = 8192;
|
||||
constexpr usize dvar_count = 0;
|
||||
constexpr usize hash_count = 178717;
|
||||
constexpr usize code_count = 16384;
|
||||
constexpr usize hash_count = 178806;
|
||||
constexpr u64 header_magic = 0x1C000A0D43534780;
|
||||
|
||||
class context : public arc::context
|
||||
|
@ -12,9 +12,8 @@ namespace xsk::arc::t8
|
||||
{
|
||||
|
||||
constexpr usize code_count = 0;
|
||||
constexpr usize dvar_count = 0;
|
||||
constexpr usize hash_count = 0;
|
||||
constexpr u64 header_magic = 0;
|
||||
constexpr u64 header_magic = 0x36000A0D43534780;
|
||||
|
||||
class context : public arc::context
|
||||
{
|
||||
|
@ -12,9 +12,8 @@ namespace xsk::arc::t9
|
||||
{
|
||||
|
||||
constexpr usize code_count = 0;
|
||||
constexpr usize dvar_count = 0;
|
||||
constexpr usize hash_count = 0;
|
||||
constexpr u64 header_magic = 0;
|
||||
constexpr u64 header_magic = 0x38000A0D43534780;
|
||||
|
||||
class context : public arc::context
|
||||
{
|
||||
|
33
include/xsk/arc/lexer.hpp
Normal file
33
include/xsk/arc/lexer.hpp
Normal file
@ -0,0 +1,33 @@
|
||||
// Copyright 2023 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 "xsk/arc/common/types.hpp"
|
||||
|
||||
namespace xsk::arc
|
||||
{
|
||||
|
||||
class lexer
|
||||
{
|
||||
context const* ctx_;
|
||||
lookahead reader_;
|
||||
location loc_;
|
||||
usize buflen_;
|
||||
spacing spacing_;
|
||||
bool indev_;
|
||||
std::array<char, 0x1000> buffer_;
|
||||
|
||||
public:
|
||||
lexer(context const* ctx, std::string const& name, char const* data, usize size);
|
||||
auto lex() -> token;
|
||||
|
||||
private:
|
||||
auto push(char c) -> void;
|
||||
auto advance() -> void;
|
||||
auto linewrap() -> void;
|
||||
};
|
||||
|
||||
} // namespace xsk::arc
|
File diff suppressed because it is too large
Load Diff
91
include/xsk/arc/preprocessor.hpp
Normal file
91
include/xsk/arc/preprocessor.hpp
Normal file
@ -0,0 +1,91 @@
|
||||
// Copyright 2023 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 "xsk/arc/common/types.hpp"
|
||||
#include "xsk/arc/lexer.hpp"
|
||||
|
||||
namespace xsk::arc
|
||||
{
|
||||
|
||||
class preprocessor
|
||||
{
|
||||
context* ctx_;
|
||||
std::stack<lexer> lexer_;
|
||||
std::stack<directive> indents_;
|
||||
std::vector<std::string> includes_;
|
||||
std::unordered_map<std::string_view, directive::kind> directives_;
|
||||
std::unordered_map<std::string, define> defines_;
|
||||
std::set<std::string> reject_;
|
||||
std::deque<token> tokens_;
|
||||
std::vector<token> expr_;
|
||||
std::string date_;
|
||||
std::string time_;
|
||||
usize curr_expr_;
|
||||
u32 expand_;
|
||||
u32 skip_;
|
||||
|
||||
public:
|
||||
preprocessor(context* ctx, std::string const& name, char const* data, usize size);
|
||||
auto process() -> token;
|
||||
auto push_header(std::string const& file) -> void;
|
||||
auto pop_header() -> void;
|
||||
auto ban_header(location const& loc) -> void;
|
||||
|
||||
private:
|
||||
auto skip_line() -> void;
|
||||
auto next_token() -> token;
|
||||
auto read_token() -> token;
|
||||
auto read_directive(token& tok) -> void;
|
||||
auto read_directive_if(token& tok) -> void;
|
||||
auto read_directive_ifdef(token& tok) -> void;
|
||||
auto read_directive_ifndef(token& tok) -> void;
|
||||
auto read_directive_elif(token& tok) -> void;
|
||||
auto read_directive_elifdef(token& tok) -> void;
|
||||
auto read_directive_elifndef(token& tok) -> void;
|
||||
auto read_directive_else(token& tok) -> void;
|
||||
auto read_directive_endif(token& tok) -> void;
|
||||
auto read_directive_define(token& tok) -> void;
|
||||
auto read_directive_undef(token& tok) -> void;
|
||||
auto read_directive_pragma(token& tok) -> void;
|
||||
auto read_directive_warning(token& tok) -> void;
|
||||
auto read_directive_error(token& tok) -> void;
|
||||
auto read_directive_line(token& tok) -> void;
|
||||
auto read_directive_include(token& hash, token& name) -> void;
|
||||
auto read_directive_inline(token& hash, token& name) -> void;
|
||||
auto read_directive_usingtree(token& hash, token& name) -> void;
|
||||
auto read_hashtoken(token& hash) -> void;
|
||||
auto read_hashtoken_animtree(token& hash, token& name) -> void;
|
||||
auto expand(token& tok, define& def) -> void;
|
||||
auto expand_params(token& tok, define& def) -> std::vector<std::vector<token>>;
|
||||
auto expect(token& tok, token::kind expected, spacing space = spacing::none) -> void;
|
||||
auto evaluate() -> bool;
|
||||
auto eval_next() -> token&;
|
||||
auto eval_peek() -> token&;
|
||||
auto eval_prev() -> token&;
|
||||
auto eval_atend() -> bool;
|
||||
auto eval_check(token::kind type) -> bool;
|
||||
auto eval_match(token::kind type) -> bool;
|
||||
auto eval_consume(token::kind type, std::string_view msg);
|
||||
auto eval_expr() -> i32;
|
||||
auto eval_expr_or() -> i32;
|
||||
auto eval_expr_and() -> i32;
|
||||
auto eval_expr_bwor() -> i32;
|
||||
auto eval_expr_bwexor() -> i32;
|
||||
auto eval_expr_bwand() -> i32;
|
||||
auto eval_expr_eq() -> i32;
|
||||
auto eval_expr_lge() -> i32;
|
||||
auto eval_expr_shift() -> i32;
|
||||
auto eval_expr_add() -> i32;
|
||||
auto eval_expr_factor() -> i32;
|
||||
auto eval_expr_unary() -> i32;
|
||||
auto eval_expr_primary() -> i32;
|
||||
auto get_local_time(std::tm& ltime) -> void;
|
||||
auto get_date_define(std::tm* time_p) -> void;
|
||||
auto get_time_define(std::tm* time_p) -> void;
|
||||
};
|
||||
|
||||
} // namespace xsk::arc
|
@ -5,7 +5,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common/types.hpp"
|
||||
#include "xsk/arc/common/types.hpp"
|
||||
|
||||
namespace xsk::arc
|
||||
{
|
||||
@ -18,6 +18,12 @@ class source
|
||||
|
||||
public:
|
||||
source(context* ctx);
|
||||
auto parse_assembly(buffer const& data) -> assembly::ptr;
|
||||
auto parse_assembly(std::vector<u8> const& data) -> assembly::ptr;
|
||||
auto parse_assembly(u8 const* data, usize size) -> assembly::ptr;
|
||||
auto parse_program(std::string const& name, buffer const& data) -> program::ptr;
|
||||
auto parse_program(std::string const& name, std::vector<u8> const& data) -> program::ptr;
|
||||
auto parse_program(std::string const& name, u8 const* data, usize size) -> program::ptr;
|
||||
auto dump(assembly const& data) -> std::vector<u8>;
|
||||
auto dump(program const& data) -> std::vector<u8>;
|
||||
|
||||
@ -33,21 +39,20 @@ private:
|
||||
auto dump_decl_namespace(decl_namespace const& dec) -> void;
|
||||
auto dump_decl_usingtree(decl_usingtree const& dec) -> void;
|
||||
auto dump_decl_function(decl_function const& dec) -> void;
|
||||
auto dump_decl_empty(decl_empty const& dec) -> void;
|
||||
auto dump_stmt(stmt const& stm) -> void;
|
||||
auto dump_stmt_empty(stmt_empty const& stm) -> void;
|
||||
auto dump_stmt_list(stmt_list const& stm) -> void;
|
||||
auto dump_stmt_comp(stmt_comp const& stm) -> void;
|
||||
auto dump_stmt_dev(stmt_dev const& stm) -> void;
|
||||
auto dump_stmt_expr(stmt_expr const& stm) -> void;
|
||||
auto dump_stmt_call(stmt_call const& stm) -> void;
|
||||
auto dump_stmt_const(stmt_const const& stm) -> void;
|
||||
auto dump_stmt_assign(stmt_assign const& stm) -> void;
|
||||
auto dump_stmt_endon(stmt_endon const& stm) -> void;
|
||||
auto dump_stmt_notify(stmt_notify const& stm) -> void;
|
||||
auto dump_stmt_realwait(stmt_realwait const& stm) -> void;
|
||||
auto dump_stmt_wait(stmt_wait const& stm) -> void;
|
||||
auto dump_stmt_waittill(stmt_waittill const& stm) -> void;
|
||||
auto dump_stmt_waittillmatch(stmt_waittillmatch const& stm) -> void;
|
||||
auto dump_stmt_waittillframeend(stmt_waittillframeend const& stm) -> void;
|
||||
auto dump_stmt_waitrealtime(stmt_waitrealtime const& stm) -> void;
|
||||
auto dump_stmt_if(stmt_if const& stm) -> void;
|
||||
auto dump_stmt_ifelse(stmt_ifelse const& stm) -> void;
|
||||
auto dump_stmt_while(stmt_while const& stm) -> void;
|
||||
@ -63,41 +68,21 @@ private:
|
||||
auto dump_stmt_breakpoint(stmt_breakpoint const& stm) -> void;
|
||||
auto dump_stmt_prof_begin(stmt_prof_begin const& stm) -> void;
|
||||
auto dump_stmt_prof_end(stmt_prof_end const& stm) -> void;
|
||||
auto dump_stmt_jmp(stmt_jmp const& stm) -> void;
|
||||
auto dump_stmt_jmp_back(stmt_jmp_back const& stm) -> void;
|
||||
auto dump_stmt_jmp_cond(stmt_jmp_cond const& stm) -> void;
|
||||
auto dump_stmt_jmp_true(stmt_jmp_true const& stm) -> void;
|
||||
auto dump_stmt_jmp_false(stmt_jmp_false const& stm) -> void;
|
||||
auto dump_stmt_jmp_switch(stmt_jmp_switch const& stm) -> void;
|
||||
auto dump_stmt_jmp_endswitch(stmt_jmp_endswitch const& stm) -> void;
|
||||
auto dump_stmt_jmp_dev(stmt_jmp_dev const& stm) -> void;
|
||||
auto dump_expr(expr const& exp) -> void;
|
||||
auto dump_expr_increment(expr_increment const& exp) -> void;
|
||||
auto dump_expr_decrement(expr_decrement const& exp) -> void;
|
||||
auto dump_expr_assign_equal(expr_assign_equal const& exp) -> void;
|
||||
auto dump_expr_assign_add(expr_assign_add const& exp) -> void;
|
||||
auto dump_expr_assign_sub(expr_assign_sub const& exp) -> void;
|
||||
auto dump_expr_assign_mul(expr_assign_mul const& exp) -> void;
|
||||
auto dump_expr_assign_div(expr_assign_div const& exp) -> void;
|
||||
auto dump_expr_assign_mod(expr_assign_mod const& exp) -> void;
|
||||
auto dump_expr_assign_shift_left(expr_assign_shift_left const& exp) -> void;
|
||||
auto dump_expr_assign_shift_right(expr_assign_shift_right const& exp) -> void;
|
||||
auto dump_expr_assign_bitwise_or(expr_assign_bitwise_or const& exp) -> void;
|
||||
auto dump_expr_assign_bitwise_and(expr_assign_bitwise_and const& exp) -> void;
|
||||
auto dump_expr_assign_bitwise_exor(expr_assign_bitwise_exor const& exp) -> void;
|
||||
auto dump_expr_assign(expr_assign const& exp) -> void;
|
||||
auto dump_expr_const(expr_const const& exp) -> void;
|
||||
auto dump_expr_ternary(expr_ternary const& exp) -> void;
|
||||
auto dump_expr_or(expr_or const& exp) -> void;
|
||||
auto dump_expr_and(expr_and const& exp) -> void;
|
||||
auto dump_expr_super_equal(expr_super_equal const& exp) -> void;
|
||||
auto dump_expr_super_not_equal(expr_super_not_equal const& exp) -> void;
|
||||
auto dump_expr_equality(expr_equality const& exp) -> void;
|
||||
auto dump_expr_inequality(expr_inequality const& exp) -> void;
|
||||
auto dump_expr_less_equal(expr_less_equal const& exp) -> void;
|
||||
auto dump_expr_greater_equal(expr_greater_equal const& exp) -> void;
|
||||
auto dump_expr_less(expr_less const& exp) -> void;
|
||||
auto dump_expr_greater(expr_greater const& exp) -> void;
|
||||
auto dump_expr_add(expr_add const& exp) -> void;
|
||||
auto dump_expr_sub(expr_sub const& exp) -> void;
|
||||
auto dump_expr_mul(expr_mul const& exp) -> void;
|
||||
auto dump_expr_div(expr_div const& exp) -> void;
|
||||
auto dump_expr_mod(expr_mod const& exp) -> void;
|
||||
auto dump_expr_shift_left(expr_shift_left const& exp) -> void;
|
||||
auto dump_expr_shift_right(expr_shift_right const& exp) -> void;
|
||||
auto dump_expr_bitwise_or(expr_bitwise_or const& exp) -> void;
|
||||
auto dump_expr_bitwise_and(expr_bitwise_and const& exp) -> void;
|
||||
auto dump_expr_bitwise_exor(expr_bitwise_exor const& exp) -> void;
|
||||
auto dump_expr_binary(expr_binary const& exp) -> void;
|
||||
auto dump_expr_not(expr_not const& exp) -> void;
|
||||
auto dump_expr_negate(expr_negate const& exp) -> void;
|
||||
auto dump_expr_complement(expr_complement const& exp) -> void;
|
||||
@ -134,6 +119,7 @@ private:
|
||||
auto dump_expr_field(expr_field const& exp) -> void;
|
||||
auto dump_expr_size(expr_size const& exp) -> void;
|
||||
auto dump_expr_paren(expr_paren const& exp) -> void;
|
||||
auto dump_expr_ellipsis(expr_ellipsis const& exp) -> void;
|
||||
auto dump_expr_empty_array(expr_empty_array const& exp) -> void;
|
||||
auto dump_expr_undefined(expr_undefined const& exp) -> void;
|
||||
auto dump_expr_game(expr_game const& exp) -> void;
|
||||
@ -154,17 +140,6 @@ private:
|
||||
auto dump_expr_integer(expr_integer const& exp) -> void;
|
||||
auto dump_expr_false(expr_false const& exp) -> void;
|
||||
auto dump_expr_true(expr_true const& exp) -> void;
|
||||
auto dump_asm_loc(asm_loc const& exp) -> void;
|
||||
auto dump_asm_jmp(asm_jmp const& exp) -> void;
|
||||
auto dump_asm_jmp_back(asm_jmp_back const& exp) -> void;
|
||||
auto dump_asm_jmp_cond(asm_jmp_cond const& exp) -> void;
|
||||
auto dump_asm_jmp_true(asm_jmp_true const& exp) -> void;
|
||||
auto dump_asm_jmp_false(asm_jmp_false const& exp) -> void;
|
||||
auto dump_asm_switch(asm_switch const& exp) -> void;
|
||||
auto dump_asm_endswitch(asm_endswitch const& exp) -> void;
|
||||
auto dump_asm_prescriptcall(asm_prescriptcall const& exp) -> void;
|
||||
auto dump_asm_voidcodepos(asm_voidcodepos const& exp) -> void;
|
||||
auto dump_asm_dev(asm_dev const& exp) -> void;
|
||||
};
|
||||
|
||||
} // namespace xsk::arc
|
||||
|
@ -6,7 +6,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "xsk/utils/writer.hpp"
|
||||
#include "common/types.hpp"
|
||||
#include "xsk/gsc/common/types.hpp"
|
||||
|
||||
namespace xsk::gsc
|
||||
{
|
||||
|
@ -228,6 +228,11 @@ struct instruction
|
||||
u32 size;
|
||||
opcode opcode;
|
||||
std::vector<std::string> data;
|
||||
|
||||
static auto make() -> instruction::ptr
|
||||
{
|
||||
return std::unique_ptr<instruction>(new instruction);
|
||||
}
|
||||
};
|
||||
|
||||
struct function
|
||||
@ -240,6 +245,11 @@ struct function
|
||||
std::string name;
|
||||
std::vector<instruction::ptr> instructions;
|
||||
std::unordered_map<u32, std::string> labels;
|
||||
|
||||
static auto make() -> function::ptr
|
||||
{
|
||||
return std::unique_ptr<function>(new function);
|
||||
}
|
||||
};
|
||||
|
||||
struct assembly
|
||||
@ -247,21 +257,11 @@ struct assembly
|
||||
using ptr = std::unique_ptr<assembly>;
|
||||
|
||||
std::vector<function::ptr> functions;
|
||||
|
||||
static auto make() -> assembly::ptr
|
||||
{
|
||||
return std::unique_ptr<assembly>(new assembly);
|
||||
}
|
||||
};
|
||||
|
||||
inline auto make_instruction() -> std::unique_ptr<instruction>
|
||||
{
|
||||
return std::unique_ptr<instruction>(new instruction);
|
||||
}
|
||||
|
||||
inline auto make_function() -> std::unique_ptr<function>
|
||||
{
|
||||
return std::unique_ptr<function>(new function);
|
||||
}
|
||||
|
||||
inline auto make_assembly() -> std::unique_ptr<assembly>
|
||||
{
|
||||
return std::unique_ptr<assembly>(new assembly);
|
||||
}
|
||||
|
||||
} // namespace xsk::gsc
|
||||
|
@ -5,18 +5,18 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "asset.hpp"
|
||||
#include "scope.hpp"
|
||||
#include "buffer.hpp"
|
||||
#include "assembly.hpp"
|
||||
#include "location.hpp"
|
||||
#include "exception.hpp"
|
||||
#include "lookahead.hpp"
|
||||
#include "directive.hpp"
|
||||
#include "space.hpp"
|
||||
#include "token.hpp"
|
||||
#include "define.hpp"
|
||||
#include "ast.hpp"
|
||||
#include "xsk/gsc/common/asset.hpp"
|
||||
#include "xsk/gsc/common/scope.hpp"
|
||||
#include "xsk/gsc/common/buffer.hpp"
|
||||
#include "xsk/gsc/common/assembly.hpp"
|
||||
#include "xsk/gsc/common/location.hpp"
|
||||
#include "xsk/gsc/common/exception.hpp"
|
||||
#include "xsk/gsc/common/lookahead.hpp"
|
||||
#include "xsk/gsc/common/directive.hpp"
|
||||
#include "xsk/gsc/common/space.hpp"
|
||||
#include "xsk/gsc/common/token.hpp"
|
||||
#include "xsk/gsc/common/define.hpp"
|
||||
#include "xsk/gsc/common/ast.hpp"
|
||||
|
||||
namespace xsk::gsc
|
||||
{
|
||||
|
@ -5,7 +5,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common/types.hpp"
|
||||
#include "xsk/gsc/common/types.hpp"
|
||||
|
||||
namespace xsk::gsc
|
||||
{
|
||||
@ -15,8 +15,8 @@ class compiler
|
||||
context* ctx_;
|
||||
assembly::ptr assembly_;
|
||||
function::ptr function_;
|
||||
std::vector<std::string> stackframe_;
|
||||
std::vector<std::string> localfuncs_;
|
||||
std::vector<std::string> stackframe_;
|
||||
std::unordered_map<std::string, expr const*> constants_;
|
||||
std::unordered_map<node*, scope::ptr> scopes_;
|
||||
std::vector<scope*> break_blks_;
|
||||
|
@ -5,12 +5,12 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common/types.hpp"
|
||||
#include "source.hpp"
|
||||
#include "assembler.hpp"
|
||||
#include "disassembler.hpp"
|
||||
#include "compiler.hpp"
|
||||
#include "decompiler.hpp"
|
||||
#include "xsk/gsc/common/types.hpp"
|
||||
#include "xsk/gsc/source.hpp"
|
||||
#include "xsk/gsc/assembler.hpp"
|
||||
#include "xsk/gsc/disassembler.hpp"
|
||||
#include "xsk/gsc/compiler.hpp"
|
||||
#include "xsk/gsc/decompiler.hpp"
|
||||
|
||||
namespace xsk::gsc
|
||||
{
|
||||
|
@ -5,7 +5,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common/types.hpp"
|
||||
#include "xsk/gsc/common/types.hpp"
|
||||
|
||||
namespace xsk::gsc
|
||||
{
|
||||
|
@ -6,7 +6,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "xsk/utils/reader.hpp"
|
||||
#include "common/types.hpp"
|
||||
#include "xsk/gsc/common/types.hpp"
|
||||
|
||||
namespace xsk::gsc
|
||||
{
|
||||
|
@ -5,7 +5,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common/types.hpp"
|
||||
#include "xsk/gsc/common/types.hpp"
|
||||
|
||||
namespace xsk::gsc
|
||||
{
|
||||
|
@ -5,8 +5,8 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common/types.hpp"
|
||||
#include "lexer.hpp"
|
||||
#include "xsk/gsc/common/types.hpp"
|
||||
#include "xsk/gsc/lexer.hpp"
|
||||
|
||||
namespace xsk::gsc
|
||||
{
|
||||
|
@ -5,7 +5,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common/types.hpp"
|
||||
#include "xsk/gsc/common/types.hpp"
|
||||
|
||||
namespace xsk::gsc
|
||||
{
|
||||
|
@ -62,4 +62,4 @@ using i64 = std::int64_t;
|
||||
using f32 = float;
|
||||
using f64 = double;
|
||||
|
||||
};
|
||||
} // namespace xsk
|
||||
|
@ -1,47 +0,0 @@
|
||||
// Copyright 2023 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 assembler : public arc::assembler
|
||||
{
|
||||
std::string filename_;
|
||||
utils::writer::ptr script_;
|
||||
assembly::ptr assembly_;
|
||||
std::unordered_map<std::uint32_t, std::string> labels_;
|
||||
std::unordered_map<std::string, std::uint16_t> stringlist_;
|
||||
std::vector<export_ref> exports_;
|
||||
std::vector<import_ref> imports_;
|
||||
std::vector<animtree_ref> animtrees_;
|
||||
std::vector<string_ref> stringtables_;
|
||||
header header_;
|
||||
|
||||
public:
|
||||
auto output() -> std::vector<std::uint8_t>;
|
||||
void assemble(const std::string& file, std::vector<std::uint8_t>& data);
|
||||
void assemble(const std::string& file, assembly::ptr& data);
|
||||
|
||||
private:
|
||||
void assemble_function(const function::ptr& func);
|
||||
void assemble_instruction(const instruction::ptr& inst);
|
||||
void assemble_localvars(const instruction::ptr& inst);
|
||||
void assemble_jump(const instruction::ptr& inst);
|
||||
void assemble_switch(const instruction::ptr& inst);
|
||||
void assemble_end_switch(const instruction::ptr& inst);
|
||||
void process_string(const std::string& data);
|
||||
void process_function(const function::ptr& func);
|
||||
void process_instruction(const instruction::ptr& inst);
|
||||
void align_instruction(const instruction::ptr& inst);
|
||||
auto resolve_label(const std::string& name) -> std::int32_t;
|
||||
auto string_offset(const std::string& data) -> std::uint16_t;
|
||||
void add_string_reference(const std::string& str, string_type type, std::uint32_t ref);
|
||||
void add_import_reference(const std::vector<std::string>& data, std::uint32_t ref);
|
||||
void add_anim_reference(const std::vector<std::string>& data, std::uint32_t ref);
|
||||
};
|
||||
|
||||
} // namespace xsk::arc::t6
|
@ -1,18 +0,0 @@
|
||||
// Copyright 2023 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 "location.hpp"
|
||||
#include "types.hpp"
|
||||
#include "block.hpp"
|
||||
#include "nodetree.hpp"
|
||||
|
||||
#include "interfaces/exception.hpp"
|
||||
#include "interfaces/assembler.hpp"
|
||||
#include "interfaces/disassembler.hpp"
|
||||
#include "interfaces/compiler.hpp"
|
||||
#include "interfaces/decompiler.hpp"
|
||||
#include "interfaces/context.hpp"
|
@ -1,25 +0,0 @@
|
||||
// Copyright 2023 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() : abort(abort_t::abort_none), is_dev(false) {}
|
||||
block(const std::string& lbreak, const std::string& lcont) : loc_break(lbreak), loc_continue(lcont), abort(abort_t::abort_none), is_dev(false) {}
|
||||
};
|
||||
|
||||
} // namespace xsk::arc
|
@ -1,22 +0,0 @@
|
||||
// Copyright 2023 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
|
@ -1,22 +0,0 @@
|
||||
// Copyright 2023 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_raw() -> std::vector<std::uint8_t> = 0;
|
||||
virtual void compile(const std::string& file, std::vector<std::uint8_t>& data) = 0;
|
||||
};
|
||||
|
||||
} // namespace xsk::arc
|
@ -1,26 +0,0 @@
|
||||
// Copyright 2023 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
|
@ -1,21 +0,0 @@
|
||||
// Copyright 2023 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
|
@ -1,22 +0,0 @@
|
||||
// Copyright 2023 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_raw() -> std::vector<std::uint8_t> = 0;
|
||||
virtual void disassemble(const std::string& file, std::vector<std::uint8_t>& data) = 0;
|
||||
};
|
||||
|
||||
} // namespace xsk::arc
|
@ -1,46 +0,0 @@
|
||||
// Copyright 2023 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
|
@ -1,229 +0,0 @@
|
||||
// Copyright 2023 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 fmt::format("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
@ -1,181 +0,0 @@
|
||||
// Copyright 2023 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
|
||||
{
|
||||
|
||||
using read_cb_type = std::function<std::vector<std::uint8_t>(const std::string&)>;
|
||||
|
||||
enum class build
|
||||
{
|
||||
prod,
|
||||
dev,
|
||||
};
|
||||
|
||||
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
|
||||
{
|
||||
export_none = 0x00,
|
||||
export_public = 0x01,
|
||||
export_autoexec = 0x02,
|
||||
export_private = 0x04,
|
||||
export_codecall = 0x08,
|
||||
export_private2 = 0x10,
|
||||
export_varargs = 0x20,
|
||||
};
|
||||
|
||||
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
|
@ -1,164 +0,0 @@
|
||||
// Copyright 2023 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
|
||||
{
|
||||
|
||||
enum class opcode : std::uint8_t;
|
||||
|
||||
class compiler : public arc::compiler
|
||||
{
|
||||
std::string filename_;
|
||||
assembly::ptr assembly_;
|
||||
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<std::string> animtrees_;
|
||||
std::unordered_map<std::string, ast::expr> constants_;
|
||||
std::vector<block> blocks_;
|
||||
bool can_break_;
|
||||
bool can_continue_;
|
||||
bool developer_thread_;
|
||||
build mode_;
|
||||
utils::writer::ptr output_;
|
||||
|
||||
public:
|
||||
auto output() -> assembly::ptr;
|
||||
auto output_raw() -> std::vector<std::uint8_t>;
|
||||
void compile(const std::string& file, std::vector<std::uint8_t>& data);
|
||||
void mode(build mode);
|
||||
|
||||
private:
|
||||
auto parse_buffer(const std::string& file, const 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);
|
||||
void emit_declaration(const ast::decl& decl);
|
||||
void emit_decl_usingtree(const ast::decl_usingtree::ptr& animtree);
|
||||
void emit_decl_thread(const ast::decl_thread::ptr& thread);
|
||||
void emit_stmt(const ast::stmt& stmt);
|
||||
void emit_stmt_list(const ast::stmt_list::ptr& stmt);
|
||||
void emit_stmt_dev(const ast::stmt_dev::ptr& stmt);
|
||||
void emit_stmt_expr(const ast::stmt_expr::ptr& stmt);
|
||||
void emit_stmt_call(const ast::stmt_call::ptr& stmt);
|
||||
void emit_stmt_const(const ast::stmt_const::ptr& stmt);
|
||||
void emit_stmt_assign(const ast::stmt_assign::ptr& stmt);
|
||||
void emit_stmt_endon(const ast::stmt_endon::ptr& stmt);
|
||||
void emit_stmt_notify(const ast::stmt_notify::ptr& stmt);
|
||||
void emit_stmt_wait(const ast::stmt_wait::ptr& stmt);
|
||||
void emit_stmt_waittill(const ast::stmt_waittill::ptr& stmt);
|
||||
void emit_stmt_waittillmatch(const ast::stmt_waittillmatch::ptr& stmt);
|
||||
void emit_stmt_waittillframeend(const ast::stmt_waittillframeend::ptr& stmt);
|
||||
void emit_stmt_if(const ast::stmt_if::ptr& stmt);
|
||||
void emit_stmt_ifelse(const ast::stmt_ifelse::ptr& stmt);
|
||||
void emit_stmt_while(const ast::stmt_while::ptr& stmt);
|
||||
void emit_stmt_dowhile(const ast::stmt_dowhile::ptr& stmt);
|
||||
void emit_stmt_for(const ast::stmt_for::ptr& stmt);
|
||||
void emit_stmt_foreach(const ast::stmt_foreach::ptr& stmt);
|
||||
void emit_stmt_switch(const ast::stmt_switch::ptr& stmt);
|
||||
void emit_stmt_case(const ast::stmt_case::ptr& stmt);
|
||||
void emit_stmt_default(const ast::stmt_default::ptr& stmt);
|
||||
void emit_stmt_break(const ast::stmt_break::ptr& stmt);
|
||||
void emit_stmt_continue(const ast::stmt_continue::ptr& stmt);
|
||||
void emit_stmt_return(const ast::stmt_return::ptr& stmt);
|
||||
void emit_stmt_prof_begin(const ast::stmt_prof_begin::ptr& stmt);
|
||||
void emit_stmt_prof_end(const ast::stmt_prof_end::ptr& stmt);
|
||||
void emit_expr(const ast::expr& expr);
|
||||
void emit_expr_assign(const ast::expr_assign::ptr& expr);
|
||||
void emit_expr_clear(const ast::expr& expr);
|
||||
void emit_expr_increment(const ast::expr_increment::ptr& expr, bool is_stmt);
|
||||
void emit_expr_decrement(const ast::expr_decrement::ptr& expr, bool is_stmt);
|
||||
void emit_expr_ternary(const ast::expr_ternary::ptr& expr);
|
||||
void emit_expr_binary(const ast::expr_binary::ptr& expr);
|
||||
void emit_expr_and(const ast::expr_and::ptr& expr);
|
||||
void emit_expr_or(const ast::expr_or::ptr& expr);
|
||||
void emit_expr_complement(const ast::expr_complement::ptr& expr);
|
||||
void emit_expr_negate(const ast::expr_negate::ptr& expr);
|
||||
void emit_expr_not(const ast::expr_not::ptr& expr);
|
||||
void emit_expr_call(const ast::expr_call::ptr& expr, bool is_stmt);
|
||||
void emit_expr_call_pointer(const ast::expr_pointer::ptr& expr, bool is_stmt);
|
||||
void emit_expr_call_function(const ast::expr_function::ptr& expr, bool is_stmt);
|
||||
void emit_expr_method(const ast::expr_method::ptr& expr, bool is_stmt);
|
||||
void emit_expr_method_pointer(const ast::expr_pointer::ptr& expr, const ast::expr& obj, bool is_stmt);
|
||||
void emit_expr_method_function(const ast::expr_function::ptr& expr, const ast::expr& obj, bool is_stmt);
|
||||
void emit_expr_parameters(const ast::expr_parameters::ptr& expr);
|
||||
void emit_expr_arguments(const ast::expr_arguments::ptr& expr);
|
||||
void emit_expr_isdefined(const ast::expr_isdefined::ptr& expr);
|
||||
void emit_expr_vectorscale(const ast::expr_vectorscale::ptr& expr);
|
||||
void emit_expr_anglestoup(const ast::expr_anglestoup::ptr& expr);
|
||||
void emit_expr_anglestoright(const ast::expr_anglestoright::ptr& expr);
|
||||
void emit_expr_anglestoforward(const ast::expr_anglestoforward::ptr& expr);
|
||||
void emit_expr_angleclamp180(const ast::expr_angleclamp180::ptr& expr);
|
||||
void emit_expr_vectortoangles(const ast::expr_vectortoangles::ptr& expr);
|
||||
void emit_expr_abs(const ast::expr_abs::ptr& expr);
|
||||
void emit_expr_gettime(const ast::expr_gettime::ptr& expr);
|
||||
void emit_expr_getdvar(const ast::expr_getdvar::ptr& expr);
|
||||
void emit_expr_getdvarint(const ast::expr_getdvarint::ptr& expr);
|
||||
void emit_expr_getdvarfloat(const ast::expr_getdvarfloat::ptr& expr);
|
||||
void emit_expr_getdvarvector(const ast::expr_getdvarvector::ptr& expr);
|
||||
void emit_expr_getdvarcolorred(const ast::expr_getdvarcolorred::ptr& expr);
|
||||
void emit_expr_getdvarcolorgreen(const ast::expr_getdvarcolorgreen::ptr& expr);
|
||||
void emit_expr_getdvarcolorblue(const ast::expr_getdvarcolorblue::ptr& expr);
|
||||
void emit_expr_getdvarcoloralpha(const ast::expr_getdvarcoloralpha::ptr& expr);
|
||||
void emit_expr_getfirstarraykey(const ast::expr_getfirstarraykey::ptr& expr);
|
||||
void emit_expr_getnextarraykey(const ast::expr_getnextarraykey::ptr& expr);
|
||||
void emit_expr_reference(const ast::expr_reference::ptr& expr);
|
||||
void emit_expr_size(const ast::expr_size::ptr& expr);
|
||||
void emit_expr_variable_ref(const ast::expr& expr, bool set);
|
||||
void emit_expr_array_ref(const ast::expr_array::ptr& expr, bool set);
|
||||
void emit_expr_field_ref(const ast::expr_field::ptr& expr, bool set);
|
||||
void emit_expr_local_ref(const ast::expr_identifier::ptr& expr, bool set);
|
||||
void emit_expr_variable(const ast::expr& expr);
|
||||
void emit_expr_array(const ast::expr_array::ptr& expr);
|
||||
void emit_expr_field(const ast::expr_field::ptr& expr);
|
||||
void emit_expr_local(const ast::expr_identifier::ptr& expr);
|
||||
void emit_expr_object(const ast::expr& expr);
|
||||
void emit_expr_vector(const ast::expr_vector::ptr& expr);
|
||||
void emit_expr_animation(const ast::expr_animation::ptr& expr);
|
||||
void emit_expr_animtree(const ast::expr_animtree::ptr& expr);
|
||||
void emit_expr_istring(const ast::expr_istring::ptr& expr);
|
||||
void emit_expr_string(const ast::expr_string::ptr& expr);
|
||||
void emit_expr_hash(const ast::expr_hash::ptr& expr);
|
||||
void emit_expr_float(const ast::expr_float::ptr& expr);
|
||||
void emit_expr_integer(const ast::expr_integer::ptr& expr);
|
||||
void emit_expr_false(const ast::expr_false::ptr& expr);
|
||||
void emit_expr_true(const ast::expr_true::ptr& expr);
|
||||
void emit_opcode(opcode op);
|
||||
void emit_opcode(opcode op, const std::string& data);
|
||||
void emit_opcode(opcode op, const std::vector<std::string>& data);
|
||||
void process_thread(const ast::decl_thread::ptr& decl);
|
||||
void process_stmt(const ast::stmt& stmt);
|
||||
void process_stmt_list(const ast::stmt_list::ptr& stmt);
|
||||
void process_stmt_dev(const ast::stmt_dev::ptr& stmt);
|
||||
void process_stmt_expr(const ast::stmt_expr::ptr& stmt);
|
||||
void process_stmt_assign(const ast::stmt_assign::ptr& stmt);
|
||||
void process_stmt_waittill(const ast::stmt_waittill::ptr& stmt);
|
||||
void process_stmt_if(const ast::stmt_if::ptr& stmt);
|
||||
void process_stmt_ifelse(const ast::stmt_ifelse::ptr& stmt);
|
||||
void process_stmt_while(const ast::stmt_while::ptr& stmt);
|
||||
void process_stmt_dowhile(const ast::stmt_dowhile::ptr& stmt);
|
||||
void process_stmt_for(const ast::stmt_for::ptr& stmt);
|
||||
void process_stmt_foreach(const ast::stmt_foreach::ptr& stmt);
|
||||
void process_stmt_switch(const ast::stmt_switch::ptr& stmt);
|
||||
void process_expr(const ast::expr& expr);
|
||||
void process_expr_parameters(const ast::expr_parameters::ptr& expr);
|
||||
void variable_register(const std::string& name);
|
||||
auto variable_access(const ast::expr_identifier::ptr& name) -> std::string;
|
||||
auto is_constant_condition(const ast::expr& 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;
|
||||
void print_function(const function::ptr& func);
|
||||
void print_instruction(const instruction::ptr& inst);
|
||||
};
|
||||
|
||||
} // namespace xsk::arc::t6
|
@ -1,28 +0,0 @@
|
||||
// Copyright 2023 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
|
@ -1,100 +0,0 @@
|
||||
// Copyright 2023 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 decompiler : public arc::decompiler
|
||||
{
|
||||
std::string filename_;
|
||||
ast::program::ptr program_;
|
||||
ast::decl_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<ast::node::ptr> stack_;
|
||||
std::vector<std::string> locals_;
|
||||
std::vector<block> blocks_;
|
||||
bool in_waittill_;
|
||||
bool retbool_;
|
||||
int retnum_;
|
||||
|
||||
public:
|
||||
auto output() -> std::vector<std::uint8_t>;
|
||||
void decompile(const std::string& file, const assembly::ptr& data);
|
||||
|
||||
private:
|
||||
void decompile_function(const function::ptr& func);
|
||||
void decompile_instruction(const instruction::ptr& inst, bool last);
|
||||
void decompile_expressions(const instruction::ptr& inst);
|
||||
void decompile_statements(const ast::stmt_list::ptr& stmt);
|
||||
void decompile_infinites(const ast::stmt_list::ptr& stmt);
|
||||
void decompile_loops(const ast::stmt_list::ptr& stmt);
|
||||
void decompile_switches(const ast::stmt_list::ptr& stmt);
|
||||
void decompile_ifelses(const ast::stmt_list::ptr& stmt);
|
||||
void decompile_aborts(const ast::stmt_list::ptr& stmt);
|
||||
void decompile_devblocks(const ast::stmt_list::ptr& stmt);
|
||||
void decompile_if(const ast::stmt_list::ptr& stmt, std::size_t begin, std::size_t end);
|
||||
void decompile_ifelse(const ast::stmt_list::ptr& stmt, std::size_t begin, std::size_t end);
|
||||
void decompile_inf(const ast::stmt_list::ptr& stmt, std::size_t begin, std::size_t end);
|
||||
void decompile_loop(const ast::stmt_list::ptr& stmt, std::size_t begin, std::size_t end);
|
||||
void decompile_while(const ast::stmt_list::ptr& stmt, std::size_t begin, std::size_t end);
|
||||
void decompile_dowhile(const ast::stmt_list::ptr& stmt, std::size_t begin, std::size_t end);
|
||||
void decompile_for(const ast::stmt_list::ptr& stmt, std::size_t begin, std::size_t end);
|
||||
void decompile_foreach(const ast::stmt_list::ptr& stmt, std::size_t begin, std::size_t end);
|
||||
void decompile_switch(const ast::stmt_list::ptr& stmt, std::size_t begin);
|
||||
auto find_location_reference(const ast::stmt_list::ptr& stmt, std::size_t begin, std::size_t end, const std::string& location) -> bool;
|
||||
auto find_location_index(const ast::stmt_list::ptr& stmt, const std::string& location) -> std::size_t;
|
||||
auto last_location_index(const ast::stmt_list::ptr& stmt, std::size_t index) -> bool;
|
||||
auto lvalues_match(const ast::stmt_assign::ptr& stmt1, const ast::stmt_assign::ptr& stmt2) -> bool;
|
||||
auto resolve_label(const std::string& name) -> std::uint32_t;
|
||||
void process_thread(const ast::decl_thread::ptr& thread);
|
||||
void process_stmt(const ast::stmt& stmt);
|
||||
void process_stmt_list(const ast::stmt_list::ptr& stmt);
|
||||
void process_stmt_dev(const ast::stmt_dev::ptr& stmt);
|
||||
void process_stmt_expr(const ast::stmt_expr::ptr& stmt);
|
||||
void process_stmt_call(const ast::stmt_call::ptr& stmt);
|
||||
void process_stmt_assign(const ast::stmt_assign::ptr& stmt);
|
||||
void process_stmt_endon(const ast::stmt_endon::ptr& stmt);
|
||||
void process_stmt_notify(const ast::stmt_notify::ptr& stmt);
|
||||
void process_stmt_wait(const ast::stmt_wait::ptr& stmt);
|
||||
void process_stmt_waittill(const ast::stmt_waittill::ptr& stmt);
|
||||
void process_stmt_waittillmatch(const ast::stmt_waittillmatch::ptr& stmt);
|
||||
void process_stmt_if(const ast::stmt_if::ptr& stmt);
|
||||
void process_stmt_ifelse(const ast::stmt_ifelse::ptr& stmt);
|
||||
void process_stmt_while(const ast::stmt_while::ptr& stmt);
|
||||
void process_stmt_dowhile(const ast::stmt_dowhile::ptr& stmt);
|
||||
void process_stmt_for(const ast::stmt_for::ptr& stmt);
|
||||
void process_stmt_foreach(const ast::stmt_foreach::ptr& stmt);
|
||||
void process_stmt_switch(const ast::stmt_switch::ptr& stmt);
|
||||
void process_stmt_cases(const ast::stmt_list::ptr& stmt);
|
||||
void process_stmt_return(const ast::stmt_return::ptr& stmt);
|
||||
void process_expr(const ast::expr& expr);
|
||||
void process_expr_assign(ast::expr_assign::ptr& expr);
|
||||
void process_expr_increment(const ast::expr_increment::ptr& expr);
|
||||
void process_expr_decrement(const ast::expr_decrement::ptr& expr);
|
||||
void process_expr_ternary(const ast::expr_ternary::ptr& expr);
|
||||
void process_expr_binary(const ast::expr_binary::ptr& expr);
|
||||
void process_expr_and(const ast::expr_and::ptr& expr);
|
||||
void process_expr_or(const ast::expr_or::ptr& expr);
|
||||
void process_expr_complement(const ast::expr_complement::ptr& expr);
|
||||
void process_expr_not(const ast::expr_not::ptr& expr);
|
||||
void process_expr_call(const ast::expr_call::ptr& expr);
|
||||
void process_expr_method(const ast::expr_method::ptr& expr);
|
||||
void process_expr_call_pointer(const ast::expr_pointer::ptr& expr);
|
||||
void process_expr_call_function(const ast::expr_function::ptr& expr);
|
||||
void process_expr_method_pointer(const ast::expr_pointer::ptr& expr, ast::expr& obj);
|
||||
void process_expr_method_function(const ast::expr_function::ptr& expr, ast::expr& obj);
|
||||
void process_expr_arguments(const ast::expr_arguments::ptr& expr);
|
||||
void process_expr_size(const ast::expr_size::ptr& expr);
|
||||
void process_array_variable(const ast::expr_array::ptr& expr);
|
||||
void process_field_variable(const ast::expr_field::ptr& expr);
|
||||
void process_expr_vector(const ast::expr_vector::ptr& expr);
|
||||
void process_expr_parameters(const ast::expr_parameters::ptr& expr);
|
||||
};
|
||||
|
||||
} // namespace xsk::arc::t6
|
@ -1,48 +0,0 @@
|
||||
// Copyright 2023 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 disassembler : public arc::disassembler
|
||||
{
|
||||
std::string filename_;
|
||||
utils::reader::ptr script_;
|
||||
utils::writer::ptr output_;
|
||||
assembly::ptr assembly_;
|
||||
std::vector<export_ref::ptr> exports_;
|
||||
std::vector<import_ref::ptr> imports_;
|
||||
std::vector<string_ref::ptr> strings_;
|
||||
std::vector<animtree_ref::ptr> animtrees_;
|
||||
std::map<std::uint32_t, std::string> stringlist_;
|
||||
std::map<std::uint32_t, import_ref::ptr> import_refs_;
|
||||
std::map<std::uint32_t, string_ref::ptr> string_refs_;
|
||||
std::map<std::uint32_t, animtree_ref::ptr> anim_refs_;
|
||||
std::unordered_map<std::uint32_t, std::string> labels_;
|
||||
header header_;
|
||||
|
||||
public:
|
||||
auto output() -> assembly::ptr;
|
||||
auto output_raw() -> std::vector<std::uint8_t>;
|
||||
void disassemble(const std::string& file, std::vector<std::uint8_t>& data);
|
||||
|
||||
private:
|
||||
void disassemble_function(const function::ptr& func);
|
||||
void disassemble_instruction(const instruction::ptr& inst);
|
||||
void disassemble_string(const instruction::ptr& inst);
|
||||
void disassemble_animtree(const instruction::ptr& inst);
|
||||
void disassemble_animation(const instruction::ptr& inst);
|
||||
void disassemble_localvars(const instruction::ptr& inst);
|
||||
void disassemble_import(const instruction::ptr& inst);
|
||||
void disassemble_jump(const instruction::ptr& inst);
|
||||
void disassemble_switch(const instruction::ptr& inst);
|
||||
void disassemble_end_switch(const instruction::ptr& inst);
|
||||
void print_function(const function::ptr& func);
|
||||
void print_instruction(const instruction::ptr& inst);
|
||||
};
|
||||
|
||||
} // namespace xsk::arc::t6
|
@ -1,78 +0,0 @@
|
||||
// Copyright 2023 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
|
||||
{
|
||||
|
||||
constexpr size_t max_buf_size = 0x2000;
|
||||
|
||||
struct buffer
|
||||
{
|
||||
char* data;
|
||||
size_t length;
|
||||
|
||||
buffer();
|
||||
~buffer();
|
||||
bool push(char c);
|
||||
};
|
||||
|
||||
struct reader
|
||||
{
|
||||
enum state_type : std::uint8_t { end, ok };
|
||||
|
||||
const char* buffer_pos;
|
||||
std::uint32_t bytes_remaining;
|
||||
char last_byte;
|
||||
char current_byte;
|
||||
state_type state;
|
||||
|
||||
reader();
|
||||
|
||||
reader(const reader& obj)
|
||||
{
|
||||
std::memcpy(this, &obj, sizeof(reader));
|
||||
}
|
||||
|
||||
reader& operator=(const reader& obj)
|
||||
{
|
||||
std::memcpy(this, &obj, sizeof(reader));
|
||||
return *this;
|
||||
}
|
||||
|
||||
void init(const char* data, size_t size);
|
||||
void advance();
|
||||
};
|
||||
|
||||
class lexer
|
||||
{
|
||||
enum class state : std::uint8_t { start, string, localize, preprocessor };
|
||||
|
||||
reader reader_;
|
||||
buffer buffer_;
|
||||
location loc_;
|
||||
std::stack<location> locs_;
|
||||
std::stack<reader> readers_;
|
||||
std::uint32_t header_top_;
|
||||
state state_;
|
||||
build mode_;
|
||||
bool indev_;
|
||||
bool clean_;
|
||||
|
||||
public:
|
||||
lexer(build mode, const std::string& name, const char* data, size_t size);
|
||||
auto lex() -> parser::symbol_type;
|
||||
void push_header(const std::string& file);
|
||||
void pop_header();
|
||||
void ban_header(const location& loc);
|
||||
|
||||
private:
|
||||
void advance();
|
||||
void preprocessor_wrap();
|
||||
void preprocessor_run(parser::token::token_kind_type token);
|
||||
};
|
||||
|
||||
} // namespace xsk::arc::t6
|
@ -1,25 +0,0 @@
|
||||
// Copyright 2023 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 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;
|
||||
|
||||
static auto make_token(std::string_view str) -> std::string;
|
||||
static auto file_data(const std::string& name) -> std::tuple<const std::string*, const char*, size_t>;
|
||||
static auto fs_to_game_path(const std::filesystem::path& file) -> std::filesystem::path;
|
||||
};
|
||||
|
||||
} // namespace xsk::arc::t6
|
@ -1,157 +0,0 @@
|
||||
// Copyright 2023 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 "xsk/stdinc.hpp"
|
||||
#include "xsk/utils/string.hpp"
|
||||
#include "xsk/utils/reader.hpp"
|
||||
#include "xsk/utils/writer.hpp"
|
||||
#include "common/arc.hpp"
|
||||
#include "assembler.hpp"
|
||||
#include "disassembler.hpp"
|
||||
#include "compiler.hpp"
|
||||
#include "decompiler.hpp"
|
||||
#include "resolver.hpp"
|
||||
#include "context.hpp"
|
||||
|
||||
namespace xsk::arc::t6
|
||||
{
|
||||
|
||||
constexpr std::uint64_t magic = 0x06000A0D43534780;
|
||||
|
||||
enum class opcode : std::uint8_t
|
||||
{
|
||||
OP_End = 0x0,
|
||||
OP_Return = 0x1,
|
||||
OP_GetUndefined = 0x2,
|
||||
OP_GetZero = 0x3,
|
||||
OP_GetByte = 0x4,
|
||||
OP_GetNegByte = 0x5,
|
||||
OP_GetUnsignedShort = 0x6,
|
||||
OP_GetNegUnsignedShort = 0x7,
|
||||
OP_GetInteger = 0x8,
|
||||
OP_GetFloat = 0x9,
|
||||
OP_GetString = 0xA,
|
||||
OP_GetIString = 0xB,
|
||||
OP_GetVector = 0xC,
|
||||
OP_GetLevelObject = 0xD,
|
||||
OP_GetAnimObject = 0xE,
|
||||
OP_GetSelf = 0xF,
|
||||
OP_GetLevel = 0x10,
|
||||
OP_GetGame = 0x11,
|
||||
OP_GetAnim = 0x12,
|
||||
OP_GetAnimation = 0x13,
|
||||
OP_GetGameRef = 0x14,
|
||||
OP_GetFunction = 0x15,
|
||||
OP_CreateLocalVariable = 0x16,
|
||||
OP_SafeCreateLocalVariables = 0x17,
|
||||
OP_RemoveLocalVariables = 0x18,
|
||||
OP_EvalLocalVariableCached = 0x19,
|
||||
OP_EvalArray = 0x1A,
|
||||
OP_EvalLocalArrayRefCached = 0x1B,
|
||||
OP_EvalArrayRef = 0x1C,
|
||||
OP_ClearArray = 0x1D,
|
||||
OP_EmptyArray = 0x1E,
|
||||
OP_GetSelfObject = 0x1F,
|
||||
OP_EvalFieldVariable = 0x20,
|
||||
OP_EvalFieldVariableRef = 0x21,
|
||||
OP_ClearFieldVariable = 0x22,
|
||||
OP_SafeSetVariableFieldCached = 0x23,
|
||||
OP_SafeSetWaittillVariableFieldCached = 0x24,
|
||||
OP_ClearParams = 0x25,
|
||||
OP_CheckClearParams = 0x26,
|
||||
OP_EvalLocalVariableRefCached = 0x27,
|
||||
OP_SetVariableField = 0x28,
|
||||
OP_CallBuiltin = 0x29,
|
||||
OP_CallBuiltinMethod = 0x2A,
|
||||
OP_Wait = 0x2B,
|
||||
OP_WaitTillFrameEnd = 0x2C,
|
||||
OP_PreScriptCall = 0x2D,
|
||||
OP_ScriptFunctionCall = 0x2E,
|
||||
OP_ScriptFunctionCallPointer = 0x2F,
|
||||
OP_ScriptMethodCall = 0x30,
|
||||
OP_ScriptMethodCallPointer = 0x31,
|
||||
OP_ScriptThreadCall = 0x32,
|
||||
OP_ScriptThreadCallPointer = 0x33,
|
||||
OP_ScriptMethodThreadCall = 0x34,
|
||||
OP_ScriptMethodThreadCallPointer = 0x35,
|
||||
OP_DecTop = 0x36,
|
||||
OP_CastFieldObject = 0x37,
|
||||
OP_CastBool = 0x38,
|
||||
OP_BoolNot = 0x39,
|
||||
OP_BoolComplement = 0x3A,
|
||||
OP_JumpOnFalse = 0x3B,
|
||||
OP_JumpOnTrue = 0x3C,
|
||||
OP_JumpOnFalseExpr = 0x3D,
|
||||
OP_JumpOnTrueExpr = 0x3E,
|
||||
OP_Jump = 0x3F,
|
||||
OP_JumpBack = 0x40,
|
||||
OP_Inc = 0x41,
|
||||
OP_Dec = 0x42,
|
||||
OP_Bit_Or = 0x43,
|
||||
OP_Bit_Xor = 0x44,
|
||||
OP_Bit_And = 0x45,
|
||||
OP_Equal = 0x46,
|
||||
OP_NotEqual = 0x47,
|
||||
OP_LessThan = 0x48,
|
||||
OP_GreaterThan = 0x49,
|
||||
OP_LessThanOrEqualTo = 0x4A,
|
||||
OP_GreaterThanOrEqualTo = 0x4B,
|
||||
OP_ShiftLeft = 0x4C,
|
||||
OP_ShiftRight = 0x4D,
|
||||
OP_Plus = 0x4E,
|
||||
OP_Minus = 0x4F,
|
||||
OP_Multiply = 0x50,
|
||||
OP_Divide = 0x51,
|
||||
OP_Modulus = 0x52,
|
||||
OP_SizeOf = 0x53,
|
||||
OP_WaitTillMatch = 0x54,
|
||||
OP_WaitTill = 0x55,
|
||||
OP_Notify = 0x56,
|
||||
OP_EndOn = 0x57,
|
||||
OP_VoidCodePos = 0x58,
|
||||
OP_Switch = 0x59,
|
||||
OP_EndSwitch = 0x5A,
|
||||
OP_Vector = 0x5B,
|
||||
OP_GetHash = 0x5C,
|
||||
OP_RealWait = 0x5D,
|
||||
OP_VectorConstant = 0x5E,
|
||||
OP_IsDefined = 0x5F,
|
||||
OP_VectorScale = 0x60,
|
||||
OP_AnglesToUp = 0x61,
|
||||
OP_AnglesToRight = 0x62,
|
||||
OP_AnglesToForward = 0x63,
|
||||
OP_AngleClamp180 = 0x64,
|
||||
OP_VectorToAngles = 0x65,
|
||||
OP_Abs = 0x66,
|
||||
OP_GetTime = 0x67,
|
||||
OP_GetDvar = 0x68,
|
||||
OP_GetDvarInt = 0x69,
|
||||
OP_GetDvarFloat = 0x6A,
|
||||
OP_GetDvarVector = 0x6B,
|
||||
OP_GetDvarColorRed = 0x6C,
|
||||
OP_GetDvarColorGreen = 0x6D,
|
||||
OP_GetDvarColorBlue = 0x6E,
|
||||
OP_GetDvarColorAlpha = 0x6F,
|
||||
OP_FirstArrayKey = 0x70,
|
||||
OP_NextArrayKey = 0x71,
|
||||
OP_ProfileStart = 0x72,
|
||||
OP_ProfileStop = 0x73,
|
||||
OP_SafeDecTop = 0x74,
|
||||
OP_Nop = 0x75,
|
||||
OP_Abort = 0x76,
|
||||
OP_Object = 0x77,
|
||||
OP_ThreadObject = 0x78,
|
||||
OP_EvalLocalVariable = 0x79,
|
||||
OP_EvalLocalVariableRef = 0x7A,
|
||||
OP_DevblockBegin = 0x7B,
|
||||
OP_DevblockEnd = 0x7C,
|
||||
OP_Count = 0x7D,
|
||||
};
|
||||
|
||||
auto opcode_size(std::uint8_t id) -> std::uint32_t;
|
||||
|
||||
} // namespace xsk::arc::t6
|
48
premake5.lua
48
premake5.lua
@ -83,9 +83,8 @@ project "xsk-tool"
|
||||
targetname "gsc-tool"
|
||||
|
||||
dependson "xsk-utils"
|
||||
-- dependson "xsk-arc"
|
||||
dependson "xsk-arc"
|
||||
dependson "xsk-gsc"
|
||||
dependson "xsk-t6"
|
||||
|
||||
files {
|
||||
"./src/tool/**.h",
|
||||
@ -95,9 +94,8 @@ project "xsk-tool"
|
||||
|
||||
links {
|
||||
"xsk-utils",
|
||||
-- "xsk-arc",
|
||||
"xsk-arc",
|
||||
"xsk-gsc",
|
||||
"xsk-t6",
|
||||
}
|
||||
|
||||
includedirs {
|
||||
@ -124,21 +122,21 @@ project "xsk-utils"
|
||||
fmt:include()
|
||||
zlib:include()
|
||||
|
||||
-- project "xsk-arc"
|
||||
-- kind "StaticLib"
|
||||
-- language "C++"
|
||||
project "xsk-arc"
|
||||
kind "StaticLib"
|
||||
language "C++"
|
||||
|
||||
-- files {
|
||||
-- "./src/arc/**.h",
|
||||
-- "./src/arc/**.hpp",
|
||||
-- "./src/arc/**.cpp"
|
||||
-- }
|
||||
files {
|
||||
"./src/arc/**.h",
|
||||
"./src/arc/**.hpp",
|
||||
"./src/arc/**.cpp"
|
||||
}
|
||||
|
||||
-- includedirs {
|
||||
-- "./include",
|
||||
-- }
|
||||
includedirs {
|
||||
"./include",
|
||||
}
|
||||
|
||||
-- fmt:include()
|
||||
fmt:include()
|
||||
|
||||
project "xsk-gsc"
|
||||
kind "StaticLib"
|
||||
@ -156,22 +154,6 @@ project "xsk-gsc"
|
||||
|
||||
fmt:include()
|
||||
|
||||
project "xsk-t6"
|
||||
kind "StaticLib"
|
||||
language "C++"
|
||||
|
||||
files {
|
||||
"./src/t6/**.h",
|
||||
"./src/t6/**.hpp",
|
||||
"./src/t6/**.cpp"
|
||||
}
|
||||
|
||||
includedirs {
|
||||
"./include",
|
||||
}
|
||||
|
||||
fmt:include()
|
||||
|
||||
group "Dependencies"
|
||||
fmt:project()
|
||||
zlib:project()
|
||||
fmt:project()
|
||||
|
925
src/arc/assembler.cpp
Normal file
925
src/arc/assembler.cpp
Normal file
@ -0,0 +1,925 @@
|
||||
// Copyright 2023 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 "xsk/stdinc.hpp"
|
||||
#include "xsk/arc/assembler.hpp"
|
||||
#include "xsk/arc/context.hpp"
|
||||
|
||||
namespace xsk::arc
|
||||
{
|
||||
|
||||
assembler::assembler(context const* ctx) : ctx_{ ctx }, script_{ ctx->endian() == endian::big }
|
||||
{
|
||||
}
|
||||
|
||||
auto assembler::assemble(assembly const& data) -> buffer
|
||||
{
|
||||
assembly_ = &data;
|
||||
script_.clear();
|
||||
strpool_.clear();
|
||||
exports_.clear();
|
||||
imports_.clear();
|
||||
strings_.clear();
|
||||
anims_.clear();
|
||||
auto head = header{};
|
||||
|
||||
script_.pos((ctx_->props() & props::headerxx) ? 0 : (ctx_->props() & props::header72) ? 72 : 64);
|
||||
process_string("");
|
||||
|
||||
for (auto const& func : assembly_->functions)
|
||||
{
|
||||
process_function(*func);
|
||||
}
|
||||
|
||||
for (auto const& incl : assembly_->includes)
|
||||
{
|
||||
process_string(incl);
|
||||
}
|
||||
|
||||
head.include_offset = script_.pos();
|
||||
head.include_count = static_cast<u8>(assembly_->includes.size());
|
||||
|
||||
for (auto const& entry : assembly_->includes)
|
||||
{
|
||||
script_.write<u32>(resolve_string(entry));
|
||||
}
|
||||
|
||||
head.cseg_offset = script_.pos();
|
||||
|
||||
for (auto const& func : assembly_->functions)
|
||||
{
|
||||
script_.align((ctx_->props() & props::size64) ? 8 : 4);
|
||||
script_.seek((ctx_->props() & props::size64) ? 8 : 4);
|
||||
assemble_function(*func);
|
||||
}
|
||||
|
||||
head.cseg_size = script_.pos() - head.cseg_offset;
|
||||
head.source_crc = 0;
|
||||
|
||||
head.exports_offset = script_.pos();
|
||||
head.exports_count = static_cast<u16>(exports_.size());
|
||||
|
||||
for (auto const& entry : exports_)
|
||||
{
|
||||
script_.write<u32>(entry.checksum);
|
||||
script_.write<u32>(entry.offset);
|
||||
|
||||
if (ctx_->props() & props::hashids)
|
||||
{
|
||||
script_.write<u32>(ctx_->hash_id(entry.name));
|
||||
script_.write<u32>(ctx_->hash_id(entry.space));
|
||||
}
|
||||
else
|
||||
{
|
||||
script_.write<u16>(resolve_string(entry.name));
|
||||
}
|
||||
|
||||
script_.write<u8>(entry.params);
|
||||
script_.write<u8>(entry.flags);
|
||||
|
||||
if (ctx_->props() & props::hashids)
|
||||
script_.seek(2);
|
||||
}
|
||||
|
||||
head.imports_offset = script_.pos();
|
||||
head.imports_count = static_cast<u16>(imports_.size());
|
||||
|
||||
for (auto const& entry : imports_)
|
||||
{
|
||||
if (ctx_->props() & props::hashids)
|
||||
{
|
||||
script_.write<u32>(ctx_->hash_id(entry.name));
|
||||
script_.write<u32>(ctx_->hash_id(entry.space));
|
||||
}
|
||||
else
|
||||
{
|
||||
script_.write<u16>(resolve_string(entry.name));
|
||||
script_.write<u16>(resolve_string(entry.space));
|
||||
}
|
||||
|
||||
script_.write<u16>(static_cast<u16>(entry.refs.size()));
|
||||
script_.write<u8>(entry.params);
|
||||
script_.write<u8>(entry.flags);
|
||||
|
||||
for (auto const& ref : entry.refs)
|
||||
{
|
||||
script_.write<u32>(ref);
|
||||
}
|
||||
}
|
||||
|
||||
head.animtree_offset = script_.pos();
|
||||
head.animtree_count = static_cast<u8>(anims_.size());
|
||||
|
||||
for (auto const& entry : anims_)
|
||||
{
|
||||
if (ctx_->props() & props::size64)
|
||||
{
|
||||
script_.write<u32>(resolve_string(entry.name));
|
||||
script_.write<u16>(static_cast<u16>(entry.refs.size()));
|
||||
script_.write<u16>(static_cast<u16>(entry.anims.size()));
|
||||
}
|
||||
else
|
||||
{
|
||||
script_.write<u16>(resolve_string(entry.name));
|
||||
script_.write<u16>(static_cast<u16>(entry.refs.size()));
|
||||
script_.write<u16>(static_cast<u16>(entry.anims.size()));
|
||||
script_.seek(2);
|
||||
}
|
||||
|
||||
for (auto const& ref : entry.refs)
|
||||
{
|
||||
script_.write<u32>(ref);
|
||||
}
|
||||
|
||||
for (auto const& anim : entry.anims)
|
||||
{
|
||||
if (ctx_->props() & props::size64)
|
||||
{
|
||||
script_.write<u64>(resolve_string(anim.name));
|
||||
script_.write<u64>(anim.ref);
|
||||
}
|
||||
else
|
||||
{
|
||||
script_.write<u32>(resolve_string(anim.name));
|
||||
script_.write<u32>(anim.ref);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
head.stringtablefixup_offset = script_.pos();
|
||||
head.stringtablefixup_count = static_cast<u16>(strings_.size());
|
||||
|
||||
for (auto const& entry : strings_)
|
||||
{
|
||||
if (ctx_->props() & props::size64)
|
||||
script_.write<u32>(resolve_string(entry.name));
|
||||
else
|
||||
script_.write<u16>(resolve_string(entry.name));
|
||||
|
||||
script_.write<u8>(static_cast<u8>(entry.refs.size()));
|
||||
script_.write<u8>(entry.type);
|
||||
|
||||
if (ctx_->props() & props::size64)
|
||||
script_.seek(2);
|
||||
|
||||
for (auto const& ref : entry.refs)
|
||||
{
|
||||
script_.write<u32>(ref);
|
||||
}
|
||||
}
|
||||
|
||||
if (ctx_->props() & props::devstr)
|
||||
{
|
||||
head.stringtablefixup_offset = script_.pos();
|
||||
head.stringtablefixup_count = 0;
|
||||
}
|
||||
|
||||
head.fixup_offset = script_.pos();
|
||||
head.fixup_count = 0;
|
||||
|
||||
head.profile_offset = script_.pos();
|
||||
head.profile_count = 0;
|
||||
|
||||
head.flags = 0;
|
||||
head.name = resolve_string("");
|
||||
|
||||
auto endpos = script_.pos();
|
||||
|
||||
script_.pos(0);
|
||||
script_.write<u64>(ctx_->magic());
|
||||
script_.write<u32>(head.source_crc);
|
||||
script_.write<u32>(head.include_offset);
|
||||
script_.write<u32>(head.animtree_offset);
|
||||
script_.write<u32>(head.cseg_offset);
|
||||
script_.write<u32>(head.stringtablefixup_offset);
|
||||
|
||||
if (ctx_->props() & props::devstr)
|
||||
script_.write<u32>(head.devblock_stringtablefixup_offset);
|
||||
|
||||
script_.write<u32>(head.exports_offset);
|
||||
script_.write<u32>(head.imports_offset);
|
||||
script_.write<u32>(head.fixup_offset);
|
||||
script_.write<u32>(head.profile_offset);
|
||||
script_.write<u32>(head.cseg_size);
|
||||
|
||||
if (ctx_->props() & props::size64)
|
||||
script_.write<u32>(head.name);
|
||||
else
|
||||
script_.write<u32>(head.name);
|
||||
|
||||
script_.write<u16>(head.stringtablefixup_count);
|
||||
script_.write<u16>(head.exports_count);
|
||||
script_.write<u16>(head.imports_count);
|
||||
script_.write<u16>(head.fixup_count);
|
||||
script_.write<u16>(head.profile_count);
|
||||
|
||||
if (ctx_->props() & props::devstr)
|
||||
script_.write<u16>(head.devblock_stringtablefixup_count);
|
||||
|
||||
script_.write<u8>(head.include_count);
|
||||
script_.write<u8>(head.animtree_count);
|
||||
script_.write<u8>(head.flags);
|
||||
script_.pos(endpos);
|
||||
|
||||
return buffer{ script_.data(), script_.pos() };
|
||||
}
|
||||
|
||||
auto assembler::assemble_function(function& func) -> void
|
||||
{
|
||||
func.index = script_.pos();
|
||||
func.size = 0;
|
||||
func_ = &func;
|
||||
|
||||
for (auto& inst : func.instructions)
|
||||
{
|
||||
auto old_idx = inst->index;
|
||||
inst->index = func.index + func.size;
|
||||
|
||||
align_instruction(*inst);
|
||||
|
||||
func.size += inst->size;
|
||||
|
||||
auto const itr = func.labels.find(old_idx);
|
||||
|
||||
if (itr != func.labels.end())
|
||||
{
|
||||
func.labels.erase(old_idx);
|
||||
func.labels.insert({ inst->index, itr->second });
|
||||
}
|
||||
}
|
||||
|
||||
script_.pos(func.index);
|
||||
|
||||
for (auto const& inst : func.instructions)
|
||||
{
|
||||
assemble_instruction(*inst);
|
||||
}
|
||||
|
||||
export_ref entry;
|
||||
entry.checksum = 0;
|
||||
entry.offset = func.index;
|
||||
entry.name = func.name;
|
||||
entry.params = func.params;
|
||||
entry.flags = func.flags;
|
||||
exports_.push_back(entry);
|
||||
}
|
||||
|
||||
auto assembler::assemble_instruction(instruction const& inst) -> void
|
||||
{
|
||||
script_.write<u8>(static_cast<u8>(ctx_->opcode_id(inst.opcode)));
|
||||
|
||||
switch (inst.opcode)
|
||||
{
|
||||
case opcode::OP_End:
|
||||
case opcode::OP_Return:
|
||||
case opcode::OP_GetUndefined:
|
||||
case opcode::OP_GetZero:
|
||||
case opcode::OP_GetLevelObject:
|
||||
case opcode::OP_GetAnimObject:
|
||||
case opcode::OP_GetSelf:
|
||||
case opcode::OP_GetLevel:
|
||||
case opcode::OP_GetGame:
|
||||
case opcode::OP_GetAnim:
|
||||
case opcode::OP_GetGameRef:
|
||||
case opcode::OP_CreateLocalVariable:
|
||||
case opcode::OP_EvalArray:
|
||||
case opcode::OP_EvalArrayRef:
|
||||
case opcode::OP_ClearArray:
|
||||
case opcode::OP_EmptyArray:
|
||||
case opcode::OP_GetSelfObject:
|
||||
case opcode::OP_SafeSetVariableFieldCached:
|
||||
case opcode::OP_ClearParams:
|
||||
case opcode::OP_CheckClearParams:
|
||||
case opcode::OP_SetVariableField:
|
||||
case opcode::OP_Wait:
|
||||
case opcode::OP_WaitTillFrameEnd:
|
||||
case opcode::OP_PreScriptCall:
|
||||
case opcode::OP_DecTop:
|
||||
case opcode::OP_CastFieldObject:
|
||||
case opcode::OP_CastBool:
|
||||
case opcode::OP_BoolNot:
|
||||
case opcode::OP_BoolComplement:
|
||||
case opcode::OP_Inc:
|
||||
case opcode::OP_Dec:
|
||||
case opcode::OP_Bit_Or:
|
||||
case opcode::OP_Bit_Xor:
|
||||
case opcode::OP_Bit_And:
|
||||
case opcode::OP_Equal:
|
||||
case opcode::OP_NotEqual:
|
||||
case opcode::OP_LessThan:
|
||||
case opcode::OP_GreaterThan:
|
||||
case opcode::OP_LessThanOrEqualTo:
|
||||
case opcode::OP_GreaterThanOrEqualTo:
|
||||
case opcode::OP_ShiftLeft:
|
||||
case opcode::OP_ShiftRight:
|
||||
case opcode::OP_Plus:
|
||||
case opcode::OP_Minus:
|
||||
case opcode::OP_Multiply:
|
||||
case opcode::OP_Divide:
|
||||
case opcode::OP_Modulus:
|
||||
case opcode::OP_SizeOf:
|
||||
case opcode::OP_WaitTill:
|
||||
case opcode::OP_Notify:
|
||||
case opcode::OP_EndOn:
|
||||
case opcode::OP_VoidCodePos:
|
||||
case opcode::OP_Vector:
|
||||
case opcode::OP_RealWait:
|
||||
case opcode::OP_IsDefined:
|
||||
case opcode::OP_VectorScale:
|
||||
case opcode::OP_AnglesToUp:
|
||||
case opcode::OP_AnglesToRight:
|
||||
case opcode::OP_AnglesToForward:
|
||||
case opcode::OP_AngleClamp180:
|
||||
case opcode::OP_VectorToAngles:
|
||||
case opcode::OP_Abs:
|
||||
case opcode::OP_GetTime:
|
||||
case opcode::OP_GetDvar:
|
||||
case opcode::OP_GetDvarInt:
|
||||
case opcode::OP_GetDvarFloat:
|
||||
case opcode::OP_GetDvarVector:
|
||||
case opcode::OP_GetDvarColorRed:
|
||||
case opcode::OP_GetDvarColorGreen:
|
||||
case opcode::OP_GetDvarColorBlue:
|
||||
case opcode::OP_GetDvarColorAlpha:
|
||||
case opcode::OP_FirstArrayKey:
|
||||
case opcode::OP_NextArrayKey:
|
||||
case opcode::OP_ProfileStart:
|
||||
case opcode::OP_ProfileStop:
|
||||
case opcode::OP_SafeDecTop:
|
||||
case opcode::OP_Nop:
|
||||
case opcode::OP_Abort:
|
||||
case opcode::OP_Object:
|
||||
case opcode::OP_ThreadObject:
|
||||
case opcode::OP_EvalLocalVariable:
|
||||
case opcode::OP_EvalLocalVariableRef:
|
||||
break;
|
||||
case opcode::OP_GetByte:
|
||||
case opcode::OP_GetNegByte:
|
||||
script_.write<u8>(static_cast<u8>(std::stoi(inst.data[0])));
|
||||
break;
|
||||
case opcode::OP_GetUnsignedShort:
|
||||
case opcode::OP_GetNegUnsignedShort:
|
||||
script_.align(2);
|
||||
script_.write<u16>(static_cast<u16>(std::stoi(inst.data[0])));
|
||||
break;
|
||||
case opcode::OP_GetInteger:
|
||||
script_.align(4);
|
||||
script_.write<i32>((inst.data.size() == 2) ? -1 : std::stoi(inst.data[0]));
|
||||
break;
|
||||
case opcode::OP_GetFloat:
|
||||
script_.align(4);
|
||||
script_.write<f32>(std::stof(inst.data[0]));
|
||||
break;
|
||||
case opcode::OP_GetVector:
|
||||
script_.align(4);
|
||||
script_.write<f32>(std::stof(inst.data[0]));
|
||||
script_.write<f32>(std::stof(inst.data[1]));
|
||||
script_.write<f32>(std::stof(inst.data[2]));
|
||||
break;
|
||||
case opcode::OP_GetString:
|
||||
case opcode::OP_GetIString:
|
||||
script_.align(2);
|
||||
script_.write<u16>(0);
|
||||
break;
|
||||
case opcode::OP_GetAnimation:
|
||||
script_.align(4);
|
||||
script_.write<u32>(0);
|
||||
break;
|
||||
case opcode::OP_WaitTillMatch:
|
||||
script_.write<u8>(static_cast<u8>(std::stoi(inst.data[0])));
|
||||
break;
|
||||
case opcode::OP_VectorConstant:
|
||||
script_.write<u8>(static_cast<u8>(std::stoi(inst.data[0])));
|
||||
break;
|
||||
case opcode::OP_GetHash:
|
||||
script_.align(4);
|
||||
script_.write<u32>(static_cast<u32>(std::stoul(inst.data[0], 0, 16)));
|
||||
break;
|
||||
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<u8>(static_cast<u8>(std::stoi(inst.data[0])));
|
||||
break;
|
||||
case opcode::OP_EvalFieldVariable:
|
||||
case opcode::OP_EvalFieldVariableRef:
|
||||
case opcode::OP_ClearFieldVariable:
|
||||
script_.align(2);
|
||||
script_.write<u16>(0);
|
||||
break;
|
||||
case opcode::OP_ScriptFunctionCallPointer:
|
||||
case opcode::OP_ScriptMethodCallPointer:
|
||||
case opcode::OP_ScriptThreadCallPointer:
|
||||
case opcode::OP_ScriptMethodThreadCallPointer:
|
||||
script_.write<u8>(static_cast<u8>(std::stoi(inst.data[0])));
|
||||
break;
|
||||
case opcode::OP_GetFunction:
|
||||
script_.align(4);
|
||||
script_.write<u32>(0);
|
||||
break;
|
||||
case opcode::OP_CallBuiltin:
|
||||
case opcode::OP_CallBuiltinMethod:
|
||||
case opcode::OP_ScriptFunctionCall:
|
||||
case opcode::OP_ScriptMethodCall:
|
||||
case opcode::OP_ScriptThreadCall:
|
||||
case opcode::OP_ScriptMethodThreadCall:
|
||||
script_.write<u8>(0);
|
||||
script_.align(4);
|
||||
script_.write<u32>(0);
|
||||
break;
|
||||
case opcode::OP_JumpOnFalse:
|
||||
case opcode::OP_JumpOnTrue:
|
||||
case opcode::OP_JumpOnFalseExpr:
|
||||
case opcode::OP_JumpOnTrueExpr:
|
||||
case opcode::OP_Jump:
|
||||
case opcode::OP_JumpBack:
|
||||
case opcode::OP_DevblockBegin:
|
||||
assemble_jump(inst);
|
||||
break;
|
||||
case opcode::OP_Switch:
|
||||
assemble_switch(inst);
|
||||
break;
|
||||
case opcode::OP_EndSwitch:
|
||||
assemble_end_switch(inst);
|
||||
break;
|
||||
default:
|
||||
throw asm_error(fmt::format("unhandled opcode {} at index {:04X}", ctx_->opcode_name(inst.opcode), inst.index));
|
||||
}
|
||||
}
|
||||
|
||||
auto assembler::assemble_localvars(instruction const& inst) -> void
|
||||
{
|
||||
script_.write<u8>(static_cast<u8>(inst.data.size()));
|
||||
|
||||
for (auto i = 0u; i < inst.data.size(); i++)
|
||||
{
|
||||
script_.align(2);
|
||||
script_.write<u16>(0);
|
||||
}
|
||||
}
|
||||
|
||||
auto assembler::assemble_jump(instruction const& inst) -> void
|
||||
{
|
||||
auto const addr = static_cast<i16>(resolve_label(inst.data[0]) - inst.index - inst.size);
|
||||
|
||||
script_.align(2);
|
||||
script_.write<i16>(addr);
|
||||
}
|
||||
|
||||
auto assembler::assemble_switch(instruction const& inst) -> void
|
||||
{
|
||||
const i32 addr = ((resolve_label(inst.data[0]) + 4) & 0xFFFFFFFC) - inst.index - inst.size;
|
||||
|
||||
script_.align(4);
|
||||
script_.write<i32>(addr);
|
||||
}
|
||||
|
||||
auto assembler::assemble_end_switch(instruction const& inst) -> void
|
||||
{
|
||||
const auto count = std::stoul(inst.data[0]);
|
||||
const auto numerical = inst.data.back() == "i";
|
||||
|
||||
script_.align(4);
|
||||
script_.write<u32>(count);
|
||||
|
||||
for (auto i = 0u; i < count; i++)
|
||||
{
|
||||
if (inst.data[1 + (3 * i)] == "case")
|
||||
{
|
||||
if (numerical /*&& utils::string::is_number(inst->data[1 + (3 * i) + 1])*/)
|
||||
{
|
||||
script_.write<u32>((std::stoi(inst.data[1 + (3 * i) + 1]) & 0xFFFFFF) + 0x800000);
|
||||
}
|
||||
else
|
||||
{
|
||||
script_.write<u32>(i + 1);
|
||||
}
|
||||
|
||||
const i32 addr = resolve_label(inst.data[1 + (3 * i) + 2]) - script_.pos() - 4;
|
||||
|
||||
script_.write<i32>(addr);
|
||||
}
|
||||
else if (inst.data[1 + (3 * i)] == "default")
|
||||
{
|
||||
script_.write<u32>(0);
|
||||
|
||||
const i32 addr = resolve_label(inst.data[1 + (3 * i) + 1]) - script_.pos() - 4;
|
||||
|
||||
script_.write<i32>(addr);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw asm_error("invalid switch case '" + inst.data[1 + (3 * i)] + "'!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto assembler::process_string(std::string const& data) -> void
|
||||
{
|
||||
if (!strpool_.contains(data))
|
||||
{
|
||||
auto pos = static_cast<u16>(script_.pos());
|
||||
script_.write_cstr(data);
|
||||
strpool_.insert({ data, pos });
|
||||
}
|
||||
}
|
||||
|
||||
auto assembler::process_function(function const& func) -> void
|
||||
{
|
||||
process_string(func.name);
|
||||
|
||||
for (auto const& inst : func.instructions)
|
||||
{
|
||||
process_instruction(*inst);
|
||||
}
|
||||
}
|
||||
|
||||
auto assembler::process_instruction(instruction const& inst) -> void
|
||||
{
|
||||
switch (inst.opcode)
|
||||
{
|
||||
case opcode::OP_GetInteger:
|
||||
if (inst.data.size() == 2)
|
||||
process_string(inst.data[0]);
|
||||
break;
|
||||
case opcode::OP_GetString:
|
||||
case opcode::OP_GetIString:
|
||||
process_string(inst.data[0]);
|
||||
break;
|
||||
case opcode::OP_GetAnimation:
|
||||
process_string(inst.data[0]);
|
||||
process_string(inst.data[1]);
|
||||
break;
|
||||
case opcode::OP_SafeCreateLocalVariables:
|
||||
{
|
||||
for (auto const& entry : inst.data)
|
||||
{
|
||||
process_string(entry);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case opcode::OP_EvalFieldVariable:
|
||||
case opcode::OP_EvalFieldVariableRef:
|
||||
case opcode::OP_ClearFieldVariable:
|
||||
process_string(inst.data[0]);
|
||||
break;
|
||||
case opcode::OP_GetFunction:
|
||||
process_string(inst.data[0]);
|
||||
process_string(inst.data[1]);
|
||||
break;
|
||||
case opcode::OP_CallBuiltin:
|
||||
case opcode::OP_CallBuiltinMethod:
|
||||
case opcode::OP_ScriptFunctionCall:
|
||||
case opcode::OP_ScriptMethodCall:
|
||||
case opcode::OP_ScriptThreadCall:
|
||||
case opcode::OP_ScriptMethodThreadCall:
|
||||
process_string(inst.data[0]);
|
||||
process_string(inst.data[1]);
|
||||
break;
|
||||
case opcode::OP_EndSwitch:
|
||||
{
|
||||
const auto count = std::stoul(inst.data[0]);
|
||||
const auto numerical = inst.data.back() == "i";
|
||||
|
||||
for (auto i = 0u; i < count; i++)
|
||||
{
|
||||
if (inst.data[1 + (3 * i)] == "case")
|
||||
{
|
||||
if (!numerical /*|| !utils::string::is_number(inst->data[1 + (3 * i) + 1])*/)
|
||||
{
|
||||
process_string(inst.data[1 + (3 * i) + 1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
auto assembler::align_instruction(instruction& inst) -> void
|
||||
{
|
||||
inst.size = ctx_->opcode_size(inst.opcode);
|
||||
script_.seek(1);
|
||||
|
||||
switch (inst.opcode)
|
||||
{
|
||||
case opcode::OP_End:
|
||||
case opcode::OP_Return:
|
||||
case opcode::OP_GetUndefined:
|
||||
case opcode::OP_GetZero:
|
||||
case opcode::OP_GetLevelObject:
|
||||
case opcode::OP_GetAnimObject:
|
||||
case opcode::OP_GetSelf:
|
||||
case opcode::OP_GetLevel:
|
||||
case opcode::OP_GetGame:
|
||||
case opcode::OP_GetAnim:
|
||||
case opcode::OP_GetGameRef:
|
||||
case opcode::OP_CreateLocalVariable:
|
||||
case opcode::OP_EvalArray:
|
||||
case opcode::OP_EvalArrayRef:
|
||||
case opcode::OP_ClearArray:
|
||||
case opcode::OP_EmptyArray:
|
||||
case opcode::OP_GetSelfObject:
|
||||
case opcode::OP_SafeSetVariableFieldCached:
|
||||
case opcode::OP_ClearParams:
|
||||
case opcode::OP_CheckClearParams:
|
||||
case opcode::OP_SetVariableField:
|
||||
case opcode::OP_Wait:
|
||||
case opcode::OP_WaitTillFrameEnd:
|
||||
case opcode::OP_PreScriptCall:
|
||||
case opcode::OP_DecTop:
|
||||
case opcode::OP_CastFieldObject:
|
||||
case opcode::OP_CastBool:
|
||||
case opcode::OP_BoolNot:
|
||||
case opcode::OP_BoolComplement:
|
||||
case opcode::OP_Inc:
|
||||
case opcode::OP_Dec:
|
||||
case opcode::OP_Bit_Or:
|
||||
case opcode::OP_Bit_Xor:
|
||||
case opcode::OP_Bit_And:
|
||||
case opcode::OP_Equal:
|
||||
case opcode::OP_NotEqual:
|
||||
case opcode::OP_LessThan:
|
||||
case opcode::OP_GreaterThan:
|
||||
case opcode::OP_LessThanOrEqualTo:
|
||||
case opcode::OP_GreaterThanOrEqualTo:
|
||||
case opcode::OP_ShiftLeft:
|
||||
case opcode::OP_ShiftRight:
|
||||
case opcode::OP_Plus:
|
||||
case opcode::OP_Minus:
|
||||
case opcode::OP_Multiply:
|
||||
case opcode::OP_Divide:
|
||||
case opcode::OP_Modulus:
|
||||
case opcode::OP_SizeOf:
|
||||
case opcode::OP_WaitTill:
|
||||
case opcode::OP_Notify:
|
||||
case opcode::OP_EndOn:
|
||||
case opcode::OP_VoidCodePos:
|
||||
case opcode::OP_Vector:
|
||||
case opcode::OP_RealWait:
|
||||
case opcode::OP_IsDefined:
|
||||
case opcode::OP_VectorScale:
|
||||
case opcode::OP_AnglesToUp:
|
||||
case opcode::OP_AnglesToRight:
|
||||
case opcode::OP_AnglesToForward:
|
||||
case opcode::OP_AngleClamp180:
|
||||
case opcode::OP_VectorToAngles:
|
||||
case opcode::OP_Abs:
|
||||
case opcode::OP_GetTime:
|
||||
case opcode::OP_GetDvar:
|
||||
case opcode::OP_GetDvarInt:
|
||||
case opcode::OP_GetDvarFloat:
|
||||
case opcode::OP_GetDvarVector:
|
||||
case opcode::OP_GetDvarColorRed:
|
||||
case opcode::OP_GetDvarColorGreen:
|
||||
case opcode::OP_GetDvarColorBlue:
|
||||
case opcode::OP_GetDvarColorAlpha:
|
||||
case opcode::OP_FirstArrayKey:
|
||||
case opcode::OP_NextArrayKey:
|
||||
case opcode::OP_ProfileStart:
|
||||
case opcode::OP_ProfileStop:
|
||||
case opcode::OP_SafeDecTop:
|
||||
case opcode::OP_Nop:
|
||||
case opcode::OP_Abort:
|
||||
case opcode::OP_Object:
|
||||
case opcode::OP_ThreadObject:
|
||||
case opcode::OP_EvalLocalVariable:
|
||||
case opcode::OP_EvalLocalVariableRef:
|
||||
break;
|
||||
case opcode::OP_GetByte:
|
||||
case opcode::OP_GetNegByte:
|
||||
script_.seek(1);
|
||||
break;
|
||||
case opcode::OP_GetUnsignedShort:
|
||||
case opcode::OP_GetNegUnsignedShort:
|
||||
inst.size += script_.align(2);
|
||||
script_.seek(2);
|
||||
break;
|
||||
case opcode::OP_GetInteger:
|
||||
inst.size += script_.align(4);
|
||||
if (inst.data.size() == 2)
|
||||
add_animref(inst.data, script_.pos());
|
||||
script_.seek(4);
|
||||
break;
|
||||
case opcode::OP_GetFloat:
|
||||
inst.size += script_.align(4);
|
||||
script_.seek(4);
|
||||
break;
|
||||
case opcode::OP_GetVector:
|
||||
inst.size += script_.align(4);
|
||||
script_.seek(12);
|
||||
break;
|
||||
case opcode::OP_GetString:
|
||||
case opcode::OP_GetIString:
|
||||
inst.size += script_.align(2);
|
||||
add_stringref(inst.data[0], string_type::literal, script_.pos());
|
||||
script_.seek(2);
|
||||
break;
|
||||
case opcode::OP_GetAnimation:
|
||||
inst.size += script_.align(4);
|
||||
add_animref(inst.data, script_.pos());
|
||||
script_.seek(4);
|
||||
break;
|
||||
case opcode::OP_WaitTillMatch:
|
||||
script_.seek(1);
|
||||
break;
|
||||
case opcode::OP_VectorConstant:
|
||||
script_.seek(1);
|
||||
break;
|
||||
case opcode::OP_GetHash:
|
||||
inst.size += script_.align(4);
|
||||
script_.seek(4);
|
||||
break;
|
||||
case opcode::OP_SafeCreateLocalVariables:
|
||||
{
|
||||
script_.seek(1);
|
||||
|
||||
for (auto i = 0u; i < inst.data.size(); i++)
|
||||
{
|
||||
inst.size += script_.align(2) + 2;
|
||||
add_stringref(inst.data[i], string_type::canonical, script_.pos());
|
||||
script_.seek(2);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case opcode::OP_RemoveLocalVariables:
|
||||
case opcode::OP_EvalLocalVariableCached:
|
||||
case opcode::OP_EvalLocalArrayRefCached:
|
||||
case opcode::OP_SafeSetWaittillVariableFieldCached:
|
||||
case opcode::OP_EvalLocalVariableRefCached:
|
||||
script_.seek(1);
|
||||
break;
|
||||
case opcode::OP_EvalFieldVariable:
|
||||
case opcode::OP_EvalFieldVariableRef:
|
||||
case opcode::OP_ClearFieldVariable:
|
||||
inst.size += script_.align(2);
|
||||
add_stringref(inst.data[0], string_type::canonical, script_.pos());
|
||||
script_.seek(2);
|
||||
break;
|
||||
case opcode::OP_ScriptFunctionCallPointer:
|
||||
case opcode::OP_ScriptMethodCallPointer:
|
||||
case opcode::OP_ScriptThreadCallPointer:
|
||||
case opcode::OP_ScriptMethodThreadCallPointer:
|
||||
script_.seek(1);
|
||||
break;
|
||||
case opcode::OP_GetFunction:
|
||||
inst.size += script_.align(4);
|
||||
script_.seek(4);
|
||||
add_importref(inst.data, inst.index);
|
||||
break;
|
||||
case opcode::OP_CallBuiltin:
|
||||
case opcode::OP_CallBuiltinMethod:
|
||||
case opcode::OP_ScriptFunctionCall:
|
||||
case opcode::OP_ScriptMethodCall:
|
||||
case opcode::OP_ScriptThreadCall:
|
||||
case opcode::OP_ScriptMethodThreadCall:
|
||||
script_.seek(1);
|
||||
inst.size += script_.align(4);
|
||||
script_.seek(4);
|
||||
add_importref(inst.data, inst.index);
|
||||
break;
|
||||
case opcode::OP_JumpOnFalse:
|
||||
case opcode::OP_JumpOnTrue:
|
||||
case opcode::OP_JumpOnFalseExpr:
|
||||
case opcode::OP_JumpOnTrueExpr:
|
||||
case opcode::OP_Jump:
|
||||
case opcode::OP_JumpBack:
|
||||
case opcode::OP_DevblockBegin:
|
||||
inst.size += script_.align(2);
|
||||
script_.seek(2);
|
||||
break;
|
||||
case opcode::OP_Switch:
|
||||
inst.size += script_.align(4);
|
||||
script_.seek(4);
|
||||
break;
|
||||
case opcode::OP_EndSwitch:
|
||||
{
|
||||
inst.size += script_.align(4);
|
||||
script_.seek(4);
|
||||
|
||||
const auto count = std::stoul(inst.data[0]);
|
||||
const auto numerical = inst.data.back() == "i";
|
||||
|
||||
for (auto i = 0u; i < count; i++)
|
||||
{
|
||||
if (inst.data[1 + (3 * i)] == "case")
|
||||
{
|
||||
if (!numerical /*|| !utils::string::is_number(inst.data[1 + (3 * i) + 1])*/)
|
||||
{
|
||||
add_stringref(inst.data[1 + (3 * i) + 1], string_type::literal, script_.pos() + 2);
|
||||
}
|
||||
}
|
||||
|
||||
inst.size += 8;
|
||||
script_.seek(8);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw asm_error(fmt::format("unhandled opcode {} at index {:04X}", ctx_->opcode_name(inst.opcode), inst.index));
|
||||
}
|
||||
}
|
||||
|
||||
auto assembler::resolve_label(std::string const& name) -> i32
|
||||
{
|
||||
for (auto const& entry : func_->labels)
|
||||
{
|
||||
if (entry.second == name)
|
||||
{
|
||||
return entry.first;
|
||||
}
|
||||
}
|
||||
|
||||
throw asm_error("couldn't resolve label address of '" + name + "'!");
|
||||
}
|
||||
|
||||
auto assembler::resolve_string(std::string const& name) -> u16
|
||||
{
|
||||
auto const itr = strpool_.find(name);
|
||||
|
||||
if (itr != strpool_.end())
|
||||
{
|
||||
return itr->second;
|
||||
}
|
||||
|
||||
throw asm_error("couldn't resolve string assembly address of '" + name + "'!");
|
||||
}
|
||||
|
||||
void assembler::add_stringref(std::string const& str, string_type type, u32 ref)
|
||||
{
|
||||
for (auto& entry : strings_)
|
||||
{
|
||||
if (entry.name == str && entry.type == static_cast<u8>(type))
|
||||
{
|
||||
entry.refs.push_back(ref);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
strings_.push_back({ str, u8(type), { ref } });
|
||||
}
|
||||
|
||||
void assembler::add_importref(std::vector<std::string> const& data, u32 ref)
|
||||
{
|
||||
for (auto& entry : imports_)
|
||||
{
|
||||
if (entry.space == data[0] && entry.name == data[1] && entry.params == std::stoi(data[2]) && entry.flags == std::stoi(data[3]))
|
||||
{
|
||||
entry.refs.push_back(ref);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
import_ref new_entry;
|
||||
new_entry.space = data[0];
|
||||
new_entry.name = data[1];
|
||||
new_entry.params = static_cast<u8>(std::stoi(data[2]));
|
||||
new_entry.flags = static_cast<u8>(std::stoi(data[3]));
|
||||
new_entry.refs.push_back(ref);
|
||||
imports_.push_back(std::move(new_entry));
|
||||
}
|
||||
|
||||
void assembler::add_animref(std::vector<std::string> const& data, u32 ref)
|
||||
{
|
||||
for (auto& entry : anims_)
|
||||
{
|
||||
if (entry.name == data[0])
|
||||
{
|
||||
if (data[1] == "-1")
|
||||
{
|
||||
entry.refs.push_back(ref);
|
||||
}
|
||||
else
|
||||
{
|
||||
entry.anims.push_back({ data[1], ref });
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
animtree_ref new_entry;
|
||||
new_entry.name = data[0];
|
||||
if (data[1] == "-1")
|
||||
{
|
||||
new_entry.refs.push_back(ref);
|
||||
}
|
||||
else
|
||||
{
|
||||
new_entry.anims.push_back({ data[1], ref });
|
||||
}
|
||||
anims_.push_back(std::move(new_entry));
|
||||
}
|
||||
|
||||
} // namespace xsk::arc
|
File diff suppressed because it is too large
Load Diff
40
src/arc/common/lookahead.cpp
Normal file
40
src/arc/common/lookahead.cpp
Normal file
@ -0,0 +1,40 @@
|
||||
// Copyright 2023 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 "xsk/stdinc.hpp"
|
||||
#include "xsk/arc/common/lookahead.hpp"
|
||||
|
||||
namespace xsk::arc
|
||||
{
|
||||
|
||||
lookahead::lookahead(char const* data, usize size) : buffer_pos{ 0 }, available{ 0 }, last_byte{ 0 }, curr_byte{ 0 }
|
||||
{
|
||||
if (data && size)
|
||||
{
|
||||
buffer_pos = data;
|
||||
available = size;
|
||||
last_byte = 0;
|
||||
curr_byte = *data;
|
||||
}
|
||||
}
|
||||
|
||||
auto lookahead::advance() -> void
|
||||
{
|
||||
++buffer_pos;
|
||||
|
||||
if (available-- == 1)
|
||||
{
|
||||
available = 0;
|
||||
last_byte = curr_byte;
|
||||
curr_byte = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
last_byte = curr_byte;
|
||||
curr_byte = *buffer_pos;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace xsk::arc
|
137
src/arc/common/token.cpp
Normal file
137
src/arc/common/token.cpp
Normal file
@ -0,0 +1,137 @@
|
||||
// Copyright 2023 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 "xsk/stdinc.hpp"
|
||||
#include "xsk/utils/string.hpp"
|
||||
#include "xsk/arc/common/location.hpp"
|
||||
#include "xsk/arc/common/space.hpp"
|
||||
#include "xsk/arc/common/token.hpp"
|
||||
|
||||
namespace xsk::arc
|
||||
{
|
||||
|
||||
auto token::to_string() -> std::string
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case token::PLUS: return "+";
|
||||
case token::MINUS: return "-";
|
||||
case token::STAR: return "*";
|
||||
case token::DIV: return "/";
|
||||
case token::MOD: return "%";
|
||||
case token::BITOR: return "|";
|
||||
case token::BITAND: return "&";
|
||||
case token::BITEXOR: return "^";
|
||||
case token::SHL: return "<<";
|
||||
case token::SHR: return ">>";
|
||||
case token::ASSIGN: return "=";
|
||||
case token::PLUSEQ: return "+=";
|
||||
case token::MINUSEQ: return "-=";
|
||||
case token::STAREQ: return "*=";
|
||||
case token::DIVEQ: return "/=";
|
||||
case token::MODEQ: return "%=";
|
||||
case token::BITOREQ: return "|=";
|
||||
case token::BITANDEQ: return "&=";
|
||||
case token::BITEXOREQ: return "^=";
|
||||
case token::SHLEQ: return "<<=";
|
||||
case token::SHREQ: return ">>=";
|
||||
case token::INC: return "++";
|
||||
case token::DEC: return "--";
|
||||
case token::GT: return ">";
|
||||
case token::LT: return "<";
|
||||
case token::GE: return ">=";
|
||||
case token::LE: return "<=";
|
||||
case token::NE: return "!=";
|
||||
case token::EQ: return "==";
|
||||
case token::OR: return "||";
|
||||
case token::AND: return "&&";
|
||||
case token::TILDE: return "~";
|
||||
case token::BANG: return "!";
|
||||
case token::QMARK: return "?";
|
||||
case token::COLON: return ":";
|
||||
case token::SHARP: return "#";
|
||||
case token::COMMA: return ",";
|
||||
case token::DOT: return ".";
|
||||
case token::DOUBLEDOT: return "..";
|
||||
case token::ELLIPSIS: return "...";
|
||||
case token::SEMICOLON: return ";";
|
||||
case token::DOUBLECOLON: return "::";
|
||||
case token::LBRACKET: return "{";
|
||||
case token::RBRACKET: return "}";
|
||||
case token::LBRACE: return "[";
|
||||
case token::RBRACE: return "]";
|
||||
case token::LPAREN: return "(";
|
||||
case token::RPAREN: return ")";
|
||||
case token::NAME: return data;
|
||||
case token::PATH: return data;
|
||||
case token::STRING: return data;
|
||||
case token::ISTRING: return data;
|
||||
case token::HASHSTR: return data;
|
||||
case token::INT: return data;
|
||||
case token::FLT: return data;
|
||||
case token::DEVBEGIN: return "/#";
|
||||
case token::DEVEND: return "#/";
|
||||
case token::INLINE: return "#inline";
|
||||
case token::INCLUDE: return "#include";
|
||||
case token::USINGTREE: return "#using_animtree";
|
||||
case token::ANIMTREE: return "#animtree";
|
||||
case token::AUTOEXEC: return "autoexec";
|
||||
case token::CODECALL: return "codecall";
|
||||
case token::PRIVATE: return "private";
|
||||
case token::ENDON: return "endon";
|
||||
case token::NOTIFY: return "notify";
|
||||
case token::WAIT: return "wait";
|
||||
case token::WAITTILL: return "waittill";
|
||||
case token::WAITTILLMATCH: return "waittillmatch";
|
||||
case token::WAITTILLFRAMEEND: return "waittillframeend";
|
||||
case token::IF: return "if";
|
||||
case token::ELSE: return "else";
|
||||
case token::DO: return "do";
|
||||
case token::WHILE: return "while";
|
||||
case token::FOR: return "for";
|
||||
case token::FOREACH: return "foreach";
|
||||
case token::IN: return "in";
|
||||
case token::SWITCH: return "switch";
|
||||
case token::CASE: return "case";
|
||||
case token::DEFAULT: return "default";
|
||||
case token::BREAK: return "break";
|
||||
case token::CONTINUE: return "continue";
|
||||
case token::RETURN: return "return";
|
||||
case token::PROFBEGIN: return "prof_begin";
|
||||
case token::PROFEND: return "prof_end";
|
||||
case token::THREAD: return "thread";
|
||||
case token::TRUE: return "true";
|
||||
case token::FALSE: return "false";
|
||||
case token::UNDEFINED: return "undefined";
|
||||
case token::SIZE: return "size";
|
||||
case token::GAME: return "game";
|
||||
case token::SELF: return "self";
|
||||
case token::ANIM: return "anim";
|
||||
case token::LEVEL: return "level";
|
||||
case token::CONST: return "const";
|
||||
case token::ISDEFINED: return "isdefined";
|
||||
case token::VECTORSCALE: return "vectorscale";
|
||||
case token::ANGLESTOUP: return "anglestoup";
|
||||
case token::ANGLESTORIGHT: return "anglestoright";
|
||||
case token::ANGLESTOFORWARD: return "anglestoforward";
|
||||
case token::ANGLECLAMP180: return "angleclamp180";
|
||||
case token::VECTORTOANGLES: return "vectorangles";
|
||||
case token::ABS: return "abs";
|
||||
case token::GETTIME: return "gettime";
|
||||
case token::GETDVAR: return "getdvar";
|
||||
case token::GETDVARINT: return "getdvarint";
|
||||
case token::GETDVARFLOAT: return "getdvarfloat";
|
||||
case token::GETDVARVECTOR: return "getdvarvector";
|
||||
case token::GETDVARCOLORRED: return "getdvarcolorred";
|
||||
case token::GETDVARCOLORGREEN: return "getdvarcolorgreen";
|
||||
case token::GETDVARCOLORBLUE: return "getdvarcolorblue";
|
||||
case token::GETDVARCOLORALPHA: return "getdvarcoloralpha";
|
||||
case token::GETFIRSTARRAYKEY: return "getfirstarraykey";
|
||||
case token::GETNEXTARRAYKEY: return "getnextarraykey";
|
||||
default: return "*INTERNAL*";
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace xsk::arc
|
2214
src/arc/compiler.cpp
Normal file
2214
src/arc/compiler.cpp
Normal file
File diff suppressed because it is too large
Load Diff
@ -13,7 +13,7 @@ extern std::array<std::pair<opcode, std::string_view>, opcode_count> const opcod
|
||||
|
||||
context::context(arc::props props, arc::engine engine, arc::endian endian, arc::system system, u64 magic)
|
||||
: props_{ props }, engine_{ engine }, endian_{ endian }, system_{ system }, instance_{ arc::instance::server }, magic_{ magic },
|
||||
source_{ this },/* assembler_{ this },*/ disassembler_{ this }/*, compiler_{ this }*/, decompiler_{ this }
|
||||
source_{ this }, assembler_{ this }, disassembler_{ this }, compiler_{ this }, decompiler_{ this }
|
||||
{
|
||||
opcode_map_.reserve(opcode_list.size());
|
||||
opcode_map_rev_.reserve(opcode_list.size());
|
||||
@ -137,9 +137,9 @@ auto context::opcode_size(opcode op) const -> u32
|
||||
case opcode::OP_GetClasses:
|
||||
case opcode::OP_SuperEqual:
|
||||
case opcode::OP_SuperNotEqual:
|
||||
return (props_ & props::version2) ? 2 : 1;
|
||||
return (props_ & props::size64) ? 2 : 1;
|
||||
case opcode::OP_SafeSetVariableFieldCached:
|
||||
return (props_ & props::version2) ? 3 : 1;
|
||||
return (props_ & props::size64) ? 3 : 1;
|
||||
case opcode::OP_GetByte:
|
||||
case opcode::OP_GetNegByte:
|
||||
case opcode::OP_SafeCreateLocalVariables:
|
||||
@ -154,7 +154,7 @@ auto context::opcode_size(opcode op) const -> u32
|
||||
case opcode::OP_ScriptMethodThreadCallPointer:
|
||||
case opcode::OP_WaitTillMatch:
|
||||
case opcode::OP_VectorConstant:
|
||||
return (props_ & props::version2) ? 3 : 2;
|
||||
return (props_ & props::size64) ? 3 : 2;
|
||||
case opcode::OP_GetUnsignedShort:
|
||||
case opcode::OP_GetNegUnsignedShort:
|
||||
case opcode::OP_JumpOnFalse:
|
||||
@ -165,13 +165,13 @@ auto context::opcode_size(opcode op) const -> u32
|
||||
case opcode::OP_JumpBack:
|
||||
case opcode::OP_DevblockBegin:
|
||||
case opcode::OP_DevblockEnd:
|
||||
return (props_ & props::version2) ? 4 : 3;
|
||||
return (props_ & props::size64) ? 4 : 3;
|
||||
case opcode::OP_GetString:
|
||||
case opcode::OP_GetIString:
|
||||
case opcode::OP_EvalFieldVariable:
|
||||
case opcode::OP_EvalFieldVariableRef:
|
||||
case opcode::OP_ClearFieldVariable:
|
||||
return (props_ & props::version2) ? 6 : 3;
|
||||
return (props_ & props::size64) ? 6 : 3;
|
||||
case opcode::OP_EvalLocalVariableCachedDebug:
|
||||
case opcode::OP_EvalLocalVariableRefCachedDebug:
|
||||
case opcode::OP_LevelEvalFieldVariableRef:
|
||||
@ -185,32 +185,32 @@ auto context::opcode_size(opcode op) const -> u32
|
||||
case opcode::OP_Switch:
|
||||
case opcode::OP_EndSwitch:
|
||||
case opcode::OP_GetHash:
|
||||
return (props_ & props::version2) ? 6 : 5;
|
||||
return (props_ & props::size64) ? 6 : 5;
|
||||
case opcode::OP_ScriptFunctionCallClass:
|
||||
case opcode::OP_ScriptThreadCallClass:
|
||||
return 7;
|
||||
case opcode::OP_GetAPIFunction:
|
||||
return 10;
|
||||
case opcode::OP_ProfileStart:
|
||||
return (props_ & props::version2) ? 10 : 1;
|
||||
return (props_ & props::size64) ? 10 : 1;
|
||||
case opcode::OP_GetAnimation:
|
||||
case opcode::OP_GetFunction:
|
||||
return (props_ & props::version2) ? 10 : 5;
|
||||
return (props_ & props::size64) ? 10 : 5;
|
||||
case opcode::OP_CallBuiltin:
|
||||
case opcode::OP_CallBuiltinMethod:
|
||||
case opcode::OP_ScriptFunctionCall:
|
||||
case opcode::OP_ScriptMethodCall:
|
||||
case opcode::OP_ScriptThreadCall:
|
||||
case opcode::OP_ScriptMethodThreadCall:
|
||||
return (props_ & props::version2) ? 11 : 6;
|
||||
return (props_ & props::size64) ? 11 : 6;
|
||||
case opcode::OP_GetVector:
|
||||
return (props_ & props::version2) ? 14 : 13;
|
||||
return (props_ & props::size64) ? 14 : 13;
|
||||
default:
|
||||
throw error(fmt::format("couldn't resolve instruction size for '{}'", opcode_name(op)));
|
||||
}
|
||||
}
|
||||
|
||||
auto context::opcode_id(opcode op) const -> u8
|
||||
auto context::opcode_id(opcode op) const -> u16
|
||||
{
|
||||
auto const itr = code_map_rev_.find(op);
|
||||
|
||||
@ -256,31 +256,36 @@ auto context::opcode_enum(u16 id) const -> opcode
|
||||
}
|
||||
|
||||
return opcode::OP_Invalid;
|
||||
//throw error(fmt::format("couldn't resolve opcode enum for '{:02X}'", id));
|
||||
}
|
||||
|
||||
auto context::dvar_id(std::string const& /*name*/) const -> u32
|
||||
auto context::hash_id(std::string const& name) const -> u32
|
||||
{
|
||||
// todo hash func
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto context::dvar_name(u32 id) const -> std::string
|
||||
{
|
||||
auto const itr = dvar_map_.find(id);
|
||||
|
||||
if (itr != dvar_map_.end())
|
||||
if (props_ & props::hashids)
|
||||
{
|
||||
return std::string(itr->second);
|
||||
auto* str = name.data();
|
||||
auto hash = 16777619u * (std::tolower(static_cast<u8>(*str)) ^ 1268436527u);
|
||||
|
||||
while (*str++)
|
||||
{
|
||||
hash = 16777619u * (std::tolower(static_cast<u8>(*str)) ^ hash);
|
||||
}
|
||||
|
||||
return fmt::format("_hash_{:08X}", id);
|
||||
}
|
||||
|
||||
auto context::hash_id(std::string const& /*name*/) const -> u32
|
||||
{
|
||||
// todo hash func
|
||||
return hash;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (name.empty())
|
||||
return 0;
|
||||
|
||||
auto hash = 5381u;
|
||||
|
||||
for (auto i = 0u; i < name.size(); i++)
|
||||
{
|
||||
hash = std::tolower(static_cast<u8>(name[i])) + 33 * hash;
|
||||
}
|
||||
|
||||
return hash;
|
||||
}
|
||||
}
|
||||
|
||||
auto context::hash_name(u32 id) const -> std::string
|
||||
@ -295,6 +300,48 @@ auto context::hash_name(u32 id) const -> std::string
|
||||
return fmt::format("_id_{:08X}", id);
|
||||
}
|
||||
|
||||
auto context::make_token(std::string_view str) const -> std::string
|
||||
{
|
||||
if (str.starts_with("_id_") || str.starts_with("_func_") || str.starts_with("_meth_"))
|
||||
{
|
||||
return std::string{ str };
|
||||
}
|
||||
|
||||
auto data = std::string{ str.begin(), str.end() };
|
||||
|
||||
for (auto i = 0u; i < data.size(); i++)
|
||||
{
|
||||
data[i] = static_cast<char>(std::tolower(static_cast<unsigned char>(str[i])));
|
||||
if (data[i] == '\\') data[i] = '/';
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
auto context::load_header(std::string const& name) -> std::tuple<std::string const*, char const*, usize>
|
||||
{
|
||||
auto const itr = header_files_.find(name);
|
||||
|
||||
if (itr != header_files_.end())
|
||||
{
|
||||
return { &itr->first, reinterpret_cast<char const*>(itr->second.data()), itr->second.size() };
|
||||
}
|
||||
|
||||
auto data = fs_callback_(name);
|
||||
|
||||
if (!data.empty())
|
||||
{
|
||||
auto const res = header_files_.insert({ name, std::move(data) });
|
||||
|
||||
if (res.second)
|
||||
{
|
||||
return { &res.first->first, reinterpret_cast<char const*>(res.first->second.data()), res.first->second.size() };
|
||||
}
|
||||
}
|
||||
|
||||
throw error(fmt::format("couldn't open gsh file '{}'", name));
|
||||
}
|
||||
|
||||
extern std::array<std::pair<opcode, std::string_view>, opcode_count> const opcode_list
|
||||
{{
|
||||
{ opcode::OP_Invalid, "OP_Invalid" },
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -4,9 +4,9 @@
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
#include "xsk/stdinc.hpp"
|
||||
#include "xsk/utils/string.hpp"
|
||||
#include "xsk/arc/disassembler.hpp"
|
||||
#include "xsk/arc/context.hpp"
|
||||
#include "xsk/utils/string.hpp"
|
||||
|
||||
namespace xsk::arc
|
||||
{
|
||||
@ -28,7 +28,7 @@ auto disassembler::disassemble(std::vector<u8> const& data) -> assembly::ptr
|
||||
auto disassembler::disassemble(u8 const* data, usize data_size) -> assembly::ptr
|
||||
{
|
||||
script_ = utils::reader{ data, static_cast<u32>(data_size), ctx_->endian() == endian::big };
|
||||
assembly_ = make_assembly();
|
||||
assembly_ = assembly::make();
|
||||
import_refs_.clear();
|
||||
string_refs_.clear();
|
||||
anim_refs_.clear();
|
||||
@ -37,7 +37,7 @@ auto disassembler::disassemble(u8 const* data, usize data_size) -> assembly::ptr
|
||||
header_.magic = script_.read<u64>();
|
||||
|
||||
if (header_.magic != ctx_->magic())
|
||||
throw disasm_error("invalid binary script file!");
|
||||
throw disasm_error("invalid script file or unsupported game version");
|
||||
|
||||
header_.source_crc = script_.read<u32>();
|
||||
header_.include_offset = script_.read<u32>();
|
||||
@ -45,16 +45,20 @@ auto disassembler::disassemble(u8 const* data, usize data_size) -> assembly::ptr
|
||||
header_.cseg_offset = script_.read<u32>();
|
||||
header_.stringtablefixup_offset = script_.read<u32>();
|
||||
|
||||
if (ctx_->props() & props::version2)
|
||||
if (ctx_->props() & props::devstr)
|
||||
header_.devblock_stringtablefixup_offset = script_.read<u32>();
|
||||
|
||||
header_.exports_offset = script_.read<u32>();
|
||||
header_.imports_offset = script_.read<u32>();
|
||||
header_.fixup_offset = script_.read<u32>();
|
||||
|
||||
if (ctx_->props() & props::globals)
|
||||
header_.globalvar_offset = script_.read<u32>();
|
||||
|
||||
header_.profile_offset = script_.read<u32>();
|
||||
header_.cseg_size = script_.read<u32>();
|
||||
|
||||
if (ctx_->props() & props::version2)
|
||||
if (ctx_->props() & props::size64)
|
||||
header_.name = script_.read<u32>();
|
||||
else
|
||||
header_.name = script_.read<u16>();
|
||||
@ -63,9 +67,13 @@ auto disassembler::disassemble(u8 const* data, usize data_size) -> assembly::ptr
|
||||
header_.exports_count = script_.read<u16>();
|
||||
header_.imports_count = script_.read<u16>();
|
||||
header_.fixup_count = script_.read<u16>();
|
||||
|
||||
if (ctx_->props() & props::globals)
|
||||
header_.globalvar_count = script_.read<u16>();
|
||||
|
||||
header_.profile_count = script_.read<u16>();
|
||||
|
||||
if (ctx_->props() & props::version2)
|
||||
if (ctx_->props() & props::devstr)
|
||||
header_.devblock_stringtablefixup_count = script_.read<u16>();
|
||||
|
||||
header_.include_count = script_.read<u8>();
|
||||
@ -73,7 +81,7 @@ auto disassembler::disassemble(u8 const* data, usize data_size) -> assembly::ptr
|
||||
header_.flags = script_.read<u8>();
|
||||
|
||||
auto string_pool = std::map<u32, std::string>{};
|
||||
script_.pos((ctx_->props() & props::version2) ? 72 : 64);
|
||||
script_.pos((ctx_->props() & props::headerxx) ? header_size_v3 : (ctx_->props() & props::header72) ? header_size_v2 : header_size_v1);
|
||||
|
||||
while (script_.pos() < header_.include_offset)
|
||||
{
|
||||
@ -93,10 +101,22 @@ auto disassembler::disassemble(u8 const* data, usize data_size) -> assembly::ptr
|
||||
for (auto i = 0u; i < header_.animtree_count; i++)
|
||||
{
|
||||
auto entry = std::make_shared<animtree_ref>();
|
||||
auto ref_count = 0u;
|
||||
auto anim_count = 0u;
|
||||
|
||||
if (ctx_->props() & props::size64)
|
||||
{
|
||||
entry->name = string_pool.at(script_.read<u32>());
|
||||
ref_count = script_.read<u16>();
|
||||
anim_count = script_.read<u16>();
|
||||
}
|
||||
else
|
||||
{
|
||||
entry->name = string_pool.at(script_.read<u16>());
|
||||
auto ref_count = script_.read<u16>();
|
||||
auto anim_count = script_.read<u16>();
|
||||
ref_count = script_.read<u16>();
|
||||
anim_count = script_.read<u16>();
|
||||
script_.seek(2);
|
||||
}
|
||||
|
||||
for (auto j = 0u; j < ref_count; j++)
|
||||
{
|
||||
@ -107,19 +127,21 @@ auto disassembler::disassemble(u8 const* data, usize data_size) -> assembly::ptr
|
||||
|
||||
for (auto j = 0u; j < anim_count; j++)
|
||||
{
|
||||
auto name = ctx_->hash_name(script_.read<u32>());
|
||||
|
||||
if (ctx_->props() & props::version2)
|
||||
script_.seek(4);
|
||||
|
||||
auto ref = script_.read<u32>();
|
||||
|
||||
if (ctx_->props() & props::version2)
|
||||
script_.seek(4);
|
||||
|
||||
if (ctx_->props() & props::size64)
|
||||
{
|
||||
auto name = string_pool.at(static_cast<u32>(script_.read<u64>()));
|
||||
auto ref = static_cast<u32>(script_.read<u64>());
|
||||
entry->anims.push_back({ name, ref });
|
||||
anim_refs_.insert({ ref, entry });
|
||||
}
|
||||
else
|
||||
{
|
||||
auto name = string_pool.at(script_.read<u32>());
|
||||
auto ref = script_.read<u32>();
|
||||
entry->anims.push_back({ name, ref });
|
||||
anim_refs_.insert({ ref, entry });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
script_.pos(header_.stringtablefixup_offset);
|
||||
@ -127,11 +149,11 @@ auto disassembler::disassemble(u8 const* data, usize data_size) -> assembly::ptr
|
||||
for (auto i = 0u; i < header_.stringtablefixup_count; i++)
|
||||
{
|
||||
auto entry = std::make_shared<string_ref>();
|
||||
entry->name = string_pool.at((ctx_->props() & props::version2) ? script_.read<u32>() : script_.read<u16>());
|
||||
entry->name = string_pool.at((ctx_->props() & props::size64) ? script_.read<u32>() : script_.read<u16>());
|
||||
auto count = script_.read<u8>();
|
||||
entry->type = script_.read<u8>();
|
||||
|
||||
if (ctx_->props() & props::version2)
|
||||
if (ctx_->props() & props::size64)
|
||||
script_.seek(2);
|
||||
|
||||
for (auto j = 0u; j < count; j++)
|
||||
@ -141,14 +163,14 @@ auto disassembler::disassemble(u8 const* data, usize data_size) -> assembly::ptr
|
||||
}
|
||||
}
|
||||
|
||||
if (ctx_->props() & props::version2)
|
||||
if (ctx_->props() & props::devstr)
|
||||
{
|
||||
script_.pos(header_.devblock_stringtablefixup_offset);
|
||||
|
||||
for (auto i = 0u; i < header_.devblock_stringtablefixup_count; i++)
|
||||
{
|
||||
auto entry = std::make_shared<string_ref>();
|
||||
entry->name = "DEVSTR";
|
||||
entry->name = "__devstr__";
|
||||
script_.seek(4);
|
||||
auto count = script_.read<u8>();
|
||||
entry->type = script_.read<u8>();
|
||||
@ -162,13 +184,29 @@ auto disassembler::disassemble(u8 const* data, usize data_size) -> assembly::ptr
|
||||
}
|
||||
}
|
||||
|
||||
if (ctx_->props() & props::globals)
|
||||
{
|
||||
script_.pos(header_.globalvar_offset);
|
||||
|
||||
for (auto i = 0u; i < header_.globalvar_count; i++)
|
||||
{
|
||||
auto name = ctx_->hash_name(script_.read<u32>());
|
||||
auto refs = script_.read<u32>();
|
||||
|
||||
for (auto j = 0u; j < refs; j++)
|
||||
{
|
||||
// todo t8 vars
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
script_.pos(header_.imports_offset);
|
||||
|
||||
for (auto i = 0u; i < header_.imports_count; i++)
|
||||
{
|
||||
auto entry = std::make_shared<import_ref>();
|
||||
|
||||
if (ctx_->props() & props::version2)
|
||||
if (ctx_->props() & props::hashids)
|
||||
{
|
||||
entry->name = ctx_->hash_name(script_.read<u32>());
|
||||
entry->space = ctx_->hash_name(script_.read<u32>());
|
||||
@ -198,7 +236,7 @@ auto disassembler::disassemble(u8 const* data, usize data_size) -> assembly::ptr
|
||||
entry->checksum = script_.read<u32>();
|
||||
entry->offset = script_.read<u32>();
|
||||
|
||||
if (ctx_->props() & props::version2)
|
||||
if (ctx_->props() & props::hashids)
|
||||
{
|
||||
entry->name = ctx_->hash_name(script_.read<u32>());
|
||||
entry->space = ctx_->hash_name(script_.read<u32>());
|
||||
@ -212,7 +250,7 @@ auto disassembler::disassemble(u8 const* data, usize data_size) -> assembly::ptr
|
||||
entry->params = script_.read<u8>();
|
||||
entry->flags = script_.read<u8>();
|
||||
|
||||
if (ctx_->props() & props::version2)
|
||||
if (ctx_->props() & props::hashids)
|
||||
script_.seek(2);
|
||||
|
||||
exports_.push_back(entry);
|
||||
@ -226,15 +264,37 @@ auto disassembler::disassemble(u8 const* data, usize data_size) -> assembly::ptr
|
||||
{
|
||||
entry->size = (exports_[i + 1]->offset - entry->offset);
|
||||
|
||||
auto pad_size = (ctx_->props() & props::version2) ? 8 : 4;
|
||||
auto pad_size = (ctx_->props() & props::size64) ? 8 : 4;
|
||||
auto end_pos = entry->offset + entry->size - pad_size;
|
||||
|
||||
script_.pos(end_pos);
|
||||
|
||||
if ((ctx_->props() & props::version2) && script_.read<u64>() == 0)
|
||||
if ((ctx_->props() & props::size64) && script_.read<u64>() == 0)
|
||||
{
|
||||
entry->size -= pad_size;
|
||||
|
||||
script_.pos(end_pos - 2);
|
||||
script_.align(2);
|
||||
for (auto j = 0; j < 4; j++)
|
||||
{
|
||||
auto op = ctx_->opcode_enum(script_.read<u16>());
|
||||
if (op == opcode::OP_End || op == opcode::OP_Return) break;
|
||||
script_.seek_neg(4);
|
||||
}
|
||||
|
||||
entry->size -= end_pos - script_.pos();
|
||||
}
|
||||
else if (script_.read<u32>() == 0)
|
||||
{
|
||||
entry->size -= pad_size;
|
||||
|
||||
for (auto j = 1; j < 4; j++)
|
||||
{
|
||||
script_.pos(end_pos - j);
|
||||
if (script_.read<u8>() <= 0x01) break;
|
||||
entry->size--;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -243,7 +303,7 @@ auto disassembler::disassemble(u8 const* data, usize data_size) -> assembly::ptr
|
||||
|
||||
script_.pos(entry->offset);
|
||||
|
||||
func_ = make_function();
|
||||
func_ = function::make();
|
||||
func_->index = entry->offset;
|
||||
func_->size = entry->size;
|
||||
func_->params = entry->params;
|
||||
@ -265,17 +325,17 @@ auto disassembler::disassemble_function(function& func) -> void
|
||||
|
||||
while (size > 0)
|
||||
{
|
||||
auto inst = make_instruction();
|
||||
auto inst = instruction::make();
|
||||
inst->index = script_.pos();
|
||||
|
||||
if (ctx_->props() & props::version2)
|
||||
if (ctx_->props() & props::size64)
|
||||
{
|
||||
auto index = script_.read<u16>();
|
||||
|
||||
if (size < 8 && (index >= 0x2000 || ctx_->opcode_enum(index) == opcode::OP_Invalid))
|
||||
if (size < 8 && (index >= 0x4000 || ctx_->opcode_enum(index) == opcode::OP_Invalid))
|
||||
break;
|
||||
|
||||
if ((index & 0x2000) == 0)
|
||||
if ((index & 0x4000) == 0)
|
||||
inst->opcode = ctx_->opcode_enum(index);
|
||||
else
|
||||
throw disasm_error(utils::string::va("invalid opcode index 0x%X at pos '%04X'!", index, inst->index));
|
||||
@ -294,7 +354,7 @@ auto disassembler::disassemble_function(function& func) -> void
|
||||
|
||||
disassemble_instruction(*inst);
|
||||
|
||||
if (ctx_->props() & props::version2)
|
||||
if (ctx_->props() & props::size64)
|
||||
inst->size += script_.align(2);
|
||||
|
||||
size -= inst->size;
|
||||
@ -302,20 +362,23 @@ auto disassembler::disassemble_function(function& func) -> void
|
||||
func.instructions.push_back(std::move(inst));
|
||||
}
|
||||
|
||||
for (auto i = func.instructions.size() - 1; i >= 1; i--)
|
||||
// remove padding garbage ops
|
||||
auto last_idx = 0;
|
||||
for (auto i = 1; i <= 4; i++)
|
||||
{
|
||||
auto& inst = func.instructions.at(i);
|
||||
auto& last = func.instructions.at(i-1);
|
||||
if (func.instructions.size() - i <= 0)
|
||||
break;
|
||||
|
||||
auto& inst = func.instructions.at(func.instructions.size() - i);
|
||||
|
||||
if (inst->opcode == opcode::OP_End || inst->opcode == opcode::OP_Return)
|
||||
last_idx = i;
|
||||
|
||||
if (func.labels.contains(inst->index))
|
||||
break;
|
||||
|
||||
if ((inst->opcode == opcode::OP_End || inst->opcode == opcode::OP_Return)
|
||||
&& (last->opcode != opcode::OP_End && last->opcode != opcode::OP_Return))
|
||||
break;
|
||||
|
||||
func.instructions.pop_back();
|
||||
}
|
||||
|
||||
while (last_idx-- > 1) func.instructions.pop_back();
|
||||
}
|
||||
|
||||
auto disassembler::disassemble_instruction(instruction& inst) -> void
|
||||
@ -456,7 +519,7 @@ auto disassembler::disassemble_instruction(instruction& inst) -> void
|
||||
break;
|
||||
case opcode::OP_GetHash:
|
||||
inst.size += script_.align(4);
|
||||
inst.data.push_back(ctx_->dvar_name(script_.read<u32>()));
|
||||
inst.data.push_back(ctx_->hash_name(script_.read<u32>()));
|
||||
break;
|
||||
case opcode::OP_ScriptFunctionCallClass:
|
||||
case opcode::OP_ScriptThreadCallClass:
|
||||
@ -526,9 +589,9 @@ auto disassembler::disassemble_instruction(instruction& inst) -> void
|
||||
|
||||
auto disassembler::disassemble_name(instruction& inst) -> void
|
||||
{
|
||||
inst.size += script_.align((ctx_->props() & props::version2) ? 4 : 2);
|
||||
inst.size += script_.align((ctx_->props() & props::hashids) ? 4 : 2);
|
||||
|
||||
if (ctx_->props() & props::version2)
|
||||
if (ctx_->props() & props::hashids)
|
||||
{
|
||||
inst.data.push_back(ctx_->hash_name(script_.read<u32>()));
|
||||
}
|
||||
@ -553,11 +616,11 @@ auto disassembler::disassemble_params(instruction& inst) -> void
|
||||
|
||||
for (auto i = 0u; i < count; i++)
|
||||
{
|
||||
if (ctx_->props() & props::version2)
|
||||
if (ctx_->props() & props::hashids)
|
||||
{
|
||||
inst.size += script_.align(4) + 5;
|
||||
inst.data.push_back(ctx_->hash_name(script_.read<u32>()));
|
||||
script_.seek(1);
|
||||
inst.data.push_back(fmt::format("{}", script_.read<u8>()));
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -569,8 +632,8 @@ auto disassembler::disassemble_params(instruction& inst) -> void
|
||||
|
||||
auto disassembler::disassemble_import(instruction& inst) -> void
|
||||
{
|
||||
inst.size += script_.align((ctx_->props() & props::version2) ? 8 : 4);
|
||||
script_.seek((ctx_->props() & props::version2) ? 8 : 4);
|
||||
inst.size += script_.align((ctx_->props() & props::size64) ? 8 : 4);
|
||||
script_.seek((ctx_->props() & props::size64) ? 8 : 4);
|
||||
|
||||
auto const itr = import_refs_.find(inst.index);
|
||||
|
||||
@ -586,14 +649,14 @@ auto disassembler::disassemble_import(instruction& inst) -> void
|
||||
|
||||
auto disassembler::disassemble_string(instruction& inst) -> void
|
||||
{
|
||||
inst.size += script_.align((ctx_->props() & props::version2) ? 4 : 2);
|
||||
inst.size += script_.align((ctx_->props() & props::size64) ? 4 : 2);
|
||||
|
||||
auto const itr = string_refs_.find(script_.pos());
|
||||
|
||||
if (itr != string_refs_.end())
|
||||
{
|
||||
inst.data.push_back(itr->second->name);
|
||||
script_.seek((ctx_->props() & props::version2) ? 4 : 2);
|
||||
script_.seek((ctx_->props() & props::size64) ? 4 : 2);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -612,7 +675,7 @@ auto disassembler::disassemble_animtree(instruction& inst) -> void
|
||||
|
||||
auto disassembler::disassemble_animation(instruction& inst) -> void
|
||||
{
|
||||
inst.size += script_.align((ctx_->props() & props::version2) ? 8 : 4);
|
||||
inst.size += script_.align((ctx_->props() & props::size64) ? 8 : 4);
|
||||
|
||||
auto const ref = script_.pos();
|
||||
auto const itr = anim_refs_.find(ref);
|
||||
@ -626,7 +689,7 @@ auto disassembler::disassemble_animation(instruction& inst) -> void
|
||||
if (anim.ref == ref)
|
||||
{
|
||||
inst.data.push_back(anim.name);
|
||||
script_.seek((ctx_->props() & props::version2) ? 8 : 4);
|
||||
script_.seek((ctx_->props() & props::size64) ? 8 : 4);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -641,7 +704,7 @@ auto disassembler::disassemble_jump(instruction& inst) -> void
|
||||
|
||||
auto addr = u32{};
|
||||
|
||||
if (ctx_->props() & props::version2)
|
||||
if (ctx_->props() & props::size64)
|
||||
addr = ((script_.read<i16>() + 1) & ~(1)) + script_.pos();
|
||||
else
|
||||
addr = script_.read<i16>() + script_.pos();
|
||||
@ -695,17 +758,16 @@ auto disassembler::disassemble_end_switch(instruction& inst) -> void
|
||||
|
||||
for (auto i = 0u; i < count; i++)
|
||||
{
|
||||
if (ctx_->props() & props::version2)
|
||||
if (ctx_->props() & props::size64)
|
||||
{
|
||||
const auto value = script_.read<u32>();
|
||||
const auto str = string_refs_.find(script_.pos() - 4);
|
||||
|
||||
const auto itr = string_refs_.find(script_.pos() - 4);
|
||||
|
||||
if (itr != string_refs_.end())
|
||||
if (str != string_refs_.end())
|
||||
{
|
||||
type = switch_type::string;
|
||||
inst.data.push_back("case");
|
||||
inst.data.push_back(itr->second->name);
|
||||
inst.data.push_back(str->second->name);
|
||||
}
|
||||
else if (value == 0 && i == count - 1)
|
||||
{
|
||||
|
@ -8,7 +8,7 @@
|
||||
namespace xsk::arc::t6
|
||||
{
|
||||
|
||||
extern std::array<std::pair<u32, char const*>, dvar_count> const dvar_list
|
||||
extern std::array<std::pair<u32, char const*>, hash_count> const hash_list
|
||||
{{
|
||||
{ 0x146F2C73, "ClickToContinue" },
|
||||
{ 0x209FFF3B, "FriendXuidToJoinOnBoot" },
|
@ -3,19 +3,24 @@
|
||||
// Use of this source code is governed by a GNU GPLv3 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
#include "xsk/arc/engine/t6.hpp"
|
||||
#include "xsk/arc/engine/t6_pc.hpp"
|
||||
|
||||
namespace xsk::arc::t6
|
||||
{
|
||||
|
||||
extern std::array<std::pair<u8, opcode>, code_count> const code_list;
|
||||
extern std::array<std::pair<u32, char const*>, dvar_count> const dvar_list;
|
||||
extern std::array<std::pair<u32, char const*>, hash_count> const hash_list;
|
||||
|
||||
} // namespace xsk::arc::t6
|
||||
|
||||
namespace xsk::arc::t6::pc
|
||||
{
|
||||
|
||||
context::context() : arc::context(props::none, engine::t6, endian::little, system::pc, header_magic)
|
||||
{
|
||||
code_map_.reserve(code_list.size());
|
||||
code_map_rev_.reserve(code_list.size());
|
||||
dvar_map_.reserve(dvar_list.size());
|
||||
hash_map_.reserve(hash_list.size());
|
||||
|
||||
for (auto const& entry : code_list)
|
||||
{
|
||||
@ -23,10 +28,10 @@ context::context() : arc::context(props::none, engine::t6, endian::little, syste
|
||||
code_map_rev_.insert({ entry.second, entry.first });
|
||||
}
|
||||
|
||||
for (auto const& entry : dvar_list)
|
||||
for (auto const& entry : hash_list)
|
||||
{
|
||||
dvar_map_.insert({ entry.first, entry.second });
|
||||
hash_map_.insert({ entry.first, entry.second });
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace xsk::arc::t6
|
||||
} // namespace xsk::arc::t6::pc
|
37
src/arc/engine/t6_ps3.cpp
Normal file
37
src/arc/engine/t6_ps3.cpp
Normal file
@ -0,0 +1,37 @@
|
||||
// Copyright 2023 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 "xsk/arc/engine/t6_ps3.hpp"
|
||||
|
||||
namespace xsk::arc::t6
|
||||
{
|
||||
|
||||
extern std::array<std::pair<u8, opcode>, code_count> const code_list;
|
||||
extern std::array<std::pair<u32, char const*>, hash_count> const hash_list;
|
||||
|
||||
} // namespace xsk::arc::t6
|
||||
|
||||
namespace xsk::arc::t6::ps3
|
||||
{
|
||||
|
||||
context::context() : arc::context(props::none, engine::t6, endian::big, system::ps3, header_magic)
|
||||
{
|
||||
code_map_.reserve(code_list.size());
|
||||
code_map_rev_.reserve(code_list.size());
|
||||
hash_map_.reserve(hash_list.size());
|
||||
|
||||
for (auto const& entry : code_list)
|
||||
{
|
||||
code_map_.insert({ entry.first, entry.second });
|
||||
code_map_rev_.insert({ entry.second, entry.first });
|
||||
}
|
||||
|
||||
for (auto const& entry : hash_list)
|
||||
{
|
||||
hash_map_.insert({ entry.first, entry.second });
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace xsk::arc::t6::ps3
|
37
src/arc/engine/t6_wiiu.cpp
Normal file
37
src/arc/engine/t6_wiiu.cpp
Normal file
@ -0,0 +1,37 @@
|
||||
// Copyright 2023 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 "xsk/arc/engine/t6_wiiu.hpp"
|
||||
|
||||
namespace xsk::arc::t6
|
||||
{
|
||||
|
||||
extern std::array<std::pair<u8, opcode>, code_count> const code_list;
|
||||
extern std::array<std::pair<u32, char const*>, hash_count> const hash_list;
|
||||
|
||||
} // namespace xsk::arc::t6
|
||||
|
||||
namespace xsk::arc::t6::wiiu
|
||||
{
|
||||
|
||||
context::context() : arc::context(props::none, engine::t6, endian::big, system::wiiu, header_magic)
|
||||
{
|
||||
code_map_.reserve(code_list.size());
|
||||
code_map_rev_.reserve(code_list.size());
|
||||
hash_map_.reserve(hash_list.size());
|
||||
|
||||
for (auto const& entry : code_list)
|
||||
{
|
||||
code_map_.insert({ entry.first, entry.second });
|
||||
code_map_rev_.insert({ entry.second, entry.first });
|
||||
}
|
||||
|
||||
for (auto const& entry : hash_list)
|
||||
{
|
||||
hash_map_.insert({ entry.first, entry.second });
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace xsk::arc::t6::wiiu
|
37
src/arc/engine/t6_xb2.cpp
Normal file
37
src/arc/engine/t6_xb2.cpp
Normal file
@ -0,0 +1,37 @@
|
||||
// Copyright 2023 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 "xsk/arc/engine/t6_xb2.hpp"
|
||||
|
||||
namespace xsk::arc::t6
|
||||
{
|
||||
|
||||
extern std::array<std::pair<u8, opcode>, code_count> const code_list;
|
||||
extern std::array<std::pair<u32, char const*>, hash_count> const hash_list;
|
||||
|
||||
} // namespace xsk::arc::t6
|
||||
|
||||
namespace xsk::arc::t6::xb2
|
||||
{
|
||||
|
||||
context::context() : arc::context(props::none, engine::t6, endian::big, system::xb2, header_magic)
|
||||
{
|
||||
code_map_.reserve(code_list.size());
|
||||
code_map_rev_.reserve(code_list.size());
|
||||
hash_map_.reserve(hash_list.size());
|
||||
|
||||
for (auto const& entry : code_list)
|
||||
{
|
||||
code_map_.insert({ entry.first, entry.second });
|
||||
code_map_rev_.insert({ entry.second, entry.first });
|
||||
}
|
||||
|
||||
for (auto const& entry : hash_list)
|
||||
{
|
||||
hash_map_.insert({ entry.first, entry.second });
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace xsk::arc::t6::xb2
|
@ -9,15 +9,13 @@ namespace xsk::arc::t7
|
||||
{
|
||||
|
||||
extern std::array<std::pair<u16, opcode>, code_count> const code_list;
|
||||
extern std::array<std::pair<u32, char const*>, dvar_count> const dvar_list;
|
||||
extern std::array<std::pair<u32, char const*>, hash_count> const hash_list;
|
||||
|
||||
context::context() : arc::context(props::version2, engine::t7, endian::little, system::pc, header_magic)
|
||||
context::context() : arc::context(props::header72 | props::size64 | props::hashids | props::devstr | props::spaces | props::refvarg | props::foreach, engine::t7, endian::little, system::pc, header_magic)
|
||||
{
|
||||
code_map_.reserve(code_list.size());
|
||||
code_map_rev_.reserve(code_list.size());
|
||||
dvar_map_.reserve(dvar_list.size());
|
||||
hash_map_.reserve(dvar_list.size());
|
||||
hash_map_.reserve(hash_list.size());
|
||||
|
||||
for (auto const& entry : code_list)
|
||||
{
|
||||
@ -25,11 +23,6 @@ context::context() : arc::context(props::version2, engine::t7, endian::little, s
|
||||
code_map_rev_.insert({ entry.second, entry.first });
|
||||
}
|
||||
|
||||
for (auto const& entry : dvar_list)
|
||||
{
|
||||
dvar_map_.insert({ entry.first, entry.second });
|
||||
}
|
||||
|
||||
for (auto const& entry : hash_list)
|
||||
{
|
||||
hash_map_.insert({ entry.first, entry.second });
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -43,12 +43,14 @@ extern std::array<std::pair<u32, char const*>, hash_count> const hash_list
|
||||
{ 0x9E8B905B, "__chance" },
|
||||
{ 0x0780CE43, "__clientfacialanimationslist" },
|
||||
{ 0xD4F49BA0, "__clientfacialanimationsthinkstarted" },
|
||||
{ 0x9B385CA5, "__constructor" },
|
||||
{ 0xF5A9BA65, "__create_client_hud_elem" },
|
||||
{ 0xC3E36C3C, "__def" },
|
||||
{ 0x2633B922, "__default" },
|
||||
{ 0xCB96917F, "__default1" },
|
||||
{ 0x598F2244, "__default2" },
|
||||
{ 0xD31F0F7B, "__delta" },
|
||||
{ 0x5FBA2032, "__destructor" },
|
||||
{ 0x2AD2861E, "__do_last_step__" },
|
||||
{ 0x23A342B8, "__e" },
|
||||
{ 0x23D5C676, "__ent" },
|
||||
@ -3515,6 +3517,7 @@ extern std::array<std::pair<u32, char const*>, hash_count> const hash_list
|
||||
{ 0x3086DAA7, "_helicopter_gunner" },
|
||||
{ 0xAE68C2F1, "_helicopter_player" },
|
||||
{ 0x623206BA, "_helicopter_sounds" },
|
||||
{ 0x795DF34D, "_hero_catch_up_teleport_" },
|
||||
{ 0xE1CAC31A, "_hero_weapons" },
|
||||
{ 0x4D5B3B7C, "_hidden" },
|
||||
{ 0x91589476, "_hide_hud_count" },
|
||||
@ -9401,6 +9404,7 @@ extern std::array<std::pair<u32, char const*>, hash_count> const hash_list
|
||||
{ 0xBC27A54D, "abomb_targets" },
|
||||
{ 0xB4B62264, "abomination" },
|
||||
{ 0xDF918999, "abort" },
|
||||
{ 0x577494DC, "abort forfeit" },
|
||||
{ 0x8A6D95B8, "abort_approach" },
|
||||
{ 0xB02DC2C7, "abort_chain" },
|
||||
{ 0xBF23185E, "abort_death_watch" },
|
||||
@ -9428,6 +9432,7 @@ extern std::array<std::pair<u32, char const*>, hash_count> const hash_list
|
||||
{ 0x2ECF4B3E, "abound" },
|
||||
{ 0x575675D4, "about" },
|
||||
{ 0x311D5773, "about_to_die" },
|
||||
{ 0xB9A2E2CB, "about_to_fire" },
|
||||
{ 0xF892DEC0, "about_to_shoot" },
|
||||
{ 0xB87057A8, "aboutotlaunch" },
|
||||
{ 0x47D871AC, "abouttobebreached" },
|
||||
@ -14166,6 +14171,7 @@ extern std::array<std::pair<u32, char const*>, hash_count> const hash_list
|
||||
{ 0xBCDA1AD4, "aivsaimeleecombat" },
|
||||
{ 0x6E8328CE, "aivsaimeleeinitialize" },
|
||||
{ 0x32BC8627, "aivsaimeleerangesq" },
|
||||
{ 0x20B9DF71, "aivsaimeleewinner" },
|
||||
{ 0x4495F04F, "aiweapon" },
|
||||
{ 0xFD2120AE, "ajoining" },
|
||||
{ 0x8C496009, "ak" },
|
||||
@ -18054,6 +18060,7 @@ extern std::array<std::pair<u32, char const*>, hash_count> const hash_list
|
||||
{ 0x448E6DC8, "asking" },
|
||||
{ 0xC865E646, "asm" },
|
||||
{ 0x0BCA5382, "asm_alias_attribute" },
|
||||
{ 0x6F82574C, "asm_complete" },
|
||||
{ 0x1A8B762F, "asm_death_notify" },
|
||||
{ 0x9C192458, "asm_faller_deathout_notetrack" },
|
||||
{ 0x55A1B5F2, "asm_faller_melee_notetrack" },
|
||||
@ -18077,6 +18084,7 @@ extern std::array<std::pair<u32, char const*>, hash_count> const hash_list
|
||||
{ 0x1951F8D4, "asm_state_running" },
|
||||
{ 0x007ED8D0, "asm_state_terminated" },
|
||||
{ 0x86C8881C, "asm_state_transition_complete" },
|
||||
{ 0x1AE8BD76, "asm_terminated" },
|
||||
{ 0x4DA9AAE3, "asm_thrasher_melee_notetrack" },
|
||||
{ 0xBDCCC6EB, "asm_zombie_crush_notetrack" },
|
||||
{ 0x9B4512F1, "asm_zombie_dog_melee_notetrack" },
|
||||
@ -22919,6 +22927,7 @@ extern std::array<std::pair<u32, char const*>, hash_count> const hash_list
|
||||
{ 0x7C4E05D3, "bgb_blow_bubble_fx_name" },
|
||||
{ 0xE4E15C9A, "bgb_current_cf_name" },
|
||||
{ 0x26B90C53, "bgb_display_cf_name" },
|
||||
{ 0xA3D84497, "bgb_flavor_hexed_give_" },
|
||||
{ 0xEBE6EB3D, "bgb_idle_eyes_active" },
|
||||
{ 0x3F330E54, "bgb_in_plain_sight_active" },
|
||||
{ 0x1D83009C, "bgb_in_use" },
|
||||
@ -22947,6 +22956,7 @@ extern std::array<std::pair<u32, char const*>, hash_count> const hash_list
|
||||
{ 0x00C0E28B, "bgb_timer_manual_lerp_threshold" },
|
||||
{ 0xADE8E118, "bgb_token" },
|
||||
{ 0xE6DEC57E, "bgb_tone_death" },
|
||||
{ 0xAE9023A9, "bgb_update_give_" },
|
||||
{ 0x37224D3F, "bgbar" },
|
||||
{ 0xA5DB58C6, "bgbignorefearinheadlights" },
|
||||
{ 0xBE22AE54, "bgelm" },
|
||||
@ -24278,6 +24288,7 @@ extern std::array<std::pair<u32, char const*>, hash_count> const hash_list
|
||||
{ 0x190777ED, "bodycolors" },
|
||||
{ 0x51D70D80, "bodydamagedmap" },
|
||||
{ 0x4E96B6ED, "bodydamagetags" },
|
||||
{ 0xFCD109C7, "bodyfall large" },
|
||||
{ 0xB4036965, "bodyfallcb" },
|
||||
{ 0x375AC166, "bodyguard_bezerk" },
|
||||
{ 0x260A8649, "bodyguard_died" },
|
||||
@ -30269,6 +30280,7 @@ extern std::array<std::pair<u32, char const*>, hash_count> const hash_list
|
||||
{ 0x89CFDADB, "canbleed" },
|
||||
{ 0x19A075AE, "canblindfire" },
|
||||
{ 0xA1AE3CCB, "cancel" },
|
||||
{ 0xAD4A3C97, "cancel speaking" },
|
||||
{ 0x9A0A3264, "cancel_anim_reach_hudson_melee" },
|
||||
{ 0xEAE92172, "cancel_button_press" },
|
||||
{ 0xDDE283EB, "cancel_button_think" },
|
||||
@ -31144,6 +31156,7 @@ extern std::array<std::pair<u32, char const*>, hash_count> const hash_list
|
||||
{ 0x9B615544, "cclass" },
|
||||
{ 0x6E63CD5E, "cclass_power" },
|
||||
{ 0x10667BA3, "ccn" },
|
||||
{ 0x4A129F22, "ccom_lock_being_targeted" },
|
||||
{ 0x74810FD1, "ccontainer" },
|
||||
{ 0xB281BE26, "ccs" },
|
||||
{ 0x5A38BDDD, "cctv" },
|
||||
@ -45011,6 +45024,7 @@ extern std::array<std::pair<u32, char const*>, hash_count> const hash_list
|
||||
{ 0x75ECA6B5, "custom_think" },
|
||||
{ 0x4F70B82F, "custom_tower_trap_fires_func" },
|
||||
{ 0x05B04D4D, "custom_trapped_zombies" },
|
||||
{ 0x154A271A, "custom_traversal_anim_finished" },
|
||||
{ 0x5B0C67F2, "custom_traversal_cleanup" },
|
||||
{ 0xB876B1D8, "custom_treasure_chest_glowfx" },
|
||||
{ 0x997A4627, "custom_umbra_hotfix" },
|
||||
@ -45255,6 +45269,7 @@ extern std::array<std::pair<u32, char const*>, hash_count> const hash_list
|
||||
{ 0x72F01E20, "dam_type" },
|
||||
{ 0xA1409ACB, "dam_types" },
|
||||
{ 0xF9348FDA, "damage" },
|
||||
{ 0x2B25E23D, "damage state" },
|
||||
{ 0x2D49FAE7, "damage1" },
|
||||
{ 0xBB428BAC, "damage2" },
|
||||
{ 0xE1450615, "damage3" },
|
||||
@ -48456,6 +48471,7 @@ extern std::array<std::pair<u32, char const*>, hash_count> const hash_list
|
||||
{ 0x7BDF1958, "destent" },
|
||||
{ 0xB3B2AB6E, "destfov" },
|
||||
{ 0xF571697F, "destination" },
|
||||
{ 0x9B1F1E2D, "destination reached" },
|
||||
{ 0x68BDA8D7, "destination_name" },
|
||||
{ 0x4F010B4E, "destination_node" },
|
||||
{ 0xE6C9F7F1, "destination_nodes" },
|
||||
@ -48468,6 +48484,7 @@ extern std::array<std::pair<u32, char const*>, hash_count> const hash_list
|
||||
{ 0x84389823, "destinationpoint" },
|
||||
{ 0x25C54C86, "destinations" },
|
||||
{ 0x6835E75F, "destinationvec" },
|
||||
{ 0xDF1F87C9, "destintation reached" },
|
||||
{ 0x459CCA09, "destiny" },
|
||||
{ 0x56375830, "destname" },
|
||||
{ 0xF95CF5A1, "destnode" },
|
||||
@ -51123,6 +51140,7 @@ extern std::array<std::pair<u32, char const*>, hash_count> const hash_list
|
||||
{ 0x4BAB3A56, "dlc3_teleporter" },
|
||||
{ 0x5EC9856D, "dlc3_threadcalls" },
|
||||
{ 0x37C12215, "dlc3_threadcalls2" },
|
||||
{ 0xCEF0D8AE, "dlc3_zombie_five_teleports" },
|
||||
{ 0x01FFF241, "dlc5" },
|
||||
{ 0xC1E325A0, "dlg" },
|
||||
{ 0xB2D1F001, "dlg_easy_rhino_done" },
|
||||
@ -52569,6 +52587,7 @@ extern std::array<std::pair<u32, char const*>, hash_count> const hash_list
|
||||
{ 0xF8857CCC, "donate" },
|
||||
{ 0xAF0772E0, "donated" },
|
||||
{ 0x355070E1, "done" },
|
||||
{ 0x90F83311, "done speaking" },
|
||||
{ 0xCC4C335B, "done_aimaware" },
|
||||
{ 0xDF245174, "done_animating" },
|
||||
{ 0x0102C0A5, "done_avoiding" },
|
||||
@ -52759,6 +52778,7 @@ extern std::array<std::pair<u32, char const*>, hash_count> const hash_list
|
||||
{ 0x1585184F, "door_align" },
|
||||
{ 0x4ABFFE9E, "door_align_node" },
|
||||
{ 0xE641AF94, "door_anglesmod" },
|
||||
{ 0x27E6C447, "door_anim" },
|
||||
{ 0x07F84216, "door_anim_node" },
|
||||
{ 0xFC29021A, "door_b" },
|
||||
{ 0xB12CEB8D, "door_b_open" },
|
||||
@ -57581,6 +57601,7 @@ extern std::array<std::pair<u32, char const*>, hash_count> const hash_list
|
||||
{ 0x3C6BCDE6, "encryption" },
|
||||
{ 0x2E848D0F, "encure" },
|
||||
{ 0x03FC1574, "end" },
|
||||
{ 0x18E2BBBB, "end line sound" },
|
||||
{ 0x6412E650, "end04" },
|
||||
{ 0x3F23B514, "end04_fade_out_black" },
|
||||
{ 0xD43651CE, "end04_start_drag" },
|
||||
@ -57616,6 +57637,8 @@ extern std::array<std::pair<u32, char const*>, hash_count> const hash_list
|
||||
{ 0xC5C17B1F, "end_anim_thread" },
|
||||
{ 0x2F2E297B, "end_arena_migs" },
|
||||
{ 0x3A271186, "end_array" },
|
||||
{ 0xE8F330BF, "end_asm_terminated_thread" },
|
||||
{ 0xF3B632F7, "end_asm_timeout_thread" },
|
||||
{ 0x61CC13FB, "end_at_node" },
|
||||
{ 0x63F079B8, "end_at_num_guys" },
|
||||
{ 0x44FD873A, "end_attack_thread" },
|
||||
@ -57810,6 +57833,7 @@ extern std::array<std::pair<u32, char const*>, hash_count> const hash_list
|
||||
{ 0x6F193E90, "end_hunt" },
|
||||
{ 0xBCAA5A3D, "end_idle" },
|
||||
{ 0xDDE01E26, "end_igc" },
|
||||
{ 0x893FBBB3, "end_immolating_thread" },
|
||||
{ 0x48926C19, "end_in_tube_rumble" },
|
||||
{ 0x4ED8D59D, "end_index" },
|
||||
{ 0xD93563AC, "end_intro_flak" },
|
||||
@ -62125,6 +62149,7 @@ extern std::array<std::pair<u32, char const*>, hash_count> const hash_list
|
||||
{ 0xC4F68E68, "evt_1_torture" },
|
||||
{ 0x4AD37599, "evt_blizzard_gust" },
|
||||
{ 0x22AA8F1C, "evt_c4_det" },
|
||||
{ 0x56449443, "evt_carpenter_end" },
|
||||
{ 0x3419DF0E, "evt_dragovich_drown_loop" },
|
||||
{ 0x1CC34FB1, "evt_jet_flyby2" },
|
||||
{ 0xAF3E5437, "evt_numbers" },
|
||||
@ -63298,6 +63323,7 @@ extern std::array<std::pair<u32, char const*>, hash_count> const hash_list
|
||||
{ 0x0225046E, "eyepos" },
|
||||
{ 0x2215B799, "eyeposition" },
|
||||
{ 0xFE56760B, "eyes" },
|
||||
{ 0xC1896D90, "eyes look now" },
|
||||
{ 0x770277DC, "eyes_on_the_wall" },
|
||||
{ 0x900FEC00, "eyes_spawned" },
|
||||
{ 0xF5478868, "eyesatenemy" },
|
||||
@ -64154,6 +64180,7 @@ extern std::array<std::pair<u32, char const*>, hash_count> const hash_list
|
||||
{ 0x104646F5, "fallanim" },
|
||||
{ 0x641392AD, "fallanimstatedef" },
|
||||
{ 0x748DB797, "fallback" },
|
||||
{ 0x05D4B3A4, "fallback initiated " },
|
||||
{ 0xBD260C57, "fallback_430" },
|
||||
{ 0x20207AE5, "fallback_add_previous_group" },
|
||||
{ 0x2B3B637C, "fallback_ai" },
|
||||
@ -65200,6 +65227,7 @@ extern std::array<std::pair<u32, char const*>, hash_count> const hash_list
|
||||
{ 0xD96F4AB1, "finishcustomtraversallistener" },
|
||||
{ 0xC92C5DD5, "finishdualhardpointlocationusage" },
|
||||
{ 0x6301ECEB, "finished" },
|
||||
{ 0xF42B7E06, "finished spawning" },
|
||||
{ 0xEA8AB8FA, "finished_boarding" },
|
||||
{ 0xF8D5F1EC, "finished_custom_animmode" },
|
||||
{ 0xA3E6B080, "finished_eating" },
|
||||
@ -66034,6 +66062,7 @@ extern std::array<std::pair<u32, char const*>, hash_count> const hash_list
|
||||
{ 0xB70EF5E0, "fl_flag" },
|
||||
{ 0xCC0982E9, "flacked" },
|
||||
{ 0xAD23E503, "flag" },
|
||||
{ 0x4008E0D0, "flag check is running" },
|
||||
{ 0xCCA6AFE0, "flag1" },
|
||||
{ 0x3EAE1F1B, "flag2" },
|
||||
{ 0x18ABA4B2, "flag3" },
|
||||
@ -67869,6 +67898,7 @@ extern std::array<std::pair<u32, char const*>, hash_count> const hash_list
|
||||
{ 0x485A51AE, "foreverever" },
|
||||
{ 0x0F5E573A, "foreverrr" },
|
||||
{ 0xBC7C993A, "forfeit" },
|
||||
{ 0xD343F3A0, "forfeit in progress" },
|
||||
{ 0x4DFB2196, "forfeit_count" },
|
||||
{ 0xE0F2E2E6, "forfeit_delay" },
|
||||
{ 0xB0BCD5CD, "forfeited" },
|
||||
@ -71240,6 +71270,7 @@ extern std::array<std::pair<u32, char const*>, hash_count> const hash_list
|
||||
{ 0x40F8302A, "gastrap_mask_off" },
|
||||
{ 0x06092F9D, "gasusage" },
|
||||
{ 0x7D67C678, "gate" },
|
||||
{ 0x91FF5153, "gate opened" },
|
||||
{ 0xA83842C1, "gate1" },
|
||||
{ 0x4CE1AFE2, "gate1_origin" },
|
||||
{ 0xCE3ABD2A, "gate2" },
|
||||
@ -74883,6 +74914,7 @@ extern std::array<std::pair<u32, char const*>, hash_count> const hash_list
|
||||
{ 0xAA49E925, "girl_dance4" },
|
||||
{ 0xF87746FE, "girls" },
|
||||
{ 0x5B0ED0BA, "give" },
|
||||
{ 0xE4AE4515, "give up" },
|
||||
{ 0x870B5138, "give_ability_now" },
|
||||
{ 0x52C9C74A, "give_achievement" },
|
||||
{ 0xAFAF20EB, "give_additional_primary_weapon_perk" },
|
||||
@ -75513,6 +75545,9 @@ extern std::array<std::pair<u32, char const*>, hash_count> const hash_list
|
||||
{ 0xEBF7D9AF, "goal_type" },
|
||||
{ 0xA5F4CEB5, "goal_volume" },
|
||||
{ 0xE13533BE, "goal_volume_init" },
|
||||
{ 0xB61DFA9E, "goal_wait_notify_lase" },
|
||||
{ 0x6A517A0A, "goal_watcher_patrol" },
|
||||
{ 0x6FB6A6D3, "goal_watcher_target" },
|
||||
{ 0xA68AD6E5, "goal_when_cantsee" },
|
||||
{ 0xFF3CC935, "goal_world_offset" },
|
||||
{ 0xA2463F80, "goal_yaw" },
|
||||
@ -75712,6 +75747,7 @@ extern std::array<std::pair<u32, char const*>, hash_count> const hash_list
|
||||
{ 0x9C0A6350, "goslowmo" },
|
||||
{ 0x34B24FD0, "gospeed" },
|
||||
{ 0x3F6AA549, "got" },
|
||||
{ 0xA5FB63C6, "got known enemy2" },
|
||||
{ 0x804F5C21, "got_a_tomahawk_kill" },
|
||||
{ 0x9443D9E6, "got_ability" },
|
||||
{ 0x6BA63C86, "got_ai" },
|
||||
@ -75735,6 +75771,7 @@ extern std::array<std::pair<u32, char const*>, hash_count> const hash_list
|
||||
{ 0xE42A4FFC, "gotime" },
|
||||
{ 0xF3C1F5D9, "gotnewhighscore" },
|
||||
{ 0x3447CCBC, "goto" },
|
||||
{ 0x1F355AD7, "goto next fallback" },
|
||||
{ 0x7317DA2E, "goto_barge" },
|
||||
{ 0xC74D9E62, "goto_current_colorindex" },
|
||||
{ 0x75B50151, "goto_func" },
|
||||
@ -79698,6 +79735,7 @@ extern std::array<std::pair<u32, char const*>, hash_count> const hash_list
|
||||
{ 0x42E82B74, "hero_append" },
|
||||
{ 0xF6F77532, "hero_attacks_enemy" },
|
||||
{ 0x2E0D60CD, "hero_call_sniper_pos" },
|
||||
{ 0x89827D0F, "hero_catch_up_teleport" },
|
||||
{ 0xBD1509CA, "hero_chain_start" },
|
||||
{ 0xE3D84590, "hero_chain_trig" },
|
||||
{ 0x61ABC45D, "hero_clientfield_power" },
|
||||
@ -82536,6 +82574,7 @@ extern std::array<std::pair<u32, char const*>, hash_count> const hash_list
|
||||
{ 0x3D2667AF, "ifadetime" },
|
||||
{ 0x410114EA, "iff" },
|
||||
{ 0x03CEDE31, "iff_override" },
|
||||
{ 0x6EB14BB1, "iff_override_reverted" },
|
||||
{ 0xF5C12ECD, "ifiretime" },
|
||||
{ 0x03B6577D, "ifirstbreachers" },
|
||||
{ 0x28768E77, "iflashfuse" },
|
||||
@ -88835,6 +88874,7 @@ extern std::array<std::pair<u32, char const*>, hash_count> const hash_list
|
||||
{ 0x5366694F, "jungle_stealth_skipto_clean_up" },
|
||||
{ 0x12D18B52, "jungle_stealth_spawn_funcs" },
|
||||
{ 0x05AEADF3, "junk" },
|
||||
{ 0xBF60BC80, "junk purchased" },
|
||||
{ 0x5ED1B490, "junk1" },
|
||||
{ 0xD0D923CB, "junk2" },
|
||||
{ 0xAAD6A962, "junk3" },
|
||||
@ -89854,6 +89894,7 @@ extern std::array<std::pair<u32, char const*>, hash_count> const hash_list
|
||||
{ 0x7155C0B3, "killdtpmonitor" },
|
||||
{ 0x48F5BB3A, "kille_ridge_vcs_quickly" },
|
||||
{ 0x39D3D8BA, "killed" },
|
||||
{ 0x9696A8AD, "killed all targets" },
|
||||
{ 0x12B3B846, "killed_50cal" },
|
||||
{ 0x6ECC9F0E, "killed_a_player" },
|
||||
{ 0x404982D1, "killed_a_zombie_player" },
|
||||
@ -90929,6 +90970,9 @@ extern std::array<std::pair<u32, char const*>, hash_count> const hash_list
|
||||
{ 0xC0938265, "larry_the_limper_tweaktech_halved" },
|
||||
{ 0xDE893D08, "larry_thread" },
|
||||
{ 0x047339A4, "lase" },
|
||||
{ 0x50B88A46, "lase_goal" },
|
||||
{ 0x565DAAC6, "lase_points" },
|
||||
{ 0xB39FFFD7, "lase_points_loop" },
|
||||
{ 0x91410B6E, "laser" },
|
||||
{ 0x9603D750, "laser_awareness" },
|
||||
{ 0x120B1E9B, "laser_death_thread_stop" },
|
||||
@ -93794,6 +93838,8 @@ extern std::array<std::pair<u32, char const*>, hash_count> const hash_list
|
||||
{ 0x0365B14C, "lockers" },
|
||||
{ 0xFB301981, "lockheliheight" },
|
||||
{ 0x30FF42E0, "locking" },
|
||||
{ 0xB081980B, "locking on" },
|
||||
{ 0xE1494B46, "locking on hacking" },
|
||||
{ 0xAE1DF088, "locking_on" },
|
||||
{ 0xEE40CEC9, "locking_on_cleared" },
|
||||
{ 0xA6523740, "locking_on_hacking" },
|
||||
@ -93982,6 +94028,7 @@ extern std::array<std::pair<u32, char const*>, hash_count> const hash_list
|
||||
{ 0x4E427F1A, "longs" },
|
||||
{ 0x8EC8835A, "longshots" },
|
||||
{ 0x73D41D3C, "look" },
|
||||
{ 0x9A1A418C, "look now" },
|
||||
{ 0x3F16A0D6, "look2" },
|
||||
{ 0x02D6B2F4, "look2alert_cornerl" },
|
||||
{ 0x5B07C260, "look4" },
|
||||
@ -100062,6 +100109,8 @@ extern std::array<std::pair<u32, char const*>, hash_count> const hash_list
|
||||
{ 0xDB6D9FE2, "missedsightchecks" },
|
||||
{ 0x0565DDD1, "misses" },
|
||||
{ 0x4A93C703, "missile" },
|
||||
{ 0xB0C5EA03, "missile fired" },
|
||||
{ 0x2FF1AD5E, "missile ready" },
|
||||
{ 0x737DC418, "missile01_end" },
|
||||
{ 0x18CD813B, "missile01_start" },
|
||||
{ 0x349D8C9B, "missile02_end" },
|
||||
@ -106560,6 +106609,7 @@ extern std::array<std::pair<u32, char const*>, hash_count> const hash_list
|
||||
{ 0x893CBBF1, "nevski_door_node" },
|
||||
{ 0xEB6D7513, "nevsky" },
|
||||
{ 0xD4305EFD, "new" },
|
||||
{ 0x3790D3C8, "new debug_vehiclesetspeed" },
|
||||
{ 0x58F8ECE5, "new2" },
|
||||
{ 0x67E94495, "new_aatarget" },
|
||||
{ 0x4FFCA9E2, "new_ability" },
|
||||
@ -107597,6 +107647,7 @@ extern std::array<std::pair<u32, char const*>, hash_count> const hash_list
|
||||
{ 0xE39956D0, "nnodes" },
|
||||
{ 0x10667DF0, "nnw" },
|
||||
{ 0x06BEE09C, "no" },
|
||||
{ 0x46D36511, "no valid boards" },
|
||||
{ 0x3DA5BD09, "no3d" },
|
||||
{ 0xE931BC28, "no_accuracy" },
|
||||
{ 0x32A28D44, "no_airstrike_ammo" },
|
||||
@ -115545,6 +115596,7 @@ extern std::array<std::pair<u32, char const*>, hash_count> const hash_list
|
||||
{ 0x5F4354B9, "patches" },
|
||||
{ 0xA832A6BF, "patching" },
|
||||
{ 0xD9A41C78, "path" },
|
||||
{ 0xDF5908AC, "path start" },
|
||||
{ 0xC8B618B8, "path1end" },
|
||||
{ 0xB5410FDB, "path1start" },
|
||||
{ 0x1951E3F1, "path2end" },
|
||||
@ -115790,6 +115842,7 @@ extern std::array<std::pair<u32, char const*>, hash_count> const hash_list
|
||||
{ 0x04DBAFFA, "patrol_guys" },
|
||||
{ 0x54DFC4BC, "patrol_init" },
|
||||
{ 0x36E51EDE, "patrol_init_custom" },
|
||||
{ 0x8D1875DC, "patrol_lase_goal_waiter" },
|
||||
{ 0x1B9E35BC, "patrol_loop" },
|
||||
{ 0xA2D2DAEA, "patrol_loop_then_retreat" },
|
||||
{ 0x04776A45, "patrol_main" },
|
||||
@ -122731,6 +122784,7 @@ extern std::array<std::pair<u32, char const*>, hash_count> const hash_list
|
||||
{ 0x48F2CA23, "power_occupied" },
|
||||
{ 0x5E20D7B6, "power_off" },
|
||||
{ 0xB5078790, "power_off_callback" },
|
||||
{ 0x5060BE39, "power_off_done" },
|
||||
{ 0xB012591F, "power_off_func" },
|
||||
{ 0xE22A8AA8, "power_on" },
|
||||
{ 0xAC043BAC, "power_on_all" },
|
||||
@ -122817,6 +122871,10 @@ extern std::array<std::pair<u32, char const*>, hash_count> const hash_list
|
||||
{ 0x568A1EF0, "powertoadd" },
|
||||
{ 0x366C6CDB, "powertoremove" },
|
||||
{ 0x0A6DB0B7, "powerup" },
|
||||
{ 0xAB83A4DB, "powerup bonfire sale" },
|
||||
{ 0x3B3C2756, "powerup fire sale" },
|
||||
{ 0x6E291DA5, "powerup instakill_" },
|
||||
{ 0x041C2BF1, "powerup points scaled_" },
|
||||
{ 0x39F3CA14, "powerup_any_team" },
|
||||
{ 0x9211EE00, "powerup_areas" },
|
||||
{ 0xF687758D, "powerup_array" },
|
||||
@ -123864,6 +123922,7 @@ extern std::array<std::pair<u32, char const*>, hash_count> const hash_list
|
||||
{ 0xD4633AC5, "primaries" },
|
||||
{ 0xEC008070, "primarily" },
|
||||
{ 0x43C330DD, "primary" },
|
||||
{ 0x907788C7, "primary acquired" },
|
||||
{ 0xDFB9CC32, "primary_ai_switchtarget" },
|
||||
{ 0x0CBE7357, "primary_alarm" },
|
||||
{ 0x175A80F7, "primary_attachment" },
|
||||
@ -127721,6 +127780,8 @@ extern std::array<std::pair<u32, char const*>, hash_count> const hash_list
|
||||
{ 0xE4631170, "recaptured" },
|
||||
{ 0x9124D82C, "receive" },
|
||||
{ 0xD145B0C0, "received" },
|
||||
{ 0x02528173, "received award" },
|
||||
{ 0xF0FA2450, "received teammessage" },
|
||||
{ 0xD8457870, "receiveddialog" },
|
||||
{ 0x1565F655, "receivedtext" },
|
||||
{ 0x157C35C6, "receiver" },
|
||||
@ -130174,6 +130235,7 @@ extern std::array<std::pair<u32, char const*>, hash_count> const hash_list
|
||||
{ 0xBBE04EFF, "resumetimer" },
|
||||
{ 0xE7089A23, "resumetimerdiscardoverride" },
|
||||
{ 0x9EC0F145, "resuming" },
|
||||
{ 0xEEAEC2A0, "resuming speed" },
|
||||
{ 0x810A3167, "resupply" },
|
||||
{ 0x183E8A4C, "resurfacetime" },
|
||||
{ 0xEEC6038F, "resurrct" },
|
||||
@ -136855,6 +136917,7 @@ extern std::array<std::pair<u32, char const*>, hash_count> const hash_list
|
||||
{ 0x20A9A491, "secondaries" },
|
||||
{ 0x17B5521C, "secondarray" },
|
||||
{ 0x1CE98AB1, "secondary" },
|
||||
{ 0x519AF70B, "secondary acquired" },
|
||||
{ 0x356CEB5B, "secondary_attachment" },
|
||||
{ 0x607A33C4, "secondary_attachment_flag" },
|
||||
{ 0xAFF3A9EE, "secondary_attachment_mask" },
|
||||
@ -137838,6 +137901,7 @@ extern std::array<std::pair<u32, char const*>, hash_count> const hash_list
|
||||
{ 0xE0BEB6EE, "sessionstate" },
|
||||
{ 0xB2E5A818, "sessionteam" },
|
||||
{ 0x74D6B22F, "set" },
|
||||
{ 0x47341E47, "set name and rank" },
|
||||
{ 0xD68111E4, "set1" },
|
||||
{ 0x4888811F, "set2" },
|
||||
{ 0x000F7196, "set2dicon" },
|
||||
@ -142741,6 +142805,7 @@ extern std::array<std::pair<u32, char const*>, hash_count> const hash_list
|
||||
{ 0x9899333A, "shuoldnt" },
|
||||
{ 0xFF326A3F, "shut" },
|
||||
{ 0xB9133872, "shut_down_chopper_support" },
|
||||
{ 0x777B79D1, "shut_off" },
|
||||
{ 0x1F78A85D, "shut_off_all_looping_sounds" },
|
||||
{ 0xA491838E, "shut_off_boat" },
|
||||
{ 0x9329F246, "shut_off_fx" },
|
||||
@ -149829,6 +149894,7 @@ extern std::array<std::pair<u32, char const*>, hash_count> const hash_list
|
||||
{ 0x8979D298, "stark" },
|
||||
{ 0xF93E58C0, "stars" },
|
||||
{ 0x034FB19F, "start" },
|
||||
{ 0x6D76E1DB, "start fx" },
|
||||
{ 0xCFE91694, "start1" },
|
||||
{ 0x41F085CF, "start2" },
|
||||
{ 0x29BF9105, "start3dcinematic" },
|
||||
@ -150617,6 +150683,7 @@ extern std::array<std::pair<u32, char const*>, hash_count> const hash_list
|
||||
{ 0x4EF23677, "start_underwater_anim" },
|
||||
{ 0x00C468D4, "start_underwater_snapshot" },
|
||||
{ 0xF96FA4C4, "start_unhide_players" },
|
||||
{ 0x8D400B59, "start_up" },
|
||||
{ 0x4A52F6BF, "start_val" },
|
||||
{ 0x5AFAD49D, "start_value" },
|
||||
{ 0x30FEF6D9, "start_van_crash" },
|
||||
@ -151744,6 +151811,16 @@ extern std::array<std::pair<u32, char const*>, hash_count> const hash_list
|
||||
{ 0x7CF47DAA, "stool" },
|
||||
{ 0xB25F4852, "stoolpush" },
|
||||
{ 0xFCF56AB5, "stop" },
|
||||
{ 0xCE9DE5D2, "stop all gunfireloopfx" },
|
||||
{ 0x87140C16, "stop current floodspawner" },
|
||||
{ 0xDE2CA008, "stop debug " },
|
||||
{ 0xAA09DE02, "stop debugline " },
|
||||
{ 0xF9604459, "stop fx" },
|
||||
{ 0x38F853E7, "stop hover" },
|
||||
{ 0x117FE2F2, "stop path" },
|
||||
{ 0xD175A918, "stop random_spread" },
|
||||
{ 0xF886F54C, "stop sound" },
|
||||
{ 0xF6285749, "stop trail" },
|
||||
{ 0x6518A180, "stop2_exposed" },
|
||||
{ 0x7B3C0817, "stop3dcinematic" },
|
||||
{ 0x31D06908, "stop_" },
|
||||
@ -152249,6 +152326,7 @@ extern std::array<std::pair<u32, char const*>, hash_count> const hash_list
|
||||
{ 0xC85E4D82, "stop_helicopter_attack" },
|
||||
{ 0x8472F674, "stop_helmet_loop" },
|
||||
{ 0x0BDB88D2, "stop_here" },
|
||||
{ 0x8882DAA6, "stop_hero_catch_up_teleport" },
|
||||
{ 0x13E77708, "stop_hero_movement" },
|
||||
{ 0x939895A9, "stop_hero_rain" },
|
||||
{ 0x5192DB11, "stop_heroberlin_talk" },
|
||||
@ -152945,6 +153023,7 @@ extern std::array<std::pair<u32, char const*>, hash_count> const hash_list
|
||||
{ 0xF2040CC4, "stopped" },
|
||||
{ 0x7EFBE79C, "stopped_anim" },
|
||||
{ 0x627B1CAB, "stopped_at_node" },
|
||||
{ 0xDEC53302, "stopped_firing" },
|
||||
{ 0xC1047831, "stopped_opening" },
|
||||
{ 0x62FC8F8D, "stopped_use_turret" },
|
||||
{ 0xD5FF12DE, "stopped_using_remote" },
|
||||
@ -155656,6 +155735,7 @@ extern std::array<std::pair<u32, char const*>, hash_count> const hash_list
|
||||
{ 0xF13B8B33, "swiped" },
|
||||
{ 0xB7165F0C, "swipes" },
|
||||
{ 0x8F6EDCBD, "switch" },
|
||||
{ 0x11675B4C, "switch group" },
|
||||
{ 0x7425001D, "switch_activated" },
|
||||
{ 0x7BE2D810, "switch_ambient_packages" },
|
||||
{ 0x94CDFFA1, "switch_and_takeover" },
|
||||
@ -158400,6 +158480,7 @@ extern std::array<std::pair<u32, char const*>, hash_count> const hash_list
|
||||
{ 0x693F168F, "tells" },
|
||||
{ 0x8A54AE0F, "telltimer" },
|
||||
{ 0xF8F608DB, "temp" },
|
||||
{ 0x0CC2DDC9, "temp proceed" },
|
||||
{ 0x00751CE8, "temp1" },
|
||||
{ 0x727C8C23, "temp2" },
|
||||
{ 0x4C7A11BA, "temp3" },
|
||||
@ -158650,6 +158731,7 @@ extern std::array<std::pair<u32, char const*>, hash_count> const hash_list
|
||||
{ 0xA8168EB3, "terminal_model" },
|
||||
{ 0xE2FDDD30, "terminals" },
|
||||
{ 0xF04E14FE, "terminate" },
|
||||
{ 0x974DE41E, "terminate_all_the_things" },
|
||||
{ 0x42453C48, "terminate_all_turrets_firing" },
|
||||
{ 0xE090D26C, "terminate_cm_watcher" },
|
||||
{ 0xD372FE9C, "terminatebsm" },
|
||||
@ -163941,6 +164023,7 @@ extern std::array<std::pair<u32, char const*>, hash_count> const hash_list
|
||||
{ 0x544DE2C5, "turnyaw" },
|
||||
{ 0xF4240167, "turrent" },
|
||||
{ 0x37B990DB, "turret" },
|
||||
{ 0x849F87BA, "turret reloading" },
|
||||
{ 0xCE4434E8, "turret1" },
|
||||
{ 0x404BA423, "turret2" },
|
||||
{ 0x1A4929BA, "turret3" },
|
||||
@ -165974,6 +166057,7 @@ extern std::array<std::pair<u32, char const*>, hash_count> const hash_list
|
||||
{ 0xA61D27D2, "updateteamtime" },
|
||||
{ 0xB81E4071, "updateteamuavstatus" },
|
||||
{ 0x7C5DCE1E, "updateteamvehicles" },
|
||||
{ 0x359CF118, "updatethread specialiststatabilityusage" },
|
||||
{ 0x89539239, "updatetiestats" },
|
||||
{ 0x4809D0B5, "updatetime" },
|
||||
{ 0xB5371B9B, "updatetimeplayedcapdvar" },
|
||||
@ -168806,6 +168890,7 @@ extern std::array<std::pair<u32, char const*>, hash_count> const hash_list
|
||||
{ 0xC75394F8, "vehiclegearmodels" },
|
||||
{ 0x4C357EB5, "vehiclegeartags" },
|
||||
{ 0x02AE0CB4, "vehiclegroup" },
|
||||
{ 0xEDB7D25E, "vehiclegroup spawned" },
|
||||
{ 0x408B946E, "vehiclegunner" },
|
||||
{ 0x27AA40D5, "vehiclehackertoolradius" },
|
||||
{ 0xED627D44, "vehiclehackertooltimems" },
|
||||
@ -168929,6 +169014,8 @@ extern std::array<std::pair<u32, char const*>, hash_count> const hash_list
|
||||
{ 0xF3C8FB41, "velocity1" },
|
||||
{ 0x19CB75AA, "velocity2" },
|
||||
{ 0x3FCDF013, "velocity3" },
|
||||
{ 0x9C1AC1CB, "velocity_approach" },
|
||||
{ 0x9744842A, "velocity_approach_early_out" },
|
||||
{ 0xD46895D5, "velocity_func" },
|
||||
{ 0x0B02FD9F, "velocity_length" },
|
||||
{ 0x829E8366, "velocity_normal" },
|
||||
@ -171898,6 +171985,7 @@ extern std::array<std::pair<u32, char const*>, hash_count> const hash_list
|
||||
{ 0xD83EAE68, "waittill_crash_done_or_stopped" },
|
||||
{ 0x8DAF7251, "waittill_damage_and_notify" },
|
||||
{ 0x21FE06CC, "waittill_dead" },
|
||||
{ 0x27BC4415, "waittill_dead guy died" },
|
||||
{ 0xCFF9A825, "waittill_dead_guy_dead_or_dying" },
|
||||
{ 0x5491EDE6, "waittill_dead_or_dying" },
|
||||
{ 0xBFB394E5, "waittill_dead_or_dying_thread" },
|
||||
@ -176882,6 +176970,7 @@ extern std::array<std::pair<u32, char const*>, hash_count> const hash_list
|
||||
{ 0x3BA768C3, "zm_bgb_machine_static_gumballs_piece_index" },
|
||||
{ 0xE137315D, "zm_bgb_machine_targetname" },
|
||||
{ 0xFB6D5153, "zm_bgb_near_death_experience" },
|
||||
{ 0xF9C8C638, "zm_bgb_near_death_experience_1p_fx_stop_" },
|
||||
{ 0x048B6019, "zm_bgb_secret_shopper" },
|
||||
{ 0x144DE88E, "zm_bgb_unbearable" },
|
||||
{ 0x5F7CF93D, "zm_bgb_wall_power_used" },
|
||||
|
32
src/arc/engine/t8.cpp
Normal file
32
src/arc/engine/t8.cpp
Normal file
@ -0,0 +1,32 @@
|
||||
// Copyright 2023 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 "xsk/arc/engine/t8.hpp"
|
||||
|
||||
namespace xsk::arc::t8
|
||||
{
|
||||
|
||||
extern std::array<std::pair<u16, opcode>, code_count> const code_list;
|
||||
// extern std::array<std::pair<u32, char const*>, hash_count> const hash_list;
|
||||
|
||||
context::context() : arc::context(props::v3, engine::t8, endian::little, system::pc, header_magic)
|
||||
{
|
||||
code_map_.reserve(code_list.size());
|
||||
code_map_rev_.reserve(code_list.size());
|
||||
// hash_map_.reserve(hash_list.size());
|
||||
|
||||
for (auto const& entry : code_list)
|
||||
{
|
||||
code_map_.insert({ entry.first, entry.second });
|
||||
code_map_rev_.insert({ entry.second, entry.first });
|
||||
}
|
||||
|
||||
// for (auto const& entry : hash_list)
|
||||
// {
|
||||
// hash_map_.insert({ entry.first, entry.second });
|
||||
// }
|
||||
}
|
||||
|
||||
} // namespace xsk::arc::t8
|
@ -3,13 +3,13 @@
|
||||
// Use of this source code is governed by a GNU GPLv3 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
#include "xsk/arc/engine/t7.hpp"
|
||||
#include "xsk/arc/engine/t8.hpp"
|
||||
|
||||
namespace xsk::arc::t7
|
||||
namespace xsk::arc::t8
|
||||
{
|
||||
|
||||
extern std::array<std::pair<u32, char const*>, dvar_count> const dvar_list
|
||||
extern std::array<std::pair<u16, opcode>, code_count> const code_list
|
||||
{{
|
||||
}};
|
||||
|
||||
} // namespace xsk::arc::t7
|
||||
} // namespace xsk::arc::t8
|
32
src/arc/engine/t9.cpp
Normal file
32
src/arc/engine/t9.cpp
Normal file
@ -0,0 +1,32 @@
|
||||
// Copyright 2023 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 "xsk/arc/engine/t9.hpp"
|
||||
|
||||
namespace xsk::arc::t9
|
||||
{
|
||||
|
||||
extern std::array<std::pair<u16, opcode>, code_count> const code_list;
|
||||
// extern std::array<std::pair<u32, char const*>, hash_count> const hash_list;
|
||||
|
||||
context::context() : arc::context(props::v3, engine::t9, endian::little, system::pc, header_magic)
|
||||
{
|
||||
code_map_.reserve(code_list.size());
|
||||
code_map_rev_.reserve(code_list.size());
|
||||
// hash_map_.reserve(hash_list.size());
|
||||
|
||||
for (auto const& entry : code_list)
|
||||
{
|
||||
code_map_.insert({ entry.first, entry.second });
|
||||
code_map_rev_.insert({ entry.second, entry.first });
|
||||
}
|
||||
|
||||
// for (auto const& entry : hash_list)
|
||||
// {
|
||||
// hash_map_.insert({ entry.first, entry.second });
|
||||
// }
|
||||
}
|
||||
|
||||
} // namespace xsk::arc::t9
|
15
src/arc/engine/t9_code.cpp
Normal file
15
src/arc/engine/t9_code.cpp
Normal file
@ -0,0 +1,15 @@
|
||||
// Copyright 2023 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 "xsk/arc/engine/t9.hpp"
|
||||
|
||||
namespace xsk::arc::t9
|
||||
{
|
||||
|
||||
extern std::array<std::pair<u16, opcode>, code_count> const code_list
|
||||
{{
|
||||
}};
|
||||
|
||||
} // namespace xsk::arc::t9
|
618
src/arc/lexer.cpp
Normal file
618
src/arc/lexer.cpp
Normal file
@ -0,0 +1,618 @@
|
||||
// Copyright 2023 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 "xsk/stdinc.hpp"
|
||||
#include "xsk/utils/string.hpp"
|
||||
#include "xsk/arc/lexer.hpp"
|
||||
#include "xsk/arc/context.hpp"
|
||||
|
||||
namespace xsk::arc
|
||||
{
|
||||
|
||||
lexer::lexer(context const* ctx, std::string const& name, char const* data, usize size) : ctx_{ ctx }, reader_{ data, size }, loc_{ &name }, buflen_{ 0 }, spacing_{ spacing::null }, indev_{ false }
|
||||
{
|
||||
}
|
||||
|
||||
auto lexer::lex() -> token
|
||||
{
|
||||
buflen_ = 0;
|
||||
|
||||
while (true)
|
||||
{
|
||||
auto& last = reader_.last_byte;
|
||||
auto& curr = reader_.curr_byte;
|
||||
auto path = false;
|
||||
auto localize = false;
|
||||
loc_.step();
|
||||
|
||||
if (reader_.ended())
|
||||
{
|
||||
if (indev_)
|
||||
throw comp_error(loc_, "unmatched devblock start ('/#')");
|
||||
|
||||
if (curr == 0 && last != '\n')
|
||||
{
|
||||
curr = -1;
|
||||
return token{ token::NEWLINE, spacing_, loc_ };
|
||||
}
|
||||
else
|
||||
return token{ token::EOS, spacing_, loc_ };
|
||||
}
|
||||
|
||||
if (last == 0 || last == '\n')
|
||||
spacing_ = spacing::null;
|
||||
else if (last == ' ' || last == '\t')
|
||||
spacing_ = (spacing_ == spacing::null) ? spacing::empty : spacing::back;
|
||||
else
|
||||
spacing_ = spacing::none;
|
||||
|
||||
advance();
|
||||
|
||||
switch (last)
|
||||
{
|
||||
case ' ':
|
||||
case '\t':
|
||||
case '\r':
|
||||
loc_.step();
|
||||
continue;
|
||||
case '\n':
|
||||
loc_.lines();
|
||||
loc_.step();
|
||||
return token{ token::NEWLINE, spacing_, loc_ };
|
||||
case '\\':
|
||||
throw comp_error(loc_, "invalid token ('\\')");
|
||||
case '/':
|
||||
if (curr != '=' && curr != '#' && curr != '@' && curr != '*' && curr != '/')
|
||||
return token{ token::DIV, spacing_, loc_ };
|
||||
|
||||
advance();
|
||||
|
||||
if (last == '=')
|
||||
return token{ token::DIVEQ, spacing_, loc_ };
|
||||
|
||||
if (last == '#')
|
||||
{
|
||||
if (indev_)
|
||||
throw comp_error(loc_, "cannot recurse devblock ('/#')");
|
||||
|
||||
if (ctx_->build() == build::dev)
|
||||
{
|
||||
indev_ = true;
|
||||
return token{ token::DEVBEGIN, spacing_, loc_ };
|
||||
}
|
||||
else
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
if (reader_.ended())
|
||||
throw comp_error(loc_, "unmatched devblock start ('/#')");
|
||||
|
||||
if (curr == '\n')
|
||||
{
|
||||
loc_.lines();
|
||||
loc_.step();
|
||||
}
|
||||
else if (last == '#' && curr == '/')
|
||||
{
|
||||
advance();
|
||||
break;
|
||||
}
|
||||
|
||||
advance();
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (last == '@')
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
if (reader_.ended())
|
||||
throw comp_error(loc_, "unmatched script doc comment start ('/@')");
|
||||
|
||||
if (curr == '\n')
|
||||
{
|
||||
loc_.lines();
|
||||
loc_.step();
|
||||
}
|
||||
else if (last == '@' && curr == '/')
|
||||
{
|
||||
advance();
|
||||
break;
|
||||
}
|
||||
|
||||
advance();
|
||||
}
|
||||
}
|
||||
else if (last == '*')
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
if (reader_.ended())
|
||||
throw comp_error(loc_, "unmatched multiline comment start ('/*')");
|
||||
|
||||
if (curr == '\n')
|
||||
{
|
||||
loc_.lines();
|
||||
loc_.step();
|
||||
}
|
||||
else if (last == '*' && curr == '/')
|
||||
{
|
||||
advance();
|
||||
break;
|
||||
}
|
||||
|
||||
advance();
|
||||
}
|
||||
}
|
||||
else if (last == '/')
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
if (reader_.ended())
|
||||
break;
|
||||
|
||||
if (curr == '\n')
|
||||
break;
|
||||
|
||||
advance();
|
||||
}
|
||||
}
|
||||
continue;
|
||||
case '#':
|
||||
if (curr == '/')
|
||||
{
|
||||
if (!indev_)
|
||||
throw comp_error(loc_, "unmatched devblock end ('#/')");
|
||||
|
||||
advance();
|
||||
indev_ = false;
|
||||
return token{ token::DEVEND, spacing_, loc_ };
|
||||
}
|
||||
|
||||
return token{ token::SHARP, spacing_, loc_ };
|
||||
case '*':
|
||||
if (curr != '=' && curr != '/')
|
||||
return token{ token::STAR, spacing_, loc_ };
|
||||
|
||||
advance();
|
||||
|
||||
if (last == '=')
|
||||
return token{ token::STAREQ, spacing_, loc_ };
|
||||
|
||||
throw comp_error(loc_, "unmatched multiline comment end ('*/')");
|
||||
case '"':
|
||||
goto lex_string;
|
||||
case '.':
|
||||
if (curr == '.')
|
||||
{
|
||||
advance();
|
||||
|
||||
if (curr != '.')
|
||||
return token{ token::DOUBLEDOT, spacing_, loc_ };
|
||||
|
||||
advance();
|
||||
return token{ token::ELLIPSIS, spacing_, loc_ };
|
||||
}
|
||||
|
||||
if (curr < '0' || curr > '9')
|
||||
return token{ token::DOT, spacing_, loc_ };
|
||||
goto lex_number;
|
||||
case '(':
|
||||
return token{ token::LPAREN, spacing_, loc_ };
|
||||
case ')':
|
||||
return token{ token::RPAREN, spacing_, loc_ };
|
||||
case '{':
|
||||
return token{ token::LBRACE, spacing_, loc_ };
|
||||
case '}':
|
||||
return token{ token::RBRACE, spacing_, loc_ };
|
||||
case '[':
|
||||
return token{ token::LBRACKET, spacing_, loc_ };
|
||||
case ']':
|
||||
return token{ token::RBRACKET, spacing_, loc_ };
|
||||
case ',':
|
||||
return token{ token::COMMA, spacing_, loc_ };
|
||||
case ';':
|
||||
return token{ token::SEMICOLON, spacing_, loc_ };
|
||||
case ':':
|
||||
if (curr != ':')
|
||||
return token{ token::COLON, spacing_, loc_ };
|
||||
|
||||
advance();
|
||||
return token{ token::DOUBLECOLON, spacing_, loc_ };
|
||||
case '?':
|
||||
return token{ token::QMARK, spacing_, loc_ };
|
||||
case '=':
|
||||
if (curr != '=')
|
||||
return token{ token::ASSIGN, spacing_, loc_ };
|
||||
|
||||
advance();
|
||||
return token{ token::EQ, spacing_, loc_ };
|
||||
case '+':
|
||||
if (curr != '+' && curr != '=')
|
||||
return token{ token::PLUS, spacing_, loc_ };
|
||||
|
||||
advance();
|
||||
|
||||
if (last == '+')
|
||||
return token{ token::INC, spacing_, loc_ };
|
||||
|
||||
return token{ token::PLUSEQ, spacing_, loc_ };
|
||||
case '-':
|
||||
if (curr != '-' && curr != '=')
|
||||
return token{ token::MINUS, spacing_, loc_ };
|
||||
|
||||
advance();
|
||||
|
||||
if (last == '-')
|
||||
return token{ token::DEC, spacing_, loc_ };
|
||||
|
||||
return token{ token::MINUSEQ, spacing_, loc_ };
|
||||
case '%':
|
||||
if (curr != '=')
|
||||
return token{ token::MOD, spacing_, loc_ };
|
||||
|
||||
advance();
|
||||
|
||||
return token{ token::MODEQ, spacing_, loc_ };
|
||||
case '|':
|
||||
if (curr != '|' && curr != '=')
|
||||
return token{ token::BITOR, spacing_, loc_ };
|
||||
|
||||
advance();
|
||||
|
||||
if (last == '|')
|
||||
return token{ token::OR, spacing_, loc_ };
|
||||
|
||||
return token{ token::BITOREQ, spacing_, loc_ };
|
||||
case '&':
|
||||
if (curr != '&' && curr != '=' && curr != '"')
|
||||
return token{ token::BITAND, spacing_, loc_ };
|
||||
|
||||
advance();
|
||||
|
||||
if (last == '&')
|
||||
return token{ token::AND, spacing_, loc_ };
|
||||
|
||||
if (last == '=')
|
||||
return token{ token::BITANDEQ, spacing_, loc_ };
|
||||
|
||||
localize = true;
|
||||
goto lex_string;
|
||||
case '^':
|
||||
if (curr != '=')
|
||||
return token{ token::BITEXOR, spacing_, loc_ };
|
||||
|
||||
advance();
|
||||
return token{ token::BITEXOREQ, spacing_, loc_ };
|
||||
case '!':
|
||||
if (curr != '=')
|
||||
return token{ token::BANG, spacing_, loc_ };
|
||||
|
||||
advance();
|
||||
return token{ token::NE, spacing_, loc_ };
|
||||
case '~':
|
||||
return token{ token::TILDE, spacing_, loc_ };
|
||||
case '<':
|
||||
if (curr != '<' && curr != '=')
|
||||
return token{ token::LT, spacing_, loc_ };
|
||||
|
||||
advance();
|
||||
if (last == '=')
|
||||
return token{ token::LE, spacing_, loc_ };
|
||||
|
||||
if (curr != '=')
|
||||
return token{ token::SHL, spacing_, loc_ };
|
||||
|
||||
advance();
|
||||
return token{ token::SHLEQ, spacing_, loc_ };
|
||||
case '>':
|
||||
if (curr != '>' && curr != '=')
|
||||
return token{ token::GT, spacing_, loc_ };
|
||||
|
||||
advance();
|
||||
|
||||
if (last == '=')
|
||||
return token{ token::GE, spacing_, loc_ };
|
||||
|
||||
if (curr != '=')
|
||||
return token{ token::SHR, spacing_, loc_ };
|
||||
|
||||
advance();
|
||||
return token{ token::SHREQ, spacing_, loc_ };
|
||||
default:
|
||||
if (last >= '0' && last <= '9')
|
||||
goto lex_number;
|
||||
else if (last == '_' || (last >= 'A' && last <= 'Z') || (last >= 'a' && last <= 'z'))
|
||||
goto lex_name;
|
||||
|
||||
throw comp_error(loc_, fmt::format("bad token: '{}'", last));
|
||||
}
|
||||
|
||||
lex_string:
|
||||
while (true)
|
||||
{
|
||||
if (reader_.ended())
|
||||
throw comp_error(loc_, "unmatched string start ('\"')");
|
||||
|
||||
if (curr == '"')
|
||||
{
|
||||
advance();
|
||||
break;
|
||||
}
|
||||
|
||||
if (curr == '\n')
|
||||
throw comp_error(loc_, "unterminated string literal");
|
||||
|
||||
if (curr == '\\')
|
||||
{
|
||||
advance();
|
||||
|
||||
if (reader_.ended())
|
||||
throw comp_error(loc_, "invalid token ('\')");
|
||||
|
||||
char c = curr;
|
||||
switch (curr)
|
||||
{
|
||||
case 't': c = '\t'; break;
|
||||
case 'r': c = '\r'; break;
|
||||
case 'n': c = '\n'; break;
|
||||
case '"': c = '\"'; break;
|
||||
case '\\': c = '\\'; break;
|
||||
default: break;
|
||||
}
|
||||
|
||||
push(c);
|
||||
}
|
||||
else
|
||||
push(curr);
|
||||
|
||||
advance();
|
||||
}
|
||||
|
||||
if (localize)
|
||||
return token{ token::ISTRING, spacing_, loc_, std::string{ &buffer_[0], buflen_ } };
|
||||
|
||||
return token{ token::STRING, spacing_, loc_, std::string{ &buffer_[0], buflen_ } };
|
||||
|
||||
lex_name:
|
||||
push(last);
|
||||
|
||||
while (true)
|
||||
{
|
||||
if (reader_.ended())
|
||||
break;
|
||||
|
||||
if (!(curr == '\\' || curr == '_' || (curr > 64 && curr < 91) || (curr > 96 && curr < 123) || (curr > 47 && curr < 58)))
|
||||
break;
|
||||
|
||||
if (curr == '\\')
|
||||
{
|
||||
if (last == '\\')
|
||||
throw comp_error(loc_, "invalid path '\\\\'");
|
||||
|
||||
path = true;
|
||||
push('/');
|
||||
}
|
||||
else
|
||||
push(curr);
|
||||
|
||||
advance();
|
||||
}
|
||||
|
||||
if (path)
|
||||
{
|
||||
if (buffer_[buflen_ - 1] == '/')
|
||||
throw comp_error(loc_, "invalid path end '\\'");
|
||||
|
||||
return token{ token::PATH, spacing_, loc_, ctx_->make_token(std::string_view{ &buffer_[0], buflen_ }) };
|
||||
}
|
||||
|
||||
return token{ token::NAME, spacing_, loc_, std::string{ &buffer_[0], buflen_ } };
|
||||
|
||||
lex_number:
|
||||
if (last == '.' || last != '0' || (last == '0' && (curr != 'o' && curr != 'b' && curr != 'x')))
|
||||
{
|
||||
push(last);
|
||||
|
||||
auto dot = last == '.' ? 1 : 0;
|
||||
auto flt = 0;
|
||||
|
||||
while (true)
|
||||
{
|
||||
if (reader_.ended())
|
||||
break;
|
||||
|
||||
if (curr == '\'' && (last == '\'' || last == 'f' || last == '.'))
|
||||
throw comp_error(loc_, "invalid number literal");
|
||||
|
||||
if ((curr == '.' || curr == 'f') && last == '\'')
|
||||
throw comp_error(loc_, "invalid number literal");
|
||||
|
||||
if (curr == '\'')
|
||||
{
|
||||
advance();
|
||||
continue;
|
||||
}
|
||||
|
||||
if (curr == 'f')
|
||||
flt++;
|
||||
else if (curr == '.')
|
||||
dot++;
|
||||
else if (!(curr > 47 && curr < 58))
|
||||
break;
|
||||
|
||||
push(curr);
|
||||
advance();
|
||||
}
|
||||
|
||||
if (last == '\'')
|
||||
throw comp_error(loc_, "invalid number literal");
|
||||
|
||||
if (dot > 1 || flt > 1 || (flt && buffer_[buflen_ - 1] != 'f'))
|
||||
throw comp_error(loc_, "invalid number literal");
|
||||
|
||||
if (dot || flt)
|
||||
return token{ token::FLT, spacing_, loc_, std::string{ &buffer_[0], buflen_ } };
|
||||
|
||||
return token{ token::INT, spacing_, loc_, std::string{ &buffer_[0], buflen_ } };
|
||||
}
|
||||
else if (curr == 'o')
|
||||
{
|
||||
advance();
|
||||
|
||||
while (true)
|
||||
{
|
||||
if (reader_.ended())
|
||||
break;
|
||||
|
||||
if ((curr == '\'' && (last == '\'' || last == 'o')) || (curr == 'o' && last == '\''))
|
||||
throw comp_error(loc_, "invalid octal literal");
|
||||
|
||||
if (curr == '\'')
|
||||
{
|
||||
advance();
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!(curr > 47 && curr < 56))
|
||||
break;
|
||||
|
||||
push(curr);
|
||||
advance();
|
||||
}
|
||||
|
||||
if (last == '\'' || buflen_ <= 0)
|
||||
throw comp_error(loc_, "invalid octal literal");
|
||||
|
||||
push('\0');
|
||||
|
||||
return token{ token::INT, spacing_, loc_, utils::string::oct_to_dec(&buffer_[0]) };
|
||||
}
|
||||
else if (curr == 'b')
|
||||
{
|
||||
push(last);
|
||||
push(curr);
|
||||
advance();
|
||||
|
||||
while (true)
|
||||
{
|
||||
if (reader_.ended())
|
||||
break;
|
||||
|
||||
if ((curr == '\'' && (last == '\'' || last == 'b')) || (curr == 'b' && last == '\''))
|
||||
throw comp_error(loc_, "invalid binary literal");
|
||||
|
||||
if (curr == '\'')
|
||||
{
|
||||
advance();
|
||||
continue;
|
||||
}
|
||||
|
||||
if (curr != '0' && curr != '1')
|
||||
break;
|
||||
|
||||
push(curr);
|
||||
advance();
|
||||
}
|
||||
|
||||
if (last == '\'' || buflen_ < 3)
|
||||
throw comp_error(loc_, "invalid binary literal");
|
||||
|
||||
push('\0');
|
||||
|
||||
return token{ token::INT, spacing_, loc_, utils::string::bin_to_dec(&buffer_[0]) };
|
||||
}
|
||||
else if (curr == 'x')
|
||||
{
|
||||
push(last);
|
||||
push(curr);
|
||||
advance();
|
||||
|
||||
while (true)
|
||||
{
|
||||
if (reader_.ended())
|
||||
break;
|
||||
|
||||
if ((curr == '\'' && (last == '\'' || last == 'x')) || (curr == 'x' && last == '\''))
|
||||
throw comp_error(loc_, "invalid hexadecimal literal");
|
||||
|
||||
if (curr == '\'')
|
||||
{
|
||||
advance();
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!((curr > 47 && curr < 58) || (curr > 64 && curr < 71) || (curr > 96 && curr < 103)))
|
||||
break;
|
||||
|
||||
push(curr);
|
||||
advance();
|
||||
}
|
||||
|
||||
if (last == '\'' || buflen_ < 3)
|
||||
throw comp_error(loc_, "invalid hexadecimal literal");
|
||||
|
||||
push('\0');
|
||||
|
||||
return token{ token::INT, spacing_, loc_, utils::string::hex_to_dec(&buffer_[0]) };
|
||||
}
|
||||
|
||||
throw error("UNEXPECTED LEXER INTERNAL ERROR");
|
||||
}
|
||||
}
|
||||
|
||||
auto lexer::push(char c) -> void
|
||||
{
|
||||
if (buflen_ >= 0x1000)
|
||||
throw error("lexer: max literal size exceeded");
|
||||
|
||||
buffer_[buflen_++] = c;
|
||||
}
|
||||
|
||||
auto lexer::advance() -> void
|
||||
{
|
||||
reader_.advance();
|
||||
loc_.end.column++;
|
||||
|
||||
if (reader_.curr_byte == '\\') [[unlikely]]
|
||||
linewrap();
|
||||
}
|
||||
|
||||
auto lexer::linewrap() -> void
|
||||
{
|
||||
while (reader_.curr_byte == '\\')
|
||||
{
|
||||
if (reader_.available == 1)
|
||||
throw comp_error(loc_, "invalid token ('\\')");
|
||||
|
||||
if (reader_.buffer_pos[1] != '\r' && reader_.buffer_pos[1] != '\n')
|
||||
break;
|
||||
|
||||
if (reader_.buffer_pos[1] == '\r')
|
||||
{
|
||||
if (reader_.available <= 3 || reader_.buffer_pos[2] != '\n')
|
||||
throw comp_error(loc_, "invalid token ('\\')");
|
||||
|
||||
reader_.buffer_pos += 3;
|
||||
reader_.available -= 3;
|
||||
}
|
||||
|
||||
if ((reader_.buffer_pos[1] == '\n'))
|
||||
{
|
||||
if (reader_.available == 2)
|
||||
throw comp_error(loc_, "invalid token ('\\')");
|
||||
|
||||
reader_.buffer_pos += 2;
|
||||
reader_.available -= 2;
|
||||
}
|
||||
|
||||
reader_.curr_byte = reader_.available ? *reader_.buffer_pos : 0;
|
||||
|
||||
loc_.lines();
|
||||
loc_.step();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace xsk::arc
|
5753
src/arc/parser.cpp
Normal file
5753
src/arc/parser.cpp
Normal file
File diff suppressed because it is too large
Load Diff
1384
src/arc/preprocessor.cpp
Normal file
1384
src/arc/preprocessor.cpp
Normal file
File diff suppressed because it is too large
Load Diff
1082
src/arc/source.cpp
1082
src/arc/source.cpp
File diff suppressed because it is too large
Load Diff
@ -28,7 +28,7 @@ auto compiler::compile(std::string const& file, std::vector<u8>& data) -> assemb
|
||||
|
||||
auto compiler::emit_program(program const& prog) -> void
|
||||
{
|
||||
assembly_ = make_assembly();
|
||||
assembly_ = assembly::make();
|
||||
localfuncs_.clear();
|
||||
constants_.clear();
|
||||
developer_thread_ = false;
|
||||
@ -128,7 +128,7 @@ auto compiler::emit_decl_function(decl_function const& func) -> void
|
||||
break_blks_.clear();
|
||||
continue_blks_.clear();
|
||||
|
||||
function_ = make_function();
|
||||
function_ = function::make();
|
||||
function_->index = index_;
|
||||
function_->name = func.name->value;
|
||||
function_->id = ctx_->token_id(function_->name);
|
||||
@ -2191,7 +2191,7 @@ auto compiler::emit_remove_local_vars(scope& scp) -> void
|
||||
|
||||
auto compiler::emit_opcode(opcode op) -> void
|
||||
{
|
||||
function_->instructions.push_back(make_instruction());
|
||||
function_->instructions.push_back(instruction::make());
|
||||
|
||||
auto& inst = function_->instructions.back();
|
||||
inst->opcode = op;
|
||||
@ -2203,7 +2203,7 @@ auto compiler::emit_opcode(opcode op) -> void
|
||||
|
||||
auto compiler::emit_opcode(opcode op, std::string const& data) -> void
|
||||
{
|
||||
function_->instructions.push_back(make_instruction());
|
||||
function_->instructions.push_back(instruction::make());
|
||||
|
||||
auto& inst = function_->instructions.back();
|
||||
inst->opcode = op;
|
||||
@ -2216,7 +2216,7 @@ auto compiler::emit_opcode(opcode op, std::string const& data) -> void
|
||||
|
||||
auto compiler::emit_opcode(opcode op, std::vector<std::string> const& data) -> void
|
||||
{
|
||||
function_->instructions.push_back(make_instruction());
|
||||
function_->instructions.push_back(instruction::make());
|
||||
|
||||
auto& inst = function_->instructions.back();
|
||||
inst->opcode = op;
|
||||
|
@ -3,7 +3,6 @@
|
||||
// Use of this source code is governed by a GNU GPLv3 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
|
||||
#include "xsk/stdinc.hpp"
|
||||
#include "xsk/utils/string.hpp"
|
||||
#include "xsk/gsc/disassembler.hpp"
|
||||
@ -30,13 +29,13 @@ auto disassembler::disassemble(u8 const* script, usize script_size, u8 const* st
|
||||
{
|
||||
stack_ = utils::reader{ stack, static_cast<u32>(stack_size), ctx_->endian() == endian::big };
|
||||
script_ = utils::reader{ script, static_cast<u32>(script_size), ctx_->endian() == endian::big };
|
||||
assembly_ = make_assembly();
|
||||
assembly_ = assembly::make();
|
||||
|
||||
script_.seek(1);
|
||||
|
||||
while (script_.is_avail() && stack_.is_avail())
|
||||
{
|
||||
func_ = make_function();
|
||||
func_ = function::make();
|
||||
func_->index = script_.pos();
|
||||
func_->size = stack_.read<u32>();
|
||||
func_->id = (ctx_->props() & props::hash) ? 0 : (ctx_->props() & props::tok4) ? stack_.read<u32>() : stack_.read<u16>();
|
||||
@ -58,7 +57,7 @@ auto disassembler::dissasemble_function(function& func) -> void
|
||||
|
||||
while (size > 0)
|
||||
{
|
||||
auto inst = make_instruction();
|
||||
auto inst = instruction::make();
|
||||
inst->index = script_.pos();
|
||||
inst->opcode = ctx_->opcode_enum(script_.read<u8>());
|
||||
inst->size = ctx_->opcode_size(inst->opcode);
|
||||
|
@ -3,7 +3,6 @@
|
||||
// Use of this source code is governed by a GNU GPLv3 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
|
||||
#include "xsk/stdinc.hpp"
|
||||
#include "xsk/utils/string.hpp"
|
||||
#include "xsk/gsc/lexer.hpp"
|
||||
@ -191,7 +190,7 @@ auto lexer::lex() -> token
|
||||
advance();
|
||||
|
||||
if (curr != '.')
|
||||
return token{ token::DOUBLECOLON, spacing_, loc_ };
|
||||
return token{ token::DOUBLEDOT, spacing_, loc_ };
|
||||
|
||||
advance();
|
||||
return token{ token::ELLIPSIS, spacing_, loc_ };
|
||||
|
@ -3,11 +3,9 @@
|
||||
// Use of this source code is governed by a GNU GPLv3 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
|
||||
#include "xsk/stdinc.hpp"
|
||||
#include "xsk/gsc/preprocessor.hpp"
|
||||
#include "xsk/gsc/context.hpp"
|
||||
#include "xsk/gsc/parser.hpp"
|
||||
|
||||
namespace xsk::gsc
|
||||
{
|
||||
|
@ -34,7 +34,7 @@ auto source::parse_assembly(u8 const* data, usize size) -> assembly::ptr
|
||||
std::memcpy(buffer.data(), data, buffer.size());
|
||||
|
||||
auto lines = utils::string::clean_buffer_lines(buffer);
|
||||
auto assembly = make_assembly();
|
||||
auto assembly = assembly::make();
|
||||
auto func = function::ptr{ nullptr };
|
||||
u32 index = 1;
|
||||
u16 switchnum = 0;
|
||||
@ -47,7 +47,7 @@ auto source::parse_assembly(u8 const* data, usize size) -> assembly::ptr
|
||||
}
|
||||
else if (line.substr(0, 4) == "sub:")
|
||||
{
|
||||
func = make_function();
|
||||
func = function::make();
|
||||
func->index = index;
|
||||
func->name = line.substr(4);
|
||||
func->id = ctx_->token_id(func->name);
|
||||
@ -84,7 +84,7 @@ auto source::parse_assembly(u8 const* data, usize size) -> assembly::ptr
|
||||
}
|
||||
else
|
||||
{
|
||||
auto inst = make_instruction();
|
||||
auto inst = instruction::make();
|
||||
inst->index = index;
|
||||
inst->opcode = ctx_->opcode_enum(opdata[0]);
|
||||
inst->size = ctx_->opcode_size(inst->opcode);
|
||||
@ -158,7 +158,7 @@ auto source::dump(assembly const& data) -> std::vector<u8>
|
||||
buf_.reserve(0x10000);
|
||||
|
||||
fmt::format_to(std::back_inserter(buf_), "// {} GSC ASSEMBLY\n", ctx_->engine_name());
|
||||
fmt::format_to(std::back_inserter(buf_), "// Dumped by https://github.com/xensik/gsc-tool\n");
|
||||
fmt::format_to(std::back_inserter(buf_), "// Generated by https://github.com/xensik/gsc-tool\n");
|
||||
|
||||
dump_assembly(data);
|
||||
|
||||
@ -171,7 +171,7 @@ auto source::dump(program const& data) -> std::vector<u8>
|
||||
buf_.reserve(0x10000);
|
||||
|
||||
fmt::format_to(std::back_inserter(buf_), "// {} GSC SOURCE\n", ctx_->engine_name());
|
||||
fmt::format_to(std::back_inserter(buf_), "// Dumped by https://github.com/xensik/gsc-tool\n");
|
||||
fmt::format_to(std::back_inserter(buf_), "// Generated by https://github.com/xensik/gsc-tool\n");
|
||||
|
||||
dump_program(data);
|
||||
|
||||
|
@ -1,883 +0,0 @@
|
||||
// Copyright 2023 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 "xsk/stdinc.hpp"
|
||||
#include "xsk/t6/t6.hpp"
|
||||
|
||||
namespace xsk::arc::t6
|
||||
{
|
||||
|
||||
auto assembler::output() -> std::vector<std::uint8_t>
|
||||
{
|
||||
std::vector<std::uint8_t> output;
|
||||
|
||||
if (script_ == nullptr) return output;
|
||||
|
||||
output.resize(script_->pos());
|
||||
std::memcpy(output.data(), script_->data(), output.size());
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
void assembler::assemble(const std::string&, std::vector<std::uint8_t>&)
|
||||
{
|
||||
throw error("assemble from source not implemented!");
|
||||
}
|
||||
|
||||
void assembler::assemble(const std::string& file, assembly::ptr& data)
|
||||
{
|
||||
script_ = std::make_unique<utils::writer>();
|
||||
filename_ = file;
|
||||
assembly_ = std::move(data);
|
||||
stringlist_.clear();
|
||||
exports_.clear();
|
||||
imports_.clear();
|
||||
animtrees_.clear();
|
||||
stringtables_.clear();
|
||||
std::memset(&header_, 0, sizeof(header_));
|
||||
|
||||
// skip header
|
||||
script_->pos(64);
|
||||
|
||||
// assemble strings
|
||||
process_string(filename_);
|
||||
|
||||
for (const auto& func : assembly_->functions)
|
||||
{
|
||||
process_function(func);
|
||||
}
|
||||
|
||||
for (const auto& entry : assembly_->includes)
|
||||
{
|
||||
process_string(entry);
|
||||
}
|
||||
|
||||
// assemble includes
|
||||
header_.include_offset = script_->pos();
|
||||
header_.include_count = static_cast<std::uint8_t>(assembly_->includes.size());
|
||||
|
||||
for (const auto& entry : assembly_->includes)
|
||||
{
|
||||
script_->write<std::uint32_t>(string_offset(entry));
|
||||
}
|
||||
|
||||
// assemble functions
|
||||
header_.cseg_offset = script_->pos();
|
||||
|
||||
for (const auto& func : assembly_->functions)
|
||||
{
|
||||
script_->align(4);
|
||||
script_->write<std::uint32_t>(0);
|
||||
assemble_function(func);
|
||||
}
|
||||
|
||||
header_.cseg_size = script_->pos() - header_.cseg_offset;
|
||||
|
||||
header_.source_crc = 0;
|
||||
|
||||
// assemble exports
|
||||
header_.exports_offset = script_->pos();
|
||||
header_.exports_count = static_cast<std::uint16_t>(exports_.size());
|
||||
|
||||
for (const auto& entry : exports_)
|
||||
{
|
||||
script_->write<std::uint32_t>(entry.checksum);
|
||||
script_->write<std::uint32_t>(entry.offset);
|
||||
script_->write<std::uint16_t>(string_offset(entry.name));
|
||||
script_->write<std::uint8_t>(entry.params);
|
||||
script_->write<std::uint8_t>(entry.flags);
|
||||
}
|
||||
|
||||
// assemble imports
|
||||
header_.imports_offset = script_->pos();
|
||||
header_.imports_count = static_cast<std::uint16_t>(imports_.size());
|
||||
|
||||
for (const auto& entry : imports_)
|
||||
{
|
||||
script_->write<std::uint16_t>(string_offset(entry.name));
|
||||
script_->write<std::uint16_t>(string_offset(entry.space));
|
||||
script_->write<std::uint16_t>(static_cast<std::uint16_t>(entry.refs.size()));
|
||||
script_->write<std::uint8_t>(entry.params);
|
||||
script_->write<std::uint8_t>(entry.flags);
|
||||
|
||||
for (const auto& ref : entry.refs)
|
||||
{
|
||||
script_->write<std::uint32_t>(ref);
|
||||
}
|
||||
}
|
||||
|
||||
// assemble animtrees
|
||||
header_.animtree_offset = script_->pos();
|
||||
header_.animtree_count = static_cast<std::uint8_t>(animtrees_.size());
|
||||
|
||||
for (const auto& entry : animtrees_)
|
||||
{
|
||||
script_->write<std::uint16_t>(string_offset(entry.name));
|
||||
script_->write<std::uint16_t>(static_cast<std::uint16_t>(entry.refs.size()));
|
||||
script_->write<std::uint16_t>(static_cast<std::uint16_t>(entry.anims.size()));
|
||||
script_->seek(2);
|
||||
|
||||
for (const auto& ref : entry.refs)
|
||||
{
|
||||
script_->write<std::uint32_t>(ref);
|
||||
}
|
||||
|
||||
for (const auto& anim : entry.anims)
|
||||
{
|
||||
script_->write<std::uint32_t>(string_offset(anim.name));
|
||||
script_->write<std::uint32_t>(anim.ref);
|
||||
}
|
||||
}
|
||||
|
||||
// assemble stringtable
|
||||
header_.stringtablefixup_offset = script_->pos();
|
||||
header_.stringtablefixup_count = static_cast<std::uint16_t>(stringtables_.size());
|
||||
|
||||
for (const auto& entry : stringtables_)
|
||||
{
|
||||
script_->write<std::uint16_t>(string_offset(entry.name));
|
||||
script_->write<std::uint8_t>(static_cast<std::uint8_t>(entry.refs.size()));
|
||||
script_->write<std::uint8_t>(entry.type);
|
||||
|
||||
for (const auto& ref : entry.refs)
|
||||
{
|
||||
script_->write<std::uint32_t>(ref);
|
||||
}
|
||||
}
|
||||
|
||||
// assemble fixup
|
||||
header_.fixup_offset = script_->pos();
|
||||
header_.fixup_count = 0;
|
||||
|
||||
// assemble profile
|
||||
header_.profile_offset = script_->pos();
|
||||
header_.profile_count = 0;
|
||||
|
||||
header_.flags = 0;
|
||||
header_.name = string_offset(filename_);
|
||||
|
||||
auto endpos = script_->pos();
|
||||
|
||||
// assemble header
|
||||
script_->pos(0);
|
||||
script_->write<std::uint64_t>(magic);
|
||||
script_->write<std::uint32_t>(header_.source_crc);
|
||||
script_->write<std::uint32_t>(header_.include_offset);
|
||||
script_->write<std::uint32_t>(header_.animtree_offset);
|
||||
script_->write<std::uint32_t>(header_.cseg_offset);
|
||||
script_->write<std::uint32_t>(header_.stringtablefixup_offset);
|
||||
script_->write<std::uint32_t>(header_.exports_offset);
|
||||
script_->write<std::uint32_t>(header_.imports_offset);
|
||||
script_->write<std::uint32_t>(header_.fixup_offset);
|
||||
script_->write<std::uint32_t>(header_.profile_offset);
|
||||
script_->write<std::uint32_t>(header_.cseg_size);
|
||||
script_->write<std::uint16_t>(header_.name);
|
||||
script_->write<std::uint16_t>(header_.stringtablefixup_count);
|
||||
script_->write<std::uint16_t>(header_.exports_count);
|
||||
script_->write<std::uint16_t>(header_.imports_count);
|
||||
script_->write<std::uint16_t>(header_.fixup_count);
|
||||
script_->write<std::uint16_t>(header_.profile_count);
|
||||
script_->write<std::uint8_t>(header_.include_count);
|
||||
script_->write<std::uint8_t>(header_.animtree_count);
|
||||
script_->write<std::uint8_t>(header_.flags);
|
||||
script_->pos(endpos);
|
||||
}
|
||||
|
||||
void assembler::assemble_function(const function::ptr& func)
|
||||
{
|
||||
func->index = script_->pos();
|
||||
func->size = 0;
|
||||
labels_.clear();
|
||||
|
||||
for (const auto& inst : func->instructions)
|
||||
{
|
||||
auto old_idx = inst->index;
|
||||
inst->index = func->index + func->size;
|
||||
|
||||
align_instruction(inst);
|
||||
|
||||
func->size += inst->size;
|
||||
|
||||
const auto itr = func->labels.find(old_idx);
|
||||
|
||||
if (itr != func->labels.end())
|
||||
{
|
||||
labels_.insert({ inst->index, itr->second });
|
||||
}
|
||||
}
|
||||
|
||||
script_->pos(func->index);
|
||||
|
||||
for (const auto& inst : func->instructions)
|
||||
{
|
||||
assemble_instruction(inst);
|
||||
}
|
||||
|
||||
export_ref entry;
|
||||
entry.checksum = 0;
|
||||
entry.offset = func->index;
|
||||
entry.name = func->name;
|
||||
entry.params = func->params;
|
||||
entry.flags = func->flags;
|
||||
exports_.push_back(entry);
|
||||
}
|
||||
|
||||
void assembler::assemble_instruction(const instruction::ptr& inst)
|
||||
{
|
||||
script_->write<std::uint8_t>(static_cast<std::uint8_t>(inst->opcode));
|
||||
|
||||
switch (static_cast<opcode>(inst->opcode))
|
||||
{
|
||||
case opcode::OP_End:
|
||||
case opcode::OP_Return:
|
||||
case opcode::OP_GetUndefined:
|
||||
case opcode::OP_GetZero:
|
||||
case opcode::OP_GetLevelObject:
|
||||
case opcode::OP_GetAnimObject:
|
||||
case opcode::OP_GetSelf:
|
||||
case opcode::OP_GetLevel:
|
||||
case opcode::OP_GetGame:
|
||||
case opcode::OP_GetAnim:
|
||||
case opcode::OP_GetGameRef:
|
||||
case opcode::OP_CreateLocalVariable:
|
||||
case opcode::OP_EvalArray:
|
||||
case opcode::OP_EvalArrayRef:
|
||||
case opcode::OP_ClearArray:
|
||||
case opcode::OP_EmptyArray:
|
||||
case opcode::OP_GetSelfObject:
|
||||
case opcode::OP_SafeSetVariableFieldCached:
|
||||
case opcode::OP_ClearParams:
|
||||
case opcode::OP_CheckClearParams:
|
||||
case opcode::OP_SetVariableField:
|
||||
case opcode::OP_Wait:
|
||||
case opcode::OP_WaitTillFrameEnd:
|
||||
case opcode::OP_PreScriptCall:
|
||||
case opcode::OP_DecTop:
|
||||
case opcode::OP_CastFieldObject:
|
||||
case opcode::OP_CastBool:
|
||||
case opcode::OP_BoolNot:
|
||||
case opcode::OP_BoolComplement:
|
||||
case opcode::OP_Inc:
|
||||
case opcode::OP_Dec:
|
||||
case opcode::OP_Bit_Or:
|
||||
case opcode::OP_Bit_Xor:
|
||||
case opcode::OP_Bit_And:
|
||||
case opcode::OP_Equal:
|
||||
case opcode::OP_NotEqual:
|
||||
case opcode::OP_LessThan:
|
||||
case opcode::OP_GreaterThan:
|
||||
case opcode::OP_LessThanOrEqualTo:
|
||||
case opcode::OP_GreaterThanOrEqualTo:
|
||||
case opcode::OP_ShiftLeft:
|
||||
case opcode::OP_ShiftRight:
|
||||
case opcode::OP_Plus:
|
||||
case opcode::OP_Minus:
|
||||
case opcode::OP_Multiply:
|
||||
case opcode::OP_Divide:
|
||||
case opcode::OP_Modulus:
|
||||
case opcode::OP_SizeOf:
|
||||
case opcode::OP_WaitTill:
|
||||
case opcode::OP_Notify:
|
||||
case opcode::OP_EndOn:
|
||||
case opcode::OP_VoidCodePos:
|
||||
case opcode::OP_Vector:
|
||||
case opcode::OP_RealWait:
|
||||
case opcode::OP_IsDefined:
|
||||
case opcode::OP_VectorScale:
|
||||
case opcode::OP_AnglesToUp:
|
||||
case opcode::OP_AnglesToRight:
|
||||
case opcode::OP_AnglesToForward:
|
||||
case opcode::OP_AngleClamp180:
|
||||
case opcode::OP_VectorToAngles:
|
||||
case opcode::OP_Abs:
|
||||
case opcode::OP_GetTime:
|
||||
case opcode::OP_GetDvar:
|
||||
case opcode::OP_GetDvarInt:
|
||||
case opcode::OP_GetDvarFloat:
|
||||
case opcode::OP_GetDvarVector:
|
||||
case opcode::OP_GetDvarColorRed:
|
||||
case opcode::OP_GetDvarColorGreen:
|
||||
case opcode::OP_GetDvarColorBlue:
|
||||
case opcode::OP_GetDvarColorAlpha:
|
||||
case opcode::OP_FirstArrayKey:
|
||||
case opcode::OP_NextArrayKey:
|
||||
case opcode::OP_ProfileStart:
|
||||
case opcode::OP_ProfileStop:
|
||||
case opcode::OP_SafeDecTop:
|
||||
case opcode::OP_Nop:
|
||||
case opcode::OP_Abort:
|
||||
case opcode::OP_Object:
|
||||
case opcode::OP_ThreadObject:
|
||||
case opcode::OP_EvalLocalVariable:
|
||||
case opcode::OP_EvalLocalVariableRef:
|
||||
break;
|
||||
case opcode::OP_GetByte:
|
||||
case opcode::OP_GetNegByte:
|
||||
script_->write<std::uint8_t>(static_cast<std::uint8_t>(std::stoi(inst->data[0])));
|
||||
break;
|
||||
case opcode::OP_GetUnsignedShort:
|
||||
case opcode::OP_GetNegUnsignedShort:
|
||||
script_->align(2);
|
||||
script_->write<std::uint16_t>(static_cast<std::uint16_t>(std::stoi(inst->data[0])));
|
||||
break;
|
||||
case opcode::OP_GetInteger:
|
||||
script_->align(4);
|
||||
script_->write<std::int32_t>((inst->data.size() == 2) ? -1 : std::stoi(inst->data[0]));
|
||||
break;
|
||||
case opcode::OP_GetFloat:
|
||||
script_->align(4);
|
||||
script_->write<float>(std::stof(inst->data[0]));
|
||||
break;
|
||||
case opcode::OP_GetVector:
|
||||
script_->align(4);
|
||||
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_->align(2);
|
||||
script_->write<std::uint16_t>(0);
|
||||
break;
|
||||
case opcode::OP_GetAnimation:
|
||||
script_->align(4);
|
||||
script_->write<std::uint32_t>(0);
|
||||
break;
|
||||
case opcode::OP_WaitTillMatch:
|
||||
script_->write<std::uint8_t>(static_cast<std::uint8_t>(std::stoi(inst->data[0])));
|
||||
break;
|
||||
case opcode::OP_VectorConstant:
|
||||
script_->write<std::uint8_t>(static_cast<std::uint8_t>(std::stoi(inst->data[0])));
|
||||
break;
|
||||
case opcode::OP_GetHash:
|
||||
script_->align(4);
|
||||
script_->write<std::uint32_t>(static_cast<std::uint32_t>(std::stoul(inst->data[0], 0, 16)));
|
||||
break;
|
||||
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>(std::stoi(inst->data[0])));
|
||||
break;
|
||||
case opcode::OP_EvalFieldVariable:
|
||||
case opcode::OP_EvalFieldVariableRef:
|
||||
case opcode::OP_ClearFieldVariable:
|
||||
script_->align(2);
|
||||
script_->write<std::uint16_t>(0);
|
||||
break;
|
||||
case opcode::OP_ScriptFunctionCallPointer:
|
||||
case opcode::OP_ScriptMethodCallPointer:
|
||||
case opcode::OP_ScriptThreadCallPointer:
|
||||
case opcode::OP_ScriptMethodThreadCallPointer:
|
||||
script_->write<std::uint8_t>(static_cast<std::uint8_t>(std::stoi(inst->data[0])));
|
||||
break;
|
||||
case opcode::OP_GetFunction:
|
||||
script_->align(4);
|
||||
script_->write<std::uint32_t>(0);
|
||||
break;
|
||||
case opcode::OP_CallBuiltin:
|
||||
case opcode::OP_CallBuiltinMethod:
|
||||
case opcode::OP_ScriptFunctionCall:
|
||||
case opcode::OP_ScriptMethodCall:
|
||||
case opcode::OP_ScriptThreadCall:
|
||||
case opcode::OP_ScriptMethodThreadCall:
|
||||
script_->write<std::uint8_t>(0);
|
||||
script_->align(4);
|
||||
script_->write<std::uint32_t>(0);
|
||||
break;
|
||||
case opcode::OP_JumpOnFalse:
|
||||
case opcode::OP_JumpOnTrue:
|
||||
case opcode::OP_JumpOnFalseExpr:
|
||||
case opcode::OP_JumpOnTrueExpr:
|
||||
case opcode::OP_Jump:
|
||||
case opcode::OP_JumpBack:
|
||||
case opcode::OP_DevblockBegin:
|
||||
assemble_jump(inst);
|
||||
break;
|
||||
case opcode::OP_Switch:
|
||||
assemble_switch(inst);
|
||||
break;
|
||||
case opcode::OP_EndSwitch:
|
||||
assemble_end_switch(inst);
|
||||
break;
|
||||
default:
|
||||
throw asm_error(utils::string::va("unhandled opcode 0x%X at index '%04X'!", inst->opcode, inst->index));
|
||||
}
|
||||
}
|
||||
|
||||
void assembler::assemble_localvars(const instruction::ptr& inst)
|
||||
{
|
||||
script_->write<std::uint8_t>(static_cast<std::uint8_t>(inst->data.size()));
|
||||
|
||||
for (auto i = 0u; i < inst->data.size(); i++)
|
||||
{
|
||||
script_->align(2);
|
||||
script_->write<std::uint16_t>(0);
|
||||
}
|
||||
}
|
||||
|
||||
void assembler::assemble_jump(const instruction::ptr& inst)
|
||||
{
|
||||
const auto addr = static_cast<std::int16_t>(resolve_label(inst->data[0]) - inst->index - inst->size);
|
||||
|
||||
script_->align(2);
|
||||
script_->write<std::int16_t>(addr);
|
||||
}
|
||||
|
||||
void assembler::assemble_switch(const instruction::ptr& inst)
|
||||
{
|
||||
const std::int32_t addr = ((resolve_label(inst->data[0]) + 4) & 0xFFFFFFFC) - inst->index - inst->size;
|
||||
|
||||
script_->align(4);
|
||||
script_->write<std::int32_t>(addr);
|
||||
}
|
||||
|
||||
void assembler::assemble_end_switch(const instruction::ptr& inst)
|
||||
{
|
||||
const auto count = std::stoul(inst->data[0]);
|
||||
const auto numerical = inst->data.back() == "i";
|
||||
|
||||
script_->align(4);
|
||||
script_->write<std::uint32_t>(count);
|
||||
|
||||
for (auto i = 0u; i < count; i++)
|
||||
{
|
||||
if (inst->data[1 + (3 * i)] == "case")
|
||||
{
|
||||
if (numerical /*&& 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);
|
||||
}
|
||||
|
||||
const std::int32_t addr = resolve_label(inst->data[1 + (3 * i) + 2]) - script_->pos() - 4;
|
||||
|
||||
script_->write<int32_t>(addr);
|
||||
}
|
||||
else if (inst->data[1 + (3 * i)] == "default")
|
||||
{
|
||||
script_->write<uint32_t>(0);
|
||||
|
||||
const std::int32_t addr = resolve_label(inst->data[1 + (3 * i) + 1]) - script_->pos() - 4;
|
||||
|
||||
script_->write<int32_t>(addr);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw asm_error("invalid switch case '" + inst->data[1 + (3 * i)] + "'!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void assembler::align_instruction(const instruction::ptr& inst)
|
||||
{
|
||||
inst->size = opcode_size(inst->opcode);
|
||||
script_->seek(1);
|
||||
|
||||
switch (static_cast<opcode>(inst->opcode))
|
||||
{
|
||||
case opcode::OP_End:
|
||||
case opcode::OP_Return:
|
||||
case opcode::OP_GetUndefined:
|
||||
case opcode::OP_GetZero:
|
||||
case opcode::OP_GetLevelObject:
|
||||
case opcode::OP_GetAnimObject:
|
||||
case opcode::OP_GetSelf:
|
||||
case opcode::OP_GetLevel:
|
||||
case opcode::OP_GetGame:
|
||||
case opcode::OP_GetAnim:
|
||||
case opcode::OP_GetGameRef:
|
||||
case opcode::OP_CreateLocalVariable:
|
||||
case opcode::OP_EvalArray:
|
||||
case opcode::OP_EvalArrayRef:
|
||||
case opcode::OP_ClearArray:
|
||||
case opcode::OP_EmptyArray:
|
||||
case opcode::OP_GetSelfObject:
|
||||
case opcode::OP_SafeSetVariableFieldCached:
|
||||
case opcode::OP_ClearParams:
|
||||
case opcode::OP_CheckClearParams:
|
||||
case opcode::OP_SetVariableField:
|
||||
case opcode::OP_Wait:
|
||||
case opcode::OP_WaitTillFrameEnd:
|
||||
case opcode::OP_PreScriptCall:
|
||||
case opcode::OP_DecTop:
|
||||
case opcode::OP_CastFieldObject:
|
||||
case opcode::OP_CastBool:
|
||||
case opcode::OP_BoolNot:
|
||||
case opcode::OP_BoolComplement:
|
||||
case opcode::OP_Inc:
|
||||
case opcode::OP_Dec:
|
||||
case opcode::OP_Bit_Or:
|
||||
case opcode::OP_Bit_Xor:
|
||||
case opcode::OP_Bit_And:
|
||||
case opcode::OP_Equal:
|
||||
case opcode::OP_NotEqual:
|
||||
case opcode::OP_LessThan:
|
||||
case opcode::OP_GreaterThan:
|
||||
case opcode::OP_LessThanOrEqualTo:
|
||||
case opcode::OP_GreaterThanOrEqualTo:
|
||||
case opcode::OP_ShiftLeft:
|
||||
case opcode::OP_ShiftRight:
|
||||
case opcode::OP_Plus:
|
||||
case opcode::OP_Minus:
|
||||
case opcode::OP_Multiply:
|
||||
case opcode::OP_Divide:
|
||||
case opcode::OP_Modulus:
|
||||
case opcode::OP_SizeOf:
|
||||
case opcode::OP_WaitTill:
|
||||
case opcode::OP_Notify:
|
||||
case opcode::OP_EndOn:
|
||||
case opcode::OP_VoidCodePos:
|
||||
case opcode::OP_Vector:
|
||||
case opcode::OP_RealWait:
|
||||
case opcode::OP_IsDefined:
|
||||
case opcode::OP_VectorScale:
|
||||
case opcode::OP_AnglesToUp:
|
||||
case opcode::OP_AnglesToRight:
|
||||
case opcode::OP_AnglesToForward:
|
||||
case opcode::OP_AngleClamp180:
|
||||
case opcode::OP_VectorToAngles:
|
||||
case opcode::OP_Abs:
|
||||
case opcode::OP_GetTime:
|
||||
case opcode::OP_GetDvar:
|
||||
case opcode::OP_GetDvarInt:
|
||||
case opcode::OP_GetDvarFloat:
|
||||
case opcode::OP_GetDvarVector:
|
||||
case opcode::OP_GetDvarColorRed:
|
||||
case opcode::OP_GetDvarColorGreen:
|
||||
case opcode::OP_GetDvarColorBlue:
|
||||
case opcode::OP_GetDvarColorAlpha:
|
||||
case opcode::OP_FirstArrayKey:
|
||||
case opcode::OP_NextArrayKey:
|
||||
case opcode::OP_ProfileStart:
|
||||
case opcode::OP_ProfileStop:
|
||||
case opcode::OP_SafeDecTop:
|
||||
case opcode::OP_Nop:
|
||||
case opcode::OP_Abort:
|
||||
case opcode::OP_Object:
|
||||
case opcode::OP_ThreadObject:
|
||||
case opcode::OP_EvalLocalVariable:
|
||||
case opcode::OP_EvalLocalVariableRef:
|
||||
break;
|
||||
case opcode::OP_GetByte:
|
||||
case opcode::OP_GetNegByte:
|
||||
script_->seek(1);
|
||||
break;
|
||||
case opcode::OP_GetUnsignedShort:
|
||||
case opcode::OP_GetNegUnsignedShort:
|
||||
inst->size += script_->align(2);
|
||||
script_->seek(2);
|
||||
break;
|
||||
case opcode::OP_GetInteger:
|
||||
inst->size += script_->align(4);
|
||||
if (inst->data.size() == 2)
|
||||
add_anim_reference(inst->data, script_->pos());
|
||||
script_->seek(4);
|
||||
break;
|
||||
case opcode::OP_GetFloat:
|
||||
inst->size += script_->align(4);
|
||||
script_->seek(4);
|
||||
break;
|
||||
case opcode::OP_GetVector:
|
||||
inst->size += script_->align(4);
|
||||
script_->seek(12);
|
||||
break;
|
||||
case opcode::OP_GetString:
|
||||
case opcode::OP_GetIString:
|
||||
inst->size += script_->align(2);
|
||||
add_string_reference(inst->data[0], string_type::literal, script_->pos());
|
||||
script_->seek(2);
|
||||
break;
|
||||
case opcode::OP_GetAnimation:
|
||||
inst->size += script_->align(4);
|
||||
add_anim_reference(inst->data, script_->pos());
|
||||
script_->seek(4);
|
||||
break;
|
||||
case opcode::OP_WaitTillMatch:
|
||||
script_->seek(1);
|
||||
break;
|
||||
case opcode::OP_VectorConstant:
|
||||
script_->seek(1);
|
||||
break;
|
||||
case opcode::OP_GetHash:
|
||||
inst->size += script_->align(4);
|
||||
script_->seek(4);
|
||||
break;
|
||||
case opcode::OP_SafeCreateLocalVariables:
|
||||
{
|
||||
script_->seek(1);
|
||||
|
||||
for (auto i = 0u; i < inst->data.size(); i++)
|
||||
{
|
||||
inst->size += script_->align(2) + 2;
|
||||
add_string_reference(inst->data[i], string_type::canonical, script_->pos());
|
||||
script_->seek(2);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case opcode::OP_RemoveLocalVariables:
|
||||
case opcode::OP_EvalLocalVariableCached:
|
||||
case opcode::OP_EvalLocalArrayRefCached:
|
||||
case opcode::OP_SafeSetWaittillVariableFieldCached:
|
||||
case opcode::OP_EvalLocalVariableRefCached:
|
||||
script_->seek(1);
|
||||
break;
|
||||
case opcode::OP_EvalFieldVariable:
|
||||
case opcode::OP_EvalFieldVariableRef:
|
||||
case opcode::OP_ClearFieldVariable:
|
||||
inst->size += script_->align(2);
|
||||
add_string_reference(inst->data[0], string_type::canonical, script_->pos());
|
||||
script_->seek(2);
|
||||
break;
|
||||
case opcode::OP_ScriptFunctionCallPointer:
|
||||
case opcode::OP_ScriptMethodCallPointer:
|
||||
case opcode::OP_ScriptThreadCallPointer:
|
||||
case opcode::OP_ScriptMethodThreadCallPointer:
|
||||
script_->seek(1);
|
||||
break;
|
||||
case opcode::OP_GetFunction:
|
||||
inst->size += script_->align(4);
|
||||
script_->seek(4);
|
||||
add_import_reference(inst->data, inst->index);
|
||||
break;
|
||||
case opcode::OP_CallBuiltin:
|
||||
case opcode::OP_CallBuiltinMethod:
|
||||
case opcode::OP_ScriptFunctionCall:
|
||||
case opcode::OP_ScriptMethodCall:
|
||||
case opcode::OP_ScriptThreadCall:
|
||||
case opcode::OP_ScriptMethodThreadCall:
|
||||
script_->seek(1);
|
||||
inst->size += script_->align(4);
|
||||
script_->seek(4);
|
||||
add_import_reference(inst->data, inst->index);
|
||||
break;
|
||||
case opcode::OP_JumpOnFalse:
|
||||
case opcode::OP_JumpOnTrue:
|
||||
case opcode::OP_JumpOnFalseExpr:
|
||||
case opcode::OP_JumpOnTrueExpr:
|
||||
case opcode::OP_Jump:
|
||||
case opcode::OP_JumpBack:
|
||||
case opcode::OP_DevblockBegin:
|
||||
inst->size += script_->align(2);
|
||||
script_->seek(2);
|
||||
break;
|
||||
case opcode::OP_Switch:
|
||||
inst->size += script_->align(4);
|
||||
script_->seek(4);
|
||||
break;
|
||||
case opcode::OP_EndSwitch:
|
||||
{
|
||||
inst->size += script_->align(4);
|
||||
script_->seek(4);
|
||||
|
||||
const auto count = std::stoul(inst->data[0]);
|
||||
const auto numerical = inst->data.back() == "i";
|
||||
|
||||
for (auto i = 0u; i < count; i++)
|
||||
{
|
||||
if (inst->data[1 + (3 * i)] == "case")
|
||||
{
|
||||
if (!numerical /*|| !utils::string::is_number(inst->data[1 + (3 * i) + 1])*/)
|
||||
{
|
||||
add_string_reference(inst->data[1 + (3 * i) + 1], string_type::literal, script_->pos() + 2);
|
||||
}
|
||||
}
|
||||
|
||||
inst->size += 8;
|
||||
script_->seek(8);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw asm_error(utils::string::va("unhandled opcode 0x%X at index '%04X'!", inst->opcode, inst->index));
|
||||
}
|
||||
}
|
||||
|
||||
void assembler::process_string(const std::string& data)
|
||||
{
|
||||
if (!stringlist_.contains(data))
|
||||
{
|
||||
auto pos = static_cast<std::uint16_t>(script_->pos());
|
||||
script_->write_cstr(data);
|
||||
stringlist_.insert({ data, pos });
|
||||
}
|
||||
}
|
||||
|
||||
void assembler::process_function(const function::ptr& func)
|
||||
{
|
||||
process_string(func->name);
|
||||
|
||||
for (const auto& inst : func->instructions)
|
||||
{
|
||||
process_instruction(inst);
|
||||
}
|
||||
}
|
||||
|
||||
void assembler::process_instruction(const instruction::ptr& inst)
|
||||
{
|
||||
switch (static_cast<opcode>(inst->opcode))
|
||||
{
|
||||
case opcode::OP_GetInteger:
|
||||
if (inst->data.size() == 2)
|
||||
process_string(inst->data[0]);
|
||||
break;
|
||||
case opcode::OP_GetString:
|
||||
case opcode::OP_GetIString:
|
||||
process_string(inst->data[0]);
|
||||
break;
|
||||
case opcode::OP_GetAnimation:
|
||||
process_string(inst->data[0]);
|
||||
process_string(inst->data[1]);
|
||||
break;
|
||||
case opcode::OP_SafeCreateLocalVariables:
|
||||
{
|
||||
for (const auto& entry : inst->data)
|
||||
{
|
||||
process_string(entry);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case opcode::OP_EvalFieldVariable:
|
||||
case opcode::OP_EvalFieldVariableRef:
|
||||
case opcode::OP_ClearFieldVariable:
|
||||
process_string(inst->data[0]);
|
||||
break;
|
||||
case opcode::OP_GetFunction:
|
||||
process_string(inst->data[0]);
|
||||
process_string(inst->data[1]);
|
||||
break;
|
||||
case opcode::OP_CallBuiltin:
|
||||
case opcode::OP_CallBuiltinMethod:
|
||||
case opcode::OP_ScriptFunctionCall:
|
||||
case opcode::OP_ScriptMethodCall:
|
||||
case opcode::OP_ScriptThreadCall:
|
||||
case opcode::OP_ScriptMethodThreadCall:
|
||||
process_string(inst->data[0]);
|
||||
process_string(inst->data[1]);
|
||||
break;
|
||||
case opcode::OP_EndSwitch:
|
||||
{
|
||||
const auto count = std::stoul(inst->data[0]);
|
||||
const auto numerical = inst->data.back() == "i";
|
||||
|
||||
for (auto i = 0u; i < count; i++)
|
||||
{
|
||||
if (inst->data[1 + (3 * i)] == "case")
|
||||
{
|
||||
if (!numerical /*|| !utils::string::is_number(inst->data[1 + (3 * i) + 1])*/)
|
||||
{
|
||||
process_string(inst->data[1 + (3 * i) + 1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
auto assembler::resolve_label(const std::string& name) -> std::int32_t
|
||||
{
|
||||
for (const auto& entry : labels_)
|
||||
{
|
||||
if (entry.second == name)
|
||||
{
|
||||
return entry.first;
|
||||
}
|
||||
}
|
||||
|
||||
throw asm_error("couldn't resolve label address of '" + name + "'!");
|
||||
}
|
||||
|
||||
auto assembler::string_offset(const std::string& name) -> std::uint16_t
|
||||
{
|
||||
const auto itr = stringlist_.find(name);
|
||||
|
||||
if (itr != stringlist_.end())
|
||||
{
|
||||
return itr->second;
|
||||
}
|
||||
|
||||
throw asm_error("couldn't resolve string assembly address of '" + name + "'!");
|
||||
}
|
||||
|
||||
void assembler::add_string_reference(const std::string& str, string_type type, std::uint32_t ref)
|
||||
{
|
||||
for (auto& entry : stringtables_)
|
||||
{
|
||||
if (entry.name == str && entry.type == static_cast<std::uint8_t>(type))
|
||||
{
|
||||
entry.refs.push_back(ref);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
stringtables_.push_back({ str, std::uint8_t(type), { ref } });
|
||||
}
|
||||
|
||||
void assembler::add_import_reference(const std::vector<std::string>& data, std::uint32_t ref)
|
||||
{
|
||||
for (auto& entry : imports_)
|
||||
{
|
||||
if (entry.space == data[0] && entry.name == data[1] && entry.params == std::stoi(data[2]) && entry.flags == std::stoi(data[3]))
|
||||
{
|
||||
entry.refs.push_back(ref);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
import_ref new_entry;
|
||||
new_entry.space = data[0];
|
||||
new_entry.name = data[1];
|
||||
new_entry.params = static_cast<std::uint8_t>(std::stoi(data[2]));
|
||||
new_entry.flags = static_cast<std::uint8_t>(std::stoi(data[3]));
|
||||
new_entry.refs.push_back(ref);
|
||||
imports_.push_back(std::move(new_entry));
|
||||
}
|
||||
|
||||
void assembler::add_anim_reference(const std::vector<std::string>& data, std::uint32_t ref)
|
||||
{
|
||||
for (auto& entry : animtrees_)
|
||||
{
|
||||
if (entry.name == data[0])
|
||||
{
|
||||
if (data[1] == "-1")
|
||||
{
|
||||
entry.refs.push_back(ref);
|
||||
}
|
||||
else
|
||||
{
|
||||
entry.anims.push_back({ data[1], ref });
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
animtree_ref new_entry;
|
||||
new_entry.name = data[0];
|
||||
if (data[1] == "-1")
|
||||
{
|
||||
new_entry.refs.push_back(ref);
|
||||
}
|
||||
else
|
||||
{
|
||||
new_entry.anims.push_back({ data[1], ref });
|
||||
}
|
||||
animtrees_.push_back(std::move(new_entry));
|
||||
}
|
||||
|
||||
} // namespace xsk::arc::t6
|
File diff suppressed because it is too large
Load Diff
2496
src/t6/compiler.cpp
2496
src/t6/compiler.cpp
File diff suppressed because it is too large
Load Diff
@ -1,23 +0,0 @@
|
||||
// Copyright 2023 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 "xsk/stdinc.hpp"
|
||||
#include "xsk/t6/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
|
File diff suppressed because it is too large
Load Diff
@ -1,710 +0,0 @@
|
||||
// Copyright 2023 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 "xsk/stdinc.hpp"
|
||||
#include "xsk/t6/t6.hpp"
|
||||
|
||||
namespace xsk::arc::t6
|
||||
{
|
||||
|
||||
auto disassembler::output() -> assembly::ptr
|
||||
{
|
||||
return std::move(assembly_);
|
||||
}
|
||||
|
||||
auto disassembler::output_raw() -> std::vector<std::uint8_t>
|
||||
{
|
||||
output_ = std::make_unique<utils::writer>();
|
||||
|
||||
output_->write_string("// T6 GSC ASSEMBLY\n");
|
||||
output_->write_string("// Disassembled by https://github.com/xensik/gsc-tool\n");
|
||||
|
||||
for (const auto& func : assembly_->functions)
|
||||
{
|
||||
this->print_function(func);
|
||||
}
|
||||
|
||||
std::vector<std::uint8_t> output;
|
||||
|
||||
output.resize(output_->pos());
|
||||
std::memcpy(output.data(), output_->data(), output.size());
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
void disassembler::disassemble(const std::string& file, std::vector<std::uint8_t>& data)
|
||||
{
|
||||
filename_ = file;
|
||||
script_ = std::make_unique<utils::reader>(data);
|
||||
assembly_ = std::make_unique<assembly>();
|
||||
exports_.clear();
|
||||
imports_.clear();
|
||||
strings_.clear();
|
||||
animtrees_.clear();
|
||||
stringlist_.clear();
|
||||
string_refs_.clear();
|
||||
anim_refs_.clear();
|
||||
import_refs_.clear();
|
||||
labels_.clear();
|
||||
std::memset(&header_, 0, sizeof(header_));
|
||||
|
||||
// header
|
||||
header_.magic = script_->read<std::uint64_t>();
|
||||
|
||||
if (header_.magic != magic)
|
||||
{
|
||||
throw error("invalid binary gsc file '" + filename_ + "'!");
|
||||
}
|
||||
|
||||
header_.source_crc = script_->read<std::uint32_t>();
|
||||
header_.include_offset = script_->read<std::uint32_t>();
|
||||
header_.animtree_offset = script_->read<std::uint32_t>();
|
||||
header_.cseg_offset = script_->read<std::uint32_t>();
|
||||
header_.stringtablefixup_offset = script_->read<std::uint32_t>();
|
||||
header_.exports_offset = script_->read<std::uint32_t>();
|
||||
header_.imports_offset = script_->read<std::uint32_t>();
|
||||
header_.fixup_offset = script_->read<std::uint32_t>();
|
||||
header_.profile_offset = script_->read<std::uint32_t>();
|
||||
header_.cseg_size = script_->read<std::uint32_t>();
|
||||
header_.name = script_->read<std::uint16_t>();
|
||||
header_.stringtablefixup_count = script_->read<std::uint16_t>();
|
||||
header_.exports_count = script_->read<std::uint16_t>();
|
||||
header_.imports_count = script_->read<std::uint16_t>();
|
||||
header_.fixup_count = script_->read<std::uint16_t>();
|
||||
header_.profile_count = script_->read<std::uint16_t>();
|
||||
header_.include_count = script_->read<std::uint8_t>();
|
||||
header_.animtree_count = script_->read<std::uint8_t>();
|
||||
header_.flags = script_->read<std::uint8_t>();
|
||||
|
||||
// string list
|
||||
script_->pos(64);
|
||||
|
||||
while (script_->pos() < header_.include_offset)
|
||||
{
|
||||
auto pos = script_->pos();
|
||||
stringlist_.insert({ pos, script_->read_cstr() });
|
||||
}
|
||||
|
||||
// include list
|
||||
script_->pos(header_.include_offset);
|
||||
|
||||
for (auto i = 0; i < header_.include_count; i++)
|
||||
{
|
||||
assembly_->includes.push_back(stringlist_.at(script_->read<std::uint32_t>()));
|
||||
}
|
||||
|
||||
// animtree list
|
||||
script_->pos(header_.animtree_offset);
|
||||
|
||||
for (auto i = 0; i < header_.animtree_count; i++)
|
||||
{
|
||||
auto entry = std::make_shared<animtree_ref>();
|
||||
entry->name = stringlist_.at(script_->read<std::uint16_t>());
|
||||
auto ref_count = script_->read<std::uint16_t>();
|
||||
auto anim_count = script_->read<std::uint16_t>();
|
||||
script_->seek(2);
|
||||
|
||||
for (auto j = 0; j < ref_count; j++)
|
||||
{
|
||||
auto ref = script_->read<std::uint32_t>();
|
||||
entry->refs.push_back(ref);
|
||||
anim_refs_.insert({ ref, entry });
|
||||
}
|
||||
|
||||
for (auto k = 0; k < anim_count; k++)
|
||||
{
|
||||
auto name = stringlist_.at(script_->read<std::uint32_t>());
|
||||
auto ref = script_->read<std::uint32_t>();
|
||||
entry->anims.push_back({ name, ref });
|
||||
}
|
||||
|
||||
for (auto& anim : entry->anims)
|
||||
{
|
||||
anim_refs_.insert({ anim.ref, entry });
|
||||
}
|
||||
|
||||
animtrees_.push_back(entry);
|
||||
}
|
||||
|
||||
// stringtable list
|
||||
script_->pos(header_.stringtablefixup_offset);
|
||||
|
||||
for (auto i = 0; i < header_.stringtablefixup_count; i++)
|
||||
{
|
||||
auto entry = std::make_shared<string_ref>();
|
||||
entry->name = stringlist_.at(script_->read<std::uint16_t>());
|
||||
auto ref_count = script_->read<std::uint8_t>();
|
||||
entry->type = script_->read<std::uint8_t>();
|
||||
|
||||
for (auto j = 0; j < ref_count; j++)
|
||||
{
|
||||
auto ref = script_->read<std::uint32_t>();
|
||||
entry->refs.push_back(ref);
|
||||
string_refs_.insert({ ref, entry });
|
||||
}
|
||||
|
||||
strings_.push_back(entry);
|
||||
}
|
||||
|
||||
// import list
|
||||
script_->pos(header_.imports_offset);
|
||||
|
||||
for (auto i = 0; i < header_.imports_count; i++)
|
||||
{
|
||||
auto entry = std::make_shared<import_ref>();
|
||||
entry->name = stringlist_.at(script_->read<std::uint16_t>());
|
||||
entry->space = stringlist_.at(script_->read<std::uint16_t>());
|
||||
auto ref_count = script_->read<std::uint16_t>();
|
||||
entry->params = script_->read<std::uint8_t>();
|
||||
entry->flags = script_->read<std::uint8_t>();
|
||||
|
||||
for (auto j = 0; j < ref_count; j++)
|
||||
{
|
||||
auto ref = script_->read<std::uint32_t>();
|
||||
entry->refs.push_back(ref);
|
||||
import_refs_.insert({ ref, entry });
|
||||
}
|
||||
|
||||
imports_.push_back(entry);
|
||||
}
|
||||
|
||||
// export list
|
||||
script_->pos(header_.exports_offset);
|
||||
|
||||
for (auto i = 0; i < header_.exports_count; i++)
|
||||
{
|
||||
auto entry = std::make_shared<export_ref>();
|
||||
entry->checksum = script_->read<std::uint32_t>();
|
||||
entry->offset = script_->read<std::uint32_t>();
|
||||
entry->name = stringlist_.at(script_->read<std::uint16_t>());
|
||||
entry->space = "";
|
||||
entry->params = script_->read<std::uint8_t>();
|
||||
entry->flags = script_->read<std::uint8_t>();
|
||||
exports_.push_back(entry);
|
||||
}
|
||||
|
||||
for (auto i = 0u; i < exports_.size(); i++)
|
||||
{
|
||||
auto& entry = exports_[i];
|
||||
|
||||
if (i < exports_.size() - 1)
|
||||
{
|
||||
entry->size = (exports_[i+1]->offset - entry->offset);
|
||||
|
||||
auto end_pos = entry->offset + entry->size - 4;
|
||||
|
||||
script_->pos(end_pos);
|
||||
|
||||
if (script_->read<std::uint32_t>() == 0)
|
||||
{
|
||||
entry->size -= 4;
|
||||
|
||||
for (auto j = 1; j < 4; j++)
|
||||
{
|
||||
script_->pos(end_pos - j);
|
||||
auto op = script_->read<std::uint8_t>();
|
||||
|
||||
if (op <= 0x01) break;
|
||||
|
||||
entry->size--;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
entry->size = (header_.cseg_offset + header_.cseg_size) - entry->offset;
|
||||
}
|
||||
|
||||
script_->pos(entry->offset);
|
||||
|
||||
assembly_->functions.push_back(std::make_unique<function>());
|
||||
auto& func = assembly_->functions.back();
|
||||
func->index = static_cast<std::uint32_t>(script_->pos());
|
||||
func->size = entry->size;
|
||||
func->params = entry->params;
|
||||
func->flags = entry->flags;
|
||||
func->name = entry->name;
|
||||
|
||||
this->disassemble_function(func);
|
||||
|
||||
func->labels = labels_;
|
||||
labels_.clear();
|
||||
}
|
||||
}
|
||||
|
||||
void disassembler::disassemble_function(const function::ptr& func)
|
||||
{
|
||||
auto size = func->size;
|
||||
|
||||
while (size > 0)
|
||||
{
|
||||
func->instructions.push_back(std::make_unique<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);
|
||||
|
||||
if (size < 4 && inst->opcode >= std::uint8_t(opcode::OP_Count))
|
||||
{
|
||||
func->instructions.pop_back();
|
||||
break;
|
||||
}
|
||||
|
||||
this->disassemble_instruction(inst);
|
||||
size -= inst->size;
|
||||
}
|
||||
|
||||
for (auto i = func->instructions.size() - 1; i >= 1; i--)
|
||||
{
|
||||
auto& inst = func->instructions.at(i);
|
||||
auto& last = func->instructions.at(i-1);
|
||||
|
||||
if (labels_.contains(inst->index))
|
||||
break;
|
||||
|
||||
if (inst->opcode <= 0x01 && (last->opcode > 0x01))
|
||||
break;
|
||||
|
||||
func->instructions.pop_back();
|
||||
}
|
||||
}
|
||||
|
||||
void disassembler::disassemble_instruction(const instruction::ptr& inst)
|
||||
{
|
||||
switch (static_cast<opcode>(inst->opcode))
|
||||
{
|
||||
case opcode::OP_End:
|
||||
case opcode::OP_Return:
|
||||
case opcode::OP_GetUndefined:
|
||||
case opcode::OP_GetZero:
|
||||
case opcode::OP_GetLevelObject:
|
||||
case opcode::OP_GetAnimObject:
|
||||
case opcode::OP_GetSelf:
|
||||
case opcode::OP_GetLevel:
|
||||
case opcode::OP_GetGame:
|
||||
case opcode::OP_GetAnim:
|
||||
case opcode::OP_GetGameRef:
|
||||
case opcode::OP_CreateLocalVariable:
|
||||
case opcode::OP_EvalArray:
|
||||
case opcode::OP_EvalArrayRef:
|
||||
case opcode::OP_ClearArray:
|
||||
case opcode::OP_EmptyArray:
|
||||
case opcode::OP_GetSelfObject:
|
||||
case opcode::OP_SafeSetVariableFieldCached:
|
||||
case opcode::OP_ClearParams:
|
||||
case opcode::OP_CheckClearParams:
|
||||
case opcode::OP_SetVariableField:
|
||||
case opcode::OP_Wait:
|
||||
case opcode::OP_WaitTillFrameEnd:
|
||||
case opcode::OP_PreScriptCall:
|
||||
case opcode::OP_DecTop:
|
||||
case opcode::OP_CastFieldObject:
|
||||
case opcode::OP_CastBool:
|
||||
case opcode::OP_BoolNot:
|
||||
case opcode::OP_BoolComplement:
|
||||
case opcode::OP_Inc:
|
||||
case opcode::OP_Dec:
|
||||
case opcode::OP_Bit_Or:
|
||||
case opcode::OP_Bit_Xor:
|
||||
case opcode::OP_Bit_And:
|
||||
case opcode::OP_Equal:
|
||||
case opcode::OP_NotEqual:
|
||||
case opcode::OP_LessThan:
|
||||
case opcode::OP_GreaterThan:
|
||||
case opcode::OP_LessThanOrEqualTo:
|
||||
case opcode::OP_GreaterThanOrEqualTo:
|
||||
case opcode::OP_ShiftLeft:
|
||||
case opcode::OP_ShiftRight:
|
||||
case opcode::OP_Plus:
|
||||
case opcode::OP_Minus:
|
||||
case opcode::OP_Multiply:
|
||||
case opcode::OP_Divide:
|
||||
case opcode::OP_Modulus:
|
||||
case opcode::OP_SizeOf:
|
||||
case opcode::OP_WaitTill:
|
||||
case opcode::OP_Notify:
|
||||
case opcode::OP_EndOn:
|
||||
case opcode::OP_VoidCodePos:
|
||||
case opcode::OP_Vector:
|
||||
case opcode::OP_RealWait:
|
||||
case opcode::OP_IsDefined:
|
||||
case opcode::OP_VectorScale:
|
||||
case opcode::OP_AnglesToUp:
|
||||
case opcode::OP_AnglesToRight:
|
||||
case opcode::OP_AnglesToForward:
|
||||
case opcode::OP_AngleClamp180:
|
||||
case opcode::OP_VectorToAngles:
|
||||
case opcode::OP_Abs:
|
||||
case opcode::OP_GetTime:
|
||||
case opcode::OP_GetDvar:
|
||||
case opcode::OP_GetDvarInt:
|
||||
case opcode::OP_GetDvarFloat:
|
||||
case opcode::OP_GetDvarVector:
|
||||
case opcode::OP_GetDvarColorRed:
|
||||
case opcode::OP_GetDvarColorGreen:
|
||||
case opcode::OP_GetDvarColorBlue:
|
||||
case opcode::OP_GetDvarColorAlpha:
|
||||
case opcode::OP_FirstArrayKey:
|
||||
case opcode::OP_NextArrayKey:
|
||||
case opcode::OP_ProfileStart:
|
||||
case opcode::OP_ProfileStop:
|
||||
case opcode::OP_SafeDecTop:
|
||||
case opcode::OP_Nop:
|
||||
case opcode::OP_Abort:
|
||||
case opcode::OP_Object:
|
||||
case opcode::OP_ThreadObject:
|
||||
case opcode::OP_EvalLocalVariable:
|
||||
case opcode::OP_EvalLocalVariableRef:
|
||||
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->size += script_->align(2);
|
||||
inst->data.push_back(utils::string::va("%i", script_->read<std::uint16_t>()));
|
||||
break;
|
||||
case opcode::OP_GetInteger:
|
||||
inst->size += script_->align(4);
|
||||
disassemble_animtree(inst);
|
||||
inst->data.push_back(utils::string::va("%i", script_->read<std::int32_t>()));
|
||||
break;
|
||||
case opcode::OP_GetFloat:
|
||||
inst->size += script_->align(4);
|
||||
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::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:
|
||||
disassemble_string(inst);
|
||||
break;
|
||||
case opcode::OP_GetAnimation:
|
||||
disassemble_animation(inst);
|
||||
break;
|
||||
case opcode::OP_WaitTillMatch:
|
||||
inst->data.push_back(utils::string::va("%i", script_->read<std::uint8_t>()));
|
||||
break;
|
||||
case opcode::OP_VectorConstant:
|
||||
inst->data.push_back(utils::string::va("%i", script_->read<std::uint8_t>()));
|
||||
break;
|
||||
case opcode::OP_GetHash:
|
||||
inst->size += script_->align(4);
|
||||
inst->data.push_back(resolver::dvar_name(script_->read<std::uint32_t>()));
|
||||
break;
|
||||
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>()));
|
||||
break;
|
||||
case opcode::OP_EvalFieldVariable:
|
||||
case opcode::OP_EvalFieldVariableRef:
|
||||
case opcode::OP_ClearFieldVariable:
|
||||
disassemble_string(inst);
|
||||
break;
|
||||
case opcode::OP_ScriptFunctionCallPointer:
|
||||
case opcode::OP_ScriptMethodCallPointer:
|
||||
case opcode::OP_ScriptThreadCallPointer:
|
||||
case opcode::OP_ScriptMethodThreadCallPointer:
|
||||
inst->data.push_back(utils::string::va("%i", script_->read<std::uint8_t>()));
|
||||
break;
|
||||
case opcode::OP_GetFunction:
|
||||
disassemble_import(inst);
|
||||
break;
|
||||
case opcode::OP_CallBuiltin:
|
||||
case opcode::OP_CallBuiltinMethod:
|
||||
case opcode::OP_ScriptFunctionCall:
|
||||
case opcode::OP_ScriptMethodCall:
|
||||
case opcode::OP_ScriptThreadCall:
|
||||
case opcode::OP_ScriptMethodThreadCall:
|
||||
script_->seek(1);
|
||||
disassemble_import(inst);
|
||||
break;
|
||||
case opcode::OP_JumpOnFalse:
|
||||
case opcode::OP_JumpOnTrue:
|
||||
case opcode::OP_JumpOnFalseExpr:
|
||||
case opcode::OP_JumpOnTrueExpr:
|
||||
case opcode::OP_Jump:
|
||||
case opcode::OP_JumpBack:
|
||||
case opcode::OP_DevblockBegin:
|
||||
disassemble_jump(inst);
|
||||
break;
|
||||
case opcode::OP_Switch:
|
||||
disassemble_switch(inst);
|
||||
break;
|
||||
case opcode::OP_EndSwitch:
|
||||
disassemble_end_switch(inst);
|
||||
break;
|
||||
default:
|
||||
throw disasm_error(utils::string::va("unhandled opcode 0x%X at index '%04X'!", inst->opcode, inst->index));
|
||||
}
|
||||
}
|
||||
|
||||
void disassembler::disassemble_string(const instruction::ptr& inst)
|
||||
{
|
||||
inst->size += script_->align(2);
|
||||
|
||||
const auto entry = string_refs_.find(script_->pos());
|
||||
|
||||
if (entry != string_refs_.end())
|
||||
{
|
||||
inst->data.push_back(entry->second->name);
|
||||
script_->seek(2);
|
||||
return;
|
||||
}
|
||||
|
||||
throw disasm_error(utils::string::va("string reference not found at index '%04X'!", inst->index));
|
||||
}
|
||||
|
||||
void disassembler::disassemble_animtree(const instruction::ptr& inst)
|
||||
{
|
||||
// GetInteger(-1) push animtree name if ref found
|
||||
|
||||
const auto ref = script_->pos();
|
||||
const auto entry = anim_refs_.find(ref);
|
||||
|
||||
if (entry != anim_refs_.end())
|
||||
{
|
||||
inst->data.push_back(entry->second->name);
|
||||
}
|
||||
}
|
||||
|
||||
void disassembler::disassemble_animation(const instruction::ptr& inst)
|
||||
{
|
||||
inst->size += script_->align(4);
|
||||
|
||||
const auto ref = script_->pos();
|
||||
const auto entry = anim_refs_.find(ref);
|
||||
|
||||
if (entry != anim_refs_.end())
|
||||
{
|
||||
inst->data.push_back(entry->second->name);
|
||||
|
||||
for (const auto& anim : entry->second->anims)
|
||||
{
|
||||
if (anim.ref == ref)
|
||||
{
|
||||
inst->data.push_back(anim.name);
|
||||
script_->seek(4);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
throw disasm_error(utils::string::va("animation reference not found at index '%04X'!", inst->index));
|
||||
}
|
||||
|
||||
void disassembler::disassemble_localvars(const instruction::ptr& inst)
|
||||
{
|
||||
const auto count = script_->read<std::uint8_t>();
|
||||
|
||||
for (auto i = 0u; i < count; i++)
|
||||
{
|
||||
disassemble_string(inst);
|
||||
inst->size += 2;
|
||||
}
|
||||
}
|
||||
|
||||
void disassembler::disassemble_import(const instruction::ptr& inst)
|
||||
{
|
||||
inst->size += script_->align(4);
|
||||
script_->seek(4);
|
||||
|
||||
const auto entry = import_refs_.find(inst->index);
|
||||
|
||||
if (entry != import_refs_.end())
|
||||
{
|
||||
inst->data.push_back(entry->second->space);
|
||||
inst->data.push_back(entry->second->name);
|
||||
return;
|
||||
}
|
||||
|
||||
throw disasm_error(utils::string::va("import reference not found at index '%04X'!", inst->index));
|
||||
}
|
||||
|
||||
void disassembler::disassemble_jump(const instruction::ptr& inst)
|
||||
{
|
||||
inst->size += script_->align(2);
|
||||
|
||||
const auto addr = script_->read<std::int16_t>() + script_->pos();
|
||||
const auto label = utils::string::va("loc_%X", addr);
|
||||
|
||||
inst->data.push_back(label);
|
||||
labels_.insert({ addr, label });
|
||||
}
|
||||
|
||||
void disassembler::disassemble_switch(const instruction::ptr& inst)
|
||||
{
|
||||
inst->size += script_->align(4);
|
||||
|
||||
const auto addr = script_->read<std::int32_t>() + script_->pos();
|
||||
const auto label = utils::string::va("loc_%X", addr);
|
||||
|
||||
inst->data.push_back(label);
|
||||
labels_.insert({ addr, label });
|
||||
}
|
||||
|
||||
void disassembler::disassemble_end_switch(const instruction::ptr& inst)
|
||||
{
|
||||
inst->size += script_->align(4);
|
||||
|
||||
const auto itr = labels_.find(script_->pos());
|
||||
|
||||
if (itr != labels_.end())
|
||||
{
|
||||
for (const auto& entry : assembly_->functions.back()->instructions)
|
||||
{
|
||||
if (opcode(entry->opcode) == opcode::OP_Switch)
|
||||
{
|
||||
if (entry->data[0] == itr->second)
|
||||
{
|
||||
labels_.erase(script_->pos());
|
||||
|
||||
const auto label = utils::string::va("loc_%X", inst->index);
|
||||
const auto itr2 = labels_.find(inst->index);
|
||||
|
||||
if (itr2 == labels_.end())
|
||||
{
|
||||
labels_.insert({ inst->index, label });
|
||||
}
|
||||
|
||||
entry->data[0] = label;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto numerical = false;
|
||||
const auto count = script_->read<std::uint32_t>();
|
||||
inst->data.push_back(utils::string::va("%i", count));
|
||||
|
||||
for (auto i = 0u; i < count; i++)
|
||||
{
|
||||
const auto value = script_->read<std::uint32_t>();
|
||||
|
||||
if (value < 0x40000 && value > 0)
|
||||
{
|
||||
inst->data.push_back("case");
|
||||
const auto& entry = string_refs_.at(script_->pos() - 2);
|
||||
inst->data.push_back(entry->name);
|
||||
}
|
||||
else if (value == 0)
|
||||
{
|
||||
inst->data.push_back("default");
|
||||
}
|
||||
else
|
||||
{
|
||||
numerical = true;
|
||||
inst->data.push_back("case");
|
||||
inst->data.push_back(utils::string::va("%i", (value - 0x800000) & 0xFFFFFF));
|
||||
}
|
||||
|
||||
const auto addr = script_->read<std::int32_t>() + script_->pos();
|
||||
const auto label = utils::string::va("loc_%X", addr);
|
||||
|
||||
inst->data.push_back(label);
|
||||
labels_.insert({ addr, label });
|
||||
|
||||
inst->size += 8;
|
||||
}
|
||||
|
||||
inst->data.push_back((numerical) ? "i" : "s");
|
||||
}
|
||||
|
||||
void disassembler::print_function(const function::ptr& func)
|
||||
{
|
||||
output_->write_string("\n");
|
||||
output_->write_string(utils::string::va("sub_%s %i %i\n", func->name.data(), func->params, func->flags));
|
||||
|
||||
for (const 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(utils::string::va("end_%s\n", func->name.data()));
|
||||
}
|
||||
|
||||
void disassembler::print_instruction(const instruction::ptr& inst)
|
||||
{
|
||||
output_->write_string(utils::string::va("\t\t%s(", resolver::opcode_name(inst->opcode).data()));
|
||||
|
||||
switch (static_cast<opcode>(inst->opcode))
|
||||
{
|
||||
case opcode::OP_GetHash:
|
||||
case opcode::OP_GetString:
|
||||
case opcode::OP_GetIString:
|
||||
case opcode::OP_ClearFieldVariable:
|
||||
case opcode::OP_EvalFieldVariable:
|
||||
case opcode::OP_EvalFieldVariableRef:
|
||||
output_->write_string(utils::string::va("\"%s\"", inst->data[0].data()));
|
||||
break;
|
||||
case opcode::OP_GetAnimation:
|
||||
case opcode::OP_GetFunction:
|
||||
case opcode::OP_CallBuiltin:
|
||||
case opcode::OP_CallBuiltinMethod:
|
||||
case opcode::OP_ScriptFunctionCall:
|
||||
case opcode::OP_ScriptMethodCall:
|
||||
case opcode::OP_ScriptThreadCall:
|
||||
case opcode::OP_ScriptMethodThreadCall:
|
||||
output_->write_string(utils::string::va("\"%s\", \"%s\"", inst->data[0].data(), inst->data[1].data()));
|
||||
break;
|
||||
case opcode::OP_SafeCreateLocalVariables:
|
||||
for (const auto& data : inst->data)
|
||||
{
|
||||
output_->write_string(utils::string::va("\"%s\"%s", data.data(), &data == &inst->data.back() ? "" : ", "));
|
||||
}
|
||||
break;
|
||||
case opcode::OP_EndSwitch:
|
||||
output_->write_string(utils::string::va("%s", inst->data[0].data()));
|
||||
{
|
||||
std::uint32_t totalcase = std::stoul(inst->data[0]);
|
||||
auto numerical = inst->data.back() == "i";
|
||||
auto index = 0;
|
||||
for (auto casenum = 0u; casenum < totalcase; casenum++)
|
||||
{
|
||||
if (inst->data[1 + index] == "case")
|
||||
{
|
||||
auto fmt = numerical ? ", %s, %s, %s"s : ", %s, \"%s\", %s"s;
|
||||
output_->write_string(utils::string::va(fmt, 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(", %s, %s", inst->data[1 + index].data(), inst->data[1 + index + 1].data()));
|
||||
index += 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
for (const auto& data : inst->data)
|
||||
{
|
||||
output_->write_string(utils::string::va("%s%s", data.data(), &data == &inst->data.back() ? "" : ", "));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
output_->write_string(");\n");
|
||||
}
|
||||
|
||||
} // namespace xsk::arc::t6
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user