s4 build
This commit is contained in:
parent
564c46cdb2
commit
ee9552fa59
@ -11,12 +11,13 @@ A utility to compile & decompile IW engine game scripts.
|
||||
- **IW8** *(Call of Duty: Modern Warfare (2019))*
|
||||
- **S1** *(Call of Duty: Advanced Warfare)*
|
||||
- **S2** *(Call of Duty: WWII)*
|
||||
- **S4** *(Call of Duty: Vanguard)*
|
||||
- **H1** *(Call of Duty: Modern Warfare Remastered)*
|
||||
- **H2** *(Call of Duty: Modern Warfare 2 Campaign Remastered)*
|
||||
## Usage
|
||||
``./gsc-tool.exe <game> <mode> <file>``
|
||||
|
||||
**game**: `-iw5`, `-iw6`, `-iw7`, `-iw8`, `-s1`, `-s2`, `-h1`, `-h2`
|
||||
**game**: `-iw5`, `-iw6`, `-iw7`, `-iw8`, `-s1`, `-s2`, `-s4`, `-h1`, `-h2`
|
||||
| Mode |Description | Output |
|
||||
|:---------|:--------------------------|:------------|
|
||||
|`-asm` |assemble a `file.gscasm` |`file.gscbin`|
|
||||
|
@ -1,4 +1,4 @@
|
||||
generate: S2
|
||||
generate: IW8
|
||||
|
||||
clean:
|
||||
rm -rf ./parser.hpp
|
||||
@ -6,6 +6,6 @@ clean:
|
||||
rm -rf ./lexer.hpp
|
||||
rm -rf ./lexer.cpp
|
||||
|
||||
S2: lexer.lpp parser.ypp
|
||||
IW8: lexer.lpp parser.ypp
|
||||
flex lexer.lpp
|
||||
bison parser.ypp -Wcounterexamples
|
||||
|
11
gen/s4/Makefile
Normal file
11
gen/s4/Makefile
Normal file
@ -0,0 +1,11 @@
|
||||
generate: S4
|
||||
|
||||
clean:
|
||||
rm -rf ./parser.hpp
|
||||
rm -rf ./parser.cpp
|
||||
rm -rf ./lexer.hpp
|
||||
rm -rf ./lexer.cpp
|
||||
|
||||
S4: lexer.lpp parser.ypp
|
||||
flex lexer.lpp
|
||||
bison parser.ypp -Wcounterexamples
|
154
gen/s4/lexer.lpp
Normal file
154
gen/s4/lexer.lpp
Normal file
@ -0,0 +1,154 @@
|
||||
/* Copyright 2021 xensik. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a GNU GPLv3 license
|
||||
// that can be found in the LICENSE file.
|
||||
*/
|
||||
|
||||
%option outfile="lexer.cpp"
|
||||
%option header-file="lexer.hpp"
|
||||
%option prefix="s4_"
|
||||
%option reentrant
|
||||
%option noyywrap batch nounput noinput
|
||||
%option never-interactive
|
||||
%option nounistd
|
||||
|
||||
%top{
|
||||
#include "stdafx.hpp"
|
||||
#include "s4.hpp"
|
||||
#include "parser.hpp"
|
||||
using namespace xsk::gsc;
|
||||
}
|
||||
|
||||
%{
|
||||
#define YY_USER_ACTION loc.columns(yyleng);
|
||||
%}
|
||||
|
||||
RGX_FILE ([_A-Za-z0-9]+\\)+[_A-Za-z0-9]+
|
||||
RGX_NAME [_A-Za-z][_A-Za-z0-9]*
|
||||
RGX_STRING \"(?:\\.|[^\"])*?\"|\'(?:\\.|[^\'])*?\'
|
||||
RGX_COLOR #([0-9a-fA-F]{6}|[0-9a-fA-F]{3})
|
||||
RGX_FLT_DEC [0-9]+\.(?:[0-9]*)?f?|\.[0-9]+f?
|
||||
RGX_INT_OCT 0[1-7][0-7]*
|
||||
RGX_INT_BIN 0[bB][01]+
|
||||
RGX_INT_HEX 0[xX][0-9a-fA-F]+
|
||||
RGX_INT_DEC [0-9]+
|
||||
RGX_DEFAULT (.|\n)
|
||||
|
||||
%x COMMENT_BLOCK_STATE
|
||||
%x DEVELOPER_BLOCK_STATE
|
||||
|
||||
%%
|
||||
|
||||
%{
|
||||
loc.step();
|
||||
%}
|
||||
|
||||
[ \t\r] { loc.step(); }
|
||||
|
||||
\n { loc.lines(yyleng); loc.step(); }
|
||||
|
||||
"//".*
|
||||
|
||||
"/*" { BEGIN(COMMENT_BLOCK_STATE); }
|
||||
<COMMENT_BLOCK_STATE>.
|
||||
<COMMENT_BLOCK_STATE>\n { loc.lines(yyleng); loc.step(); }
|
||||
<COMMENT_BLOCK_STATE>"*/" { BEGIN(INITIAL); }
|
||||
|
||||
"/#" { BEGIN(DEVELOPER_BLOCK_STATE); }
|
||||
<DEVELOPER_BLOCK_STATE>.
|
||||
<DEVELOPER_BLOCK_STATE>\n { loc.lines(yyleng); loc.step(); }
|
||||
<DEVELOPER_BLOCK_STATE>"#/" { BEGIN(INITIAL); }
|
||||
|
||||
"#include" { return s4::parser::make_INCLUDE(loc); }
|
||||
"#using_animtree" { return s4::parser::make_USINGTREE(loc); }
|
||||
"#animtree" { return s4::parser::make_ANIMTREE(loc); }
|
||||
"endon" { return s4::parser::make_ENDON(loc); }
|
||||
"notify" { return s4::parser::make_NOTIFY(loc); }
|
||||
"wait" { return s4::parser::make_WAIT(loc); }
|
||||
"waittill" { return s4::parser::make_WAITTILL(loc); }
|
||||
"waittillmatch" { return s4::parser::make_WAITTILLMATCH(loc); }
|
||||
"waittillframeend" { return s4::parser::make_WAITTILLFRAMEEND(loc); }
|
||||
"waitframe" { return s4::parser::make_WAITFRAME(loc); }
|
||||
"if" { return s4::parser::make_IF(loc); }
|
||||
"else" { return s4::parser::make_ELSE(loc); }
|
||||
"while" { return s4::parser::make_WHILE(loc); }
|
||||
"for" { return s4::parser::make_FOR(loc); }
|
||||
"foreach" { return s4::parser::make_FOREACH(loc); }
|
||||
"in" { return s4::parser::make_IN(loc); }
|
||||
"switch" { return s4::parser::make_SWITCH(loc); }
|
||||
"case" { return s4::parser::make_CASE(loc); }
|
||||
"default" { return s4::parser::make_DEFAULT(loc); }
|
||||
"break" { return s4::parser::make_BREAK(loc); }
|
||||
"continue" { return s4::parser::make_CONTINUE(loc); }
|
||||
"return" { return s4::parser::make_RETURN(loc); }
|
||||
"thread" { return s4::parser::make_THREAD(loc); }
|
||||
"childthread" { return s4::parser::make_CHILDTHREAD(loc); }
|
||||
"thisthread" { return s4::parser::make_THISTHREAD(loc); }
|
||||
"call" { return s4::parser::make_CALL(loc); }
|
||||
"true" { return s4::parser::make_TRUE(loc); }
|
||||
"false" { return s4::parser::make_FALSE(loc); }
|
||||
"undefined" { return s4::parser::make_UNDEFINED(loc); }
|
||||
"size" { return s4::parser::make_SIZE(loc); }
|
||||
"game" { return s4::parser::make_GAME(loc); }
|
||||
"self" { return s4::parser::make_SELF(loc); }
|
||||
"anim" { return s4::parser::make_ANIM(loc); }
|
||||
"level" { return s4::parser::make_LEVEL(loc); }
|
||||
\( { return s4::parser::make_LPAREN(loc); }
|
||||
\) { return s4::parser::make_RPAREN(loc); }
|
||||
\{ { return s4::parser::make_LBRACE(loc); }
|
||||
\} { return s4::parser::make_RBRACE(loc); }
|
||||
\[ { return s4::parser::make_LBRACKET(loc); }
|
||||
\] { return s4::parser::make_RBRACKET(loc); }
|
||||
\, { return s4::parser::make_COMMA(loc); }
|
||||
\. { return s4::parser::make_DOT(loc); }
|
||||
\:\: { return s4::parser::make_DOUBLECOLON(loc); }
|
||||
\: { return s4::parser::make_COLON(loc); }
|
||||
\; { return s4::parser::make_SEMICOLON(loc); }
|
||||
\? { return s4::parser::make_QMARK(loc); }
|
||||
\+\+ { return s4::parser::make_INCREMENT(loc); }
|
||||
\-\- { return s4::parser::make_DECREMENT(loc); }
|
||||
\<\<\= { return s4::parser::make_ASSIGN_LSHIFT(loc); }
|
||||
\>\>\= { return s4::parser::make_ASSIGN_RSHIFT(loc); }
|
||||
\<\< { return s4::parser::make_LSHIFT(loc); }
|
||||
\>\> { return s4::parser::make_RSHIFT(loc); }
|
||||
\|\| { return s4::parser::make_OR(loc); }
|
||||
\&\& { return s4::parser::make_AND(loc); }
|
||||
\=\= { return s4::parser::make_EQUALITY(loc); }
|
||||
\!\= { return s4::parser::make_INEQUALITY(loc); }
|
||||
\<\= { return s4::parser::make_LESS_EQUAL(loc); }
|
||||
\>\= { return s4::parser::make_GREATER_EQUAL(loc); }
|
||||
\< { return s4::parser::make_LESS(loc); }
|
||||
\> { return s4::parser::make_GREATER(loc); }
|
||||
\+\= { return s4::parser::make_ASSIGN_ADD(loc); }
|
||||
\-\= { return s4::parser::make_ASSIGN_SUB(loc); }
|
||||
\*\= { return s4::parser::make_ASSIGN_MULT(loc); }
|
||||
\/\= { return s4::parser::make_ASSIGN_DIV(loc); }
|
||||
\%\= { return s4::parser::make_ASSIGN_MOD(loc); }
|
||||
\|\= { return s4::parser::make_ASSIGN_BITWISE_OR(loc); }
|
||||
\&\= { return s4::parser::make_ASSIGN_BITWISE_AND(loc); }
|
||||
\^\= { return s4::parser::make_ASSIGN_BITWISE_EXOR(loc); }
|
||||
\= { return s4::parser::make_ASSIGN(loc); }
|
||||
\+ { return s4::parser::make_ADD(loc); }
|
||||
\- { return s4::parser::make_SUB(loc); }
|
||||
\* { return s4::parser::make_MULT(loc); }
|
||||
\/ { return s4::parser::make_DIV(loc); }
|
||||
\% { return s4::parser::make_MOD(loc); }
|
||||
\! { return s4::parser::make_NOT(loc); }
|
||||
\~ { return s4::parser::make_COMPLEMENT(loc); }
|
||||
\| { return s4::parser::make_BITWISE_OR(loc); }
|
||||
\& { return s4::parser::make_BITWISE_AND(loc); }
|
||||
\^ { return s4::parser::make_BITWISE_EXOR(loc); }
|
||||
{RGX_FILE} { return s4::parser::make_FILE(utils::string::fordslash(yytext), loc); }
|
||||
{RGX_NAME} { return s4::parser::make_NAME((std::string(yytext, 3) == "_ID") ? std::string(yytext) : utils::string::to_lower(yytext), loc); }
|
||||
\&{RGX_STRING} { return s4::parser::make_ISTRING(std::string(yytext).substr(1), loc); }
|
||||
{RGX_STRING} { return s4::parser::make_STRING(std::string(yytext), loc); }
|
||||
{RGX_COLOR} { return s4::parser::make_COLOR(std::string(yytext).substr(1), loc); }
|
||||
{RGX_FLT_DEC} { return s4::parser::make_FLOAT(std::string(yytext), loc); }
|
||||
{RGX_INT_OCT} { return s4::parser::make_INT_OCT(utils::string::oct_to_dec(yytext), loc); }
|
||||
{RGX_INT_BIN} { return s4::parser::make_INT_BIN(utils::string::bin_to_dec(yytext), loc); }
|
||||
{RGX_INT_HEX} { return s4::parser::make_INT_HEX(utils::string::hex_to_dec(yytext), loc); }
|
||||
{RGX_INT_DEC} { return s4::parser::make_INT_DEC(std::string(yytext), loc); }
|
||||
<<EOF>> { return s4::parser::make_S4EOF(loc); }
|
||||
<*>{RGX_DEFAULT} { throw s4::parser::syntax_error(loc, "bad token: \'" + std::string(yytext) + "\'"); }
|
||||
|
||||
%%
|
663
gen/s4/parser.ypp
Normal file
663
gen/s4/parser.ypp
Normal file
@ -0,0 +1,663 @@
|
||||
/* Copyright 2021 xensik. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a GNU GPLv3 license
|
||||
// that can be found in the LICENSE file.
|
||||
*/
|
||||
|
||||
%require "3.7"
|
||||
%skeleton "lalr1.cc"
|
||||
%language "c++"
|
||||
%output "parser.cpp"
|
||||
%defines "parser.hpp"
|
||||
%define api.prefix {S4}
|
||||
%define api.namespace {xsk::gsc::s4}
|
||||
%define api.location.type {xsk::gsc::location}
|
||||
%define api.value.type variant
|
||||
%define api.token.constructor
|
||||
%define api.token.raw
|
||||
%define parse.assert
|
||||
%define parse.trace
|
||||
%define parse.error detailed
|
||||
%define parse.lac full
|
||||
|
||||
%locations
|
||||
|
||||
%lex-param { yyscan_t yyscanner }
|
||||
%lex-param { xsk::gsc::location& loc }
|
||||
|
||||
%parse-param { yyscan_t yyscanner }
|
||||
%parse-param { xsk::gsc::location& loc }
|
||||
%parse-param { xsk::gsc::program_ptr& ast }
|
||||
|
||||
%code requires
|
||||
{
|
||||
#include "s4.hpp"
|
||||
typedef void *yyscan_t;
|
||||
#define YY_DECL xsk::gsc::s4::parser::symbol_type S4lex(yyscan_t yyscanner, xsk::gsc::location& loc)
|
||||
}
|
||||
|
||||
%code top
|
||||
{
|
||||
#include "stdafx.hpp"
|
||||
#include "parser.hpp"
|
||||
#include "lexer.hpp"
|
||||
using namespace xsk::gsc;
|
||||
xsk::gsc::s4::parser::symbol_type S4lex(yyscan_t yyscanner, xsk::gsc::location& loc);
|
||||
}
|
||||
|
||||
%token INCLUDE "#include"
|
||||
%token USINGTREE "#using_animtree"
|
||||
%token ANIMTREE "#animtree"
|
||||
%token ENDON "endon"
|
||||
%token NOTIFY "notify"
|
||||
%token WAIT "wait"
|
||||
%token WAITTILL "waittill"
|
||||
%token WAITTILLMATCH "waittillmatch"
|
||||
%token WAITTILLFRAMEEND "waittillframeend"
|
||||
%token WAITFRAME "waitframe"
|
||||
%token IF "if"
|
||||
%token ELSE "else"
|
||||
%token WHILE "while"
|
||||
%token FOR "for"
|
||||
%token FOREACH "foreach"
|
||||
%token IN "in"
|
||||
%token SWITCH "switch"
|
||||
%token CASE "case"
|
||||
%token DEFAULT "default"
|
||||
%token BREAK "break"
|
||||
%token CONTINUE "continue"
|
||||
%token RETURN "return"
|
||||
%token THREAD "thread"
|
||||
%token CHILDTHREAD "childthread"
|
||||
%token THISTHREAD "thisthread"
|
||||
%token CALL "call"
|
||||
%token TRUE "true"
|
||||
%token FALSE "false"
|
||||
%token UNDEFINED "undefined"
|
||||
%token SIZE "size"
|
||||
%token GAME "game"
|
||||
%token SELF "self"
|
||||
%token ANIM "anim"
|
||||
%token LEVEL "level"
|
||||
%token LPAREN "("
|
||||
%token RPAREN ")"
|
||||
%token LBRACE "{"
|
||||
%token RBRACE "}"
|
||||
%token LBRACKET "["
|
||||
%token RBRACKET "]"
|
||||
%token COMMA ","
|
||||
%token DOT "."
|
||||
%token DOUBLECOLON "::"
|
||||
%token COLON ":"
|
||||
%token SEMICOLON ";"
|
||||
%token QMARK "?"
|
||||
%token INCREMENT "++"
|
||||
%token DECREMENT "--"
|
||||
%token LSHIFT "<<"
|
||||
%token RSHIFT ">>"
|
||||
%token OR "||"
|
||||
%token AND "&&"
|
||||
%token EQUALITY "=="
|
||||
%token INEQUALITY "!="
|
||||
%token LESS_EQUAL "<="
|
||||
%token GREATER_EQUAL ">="
|
||||
%token LESS "<"
|
||||
%token GREATER ">"
|
||||
%token NOT "!"
|
||||
%token COMPLEMENT "~"
|
||||
%token ASSIGN "="
|
||||
%token ASSIGN_ADD "+="
|
||||
%token ASSIGN_SUB "-="
|
||||
%token ASSIGN_MULT "*="
|
||||
%token ASSIGN_DIV "/="
|
||||
%token ASSIGN_MOD "%="
|
||||
%token ASSIGN_BITWISE_OR "|="
|
||||
%token ASSIGN_BITWISE_AND "&="
|
||||
%token ASSIGN_BITWISE_EXOR "^="
|
||||
%token ASSIGN_RSHIFT ">>="
|
||||
%token ASSIGN_LSHIFT "<<="
|
||||
%token BITWISE_OR "|"
|
||||
%token BITWISE_AND "&"
|
||||
%token BITWISE_EXOR "^"
|
||||
%token ADD "+"
|
||||
%token SUB "-"
|
||||
%token MULT "*"
|
||||
%token DIV "/"
|
||||
%token MOD "%"
|
||||
%token <std::string> FILE "file path"
|
||||
%token <std::string> NAME "identifier"
|
||||
%token <std::string> STRING "string literal"
|
||||
%token <std::string> ISTRING "localized string"
|
||||
%token <std::string> COLOR "color"
|
||||
%token <std::string> FLOAT "float"
|
||||
%token <std::string> INT_DEC "int"
|
||||
%token <std::string> INT_OCT "octal int"
|
||||
%token <std::string> INT_BIN "binary int"
|
||||
%token <std::string> INT_HEX "hexadecimal int"
|
||||
|
||||
%type <program_ptr> program
|
||||
%type <include_ptr> include
|
||||
%type <define_ptr> define
|
||||
%type <usingtree_ptr> usingtree
|
||||
%type <constant_ptr> constant
|
||||
%type <thread_ptr> thread
|
||||
%type <parameters_ptr> parameters
|
||||
%type <stmt_ptr> stmt
|
||||
%type <stmt_list_ptr> stmt_block
|
||||
%type <stmt_list_ptr> stmt_list
|
||||
%type <stmt_call_ptr> stmt_call
|
||||
%type <stmt_assign_ptr> stmt_assign
|
||||
%type <stmt_endon_ptr> stmt_endon
|
||||
%type <stmt_notify_ptr> stmt_notify
|
||||
%type <stmt_wait_ptr> stmt_wait
|
||||
%type <stmt_waittill_ptr> stmt_waittill
|
||||
%type <stmt_waittillmatch_ptr> stmt_waittillmatch
|
||||
%type <stmt_waittillframeend_ptr> stmt_waittillframeend
|
||||
%type <stmt_waitframe_ptr> stmt_waitframe
|
||||
%type <stmt_if_ptr> stmt_if
|
||||
%type <stmt_ifelse_ptr> stmt_ifelse
|
||||
%type <stmt_while_ptr> stmt_while
|
||||
%type <stmt_for_ptr> stmt_for
|
||||
%type <stmt_foreach_ptr> stmt_foreach
|
||||
%type <stmt_switch_ptr> stmt_switch
|
||||
%type <stmt_case_ptr> stmt_case
|
||||
%type <stmt_default_ptr> stmt_default
|
||||
%type <stmt_break_ptr> stmt_break
|
||||
%type <stmt_continue_ptr> stmt_continue
|
||||
%type <stmt_return_ptr> stmt_return
|
||||
%type <stmt_ptr> for_stmt
|
||||
%type <expr_ptr> for_expr
|
||||
%type <expr_assign_ptr> expr_assign
|
||||
%type <expr_ptr> expr
|
||||
%type <expr_ptr> expr_compare
|
||||
%type <expr_ptr> expr_ternary
|
||||
%type <expr_ptr> expr_binary
|
||||
%type <expr_ptr> expr_primitive
|
||||
%type <expr_call_ptr> expr_call
|
||||
%type <expr_call_ptr> expr_call_thread
|
||||
%type <expr_call_ptr> expr_call_childthread
|
||||
%type <expr_call_type_ptr> expr_call_function
|
||||
%type <expr_call_type_ptr> expr_call_pointer
|
||||
%type <expr_arguments_ptr> expr_arguments
|
||||
%type <expr_arguments_ptr> expr_arguments_filled
|
||||
%type <expr_arguments_ptr> expr_arguments_empty
|
||||
%type <node_ptr> expr_function
|
||||
%type <node_ptr> expr_add_array
|
||||
%type <node_ptr> expr_array
|
||||
%type <node_ptr> expr_field
|
||||
%type <node_ptr> expr_size
|
||||
%type <node_ptr> object
|
||||
%type <thisthread_ptr> thisthread
|
||||
%type <empty_array_ptr> empty_array
|
||||
%type <undefined_ptr> undefined
|
||||
%type <game_ptr> game
|
||||
%type <self_ptr> self
|
||||
%type <anim_ptr> anim
|
||||
%type <level_ptr> level
|
||||
%type <animation_ptr> animation
|
||||
%type <animtree_ptr> animtree
|
||||
%type <name_ptr> name
|
||||
%type <file_ptr> file
|
||||
%type <istring_ptr> istring
|
||||
%type <string_ptr> string
|
||||
%type <color_ptr> color
|
||||
%type <vector_ptr> vector
|
||||
%type <float_ptr> float
|
||||
%type <integer_ptr> integer
|
||||
%type <false_ptr> false
|
||||
%type <true_ptr> true
|
||||
|
||||
%nonassoc ADD_ARRAY
|
||||
%nonassoc RBRACKET
|
||||
%nonassoc THEN
|
||||
%nonassoc ELSE
|
||||
%nonassoc INCREMENT DECREMENT
|
||||
|
||||
%precedence TERN
|
||||
%right QMARK
|
||||
%left OR
|
||||
%left AND
|
||||
%left BITWISE_OR
|
||||
%left BITWISE_AND
|
||||
%left BITWISE_EXOR
|
||||
%left EQUALITY INEQUALITY
|
||||
%left LESS GREATER LESS_EQUAL GREATER_EQUAL
|
||||
%left LSHIFT RSHIFT
|
||||
%left ADD SUB
|
||||
%left MULT DIV MOD
|
||||
%right NOT COMPLEMENT
|
||||
|
||||
%precedence NEG
|
||||
%precedence ANIMREF
|
||||
%precedence PREINC PREDEC
|
||||
%precedence POSTINC POSTDEC
|
||||
|
||||
%start root
|
||||
|
||||
%%
|
||||
|
||||
root
|
||||
: program { ast = std::move($1); }
|
||||
| { ast = std::make_unique<node_program>(@$); }
|
||||
;
|
||||
|
||||
program
|
||||
: program include
|
||||
{ $$ = std::move($1); $$->includes.push_back(std::move($2)); }
|
||||
| program define
|
||||
{ $$ = std::move($1); $$->definitions.push_back(std::move($2)); }
|
||||
| include
|
||||
{ $$ = std::make_unique<node_program>(@$); $$->includes.push_back(std::move($1)); }
|
||||
| define
|
||||
{ $$ = std::make_unique<node_program>(@$); $$->definitions.push_back(std::move($1)); }
|
||||
;
|
||||
|
||||
include
|
||||
: INCLUDE file SEMICOLON
|
||||
{ $$ = std::make_unique<node_include>(@$, std::move($2)); }
|
||||
;
|
||||
|
||||
define
|
||||
: usingtree { $$.as_usingtree = std::move($1); }
|
||||
| constant { $$.as_constant = std::move($1); }
|
||||
| thread { $$.as_thread = std::move($1); }
|
||||
;
|
||||
|
||||
usingtree
|
||||
: USINGTREE LPAREN string RPAREN SEMICOLON
|
||||
{ $$ = std::make_unique<node_usingtree>(@$, std::move($3)); }
|
||||
;
|
||||
|
||||
constant
|
||||
: name ASSIGN expr SEMICOLON
|
||||
{ $$ = std::make_unique<node_constant>(@$, std::move($1), std::move($3)); }
|
||||
;
|
||||
|
||||
thread
|
||||
: name LPAREN parameters RPAREN stmt_block
|
||||
{ $$ = std::make_unique<node_thread>(@$, std::move($1), std::move($3), std::move($5)); }
|
||||
;
|
||||
|
||||
parameters
|
||||
: parameters COMMA name
|
||||
{ $$ = std::move($1); $$->list.push_back(std::move($3)); }
|
||||
| name
|
||||
{ $$ = std::make_unique<node_parameters>(@$); $$->list.push_back(std::move($1)); }
|
||||
|
|
||||
{ $$ = std::make_unique<node_parameters>(@$); }
|
||||
;
|
||||
|
||||
stmt
|
||||
: stmt_block { $$.as_list = std::move($1); }
|
||||
| stmt_call { $$.as_call = std::move($1); }
|
||||
| stmt_assign { $$.as_assign = std::move($1); }
|
||||
| stmt_endon { $$.as_endon = std::move($1); }
|
||||
| stmt_notify { $$.as_notify = std::move($1); }
|
||||
| stmt_wait { $$.as_wait = std::move($1); }
|
||||
| stmt_waittill { $$.as_waittill = std::move($1); }
|
||||
| stmt_waittillmatch { $$.as_waittillmatch = std::move($1); }
|
||||
| stmt_waittillframeend { $$.as_waittillframeend = std::move($1); }
|
||||
| stmt_waitframe { $$.as_waitframe = std::move($1); }
|
||||
| stmt_if { $$.as_if = std::move($1); }
|
||||
| stmt_ifelse { $$.as_ifelse = std::move($1); }
|
||||
| stmt_while { $$.as_while = std::move($1); }
|
||||
| stmt_for { $$.as_for = std::move($1); }
|
||||
| stmt_foreach { $$.as_foreach = std::move($1); }
|
||||
| stmt_switch { $$.as_switch = std::move($1); }
|
||||
| stmt_case { $$.as_case = std::move($1); }
|
||||
| stmt_default { $$.as_default = std::move($1); }
|
||||
| stmt_break { $$.as_break = std::move($1); }
|
||||
| stmt_continue { $$.as_continue = std::move($1); }
|
||||
| stmt_return { $$.as_return = std::move($1); }
|
||||
;
|
||||
|
||||
stmt_block
|
||||
: LBRACE stmt_list RBRACE { $$ = std::move($2); }
|
||||
| LBRACE RBRACE { $$ = std::make_unique<node_stmt_list>(@$); }
|
||||
;
|
||||
|
||||
stmt_list
|
||||
: stmt_list stmt
|
||||
{ $$ = std::move($1); $$->stmts.push_back(std::move($2)); }
|
||||
| stmt
|
||||
{ $$ = std::make_unique<node_stmt_list>(@$); $$->stmts.push_back(std::move($1)); }
|
||||
;
|
||||
|
||||
stmt_call
|
||||
: expr_call SEMICOLON
|
||||
{ $$ = std::make_unique<node_stmt_call>(@$, std::move($1)); }
|
||||
| expr_call_thread SEMICOLON
|
||||
{ $$ = std::make_unique<node_stmt_call>(@$, std::move($1)); }
|
||||
;
|
||||
|
||||
stmt_assign
|
||||
: expr_assign SEMICOLON
|
||||
{ $$ = std::make_unique<node_stmt_assign>(@$, std::move($1)); }
|
||||
;
|
||||
|
||||
stmt_endon
|
||||
: object ENDON LPAREN expr RPAREN SEMICOLON
|
||||
{ $$ = std::make_unique<node_stmt_endon>(@$, std::move($1), std::move($4)); }
|
||||
;
|
||||
|
||||
stmt_notify
|
||||
: object NOTIFY LPAREN expr COMMA expr_arguments RPAREN SEMICOLON
|
||||
{ $$ = std::make_unique<node_stmt_notify>(@$, std::move($1), std::move($4), std::move($6)); }
|
||||
| object NOTIFY LPAREN expr RPAREN SEMICOLON
|
||||
{ $$ = std::make_unique<node_stmt_notify>(@$, std::move($1), std::move($4), std::make_unique<node_expr_arguments>(@$)); }
|
||||
;
|
||||
|
||||
stmt_wait
|
||||
: WAIT expr SEMICOLON
|
||||
{ $$ = std::make_unique<node_stmt_wait>(@$, std::move($2)); }
|
||||
;
|
||||
|
||||
stmt_waittill
|
||||
: object WAITTILL LPAREN expr COMMA expr_arguments RPAREN SEMICOLON
|
||||
{ $$ = std::make_unique<node_stmt_waittill>(@$, std::move($1), std::move($4), std::move($6)); }
|
||||
| object WAITTILL LPAREN expr RPAREN SEMICOLON
|
||||
{ $$ = std::make_unique<node_stmt_waittill>(@$, std::move($1), std::move($4), std::make_unique<node_expr_arguments>(@$)); }
|
||||
;
|
||||
|
||||
stmt_waittillmatch
|
||||
: object WAITTILLMATCH LPAREN expr COMMA expr_arguments RPAREN SEMICOLON
|
||||
{ $$ = std::make_unique<node_stmt_waittillmatch>(@$, std::move($1), std::move($4), std::move($6)); }
|
||||
| object WAITTILLMATCH LPAREN expr RPAREN SEMICOLON
|
||||
{ $$ = std::make_unique<node_stmt_waittillmatch>(@$, std::move($1), std::move($4), std::make_unique<node_expr_arguments>(@$)); }
|
||||
;
|
||||
|
||||
stmt_waittillframeend
|
||||
: WAITTILLFRAMEEND SEMICOLON
|
||||
{ $$ = std::make_unique<node_stmt_waittillframeend>(@$); }
|
||||
;
|
||||
|
||||
stmt_waitframe
|
||||
: WAITFRAME SEMICOLON
|
||||
{ $$ = std::make_unique<node_stmt_waitframe>(@$); }
|
||||
| WAITFRAME LPAREN RPAREN SEMICOLON
|
||||
{ $$ = std::make_unique<node_stmt_waitframe>(@$); }
|
||||
;
|
||||
|
||||
stmt_if
|
||||
: IF LPAREN expr RPAREN stmt %prec THEN
|
||||
{ $$ = std::make_unique<node_stmt_if>(@$, std::move($3), std::move($5)); }
|
||||
;
|
||||
|
||||
stmt_ifelse
|
||||
: IF LPAREN expr RPAREN stmt ELSE stmt
|
||||
{ $$ = std::make_unique<node_stmt_ifelse>(@$, std::move($3), std::move($5), std::move($7)); }
|
||||
;
|
||||
|
||||
stmt_while
|
||||
: WHILE LPAREN expr RPAREN stmt
|
||||
{ $$ = std::make_unique<node_stmt_while>(@$, std::move($3), std::move($5)); }
|
||||
;
|
||||
|
||||
stmt_for
|
||||
: FOR LPAREN for_stmt SEMICOLON for_expr SEMICOLON for_stmt RPAREN stmt
|
||||
{ $$ = std::make_unique<node_stmt_for>(@$, std::move($3), std::move($5), std::move($7), std::move($9)); }
|
||||
;
|
||||
|
||||
stmt_foreach
|
||||
: FOREACH LPAREN name IN expr RPAREN stmt
|
||||
{ $$ = std::make_unique<node_stmt_foreach>(@$, expr_ptr(std::move($3)), std::move($5), std::move($7)); }
|
||||
| FOREACH LPAREN name COMMA name IN expr RPAREN stmt
|
||||
{ $$ = std::make_unique<node_stmt_foreach>(@$, expr_ptr(std::move($3)), expr_ptr(std::move($5)), std::move($7), std::move($9)); }
|
||||
;
|
||||
|
||||
stmt_switch
|
||||
: SWITCH LPAREN expr RPAREN stmt_block
|
||||
{ $$ = std::make_unique<node_stmt_switch>(@$, std::move($3), std::move($5)); }
|
||||
;
|
||||
|
||||
stmt_case
|
||||
: CASE integer COLON
|
||||
{ $$ = std::make_unique<node_stmt_case>(@$, expr_ptr(std::move($2)), std::make_unique<gsc::node_stmt_list>(@$)); }
|
||||
| CASE string COLON
|
||||
{ $$ = std::make_unique<node_stmt_case>(@$, expr_ptr(std::move($2)), std::make_unique<gsc::node_stmt_list>(@$)); }
|
||||
;
|
||||
|
||||
stmt_default
|
||||
: DEFAULT COLON
|
||||
{ $$ = std::make_unique<node_stmt_default>(@$, std::make_unique<gsc::node_stmt_list>(@$)); }
|
||||
;
|
||||
|
||||
stmt_break
|
||||
: BREAK SEMICOLON
|
||||
{ $$ = std::make_unique<node_stmt_break>(@$); }
|
||||
;
|
||||
|
||||
stmt_continue
|
||||
: CONTINUE SEMICOLON
|
||||
{ $$ = std::make_unique<node_stmt_continue>(@$); }
|
||||
;
|
||||
|
||||
stmt_return
|
||||
: RETURN expr SEMICOLON
|
||||
{ $$ = std::make_unique<node_stmt_return>(@$, std::move($2)); }
|
||||
| RETURN SEMICOLON
|
||||
{ $$ = std::make_unique<node_stmt_return>(@$, std::make_unique<node>(@$)); }
|
||||
;
|
||||
|
||||
for_stmt
|
||||
: expr_assign { $$.as_list = std::make_unique<node_stmt_list>(@$); $$.as_list->stmts.push_back(stmt_ptr(std::make_unique<node_stmt_assign>(@$, std::move($1)))); }
|
||||
| { $$.as_node = std::make_unique<node>(@$); }
|
||||
;
|
||||
|
||||
for_expr
|
||||
: expr { $$ = std::move($1); }
|
||||
| { $$.as_node = std::make_unique<node>(@$); }
|
||||
;
|
||||
|
||||
expr
|
||||
: expr_compare { $$ = std::move($1); }
|
||||
| expr_ternary { $$ = std::move($1); }
|
||||
| expr_binary { $$ = std::move($1); }
|
||||
| expr_primitive { $$ = std::move($1); }
|
||||
;
|
||||
|
||||
expr_assign
|
||||
: INCREMENT object %prec PREINC { $$ = std::make_unique<node_expr_increment>(@$, std::move($2)); }
|
||||
| DECREMENT object %prec PREDEC { $$ = std::make_unique<node_expr_decrement>(@$, std::move($2)); }
|
||||
| object INCREMENT %prec POSTINC { $$ = std::make_unique<node_expr_increment>(@$, std::move($1)); }
|
||||
| object DECREMENT %prec POSTDEC { $$ = std::make_unique<node_expr_decrement>(@$, std::move($1)); }
|
||||
| object ASSIGN expr { $$ = std::make_unique<node_expr_assign_equal>(@$, std::move($1), std::move($3)); }
|
||||
| object ASSIGN_BITWISE_OR expr { $$ = std::make_unique<node_expr_assign_bitwise_or>(@$, std::move($1), std::move($3)); }
|
||||
| object ASSIGN_BITWISE_AND expr { $$ = std::make_unique<node_expr_assign_bitwise_and>(@$, std::move($1), std::move($3)); }
|
||||
| object ASSIGN_BITWISE_EXOR expr { $$ = std::make_unique<node_expr_assign_bitwise_exor>(@$, std::move($1), std::move($3)); }
|
||||
| object ASSIGN_LSHIFT expr { $$ = std::make_unique<node_expr_assign_shift_left>(@$, std::move($1),std::move( $3)); }
|
||||
| object ASSIGN_RSHIFT expr { $$ = std::make_unique<node_expr_assign_shift_right>(@$, std::move($1), std::move($3)); }
|
||||
| object ASSIGN_ADD expr { $$ = std::make_unique<node_expr_assign_add>(@$, std::move($1), std::move($3)); }
|
||||
| object ASSIGN_SUB expr { $$ = std::make_unique<node_expr_assign_sub>(@$, std::move($1), std::move($3)); }
|
||||
| object ASSIGN_MULT expr { $$ = std::make_unique<node_expr_assign_mult>(@$, std::move($1), std::move($3)); }
|
||||
| object ASSIGN_DIV expr { $$ = std::make_unique<node_expr_assign_div>(@$, std::move($1), std::move($3)); }
|
||||
| object ASSIGN_MOD expr { $$ = std::make_unique<node_expr_assign_mod>(@$, std::move($1), std::move($3)); }
|
||||
;
|
||||
|
||||
expr_compare
|
||||
: expr OR expr { $$.as_node = std::make_unique<node_expr_or>(@$, std::move($1), std::move($3)); }
|
||||
| expr AND expr { $$.as_node = std::make_unique<node_expr_and>(@$, std::move($1), std::move($3)); }
|
||||
| expr EQUALITY expr { $$.as_node = std::make_unique<node_expr_equality>(@$, std::move($1), std::move($3)); }
|
||||
| expr INEQUALITY expr { $$.as_node = std::make_unique<node_expr_inequality>(@$, std::move($1), std::move($3)); }
|
||||
| expr LESS_EQUAL expr { $$.as_node = std::make_unique<node_expr_less_equal>(@$, std::move($1), std::move($3)); }
|
||||
| expr GREATER_EQUAL expr { $$.as_node = std::make_unique<node_expr_greater_equal>(@$, std::move($1), std::move($3)); }
|
||||
| expr LESS expr { $$.as_node = std::make_unique<node_expr_less>(@$, std::move($1), std::move($3)); }
|
||||
| expr GREATER expr { $$.as_node = std::make_unique<node_expr_greater>(@$, std::move($1), std::move($3)); }
|
||||
;
|
||||
|
||||
expr_ternary
|
||||
: expr QMARK expr COLON expr %prec TERN { $$.as_node = std::make_unique<node_expr_ternary>(@$, std::move($1), std::move($3), std::move($5)); }
|
||||
;
|
||||
|
||||
expr_binary
|
||||
: expr BITWISE_OR expr { $$.as_node = std::make_unique<node_expr_bitwise_or>(@$, std::move($1), std::move($3)); }
|
||||
| expr BITWISE_AND expr { $$.as_node = std::make_unique<node_expr_bitwise_and>(@$, std::move($1), std::move($3)); }
|
||||
| expr BITWISE_EXOR expr { $$.as_node = std::make_unique<node_expr_bitwise_exor>(@$, std::move($1), std::move($3)); }
|
||||
| expr LSHIFT expr { $$.as_node = std::make_unique<node_expr_shift_left>(@$, std::move($1), std::move($3)); }
|
||||
| expr RSHIFT expr { $$.as_node = std::make_unique<node_expr_shift_right>(@$, std::move($1), std::move($3)); }
|
||||
| expr ADD expr { $$.as_node = std::make_unique<node_expr_add>(@$, std::move($1), std::move($3)); }
|
||||
| expr SUB expr { $$.as_node = std::make_unique<node_expr_sub>(@$, std::move($1), std::move($3)); }
|
||||
| expr MULT expr { $$.as_node = std::make_unique<node_expr_mult>(@$, std::move($1), std::move($3)); }
|
||||
| expr DIV expr { $$.as_node = std::make_unique<node_expr_div>(@$, std::move($1), std::move($3)); }
|
||||
| expr MOD expr { $$.as_node = std::make_unique<node_expr_mod>(@$, std::move($1), std::move($3)); }
|
||||
;
|
||||
|
||||
expr_primitive
|
||||
: LPAREN expr RPAREN { $$ = std::move($2); }
|
||||
| COMPLEMENT expr { $$.as_node = std::make_unique<node_expr_complement>(@$, std::move($2)); }
|
||||
| NOT expr { $$.as_node = std::make_unique<node_expr_not>(@$, std::move($2)); }
|
||||
| expr_call { $$.as_node = std::move($1); }
|
||||
| expr_call_thread { $$.as_node = std::move($1); }
|
||||
| expr_call_childthread { $$.as_node = std::move($1); }
|
||||
| expr_function { $$.as_node = std::move($1); }
|
||||
| expr_add_array { $$.as_node = std::move($1); }
|
||||
| expr_array { $$.as_node = std::move($1); }
|
||||
| expr_field { $$.as_node = std::move($1); }
|
||||
| expr_size { $$.as_node = std::move($1); }
|
||||
| thisthread { $$.as_node = std::move($1); }
|
||||
| empty_array { $$.as_node = std::move($1); }
|
||||
| undefined { $$.as_node = std::move($1); }
|
||||
| game { $$.as_node = std::move($1); }
|
||||
| self { $$.as_node = std::move($1); }
|
||||
| anim { $$.as_node = std::move($1); }
|
||||
| level { $$.as_node = std::move($1); }
|
||||
| animation { $$.as_node = std::move($1); }
|
||||
| animtree { $$.as_node = std::move($1); }
|
||||
| name { $$.as_node = std::move($1); }
|
||||
| istring { $$.as_node = std::move($1); }
|
||||
| string { $$.as_node = std::move($1); }
|
||||
| color { $$.as_node = std::move($1); }
|
||||
| vector { $$.as_node = std::move($1); }
|
||||
| float { $$.as_node = std::move($1); }
|
||||
| integer { $$.as_node = std::move($1); }
|
||||
| false { $$.as_node = std::move($1); }
|
||||
| true { $$.as_node = std::move($1); }
|
||||
;
|
||||
|
||||
expr_call
|
||||
: expr_call_function { $$ = std::make_unique<node_expr_call>(@$, false, false, std::make_unique<node>(@$), std::move($1)); }
|
||||
| expr_call_pointer { $$ = std::make_unique<node_expr_call>(@$, false, false, std::make_unique<node>(@$), std::move($1)); }
|
||||
| object expr_call_function { $$ = std::make_unique<node_expr_call>(@$, false, false, std::move($1), std::move($2)); }
|
||||
| object expr_call_pointer { $$ = std::make_unique<node_expr_call>(@$, false, false, std::move($1), std::move($2)); }
|
||||
;
|
||||
|
||||
expr_call_thread
|
||||
: THREAD expr_call_function { $$ = std::make_unique<node_expr_call>(@$, true, false, std::make_unique<node>(@$), std::move($2)); }
|
||||
| THREAD expr_call_pointer { $$ = std::make_unique<node_expr_call>(@$, true, false, std::make_unique<node>(@$), std::move($2)); }
|
||||
| object THREAD expr_call_function { $$ = std::make_unique<node_expr_call>(@$, true, false, std::move($1), std::move($3)); }
|
||||
| object THREAD expr_call_pointer { $$ = std::make_unique<node_expr_call>(@$, true, false, std::move($1), std::move($3)); }
|
||||
;
|
||||
|
||||
expr_call_childthread
|
||||
: CHILDTHREAD expr_call_function { $$ = std::make_unique<node_expr_call>(@$, false, true, std::make_unique<node>(@$), std::move($2)); }
|
||||
| CHILDTHREAD expr_call_pointer { $$ = std::make_unique<node_expr_call>(@$, false, true, std::make_unique<node>(@$), std::move($2)); }
|
||||
| object CHILDTHREAD expr_call_function { $$ = std::make_unique<node_expr_call>(@$, false, true, std::move($1), std::move($3)); }
|
||||
| object CHILDTHREAD expr_call_pointer { $$ = std::make_unique<node_expr_call>(@$, false, true, std::move($1), std::move($3)); }
|
||||
;
|
||||
|
||||
expr_call_function
|
||||
: name LPAREN expr_arguments RPAREN
|
||||
{$$.as_func = std::make_unique<node_expr_call_function>(@$, std::make_unique<node_file>(), std::move($1), std::move($3)); }
|
||||
| file DOUBLECOLON name LPAREN expr_arguments RPAREN
|
||||
{ $$.as_func = std::make_unique<node_expr_call_function>(@$, std::move($1), std::move($3), std::move($5)); }
|
||||
;
|
||||
|
||||
expr_call_pointer
|
||||
: LBRACKET LBRACKET expr RBRACKET RBRACKET LPAREN expr_arguments RPAREN
|
||||
{ $$.as_pointer = std::make_unique<node_expr_call_pointer>(@$, false, std::move($3), std::move($7)); }
|
||||
| CALL LBRACKET LBRACKET expr RBRACKET RBRACKET LPAREN expr_arguments RPAREN
|
||||
{ $$.as_pointer = std::make_unique<node_expr_call_pointer>(@$, true, std::move($4), std::move($8)); }
|
||||
;
|
||||
|
||||
expr_arguments
|
||||
: expr_arguments_filled { $$ = std::move($1); }
|
||||
| expr_arguments_empty { $$ = std::move($1); }
|
||||
;
|
||||
|
||||
expr_arguments_filled
|
||||
: expr_arguments COMMA expr
|
||||
{ $$ = std::move($1); $$->list.push_back(std::move($3)); }
|
||||
| expr %prec ADD_ARRAY
|
||||
{ $$ = std::make_unique<node_expr_arguments>(@$); $$->list.push_back(std::move($1)); }
|
||||
;
|
||||
|
||||
expr_arguments_empty
|
||||
:
|
||||
{ $$ = std::make_unique<node_expr_arguments>(@$); }
|
||||
;
|
||||
|
||||
expr_function
|
||||
: DOUBLECOLON name
|
||||
{ $$ = std::make_unique<node_expr_function>(@$, std::make_unique<node_file>(@$), std::move($2)); }
|
||||
| file DOUBLECOLON name
|
||||
{ $$ = std::make_unique<node_expr_function>(@$, std::move($1), std::move($3)); }
|
||||
;
|
||||
|
||||
expr_add_array
|
||||
: LBRACKET expr_arguments_filled RBRACKET
|
||||
{ $$ = std::make_unique<node_expr_add_array>(@$, std::move($2)); }
|
||||
;
|
||||
|
||||
expr_array
|
||||
: object LBRACKET expr RBRACKET
|
||||
{ $$ = std::make_unique<node_expr_array>(@$, std::move($1), std::move($3)); }
|
||||
;
|
||||
|
||||
expr_field
|
||||
: object DOT name
|
||||
{ $$ = std::make_unique<node_expr_field>(@$, std::move($1), std::move($3)); }
|
||||
;
|
||||
|
||||
expr_size
|
||||
: object DOT SIZE
|
||||
{ $$ = std::make_unique<node_expr_size>(@$, std::move($1)); }
|
||||
;
|
||||
|
||||
object
|
||||
: expr_call { $$ = std::move($1); }
|
||||
| expr_array { $$ = std::move($1); }
|
||||
| expr_field { $$ = std::move($1); }
|
||||
| game { $$ = std::move($1); }
|
||||
| self { $$ = std::move($1); }
|
||||
| anim { $$ = std::move($1); }
|
||||
| level { $$ = std::move($1); }
|
||||
| name { $$ = std::move($1); }
|
||||
;
|
||||
|
||||
float
|
||||
: SUB FLOAT %prec NEG { $$ = std::make_unique<node_float>(@$, "-" + $2); };
|
||||
| FLOAT { $$ = std::make_unique<node_float>(@$, $1); };
|
||||
;
|
||||
|
||||
integer
|
||||
: SUB INT_DEC %prec NEG { $$ = std::make_unique<node_integer>(@$, "-" + $2); };
|
||||
| INT_DEC { $$ = std::make_unique<node_integer>(@$, $1); };
|
||||
| INT_OCT { $$ = std::make_unique<node_integer>(@$, $1); };
|
||||
| INT_BIN { $$ = std::make_unique<node_integer>(@$, $1); };
|
||||
| INT_HEX { $$ = std::make_unique<node_integer>(@$, $1); };
|
||||
;
|
||||
|
||||
thisthread : THISTHREAD { $$ = std::make_unique<node_thisthread>(@$); };
|
||||
empty_array : LBRACKET RBRACKET { $$ = std::make_unique<node_empty_array>(@$); };
|
||||
undefined : UNDEFINED { $$ = std::make_unique<node_undefined>(@$); };
|
||||
game : GAME { $$ = std::make_unique<node_game>(@$); };
|
||||
self : SELF { $$ = std::make_unique<node_self>(@$); };
|
||||
anim : ANIM { $$ = std::make_unique<node_anim>(@$); };
|
||||
level : LEVEL { $$ = std::make_unique<node_level>(@$); };
|
||||
animation : MOD NAME %prec ANIMREF { $$ = std::make_unique<node_animation>(@$, $2); };
|
||||
animtree : ANIMTREE { $$ = std::make_unique<node_animtree>(@$); };
|
||||
name : NAME { $$ = std::make_unique<node_name>(@$, $1); };
|
||||
file : FILE { $$ = std::make_unique<node_file>(@$, $1); };
|
||||
istring : ISTRING { $$ = std::make_unique<node_istring>(@$, $1); };
|
||||
string : STRING { $$ = std::make_unique<node_string>(@$, $1); };
|
||||
color : COLOR { $$ = std::make_unique<node_color>(@$, $1); };
|
||||
vector : LPAREN expr COMMA expr COMMA expr RPAREN { $$ = std::make_unique<node_vector>(@$, std::move($2), std::move($4), std::move($6)); };
|
||||
false : FALSE { $$ = std::make_unique<node_false>(@$); };
|
||||
true : TRUE { $$ = std::make_unique<node_true>(@$); };
|
||||
|
||||
%%
|
||||
|
||||
void xsk::gsc::s4::parser::error(const xsk::gsc::location& loc, const std::string& msg)
|
||||
{
|
||||
throw xsk::gsc::comp_error(loc, msg);
|
||||
}
|
20
premake5.lua
20
premake5.lua
@ -55,6 +55,7 @@ project "xsk-gsc-tool"
|
||||
dependson "xsk-gsc-iw8"
|
||||
dependson "xsk-gsc-s1"
|
||||
dependson "xsk-gsc-s2"
|
||||
dependson "xsk-gsc-s4"
|
||||
dependson "xsk-gsc-h1"
|
||||
dependson "xsk-gsc-h2"
|
||||
|
||||
@ -75,6 +76,7 @@ project "xsk-gsc-tool"
|
||||
"xsk-gsc-iw8",
|
||||
"xsk-gsc-s1",
|
||||
"xsk-gsc-s2",
|
||||
"xsk-gsc-s4",
|
||||
"xsk-gsc-h1",
|
||||
"xsk-gsc-h2"
|
||||
}
|
||||
@ -214,6 +216,24 @@ project "xsk-gsc-s2"
|
||||
"./src"
|
||||
}
|
||||
|
||||
project "xsk-gsc-s4"
|
||||
kind "StaticLib"
|
||||
language "C++"
|
||||
|
||||
pchheader "stdafx.hpp"
|
||||
pchsource "src/s4/stdafx.cpp"
|
||||
|
||||
files {
|
||||
"./src/s4/**.h",
|
||||
"./src/s4/**.hpp",
|
||||
"./src/s4/**.cpp"
|
||||
}
|
||||
|
||||
includedirs {
|
||||
"./src/s4",
|
||||
"./src"
|
||||
}
|
||||
|
||||
project "xsk-gsc-h1"
|
||||
kind "StaticLib"
|
||||
language "C++"
|
||||
|
6
src/s4/stdafx.cpp
Normal file
6
src/s4/stdafx.cpp
Normal file
@ -0,0 +1,6 @@
|
||||
// Copyright 2021 xensik. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a GNU GPLv3 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
#include "stdafx.hpp"
|
38
src/s4/stdafx.hpp
Normal file
38
src/s4/stdafx.hpp
Normal file
@ -0,0 +1,38 @@
|
||||
// Copyright 2021 xensik. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a GNU GPLv3 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
#pragma once
|
||||
|
||||
// Warnings
|
||||
#ifdef _WIN32
|
||||
#pragma warning(disable:4244)
|
||||
#pragma warning(disable:4267)
|
||||
#pragma warning(disable:4005)
|
||||
#pragma warning(disable:4065)
|
||||
#define _CRT_SECURE_NO_WARNINGS
|
||||
#endif
|
||||
|
||||
// C/C++
|
||||
#include <regex>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include <algorithm>
|
||||
#include <filesystem>
|
||||
#include <functional>
|
||||
#include <stdexcept>
|
||||
#include <map>
|
||||
#include <stack>
|
||||
#include <array>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <fstream>
|
||||
#include <unordered_map>
|
||||
#include <stdio.h>
|
||||
|
||||
// Ext
|
||||
using namespace std::literals;
|
||||
|
||||
#include "xsk/s4.hpp"
|
682
src/s4/xsk/assembler.cpp
Normal file
682
src/s4/xsk/assembler.cpp
Normal file
@ -0,0 +1,682 @@
|
||||
// Copyright 2021 xensik. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a GNU GPLv3 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
#include "stdafx.hpp"
|
||||
#include "s4.hpp"
|
||||
|
||||
namespace xsk::gsc::s4
|
||||
{
|
||||
|
||||
auto assembler::output_script() -> std::vector<std::uint8_t>
|
||||
{
|
||||
std::vector<std::uint8_t> script;
|
||||
|
||||
if(script_ == nullptr) return script;
|
||||
|
||||
script.resize(script_->pos());
|
||||
memcpy(script.data(), script_->buffer().data(), script.size());
|
||||
|
||||
return script;
|
||||
}
|
||||
|
||||
auto assembler::output_stack() -> std::vector<std::uint8_t>
|
||||
{
|
||||
std::vector<std::uint8_t> stack;
|
||||
|
||||
if(stack_ == nullptr) return stack;
|
||||
|
||||
stack.resize(stack_->pos());
|
||||
memcpy(stack.data(), stack_->buffer().data(), stack.size());
|
||||
|
||||
return stack;
|
||||
}
|
||||
|
||||
void assembler::assemble(const std::string& file, std::vector<std::uint8_t>& data)
|
||||
{
|
||||
std::vector<std::string> assembly = utils::string::clean_buffer_lines(data);
|
||||
std::vector<gsc::function_ptr> functions;
|
||||
gsc::function_ptr func = nullptr;
|
||||
std::uint32_t index = 1;
|
||||
std::uint16_t switchnum = 0;
|
||||
|
||||
for (auto& line : assembly)
|
||||
{
|
||||
if (line == "" || line.substr(0, 2) == "//")
|
||||
{
|
||||
continue;
|
||||
}
|
||||
else if (line.substr(0, 4) == "sub_")
|
||||
{
|
||||
func = std::make_unique<gsc::function>();
|
||||
func->index = index;
|
||||
func->name = line.substr(4);
|
||||
}
|
||||
else if (line.substr(0, 4) == "end_")
|
||||
{
|
||||
if (func != nullptr)
|
||||
{
|
||||
func->size = index - func->index;
|
||||
functions.push_back(std::move(func));
|
||||
}
|
||||
}
|
||||
else if (line.substr(0, 4) == "loc_")
|
||||
{
|
||||
func->labels[index] = line;
|
||||
}
|
||||
else
|
||||
{
|
||||
auto data = utils::string::parse_code(line);
|
||||
|
||||
if (switchnum)
|
||||
{
|
||||
if (data[0] == "case" || data[0] == "default")
|
||||
{
|
||||
for (auto& entry : data)
|
||||
{
|
||||
func->instructions.back()->data.push_back(entry);
|
||||
}
|
||||
switchnum--;
|
||||
continue;
|
||||
}
|
||||
|
||||
throw gsc::asm_error("invalid instruction inside endswitch \""s + line + "\"!");
|
||||
}
|
||||
else
|
||||
{
|
||||
auto inst = std::make_unique<gsc::instruction>();
|
||||
inst->index = index;
|
||||
inst->opcode = static_cast<std::uint8_t>(resolver::opcode_id(data[0]));
|
||||
inst->size = opcode_size(inst->opcode);
|
||||
data.erase(data.begin());
|
||||
inst->data = std::move(data);
|
||||
|
||||
if (opcode(inst->opcode) == opcode::OP_endswitch)
|
||||
{
|
||||
switchnum = static_cast<std::uint16_t>(std::stoi(inst->data[0]));
|
||||
inst->size += 7 * switchnum;
|
||||
}
|
||||
|
||||
index += inst->size;
|
||||
func->instructions.push_back(std::move(inst));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this->assemble(file, functions);
|
||||
}
|
||||
|
||||
void assembler::assemble(const std::string& file, std::vector<gsc::function_ptr>& functions)
|
||||
{
|
||||
script_ = std::make_unique<utils::byte_buffer>(0x100000);
|
||||
stack_ = std::make_unique<utils::byte_buffer>(0x100000);
|
||||
filename_ = file;
|
||||
functions_ = std::move(functions);
|
||||
|
||||
script_->write<std::uint8_t>(static_cast<std::uint8_t>(opcode::OP_End));
|
||||
|
||||
for (const auto& func : functions_)
|
||||
{
|
||||
this->assemble_function(func);
|
||||
}
|
||||
}
|
||||
|
||||
void assembler::assemble_function(const gsc::function_ptr& func)
|
||||
{
|
||||
labels_ = func->labels;
|
||||
|
||||
stack_->write<std::uint32_t>(func->size);
|
||||
|
||||
func->id = func->name.substr(0, 3) == "_ID" ? std::stoi(func->name.substr(3)) : resolver::token_id(func->name);
|
||||
stack_->write<std::uint32_t>(func->id);
|
||||
|
||||
if (func->id == 0)
|
||||
{
|
||||
stack_->write_c_string(func->name);
|
||||
}
|
||||
|
||||
for (const auto& inst : func->instructions)
|
||||
{
|
||||
this->assemble_instruction(inst);
|
||||
}
|
||||
}
|
||||
|
||||
void assembler::assemble_instruction(const gsc::instruction_ptr& inst)
|
||||
{
|
||||
switch (opcode(inst->opcode))
|
||||
{
|
||||
case opcode::OP_CastFieldObject:
|
||||
case opcode::OP_plus:
|
||||
case opcode::OP_GetGameRef:
|
||||
case opcode::OP_GetThisthread:
|
||||
case opcode::OP_greater:
|
||||
case opcode::OP_shift_right:
|
||||
case opcode::OP_dec:
|
||||
case opcode::OP_bit_or:
|
||||
case opcode::OP_equality:
|
||||
case opcode::OP_ClearLocalVariableFieldCached0:
|
||||
case opcode::OP_notify:
|
||||
case opcode::OP_PreScriptCall:
|
||||
case opcode::OP_GetUndefined:
|
||||
case opcode::OP_SetLocalVariableFieldCached0:
|
||||
case opcode::OP_GetLevel:
|
||||
case opcode::OP_size:
|
||||
case opcode::OP_AddArray:
|
||||
case opcode::OP_endon:
|
||||
case opcode::OP_shift_left:
|
||||
case opcode::OP_EvalLocalArrayRefCached0:
|
||||
case opcode::OP_Return:
|
||||
case opcode::OP_SafeSetVariableFieldCached0:
|
||||
case opcode::OP_GetSelfObject:
|
||||
case opcode::OP_GetGame:
|
||||
case opcode::OP_EvalArray:
|
||||
case opcode::OP_GetSelf:
|
||||
case opcode::OP_End:
|
||||
case opcode::OP_less_equal:
|
||||
case opcode::OP_EvalLocalVariableCached0:
|
||||
case opcode::OP_EvalLocalVariableCached1:
|
||||
case opcode::OP_EvalLocalVariableCached2:
|
||||
case opcode::OP_EvalLocalVariableCached3:
|
||||
case opcode::OP_EvalLocalVariableCached4:
|
||||
case opcode::OP_EvalLocalVariableCached5:
|
||||
case opcode::OP_ScriptMethodCallPointer:
|
||||
case opcode::OP_checkclearparams:
|
||||
case opcode::OP_waittillmatch2:
|
||||
case opcode::OP_minus:
|
||||
case opcode::OP_greater_equal:
|
||||
case opcode::OP_vector:
|
||||
case opcode::OP_ClearArray:
|
||||
case opcode::OP_DecTop:
|
||||
case opcode::OP_CastBool:
|
||||
case opcode::OP_EvalArrayRef:
|
||||
case opcode::OP_GetZero:
|
||||
case opcode::OP_wait:
|
||||
case opcode::OP_waittill:
|
||||
case opcode::OP_GetAnimObject:
|
||||
case opcode::OP_mod:
|
||||
case opcode::OP_clearparams:
|
||||
case opcode::OP_ScriptFunctionCallPointer:
|
||||
case opcode::OP_EmptyArray:
|
||||
case opcode::OP_ClearVariableField:
|
||||
case opcode::OP_EvalNewLocalVariableRefCached0:
|
||||
case opcode::OP_BoolComplement:
|
||||
case opcode::OP_less:
|
||||
case opcode::OP_BoolNot:
|
||||
case opcode::OP_waittillFrameEnd:
|
||||
case opcode::OP_waitframe:
|
||||
case opcode::OP_GetLevelObject:
|
||||
case opcode::OP_inc:
|
||||
case opcode::OP_GetAnim:
|
||||
case opcode::OP_SetVariableField:
|
||||
case opcode::OP_divide:
|
||||
case opcode::OP_multiply:
|
||||
case opcode::OP_EvalLocalVariableRefCached0:
|
||||
case opcode::OP_bit_and:
|
||||
case opcode::OP_voidCodepos:
|
||||
case opcode::OP_inequality:
|
||||
case opcode::OP_bit_ex_or:
|
||||
/*
|
||||
case opcode::OP_NOP:
|
||||
case opcode::OP_abort:
|
||||
case opcode::OP_object:
|
||||
case opcode::OP_thread_object:
|
||||
case opcode::OP_EvalLocalVariable:
|
||||
case opcode::OP_EvalLocalVariableRef:
|
||||
case opcode::OP_breakpoint:
|
||||
case opcode::OP_assignmentBreakpoint:
|
||||
case opcode::OP_manualAndAssignmentBreakpoint:
|
||||
*/
|
||||
case opcode::OP_BoolNotAfterAnd:
|
||||
case opcode::OP_IsDefined:
|
||||
case opcode::OP_IsTrue:
|
||||
script_->write<std::uint8_t>(static_cast<std::uint8_t>(inst->opcode));
|
||||
break;
|
||||
case opcode::OP_GetByte:
|
||||
script_->write<std::uint8_t>(static_cast<std::uint8_t>(inst->opcode));
|
||||
script_->write<std::uint8_t>(static_cast<std::uint8_t>(std::stoi(inst->data[0])));
|
||||
break;
|
||||
case opcode::OP_GetNegByte:
|
||||
script_->write<std::uint8_t>(static_cast<std::uint8_t>(inst->opcode));
|
||||
script_->write<std::int8_t>(static_cast<std::int8_t>(std::stoi(inst->data[0])));
|
||||
break;
|
||||
case opcode::OP_GetUnsignedShort:
|
||||
script_->write<std::uint8_t>(static_cast<std::uint8_t>(inst->opcode));
|
||||
script_->write<std::uint16_t>(static_cast<std::uint16_t>(std::stoi(inst->data[0])));
|
||||
break;
|
||||
case opcode::OP_GetNegUnsignedShort:
|
||||
script_->write<std::uint8_t>(static_cast<std::uint8_t>(inst->opcode));
|
||||
script_->write<std::int16_t>(static_cast<std::int16_t>(std::stoi(inst->data[0])));
|
||||
case opcode::OP_GetInteger:
|
||||
script_->write<std::uint8_t>(static_cast<std::uint8_t>(inst->opcode));
|
||||
script_->write<std::int32_t>(std::stoi(inst->data[0]));
|
||||
break;
|
||||
case opcode::OP_GetFloat:
|
||||
script_->write<std::uint8_t>(static_cast<std::uint8_t>(inst->opcode));
|
||||
script_->write<float>(std::stof(inst->data[0]));
|
||||
break;
|
||||
case opcode::OP_GetVector:
|
||||
script_->write<std::uint8_t>(static_cast<std::uint8_t>(inst->opcode));
|
||||
script_->write<float>(std::stof(inst->data[0]));
|
||||
script_->write<float>(std::stof(inst->data[1]));
|
||||
script_->write<float>(std::stof(inst->data[2]));
|
||||
break;
|
||||
case opcode::OP_GetString:
|
||||
case opcode::OP_GetIString:
|
||||
script_->write<std::uint8_t>(static_cast<std::uint8_t>(inst->opcode));
|
||||
script_->write<std::uint32_t>(0);
|
||||
stack_->write_c_string(utils::string::to_code(inst->data[0]));
|
||||
break;
|
||||
case opcode::OP_GetAnimation:
|
||||
script_->write<std::uint8_t>(static_cast<std::uint8_t>(inst->opcode));
|
||||
script_->write<std::uint32_t>(0);
|
||||
script_->write<std::uint32_t>(0);
|
||||
stack_->write_c_string(utils::string::unquote(inst->data[0]));
|
||||
stack_->write_c_string(utils::string::unquote(inst->data[1]));
|
||||
break;
|
||||
case opcode::OP_GetAnimTree:
|
||||
script_->write<std::uint8_t>(static_cast<std::uint8_t>(inst->opcode));
|
||||
script_->write<std::uint8_t>(0);
|
||||
stack_->write_c_string(utils::string::unquote(inst->data[0]));
|
||||
break;
|
||||
case opcode::OP_waittillmatch:
|
||||
script_->write<std::uint8_t>(static_cast<std::uint8_t>(inst->opcode));
|
||||
script_->write<std::uint16_t>(0);
|
||||
break;
|
||||
case opcode::OP_SetNewLocalVariableFieldCached0:
|
||||
case opcode::OP_EvalNewLocalArrayRefCached0:
|
||||
case opcode::OP_SafeCreateVariableFieldCached:
|
||||
case opcode::OP_ClearLocalVariableFieldCached:
|
||||
case opcode::OP_SetLocalVariableFieldCached:
|
||||
case opcode::OP_RemoveLocalVariables:
|
||||
case opcode::OP_EvalLocalVariableRefCached:
|
||||
case opcode::OP_EvalLocalArrayRefCached:
|
||||
case opcode::OP_SafeSetVariableFieldCached:
|
||||
case opcode::OP_EvalLocalVariableCached:
|
||||
case opcode::OP_SafeSetWaittillVariableFieldCached:
|
||||
case opcode::OP_CreateLocalVariable:
|
||||
case opcode::OP_EvalLocalVariableObjectCached:
|
||||
case opcode::OP_EvalLocalArrayCached:
|
||||
script_->write<std::uint8_t>(static_cast<std::uint8_t>(inst->opcode));
|
||||
script_->write<std::uint8_t>(static_cast<std::uint8_t>(std::stoi(inst->data[0])));
|
||||
break;
|
||||
case opcode::OP_EvalSelfFieldVariable:
|
||||
case opcode::OP_SetLevelFieldVariableField:
|
||||
case opcode::OP_ClearFieldVariable:
|
||||
case opcode::OP_EvalFieldVariable:
|
||||
case opcode::OP_EvalFieldVariableRef:
|
||||
case opcode::OP_EvalLevelFieldVariable:
|
||||
case opcode::OP_SetAnimFieldVariableField:
|
||||
case opcode::OP_SetSelfFieldVariableField:
|
||||
case opcode::OP_EvalAnimFieldVariableRef:
|
||||
case opcode::OP_EvalLevelFieldVariableRef:
|
||||
case opcode::OP_EvalAnimFieldVariable:
|
||||
case opcode::OP_EvalSelfFieldVariableRef:
|
||||
this->assemble_field_variable(inst);
|
||||
break;
|
||||
case opcode::OP_CallBuiltinPointer:
|
||||
case opcode::OP_CallBuiltinMethodPointer:
|
||||
case opcode::OP_ScriptThreadCallPointer:
|
||||
case opcode::OP_ScriptChildThreadCallPointer:
|
||||
case opcode::OP_ScriptMethodThreadCallPointer:
|
||||
case opcode::OP_ScriptMethodChildThreadCallPointer:
|
||||
script_->write<std::uint8_t>(static_cast<std::uint8_t>(inst->opcode));
|
||||
script_->write<std::uint8_t>(static_cast<std::uint8_t>(std::stoi(inst->data[0])));
|
||||
break;
|
||||
case opcode::OP_GetLocalFunction:
|
||||
case opcode::OP_ScriptLocalFunctionCall2:
|
||||
case opcode::OP_ScriptLocalFunctionCall:
|
||||
case opcode::OP_ScriptLocalMethodCall:
|
||||
this->assemble_local_call(inst, false);
|
||||
break;
|
||||
case opcode::OP_ScriptLocalThreadCall:
|
||||
case opcode::OP_ScriptLocalChildThreadCall:
|
||||
case opcode::OP_ScriptLocalMethodThreadCall:
|
||||
case opcode::OP_ScriptLocalMethodChildThreadCall:
|
||||
this->assemble_local_call(inst, true);
|
||||
break;
|
||||
case opcode::OP_GetFarFunction:
|
||||
case opcode::OP_ScriptFarFunctionCall2:
|
||||
case opcode::OP_ScriptFarFunctionCall:
|
||||
case opcode::OP_ScriptFarMethodCall:
|
||||
this->assemble_far_call(inst, false);
|
||||
break;
|
||||
case opcode::OP_ScriptFarThreadCall:
|
||||
case opcode::OP_ScriptFarChildThreadCall:
|
||||
case opcode::OP_ScriptFarMethodThreadCall:
|
||||
case opcode::OP_ScriptFarMethodChildThreadCall:
|
||||
this->assemble_far_call(inst, true);
|
||||
break;
|
||||
case opcode::OP_CallBuiltin:
|
||||
this->assemble_builtin_call(inst, false, true);
|
||||
break;
|
||||
case opcode::OP_CallBuiltinMethod:
|
||||
this->assemble_builtin_call(inst, true, true);
|
||||
break;
|
||||
case opcode::OP_GetBuiltinFunction:
|
||||
case opcode::OP_CallBuiltin0:
|
||||
case opcode::OP_CallBuiltin1:
|
||||
case opcode::OP_CallBuiltin2:
|
||||
case opcode::OP_CallBuiltin3:
|
||||
case opcode::OP_CallBuiltin4:
|
||||
case opcode::OP_CallBuiltin5:
|
||||
this->assemble_builtin_call(inst, false, false);
|
||||
break;
|
||||
case opcode::OP_GetBuiltinMethod:
|
||||
case opcode::OP_CallBuiltinMethod0:
|
||||
case opcode::OP_CallBuiltinMethod1:
|
||||
case opcode::OP_CallBuiltinMethod2:
|
||||
case opcode::OP_CallBuiltinMethod3:
|
||||
case opcode::OP_CallBuiltinMethod4:
|
||||
case opcode::OP_CallBuiltinMethod5:
|
||||
this->assemble_builtin_call(inst, true, false);
|
||||
break;
|
||||
case opcode::OP_JumpOnFalseExpr:
|
||||
case opcode::OP_JumpOnTrueExpr:
|
||||
case opcode::OP_JumpOnFalse:
|
||||
case opcode::OP_JumpOnTrue:
|
||||
this->assemble_jump(inst, true, false);
|
||||
break;
|
||||
case opcode::OP_jumpback:
|
||||
this->assemble_jump(inst, false, true);
|
||||
break;
|
||||
case opcode::OP_jump:
|
||||
this->assemble_jump(inst, false, false);
|
||||
break;
|
||||
case opcode::OP_switch:
|
||||
this->assemble_switch(inst);
|
||||
break;
|
||||
case opcode::OP_endswitch:
|
||||
this->assemble_end_switch(inst);
|
||||
break;
|
||||
/*
|
||||
case opcode::OP_prof_begin:
|
||||
script_->write<std::uint32_t>(0); // TODO: skipped data
|
||||
script_->write<std::uint8_t>(0);
|
||||
break;
|
||||
case opcode::OP_prof_end:
|
||||
script_->write<std::uint8_t>(0); // TODO: skipped data
|
||||
break;
|
||||
case opcode::OP_EvalNewLocalArrayRefCached0_Precompiled:
|
||||
case opcode::OP_SetNewLocalVariableFieldCached0_Precompiled:
|
||||
case opcode::OP_CreateLocalVariable_Precompiled:
|
||||
case opcode::OP_SafeCreateVariableFieldCached_Precompiled:
|
||||
script_->write<std::uint8_t>(static_cast<std::uint8_t>(inst->opcode));
|
||||
script_->write<std::uint8_t>(static_cast<std::uint8_t>(std::stoi(inst->data[0])));
|
||||
break;
|
||||
*/
|
||||
case opcode::OP_FormalParams:
|
||||
// case opcode::OP_FormalParams_Precompiled:
|
||||
this->assemble_formal_params(inst);
|
||||
break;
|
||||
/*
|
||||
case opcode::OP_NativeGetLocalFunction:
|
||||
case opcode::OP_NativeLocalFunctionCall:
|
||||
case opcode::OP_NativeLocalFunctionCall2:
|
||||
case opcode::OP_NativeLocalMethodCall:
|
||||
this->assemble_local_call(inst, false);
|
||||
break;
|
||||
case opcode::OP_NativeGetFarFunction:
|
||||
case opcode::OP_NativeFarFunctionCall:
|
||||
case opcode::OP_NativeFarFunctionCall2:
|
||||
case opcode::OP_NativeFarMethodCall:
|
||||
this->assemble_far_call(inst, false);
|
||||
break;
|
||||
case opcode::OP_NativeLocalFunctionThreadCall:
|
||||
case opcode::OP_NativeLocalMethodThreadCall:
|
||||
case opcode::OP_NativeLocalFunctionChildThreadCall:
|
||||
case opcode::OP_NativeLocalMethodChildThreadCall:
|
||||
this->assemble_local_call(inst, true);
|
||||
break;
|
||||
case opcode::OP_NativeFarFunctionThreadCall:
|
||||
case opcode::OP_NativeFarMethodThreadCall:
|
||||
case opcode::OP_NativeFarFunctionChildThreadCall:
|
||||
case opcode::OP_NativeFarMethodChildThreadCall:
|
||||
this->assemble_far_call(inst, true);
|
||||
break;
|
||||
*/
|
||||
default:
|
||||
throw gsc::asm_error(utils::string::va("Unhandled opcode 0x%X at index '%04X'!", inst->opcode, inst->index));
|
||||
}
|
||||
}
|
||||
|
||||
void assembler::assemble_builtin_call(const gsc::instruction_ptr& inst, bool method, bool arg_num)
|
||||
{
|
||||
script_->write<std::uint8_t>(static_cast<std::uint8_t>(inst->opcode));
|
||||
|
||||
std::uint16_t id = 0;
|
||||
|
||||
if (arg_num)
|
||||
{
|
||||
script_->write<std::uint8_t>(static_cast<std::uint8_t>(std::stoi(inst->data[0])));
|
||||
|
||||
if (method)
|
||||
id = inst->data[1].substr(0, 3) == "_ID" ? std::stoi(inst->data[1].substr(3)) : resolver::method_id(inst->data[1]);
|
||||
else
|
||||
id = inst->data[1].substr(0, 3) == "_ID" ? std::stoi(inst->data[1].substr(3)) : resolver::function_id(inst->data[1]);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (method)
|
||||
id = inst->data[0].substr(0, 3) == "_ID" ? std::stoi(inst->data[0].substr(3)) : resolver::method_id(inst->data[0]);
|
||||
else
|
||||
id = inst->data[0].substr(0, 3) == "_ID" ? std::stoi(inst->data[0].substr(3)) : resolver::function_id(inst->data[0]);
|
||||
}
|
||||
|
||||
script_->write<std::uint16_t>(id);
|
||||
}
|
||||
|
||||
void assembler::assemble_local_call(const gsc::instruction_ptr& inst, bool thread)
|
||||
{
|
||||
script_->write<std::uint8_t>(static_cast<std::uint8_t>(inst->opcode));
|
||||
|
||||
std::int32_t addr = this->resolve_function(inst->data[0]);
|
||||
|
||||
std::int32_t offset = addr - inst->index - 1;
|
||||
|
||||
this->assemble_offset(offset);
|
||||
|
||||
if (thread)
|
||||
{
|
||||
script_->write<std::uint8_t>(static_cast<std::uint8_t>(std::stoi(inst->data[1])));
|
||||
}
|
||||
}
|
||||
|
||||
void assembler::assemble_far_call(const gsc::instruction_ptr& inst, bool thread)
|
||||
{
|
||||
script_->write<std::uint8_t>(static_cast<std::uint8_t>(inst->opcode));
|
||||
script_->write<std::uint8_t>(0);
|
||||
script_->write<std::uint16_t>(0);
|
||||
|
||||
std::uint32_t file_id = 0;
|
||||
std::uint32_t func_id = 0;
|
||||
|
||||
if (thread)
|
||||
{
|
||||
script_->write<std::uint8_t>(static_cast<std::uint8_t>(std::stoi(inst->data[0])));
|
||||
|
||||
file_id = inst->data[1].substr(0, 3) == "_ID" ? std::stoi(inst->data[1].substr(3)) : resolver::file_id(inst->data[1]);
|
||||
func_id = inst->data[2].substr(0, 3) == "_ID" ? std::stoi(inst->data[2].substr(3)) : resolver::token_id(inst->data[2]);
|
||||
}
|
||||
else
|
||||
{
|
||||
file_id = inst->data[0].substr(0, 3) == "_ID" ? std::stoi(inst->data[0].substr(3)) : resolver::file_id(inst->data[0]);
|
||||
func_id = inst->data[1].substr(0, 3) == "_ID" ? std::stoi(inst->data[1].substr(3)) : resolver::token_id(inst->data[1]);
|
||||
}
|
||||
|
||||
stack_->write<std::uint32_t>(file_id);
|
||||
if (file_id == 0) stack_->write_c_string(thread ? inst->data[1] : inst->data[0]);
|
||||
stack_->write<std::uint32_t>(func_id);
|
||||
if (func_id == 0) stack_->write_c_string(thread ? inst->data[2] : inst->data[1]);
|
||||
}
|
||||
|
||||
void assembler::assemble_jump(const gsc::instruction_ptr& inst, bool expr, bool back)
|
||||
{
|
||||
script_->write<std::uint8_t>(static_cast<std::uint8_t>(inst->opcode));
|
||||
|
||||
std::int32_t addr = this->resolve_label(inst->data[0]);
|
||||
|
||||
if (expr)
|
||||
{
|
||||
script_->write<std::int16_t>(addr - inst->index - 3);
|
||||
}
|
||||
else if (back)
|
||||
{
|
||||
script_->write<std::int16_t>((inst->index + 3) - addr);
|
||||
}
|
||||
else
|
||||
{
|
||||
script_->write<std::int32_t>(addr - inst->index - 5);
|
||||
}
|
||||
}
|
||||
|
||||
void assembler::assemble_field_variable(const gsc::instruction_ptr& inst)
|
||||
{
|
||||
script_->write<std::uint8_t>(static_cast<std::uint8_t>(inst->opcode));
|
||||
|
||||
std::uint32_t field_id = 0;
|
||||
|
||||
if (inst->data[0].substr(0, 3) == "_ID")
|
||||
{
|
||||
field_id = std::stoi(inst->data[0].substr(3));
|
||||
}
|
||||
else
|
||||
{
|
||||
field_id = resolver::token_id(inst->data[0]);
|
||||
|
||||
if (field_id == 0)
|
||||
{
|
||||
field_id = 0xFFFF;
|
||||
}
|
||||
}
|
||||
|
||||
script_->write<std::uint32_t>(field_id);
|
||||
|
||||
if (field_id > 0x1C000)
|
||||
{
|
||||
stack_->write<std::uint32_t>(0);
|
||||
stack_->write_c_string(inst->data[0]);
|
||||
}
|
||||
}
|
||||
|
||||
void assembler::assemble_formal_params(const gsc::instruction_ptr& inst)
|
||||
{
|
||||
script_->write<std::uint8_t>(static_cast<std::uint8_t>(inst->opcode));
|
||||
|
||||
auto size = std::stoi(inst->data[0]);
|
||||
|
||||
script_->write<std::uint8_t>(static_cast<std::uint8_t>(size));
|
||||
|
||||
for(auto i = 1; i <= size; i++)
|
||||
{
|
||||
script_->write<std::uint8_t>(static_cast<std::uint8_t>(std::stoi(inst->data[i])));
|
||||
}
|
||||
}
|
||||
|
||||
void assembler::assemble_switch(const gsc::instruction_ptr& inst)
|
||||
{
|
||||
script_->write<std::uint8_t>(static_cast<std::uint8_t>(inst->opcode));
|
||||
|
||||
std::int32_t addr = this->resolve_label(inst->data[0]);
|
||||
|
||||
script_->write<std::int32_t>(addr - inst->index - 4);
|
||||
}
|
||||
|
||||
void assembler::assemble_end_switch(const gsc::instruction_ptr& inst)
|
||||
{
|
||||
script_->write<std::uint8_t>(static_cast<std::uint8_t>(inst->opcode));
|
||||
|
||||
std::uint16_t casenum = 0;
|
||||
|
||||
if (utils::string::is_number(inst->data[0]))
|
||||
{
|
||||
casenum = std::stoi(inst->data[0]);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw gsc::asm_error("invalid endswitch number!");
|
||||
}
|
||||
|
||||
script_->write<std::uint16_t>(casenum);
|
||||
|
||||
std::uint32_t internal_index = inst->index + 3;
|
||||
|
||||
for (std::uint16_t i = 0; i < casenum; i++)
|
||||
{
|
||||
if (inst->data[1 + (3 * i)] == "case")
|
||||
{
|
||||
if (utils::string::is_number(inst->data[1 + (3 * i) + 1]))
|
||||
{
|
||||
script_->write<uint32_t>((std::stoi(inst->data[1 + (3 * i) + 1]) & 0xFFFFFF) + 0x800000);
|
||||
}
|
||||
else
|
||||
{
|
||||
script_->write<uint32_t>(i + 1);
|
||||
stack_->write_c_string(utils::string::unquote(inst->data[1 + (3 * i) + 1]));
|
||||
}
|
||||
|
||||
internal_index += 4;
|
||||
|
||||
std::int32_t addr = this->resolve_label(inst->data[1 + (3 * i) + 2]);
|
||||
|
||||
this->assemble_offset(addr - internal_index);
|
||||
|
||||
internal_index += 3;
|
||||
}
|
||||
else if (inst->data[1 + (3 * i)] == "default")
|
||||
{
|
||||
script_->write<uint32_t>(0);
|
||||
stack_->write_c_string("\x01");
|
||||
|
||||
internal_index += 4;
|
||||
std::int32_t addr = this->resolve_label(inst->data[1 + (3 * i) + 1]);
|
||||
|
||||
this->assemble_offset(addr - internal_index);
|
||||
|
||||
internal_index += 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void assembler::assemble_offset(std::int32_t offset)
|
||||
{
|
||||
std::array<std::uint8_t, 4> bytes = {};
|
||||
|
||||
offset = (offset << 8) >> 8;
|
||||
|
||||
*reinterpret_cast<std::int32_t*>(bytes.data()) = offset;
|
||||
|
||||
script_->write<std::uint8_t>(bytes[0]);
|
||||
script_->write<std::uint8_t>(bytes[1]);
|
||||
script_->write<std::uint8_t>(bytes[2]);
|
||||
}
|
||||
|
||||
auto assembler::resolve_function(const std::string& name) -> std::uint32_t
|
||||
{
|
||||
auto temp = name.substr(0, 4) == "sub_" ? name.substr(4) : name;
|
||||
|
||||
for (const auto& func : functions_)
|
||||
{
|
||||
if (func->name == temp)
|
||||
{
|
||||
return func->index;
|
||||
}
|
||||
}
|
||||
|
||||
throw gsc::asm_error("Couldn't resolve local function address of '" + temp + "'!");
|
||||
}
|
||||
|
||||
auto assembler::resolve_label(const std::string& name) -> std::uint32_t
|
||||
{
|
||||
for (auto& func : labels_)
|
||||
{
|
||||
if (func.second == name)
|
||||
{
|
||||
return func.first;
|
||||
}
|
||||
}
|
||||
|
||||
throw gsc::asm_error("Couldn't resolve label address of '" + name + "'!");
|
||||
}
|
||||
|
||||
} // namespace xsk::gsc::s4
|
41
src/s4/xsk/assembler.hpp
Normal file
41
src/s4/xsk/assembler.hpp
Normal file
@ -0,0 +1,41 @@
|
||||
// Copyright 2021 xensik. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a GNU GPLv3 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace xsk::gsc::s4
|
||||
{
|
||||
|
||||
class assembler : public gsc::assembler
|
||||
{
|
||||
std::string filename_;
|
||||
utils::byte_buffer_ptr script_;
|
||||
utils::byte_buffer_ptr stack_;
|
||||
std::vector<gsc::function_ptr> functions_;
|
||||
std::unordered_map<std::uint32_t, std::string> labels_;
|
||||
|
||||
public:
|
||||
auto output_script() -> std::vector<std::uint8_t>;
|
||||
auto output_stack() -> std::vector<std::uint8_t>;
|
||||
void assemble(const std::string& file, std::vector<std::uint8_t>& data);
|
||||
void assemble(const std::string& file, std::vector<gsc::function_ptr>& functions);
|
||||
|
||||
private:
|
||||
void assemble_function(const gsc::function_ptr& func);
|
||||
void assemble_instruction(const gsc::instruction_ptr& inst);
|
||||
void assemble_builtin_call(const gsc::instruction_ptr& inst, bool method, bool arg_num);
|
||||
void assemble_local_call(const gsc::instruction_ptr& inst, bool thread);
|
||||
void assemble_far_call(const gsc::instruction_ptr& inst, bool thread);
|
||||
void assemble_jump(const gsc::instruction_ptr& inst, bool expr, bool back);
|
||||
void assemble_field_variable(const gsc::instruction_ptr& inst);
|
||||
void assemble_formal_params(const gsc::instruction_ptr& inst);
|
||||
void assemble_switch(const gsc::instruction_ptr& inst);
|
||||
void assemble_end_switch(const gsc::instruction_ptr& inst);
|
||||
void assemble_offset(std::int32_t offset);
|
||||
auto resolve_function(const std::string& name) -> std::uint32_t;
|
||||
auto resolve_label(const std::string& name) -> std::uint32_t;
|
||||
};
|
||||
|
||||
} // namespace xsk::gsc::s4
|
2453
src/s4/xsk/compiler.cpp
Normal file
2453
src/s4/xsk/compiler.cpp
Normal file
File diff suppressed because it is too large
Load Diff
152
src/s4/xsk/compiler.hpp
Normal file
152
src/s4/xsk/compiler.hpp
Normal file
@ -0,0 +1,152 @@
|
||||
// Copyright 2021 xensik. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a GNU GPLv3 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace xsk::gsc::s4
|
||||
{
|
||||
|
||||
enum class opcode : std::uint8_t;
|
||||
|
||||
class compiler : public gsc::compiler
|
||||
{
|
||||
std::string filename_;
|
||||
std::vector<gsc::function_ptr> assembly_;
|
||||
gsc::function_ptr function_;
|
||||
std::uint32_t index_;
|
||||
std::uint32_t label_idx_;
|
||||
std::uint8_t stack_idx_;
|
||||
std::vector<std::string> local_stack_;
|
||||
std::vector<std::string> local_functions_;
|
||||
std::vector<include_t> includes_;
|
||||
std::vector<animtree_t> animtrees_;
|
||||
std::unordered_map<std::string, gsc::expr_ptr> constants_;
|
||||
std::function<std::vector<std::uint8_t>(const std::string&)> callback_readf_;
|
||||
std::vector<gsc::context*> break_ctxs_;
|
||||
std::vector<gsc::context*> continue_ctxs_;
|
||||
bool can_break_;
|
||||
bool can_continue_;
|
||||
|
||||
public:
|
||||
auto output() -> std::vector<gsc::function_ptr>;
|
||||
void compile(const std::string& file, std::vector<std::uint8_t>& data);
|
||||
void set_readf_callback(std::function<std::vector<std::uint8_t>(const std::string&)> func);
|
||||
|
||||
private:
|
||||
auto parse_buffer(const std::string& file, std::vector<std::uint8_t>& data) -> gsc::program_ptr;
|
||||
auto parse_file(const std::string& file) -> gsc::program_ptr;
|
||||
void compile_program(const gsc::program_ptr& program);
|
||||
void emit_include(const gsc::include_ptr& include);
|
||||
void emit_define(const gsc::define_ptr& define);
|
||||
void emit_usingtree(const gsc::usingtree_ptr& animtree);
|
||||
void emit_constant(const gsc::constant_ptr& constant);
|
||||
void emit_thread(const gsc::thread_ptr& thread);
|
||||
void emit_parameters(const gsc::context_ptr& ctx, const gsc::parameters_ptr& params);
|
||||
void emit_stmt(const gsc::context_ptr& ctx, const gsc::stmt_ptr& stmt, bool last);
|
||||
void emit_stmt_list(const gsc::context_ptr& ctx, const gsc::stmt_list_ptr& stmt, bool last);
|
||||
void emit_stmt_call(const gsc::context_ptr& ctx, const gsc::stmt_call_ptr& stmt);
|
||||
void emit_stmt_assign(const gsc::context_ptr& ctx, const gsc::stmt_assign_ptr& stmt);
|
||||
void emit_stmt_endon(const gsc::context_ptr& ctx, const gsc::stmt_endon_ptr& stmt);
|
||||
void emit_stmt_notify(const gsc::context_ptr& ctx, const gsc::stmt_notify_ptr& stmt);
|
||||
void emit_stmt_wait(const gsc::context_ptr& ctx, const gsc::stmt_wait_ptr& stmt);
|
||||
void emit_stmt_waittill(const gsc::context_ptr& ctx, const gsc::stmt_waittill_ptr& stmt);
|
||||
void emit_stmt_waittillmatch(const gsc::context_ptr& ctx, const gsc::stmt_waittillmatch_ptr& stmt);
|
||||
void emit_stmt_waittillframeend(const gsc::context_ptr& ctx, const gsc::stmt_waittillframeend_ptr& stmt);
|
||||
void emit_stmt_waitframe(const gsc::context_ptr& ctx, const gsc::stmt_waitframe_ptr& stmt);
|
||||
void emit_stmt_if(const gsc::context_ptr& ctx, const gsc::stmt_if_ptr& stmt, bool last);
|
||||
void emit_stmt_ifelse(const gsc::context_ptr& ctx, const gsc::stmt_ifelse_ptr& stmt, bool last);
|
||||
void emit_stmt_while(const gsc::context_ptr& ctx, const gsc::stmt_while_ptr& stmt);
|
||||
void emit_stmt_for(const gsc::context_ptr& ctx, const gsc::stmt_for_ptr& stmt);
|
||||
void emit_stmt_foreach(const gsc::context_ptr& ctx, const gsc::stmt_foreach_ptr& stmt);
|
||||
void emit_stmt_switch(const gsc::context_ptr& ctx, const gsc::stmt_switch_ptr& stmt);
|
||||
void emit_stmt_case(const gsc::context_ptr& ctx, const gsc::stmt_case_ptr& stmt);
|
||||
void emit_stmt_default(const gsc::context_ptr& ctx, const gsc::stmt_default_ptr& stmt);
|
||||
void emit_stmt_break(const gsc::context_ptr& ctx, const gsc::stmt_break_ptr& stmt);
|
||||
void emit_stmt_continue(const gsc::context_ptr& ctx, const gsc::stmt_continue_ptr& stmt);
|
||||
void emit_stmt_return(const gsc::context_ptr& ctx, const gsc::stmt_return_ptr& stmt);
|
||||
void emit_expr(const gsc::context_ptr& ctx, const gsc::expr_ptr& expr);
|
||||
void emit_expr_assign(const gsc::context_ptr& ctx, const gsc::expr_assign_ptr& expr);
|
||||
void emit_expr_ternary(const gsc::context_ptr& ctx, const gsc::expr_ternary_ptr& expr);
|
||||
void emit_expr_binary(const gsc::context_ptr& ctx, const gsc::expr_binary_ptr& expr);
|
||||
void emit_expr_isdefined(const gsc::context_ptr& ctx, const gsc::expr_arguments_ptr& expr);
|
||||
void emit_expr_istrue(const gsc::context_ptr& ctx, const gsc::expr_arguments_ptr& expr);
|
||||
void emit_expr_bool_not_after_and(const gsc::context_ptr& ctx, const gsc::expr_ptr& expr);
|
||||
void emit_expr_and(const gsc::context_ptr& ctx, const gsc::expr_and_ptr& expr);
|
||||
void emit_expr_or(const gsc::context_ptr& ctx, const gsc::expr_or_ptr& expr);
|
||||
void emit_expr_complement(const gsc::context_ptr& ctx, const gsc::expr_complement_ptr& expr);
|
||||
void emit_expr_not(const gsc::context_ptr& ctx, const gsc::expr_not_ptr& expr);
|
||||
void emit_expr_call(const gsc::context_ptr& ctx, const gsc::expr_call_ptr& expr);
|
||||
void emit_expr_call_pointer(const gsc::context_ptr& ctx, const gsc::expr_call_ptr& expr);
|
||||
void emit_expr_call_pointer_type(const gsc::context_ptr& ctx, int args, bool builtin, bool method, bool thread, bool child);
|
||||
void emit_expr_call_function(const gsc::context_ptr& ctx, const gsc::expr_call_ptr& expr);
|
||||
void emit_expr_call_function_builtin(const gsc::context_ptr& ctx, const std::string& func, int args, bool method);
|
||||
void emit_expr_call_function_local(const gsc::context_ptr& ctx, const std::string& func, int args, bool method, bool thread, bool child);
|
||||
void emit_expr_call_function_far(const gsc::context_ptr& ctx, const std::string& file, const std::string& func, int args, bool method, bool thread, bool child);
|
||||
void emit_expr_arguments(const gsc::context_ptr& ctx, const gsc::expr_arguments_ptr& arg_list);
|
||||
void emit_expr_function(const gsc::context_ptr& ctx, const gsc::expr_function_ptr& node);
|
||||
void emit_expr_clear_variable(const gsc::context_ptr& ctx, const gsc::expr_ptr& lvalue);
|
||||
void emit_expr_add_array(const gsc::context_ptr& ctx, const gsc::expr_add_array_ptr& expr);
|
||||
void emit_expr_size(const gsc::context_ptr& ctx, const gsc::expr_size_ptr& expr);
|
||||
void emit_variable_ref(const gsc::context_ptr& ctx, const gsc::expr_ptr& expr, bool set);
|
||||
void emit_array_variable_ref(const gsc::context_ptr& ctx, const gsc::expr_array_ptr& expr, bool set);
|
||||
void emit_field_variable_ref(const gsc::context_ptr& ctx, const gsc::expr_field_ptr& expr, bool set);
|
||||
void emit_local_variable_ref(const gsc::context_ptr& ctx, const gsc::name_ptr& expr, bool set);
|
||||
void emit_variable(const gsc::context_ptr& ctx, const gsc::expr_ptr& expr);
|
||||
void emit_array_variable(const gsc::context_ptr& ctx, const gsc::expr_array_ptr& expr);
|
||||
void emit_field_variable(const gsc::context_ptr& ctx, const gsc::expr_field_ptr& expr);
|
||||
void emit_local_variable(const gsc::context_ptr& ctx, const gsc::name_ptr& expr);
|
||||
void emit_clear_local_variable(const gsc::context_ptr& ctx, const gsc::name_ptr& expr);
|
||||
void emit_create_local_vars(const gsc::context_ptr& ctx);
|
||||
void emit_remove_local_vars(const gsc::context_ptr& ctx);
|
||||
void emit_object(const gsc::context_ptr& ctx, const gsc::expr_ptr& expr);
|
||||
void emit_animtree(const gsc::context_ptr& ctx, const gsc::animtree_ptr& animtree);
|
||||
void emit_animation(const gsc::context_ptr& ctx, const gsc::animation_ptr& animation);
|
||||
void emit_istring(const gsc::context_ptr& ctx, const gsc::istring_ptr& str);
|
||||
void emit_string(const gsc::context_ptr& ctx, const gsc::string_ptr& str);
|
||||
void emit_color(const gsc::context_ptr& ctx, const gsc::color_ptr& color);
|
||||
void emit_vector(const gsc::context_ptr& ctx, const gsc::vector_ptr& vec);
|
||||
void emit_float(const gsc::context_ptr& ctx, const gsc::float_ptr& num);
|
||||
void emit_integer(const gsc::context_ptr& ctx, const gsc::integer_ptr& num);
|
||||
void emit_false(const gsc::context_ptr& ctx, const gsc::false_ptr& expr);
|
||||
void emit_true(const gsc::context_ptr& ctx, const gsc::true_ptr& expr);
|
||||
void emit_opcode(const gsc::context_ptr& ctx, opcode op);
|
||||
void emit_opcode(const gsc::context_ptr& ctx, opcode op, const std::string& data);
|
||||
void emit_opcode(const gsc::context_ptr& ctx, opcode op, const std::vector<std::string>& data);
|
||||
void process_thread(const gsc::context_ptr& ctx, const gsc::thread_ptr& thread);
|
||||
void process_parameters(const gsc::context_ptr& ctx, const gsc::parameters_ptr& params);
|
||||
void process_stmt(const gsc::context_ptr& ctx, const gsc::stmt_ptr& stmt);
|
||||
void process_stmt_list(const gsc::context_ptr& ctx, const gsc::stmt_list_ptr& stmt);
|
||||
void process_expr(const gsc::context_ptr& ctx, const gsc::expr_ptr& expr);
|
||||
void process_stmt_waittill(const gsc::context_ptr& ctx, const gsc::stmt_waittill_ptr& stmt);
|
||||
void process_stmt_if(const gsc::context_ptr& ctx, const gsc::stmt_if_ptr& stmt);
|
||||
void process_stmt_ifelse(const gsc::context_ptr& ctx, const gsc::stmt_ifelse_ptr& stmt);
|
||||
void process_stmt_while(const gsc::context_ptr& ctx, const gsc::stmt_while_ptr& stmt);
|
||||
void process_stmt_for(const gsc::context_ptr& ctx, const gsc::stmt_for_ptr& stmt);
|
||||
void process_stmt_foreach(const gsc::context_ptr& ctx, const gsc::stmt_foreach_ptr& stmt);
|
||||
void process_stmt_switch(const gsc::context_ptr& ctx, const gsc::stmt_switch_ptr& stmt);
|
||||
void process_stmt_break(const gsc::context_ptr& ctx, const gsc::stmt_break_ptr& stmt);
|
||||
void process_stmt_continue(const gsc::context_ptr& ctx, const gsc::stmt_continue_ptr& stmt);
|
||||
void process_stmt_return(const gsc::context_ptr& ctx, const gsc::stmt_return_ptr& stmt);
|
||||
void register_variable(const gsc::context_ptr& ctx, const std::string& name);
|
||||
void initialize_variable(const gsc::context_ptr& ctx, const gsc::name_ptr& name);
|
||||
void create_variable(const gsc::context_ptr& ctx, const gsc::name_ptr& name);
|
||||
auto variable_stack_index(const gsc::context_ptr& ctx, const gsc::name_ptr& name) -> std::uint8_t;
|
||||
auto variable_create_index(const gsc::context_ptr& ctx, const gsc::name_ptr& name) -> std::string;
|
||||
auto variable_access_index(const gsc::context_ptr& ctx, const gsc::name_ptr& name) -> std::string;
|
||||
auto variable_initialized(const gsc::context_ptr& ctx, const gsc::name_ptr& name) -> bool;
|
||||
auto is_include_call(const std::string& name, std::string& file) -> bool;
|
||||
auto is_local_call(const std::string& name) -> bool;
|
||||
auto is_builtin_call(const std::string& name) -> bool;
|
||||
auto is_builtin_func(const std::string& name) -> bool;
|
||||
auto is_builtin_method(const std::string& name) -> bool;
|
||||
auto is_constant_condition(const gsc::expr_ptr& expr) -> bool;
|
||||
auto create_label() -> std::string;
|
||||
auto insert_label() -> std::string;
|
||||
void insert_label(const std::string& label);
|
||||
|
||||
auto map_known_includes(const std::string& include) -> bool;
|
||||
};
|
||||
|
||||
} // namespace xsk::gsc::s4
|
3386
src/s4/xsk/decompiler.cpp
Normal file
3386
src/s4/xsk/decompiler.cpp
Normal file
File diff suppressed because it is too large
Load Diff
95
src/s4/xsk/decompiler.hpp
Normal file
95
src/s4/xsk/decompiler.hpp
Normal file
@ -0,0 +1,95 @@
|
||||
// Copyright 2021 xensik. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a GNU GPLv3 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace xsk::gsc::s4
|
||||
{
|
||||
|
||||
class decompiler : public gsc::decompiler
|
||||
{
|
||||
std::string filename_;
|
||||
std::unique_ptr<utils::byte_buffer> output_;
|
||||
gsc::program_ptr program_;
|
||||
gsc::thread_ptr func_;
|
||||
std::unordered_map<std::uint32_t, std::string> labels_;
|
||||
std::vector<std::string> expr_labels_;
|
||||
std::vector<std::string> tern_labels_;
|
||||
std::stack<gsc::node_ptr> stack_;
|
||||
std::vector<gsc::context> blocks_;
|
||||
|
||||
public:
|
||||
auto output() -> std::vector<std::uint8_t>;
|
||||
void decompile(const std::string& file, std::vector<gsc::function_ptr>& functions);
|
||||
|
||||
private:
|
||||
void decompile_function(const gsc::function_ptr& func);
|
||||
void decompile_statements(const gsc::function_ptr& func);
|
||||
void decompile_expr();
|
||||
void decompile_ternary();
|
||||
void decompile_block(const gsc::stmt_list_ptr& block);
|
||||
void decompile_search_infinite(const gsc::stmt_list_ptr& block);
|
||||
void decompile_search_loop(const gsc::stmt_list_ptr& block);
|
||||
void decompile_search_switch(const gsc::stmt_list_ptr& block);
|
||||
void decompile_search_ifelse(const gsc::stmt_list_ptr& block);
|
||||
void decompile_break_continue(const gsc::stmt_list_ptr& block);
|
||||
void decompile_if(const gsc::stmt_list_ptr& block, std::uint32_t start, std::uint32_t end);
|
||||
void decompile_ifelse(const gsc::stmt_list_ptr& block, std::uint32_t start, std::uint32_t end);
|
||||
void decompile_last_ifelse(const gsc::stmt_list_ptr& block, std::uint32_t start, std::uint32_t end);
|
||||
void decompile_infinite(const gsc::stmt_list_ptr& block, std::uint32_t start, std::uint32_t end);
|
||||
void decompile_loop(const gsc::stmt_list_ptr& block, std::uint32_t start, std::uint32_t end);
|
||||
void decompile_while(const gsc::stmt_list_ptr& block, std::uint32_t start, std::uint32_t end);
|
||||
void decompile_for(const gsc::stmt_list_ptr& block, std::uint32_t start, std::uint32_t end);
|
||||
void decompile_foreach(const gsc::stmt_list_ptr& block, std::uint32_t start, std::uint32_t end);
|
||||
void decompile_switch(const gsc::stmt_list_ptr& block, std::uint32_t start);
|
||||
auto find_location_reference(const gsc::stmt_list_ptr& block, std::uint32_t start, std::uint32_t end, const std::string& location) -> bool;
|
||||
auto find_location_index(const gsc::stmt_list_ptr& block, const std::string& location) -> std::uint32_t;
|
||||
auto last_location_index(const gsc::stmt_list_ptr& block, std::uint32_t index) -> bool;
|
||||
void process_stack(const gsc::thread_ptr& thread);
|
||||
void process_parameters(const gsc::context_ptr& ctx, const gsc::parameters_ptr& params);
|
||||
void process_stmt(const gsc::context_ptr& ctx, const gsc::stmt_ptr& stmt);
|
||||
void process_stmt_list(const gsc::context_ptr& ctx, const gsc::stmt_list_ptr& stmt);
|
||||
void process_stmt_call(const gsc::context_ptr& ctx, const gsc::stmt_call_ptr& stmt);
|
||||
void process_stmt_assign(const gsc::context_ptr& ctx, const gsc::stmt_assign_ptr& stmt);
|
||||
void process_stmt_endon(const gsc::context_ptr& ctx, const gsc::stmt_endon_ptr& stmt);
|
||||
void process_stmt_notify(const gsc::context_ptr& ctx, const gsc::stmt_notify_ptr& stmt);
|
||||
void process_stmt_wait(const gsc::context_ptr& ctx, const gsc::stmt_wait_ptr& stmt);
|
||||
void process_stmt_waittill(const gsc::context_ptr& ctx, const gsc::stmt_waittill_ptr& stmt);
|
||||
void process_stmt_waittillmatch(const gsc::context_ptr& ctx, const gsc::stmt_waittillmatch_ptr& stmt);
|
||||
void process_stmt_waittillframeend(const gsc::context_ptr& ctx, const gsc::stmt_waittillframeend_ptr& stmt);
|
||||
void process_stmt_if(const gsc::context_ptr& ctx, const gsc::stmt_if_ptr& stmt);
|
||||
void process_stmt_ifelse(const gsc::context_ptr& ctx, const gsc::stmt_ifelse_ptr& stmt);
|
||||
void process_stmt_while(const gsc::context_ptr& ctx, const gsc::stmt_while_ptr& stmt);
|
||||
void process_stmt_for(const gsc::context_ptr& ctx, const gsc::stmt_for_ptr& stmt);
|
||||
void process_stmt_foreach(const gsc::context_ptr& ctx, const gsc::stmt_foreach_ptr& stmt);
|
||||
void process_stmt_switch(const gsc::context_ptr& ctx, const gsc::stmt_switch_ptr& stmt);
|
||||
void process_stmt_cases(const gsc::context_ptr& ctx, const gsc::stmt_list_ptr& stmt);
|
||||
void process_stmt_break(const gsc::context_ptr& ctx, const gsc::stmt_break_ptr& stmt);
|
||||
void process_stmt_return(const gsc::context_ptr& ctx, const gsc::stmt_return_ptr& stmt);
|
||||
void process_expr(const gsc::context_ptr& ctx, gsc::expr_ptr& expr);
|
||||
void process_expr_assign(const gsc::context_ptr& ctx, gsc::expr_assign_ptr& expr);
|
||||
void process_expr_ternary(const gsc::context_ptr& ctx, const gsc::expr_ternary_ptr& expr);
|
||||
void process_expr_binary(const gsc::context_ptr& ctx, const gsc::expr_binary_ptr& expr);
|
||||
void process_expr_and(const gsc::context_ptr& ctx, const gsc::expr_and_ptr& expr);
|
||||
void process_expr_or(const gsc::context_ptr& ctx, const gsc::expr_or_ptr& expr);
|
||||
void process_expr_complement(const gsc::context_ptr& ctx, const gsc::expr_complement_ptr& expr);
|
||||
void process_expr_not(const gsc::context_ptr& ctx, const gsc::expr_not_ptr& expr);
|
||||
void process_expr_call(const gsc::context_ptr& ctx, const gsc::expr_call_ptr& expr);
|
||||
void process_expr_call_pointer(const gsc::context_ptr& ctx, const gsc::expr_call_ptr& expr);
|
||||
void process_expr_call_function(const gsc::context_ptr& ctx, const gsc::expr_call_ptr& expr);
|
||||
void process_expr_arguments(const gsc::context_ptr& ctx, const gsc::expr_arguments_ptr& arg_list);
|
||||
void process_expr_function(const gsc::context_ptr& ctx, const gsc::expr_function_ptr& node);
|
||||
void process_expr_add_array(const gsc::context_ptr& ctx, const gsc::expr_add_array_ptr& expr);
|
||||
void process_expr_size(const gsc::context_ptr& ctx, const gsc::expr_size_ptr& expr);
|
||||
void process_array_variable(const gsc::context_ptr& ctx, const gsc::expr_array_ptr& expr);
|
||||
void process_field_variable(const gsc::context_ptr& ctx, const gsc::expr_field_ptr& expr);
|
||||
void process_local_variable(const gsc::context_ptr& ctx, const gsc::name_ptr& expr);
|
||||
void process_vector(const gsc::context_ptr& ctx, const gsc::vector_ptr& vec);
|
||||
void process_var_create(const gsc::context_ptr& ctx, gsc::expr_ptr& expr, bool fromstmt = false);
|
||||
void process_var_access(const gsc::context_ptr& ctx, gsc::expr_ptr& expr);
|
||||
void process_var_remove(const gsc::context_ptr& ctx, const gsc::asm_remove_ptr& expr);
|
||||
};
|
||||
|
||||
} // namespace xsk::gsc::s4
|
644
src/s4/xsk/disassembler.cpp
Normal file
644
src/s4/xsk/disassembler.cpp
Normal file
@ -0,0 +1,644 @@
|
||||
// Copyright 2021 xensik. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a GNU GPLv3 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
#include "stdafx.hpp"
|
||||
#include "s4.hpp"
|
||||
|
||||
namespace xsk::gsc::s4
|
||||
{
|
||||
|
||||
auto disassembler::output() -> std::vector<gsc::function_ptr>
|
||||
{
|
||||
return std::move(functions_);
|
||||
}
|
||||
|
||||
auto disassembler::output_data() -> std::vector<std::uint8_t>
|
||||
{
|
||||
output_ = std::make_unique<utils::byte_buffer>(0x100000);
|
||||
|
||||
output_->write_string("// S4 PC GSCASM\n");
|
||||
output_->write_string("// Disassembled by https://github.com/xensik/gsc-tool\n");
|
||||
|
||||
for (auto& func : functions_)
|
||||
{
|
||||
this->print_function(func);
|
||||
}
|
||||
|
||||
std::vector<std::uint8_t> output;
|
||||
|
||||
output.resize(output_->pos());
|
||||
memcpy(output.data(), output_->buffer().data(), output.size());
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
void disassembler::disassemble(const std::string& file, std::vector<std::uint8_t>& script, std::vector<std::uint8_t>& stack)
|
||||
{
|
||||
filename_ = file;
|
||||
script_ = std::make_unique<utils::byte_buffer>(script);
|
||||
stack_ = std::make_unique<utils::byte_buffer>(stack);
|
||||
functions_.clear();
|
||||
|
||||
script_->seek(1);
|
||||
|
||||
while (stack_->is_avail() && script_->is_avail())
|
||||
{
|
||||
functions_.push_back(std::make_unique<gsc::function>());
|
||||
auto& func = functions_.back();
|
||||
|
||||
func->index = static_cast<std::uint32_t>(script_->pos());
|
||||
func->size = stack_->read<std::uint32_t>();
|
||||
func->id = stack_->read<std::uint32_t>();
|
||||
func->name = "sub_"s + (func->id == 0 ? stack_->read_c_string() : resolver::token_name(func->id));
|
||||
|
||||
this->dissasemble_function(func);
|
||||
|
||||
func->labels = labels_;
|
||||
labels_.clear();
|
||||
}
|
||||
|
||||
this->resolve_local_functions();
|
||||
}
|
||||
|
||||
void disassembler::dissasemble_function(const gsc::function_ptr& func)
|
||||
{
|
||||
auto size = func->size;
|
||||
|
||||
while (size > 0)
|
||||
{
|
||||
func->instructions.push_back(std::make_unique<gsc::instruction>());
|
||||
|
||||
auto& inst = func->instructions.back();
|
||||
inst->index = static_cast<std::uint32_t>(script_->pos());
|
||||
inst->opcode = script_->read<std::uint8_t>();
|
||||
inst->size = opcode_size(inst->opcode);
|
||||
|
||||
this->dissasemble_instruction(inst);
|
||||
|
||||
size -= inst->size;
|
||||
}
|
||||
}
|
||||
|
||||
void disassembler::dissasemble_instruction(const gsc::instruction_ptr& inst)
|
||||
{
|
||||
switch (opcode(inst->opcode))
|
||||
{
|
||||
case opcode::OP_CastFieldObject:
|
||||
case opcode::OP_plus:
|
||||
case opcode::OP_GetGameRef:
|
||||
case opcode::OP_GetThisthread:
|
||||
case opcode::OP_greater:
|
||||
case opcode::OP_shift_right:
|
||||
case opcode::OP_dec:
|
||||
case opcode::OP_bit_or:
|
||||
case opcode::OP_equality:
|
||||
case opcode::OP_ClearLocalVariableFieldCached0:
|
||||
case opcode::OP_notify:
|
||||
case opcode::OP_PreScriptCall:
|
||||
case opcode::OP_GetUndefined:
|
||||
case opcode::OP_SetLocalVariableFieldCached0:
|
||||
case opcode::OP_GetLevel:
|
||||
case opcode::OP_size:
|
||||
case opcode::OP_AddArray:
|
||||
case opcode::OP_endon:
|
||||
case opcode::OP_shift_left:
|
||||
case opcode::OP_EvalLocalArrayRefCached0:
|
||||
case opcode::OP_Return:
|
||||
case opcode::OP_SafeSetVariableFieldCached0:
|
||||
case opcode::OP_GetSelfObject:
|
||||
case opcode::OP_GetGame:
|
||||
case opcode::OP_EvalArray:
|
||||
case opcode::OP_GetSelf:
|
||||
case opcode::OP_End:
|
||||
case opcode::OP_less_equal:
|
||||
case opcode::OP_EvalLocalVariableCached0:
|
||||
case opcode::OP_EvalLocalVariableCached1:
|
||||
case opcode::OP_EvalLocalVariableCached2:
|
||||
case opcode::OP_EvalLocalVariableCached3:
|
||||
case opcode::OP_EvalLocalVariableCached4:
|
||||
case opcode::OP_EvalLocalVariableCached5:
|
||||
case opcode::OP_ScriptMethodCallPointer:
|
||||
case opcode::OP_checkclearparams:
|
||||
case opcode::OP_waittillmatch2:
|
||||
case opcode::OP_minus:
|
||||
case opcode::OP_greater_equal:
|
||||
case opcode::OP_vector:
|
||||
case opcode::OP_ClearArray:
|
||||
case opcode::OP_DecTop:
|
||||
case opcode::OP_CastBool:
|
||||
case opcode::OP_EvalArrayRef:
|
||||
case opcode::OP_GetZero:
|
||||
case opcode::OP_wait:
|
||||
case opcode::OP_waittill:
|
||||
case opcode::OP_GetAnimObject:
|
||||
case opcode::OP_mod:
|
||||
case opcode::OP_clearparams:
|
||||
case opcode::OP_ScriptFunctionCallPointer:
|
||||
case opcode::OP_EmptyArray:
|
||||
case opcode::OP_ClearVariableField:
|
||||
case opcode::OP_EvalNewLocalVariableRefCached0:
|
||||
case opcode::OP_BoolComplement:
|
||||
case opcode::OP_less:
|
||||
case opcode::OP_BoolNot:
|
||||
case opcode::OP_waittillFrameEnd:
|
||||
case opcode::OP_waitframe:
|
||||
case opcode::OP_GetLevelObject:
|
||||
case opcode::OP_inc:
|
||||
case opcode::OP_GetAnim:
|
||||
case opcode::OP_SetVariableField:
|
||||
case opcode::OP_divide:
|
||||
case opcode::OP_multiply:
|
||||
case opcode::OP_EvalLocalVariableRefCached0:
|
||||
case opcode::OP_bit_and:
|
||||
case opcode::OP_voidCodepos:
|
||||
case opcode::OP_inequality:
|
||||
case opcode::OP_bit_ex_or:
|
||||
// case opcode::OP_NOP:
|
||||
// case opcode::OP_abort:
|
||||
// case opcode::OP_object:
|
||||
// case opcode::OP_thread_object:
|
||||
case opcode::OP_EvalLocalVariable:
|
||||
case opcode::OP_EvalLocalVariableRef:
|
||||
// case opcode::OP_breakpoint:
|
||||
// case opcode::OP_assignmentBreakpoint:
|
||||
// case opcode::OP_manualAndAssignmentBreakpoint:
|
||||
case opcode::OP_BoolNotAfterAnd:
|
||||
case opcode::OP_IsDefined:
|
||||
case opcode::OP_IsTrue:
|
||||
break;
|
||||
case opcode::OP_GetByte:
|
||||
case opcode::OP_GetNegByte:
|
||||
inst->data.push_back(utils::string::va("%i", script_->read<std::uint8_t>()));
|
||||
break;
|
||||
case opcode::OP_GetUnsignedShort:
|
||||
case opcode::OP_GetNegUnsignedShort:
|
||||
inst->data.push_back(utils::string::va("%i", script_->read<std::uint16_t>()));
|
||||
break;
|
||||
case opcode::OP_GetInteger:
|
||||
inst->data.push_back(utils::string::va("%i", script_->read<std::int32_t>()));
|
||||
break;
|
||||
case opcode::OP_GetFloat:
|
||||
{
|
||||
auto val = script_->read<float>();
|
||||
inst->data.push_back(utils::string::va("%g%s", val, val == int(val) ? ".0" : ""));
|
||||
}
|
||||
break;
|
||||
case opcode::OP_GetVector:
|
||||
inst->data.push_back(utils::string::va("%g", script_->read<float>()));
|
||||
inst->data.push_back(utils::string::va("%g", script_->read<float>()));
|
||||
inst->data.push_back(utils::string::va("%g", script_->read<float>()));
|
||||
break;
|
||||
case opcode::OP_GetString:
|
||||
case opcode::OP_GetIString:
|
||||
script_->seek(4);
|
||||
inst->data.push_back(utils::string::to_literal(stack_->read_c_string()));
|
||||
break;
|
||||
case opcode::OP_GetAnimation:
|
||||
script_->seek(8);
|
||||
inst->data.push_back(utils::string::quote(stack_->read_c_string().data(), false));
|
||||
inst->data.push_back(utils::string::quote(stack_->read_c_string().data(), false));
|
||||
break;
|
||||
case opcode::OP_GetAnimTree:
|
||||
script_->seek(1);
|
||||
inst->data.push_back(utils::string::quote(stack_->read_c_string().data(), false));
|
||||
break;
|
||||
case opcode::OP_waittillmatch:
|
||||
inst->data.push_back(utils::string::va("%i", script_->read<std::uint16_t>()));
|
||||
break;
|
||||
case opcode::OP_SetNewLocalVariableFieldCached0:
|
||||
case opcode::OP_EvalNewLocalArrayRefCached0:
|
||||
case opcode::OP_SafeCreateVariableFieldCached:
|
||||
case opcode::OP_ClearLocalVariableFieldCached:
|
||||
case opcode::OP_SetLocalVariableFieldCached:
|
||||
case opcode::OP_RemoveLocalVariables:
|
||||
case opcode::OP_EvalLocalVariableRefCached:
|
||||
case opcode::OP_EvalLocalArrayRefCached:
|
||||
case opcode::OP_SafeSetVariableFieldCached:
|
||||
case opcode::OP_EvalLocalVariableCached:
|
||||
case opcode::OP_SafeSetWaittillVariableFieldCached:
|
||||
case opcode::OP_CreateLocalVariable:
|
||||
case opcode::OP_EvalLocalVariableObjectCached:
|
||||
case opcode::OP_EvalLocalArrayCached:
|
||||
inst->data.push_back(utils::string::va("%i", script_->read<std::uint8_t>()));
|
||||
break;
|
||||
case opcode::OP_EvalSelfFieldVariable:
|
||||
case opcode::OP_SetLevelFieldVariableField:
|
||||
case opcode::OP_ClearFieldVariable:
|
||||
case opcode::OP_EvalFieldVariable:
|
||||
case opcode::OP_EvalFieldVariableRef:
|
||||
case opcode::OP_EvalLevelFieldVariable:
|
||||
case opcode::OP_SetAnimFieldVariableField:
|
||||
case opcode::OP_SetSelfFieldVariableField:
|
||||
case opcode::OP_EvalAnimFieldVariableRef:
|
||||
case opcode::OP_EvalLevelFieldVariableRef:
|
||||
case opcode::OP_EvalAnimFieldVariable:
|
||||
case opcode::OP_EvalSelfFieldVariableRef:
|
||||
this->disassemble_field_variable(inst);
|
||||
break;
|
||||
case opcode::OP_CallBuiltinPointer:
|
||||
case opcode::OP_CallBuiltinMethodPointer:
|
||||
case opcode::OP_ScriptThreadCallPointer:
|
||||
case opcode::OP_ScriptChildThreadCallPointer:
|
||||
case opcode::OP_ScriptMethodThreadCallPointer:
|
||||
case opcode::OP_ScriptMethodChildThreadCallPointer:
|
||||
inst->data.push_back(utils::string::va("%i", script_->read<std::uint8_t>()));
|
||||
break;
|
||||
case opcode::OP_GetLocalFunction:
|
||||
case opcode::OP_ScriptLocalFunctionCall2:
|
||||
case opcode::OP_ScriptLocalFunctionCall:
|
||||
case opcode::OP_ScriptLocalMethodCall:
|
||||
this->disassemble_local_call(inst, false);
|
||||
break;
|
||||
case opcode::OP_ScriptLocalThreadCall:
|
||||
case opcode::OP_ScriptLocalChildThreadCall:
|
||||
case opcode::OP_ScriptLocalMethodThreadCall:
|
||||
case opcode::OP_ScriptLocalMethodChildThreadCall:
|
||||
this->disassemble_local_call(inst, true);
|
||||
break;
|
||||
case opcode::OP_GetFarFunction:
|
||||
case opcode::OP_ScriptFarFunctionCall2:
|
||||
case opcode::OP_ScriptFarFunctionCall:
|
||||
case opcode::OP_ScriptFarMethodCall:
|
||||
this->disassemble_far_call(inst, false);
|
||||
break;
|
||||
case opcode::OP_ScriptFarThreadCall:
|
||||
case opcode::OP_ScriptFarChildThreadCall:
|
||||
case opcode::OP_ScriptFarMethodThreadCall:
|
||||
case opcode::OP_ScriptFarMethodChildThreadCall:
|
||||
this->disassemble_far_call(inst, true);
|
||||
break;
|
||||
case opcode::OP_CallBuiltin:
|
||||
this->disassemble_builtin_call(inst, false, true);
|
||||
break;
|
||||
case opcode::OP_CallBuiltinMethod:
|
||||
this->disassemble_builtin_call(inst, true, true);
|
||||
break;
|
||||
case opcode::OP_GetBuiltinFunction:
|
||||
case opcode::OP_CallBuiltin0:
|
||||
case opcode::OP_CallBuiltin1:
|
||||
case opcode::OP_CallBuiltin2:
|
||||
case opcode::OP_CallBuiltin3:
|
||||
case opcode::OP_CallBuiltin4:
|
||||
case opcode::OP_CallBuiltin5:
|
||||
this->disassemble_builtin_call(inst, false, false);
|
||||
break;
|
||||
case opcode::OP_GetBuiltinMethod:
|
||||
case opcode::OP_CallBuiltinMethod0:
|
||||
case opcode::OP_CallBuiltinMethod1:
|
||||
case opcode::OP_CallBuiltinMethod2:
|
||||
case opcode::OP_CallBuiltinMethod3:
|
||||
case opcode::OP_CallBuiltinMethod4:
|
||||
case opcode::OP_CallBuiltinMethod5:
|
||||
this->disassemble_builtin_call(inst, true, false);
|
||||
break;
|
||||
case opcode::OP_JumpOnFalse:
|
||||
case opcode::OP_JumpOnTrue:
|
||||
case opcode::OP_JumpOnFalseExpr:
|
||||
case opcode::OP_JumpOnTrueExpr:
|
||||
this->disassemble_jump(inst, true, false);
|
||||
break;
|
||||
case opcode::OP_jumpback:
|
||||
this->disassemble_jump(inst, false, true);
|
||||
break;
|
||||
case opcode::OP_jump:
|
||||
this->disassemble_jump(inst, false, false);
|
||||
break;
|
||||
case opcode::OP_switch:
|
||||
this->disassemble_switch(inst);
|
||||
break;
|
||||
case opcode::OP_endswitch:
|
||||
this->disassemble_end_switch(inst);
|
||||
break;
|
||||
/*
|
||||
case opcode::OP_prof_begin:
|
||||
script_->seek(5); // TODO: skipped data
|
||||
break;
|
||||
case opcode::OP_prof_end:
|
||||
script_->seek(1); // TODO: skipped data
|
||||
break;
|
||||
case opcode::OP_EvalNewLocalArrayRefCached0_Precompiled:
|
||||
case opcode::OP_SetNewLocalVariableFieldCached0_Precompiled:
|
||||
case opcode::OP_CreateLocalVariable_Precompiled:
|
||||
case opcode::OP_SafeCreateVariableFieldCached_Precompiled:
|
||||
inst->data.push_back(utils::string::va("%i", script_->read<std::uint8_t>()));
|
||||
break;
|
||||
*/
|
||||
case opcode::OP_FormalParams:
|
||||
case opcode::OP_FormalParams_Precompiled:
|
||||
this->disassemble_formal_params(inst);
|
||||
break;
|
||||
/* case opcode::OP_NativeGetLocalFunction:
|
||||
case opcode::OP_NativeLocalFunctionCall:
|
||||
case opcode::OP_NativeLocalFunctionCall2:
|
||||
case opcode::OP_NativeLocalMethodCall:
|
||||
this->disassemble_local_call(inst, false);
|
||||
break;
|
||||
case opcode::OP_NativeGetFarFunction:
|
||||
case opcode::OP_NativeFarFunctionCall:
|
||||
case opcode::OP_NativeFarFunctionCall2:
|
||||
case opcode::OP_NativeFarMethodCall:
|
||||
this->disassemble_far_call(inst, false);
|
||||
break;
|
||||
case opcode::OP_NativeLocalFunctionThreadCall:
|
||||
case opcode::OP_NativeLocalMethodThreadCall:
|
||||
case opcode::OP_NativeLocalFunctionChildThreadCall:
|
||||
case opcode::OP_NativeLocalMethodChildThreadCall:
|
||||
this->disassemble_local_call(inst, true);
|
||||
break;
|
||||
case opcode::OP_NativeFarFunctionThreadCall:
|
||||
case opcode::OP_NativeFarMethodThreadCall:
|
||||
case opcode::OP_NativeFarFunctionChildThreadCall:
|
||||
case opcode::OP_NativeFarMethodChildThreadCall:
|
||||
this->disassemble_far_call(inst, true);
|
||||
break;
|
||||
*/
|
||||
default:
|
||||
throw gsc::disasm_error(utils::string::va("Unhandled opcode 0x%X at index '%04X'!", inst->opcode, inst->index));
|
||||
}
|
||||
}
|
||||
|
||||
void disassembler::disassemble_builtin_call(const gsc::instruction_ptr& inst, bool method, bool arg_num)
|
||||
{
|
||||
if (arg_num)
|
||||
{
|
||||
inst->data.push_back(utils::string::va("%i", script_->read<std::uint8_t>()));
|
||||
}
|
||||
|
||||
if (method)
|
||||
{
|
||||
inst->data.push_back(resolver::method_name(script_->read<std::uint16_t>()));
|
||||
}
|
||||
else
|
||||
{
|
||||
inst->data.push_back(resolver::function_name(script_->read<std::uint16_t>()));
|
||||
}
|
||||
}
|
||||
|
||||
void disassembler::disassemble_local_call(const gsc::instruction_ptr& inst, bool thread)
|
||||
{
|
||||
std::int32_t offset = this->disassemble_offset();
|
||||
|
||||
inst->data.push_back(utils::string::va("%X", offset + inst->index + 1));
|
||||
|
||||
if (thread)
|
||||
{
|
||||
inst->data.push_back(utils::string::va("%i", script_->read<std::uint8_t>()));
|
||||
}
|
||||
}
|
||||
|
||||
void disassembler::disassemble_far_call(const gsc::instruction_ptr& inst, bool thread)
|
||||
{
|
||||
script_->seek(3);
|
||||
|
||||
if (thread)
|
||||
{
|
||||
inst->data.push_back(utils::string::va("%i", script_->read<std::uint8_t>()));
|
||||
}
|
||||
|
||||
auto file_id = stack_->read<std::uint32_t>();
|
||||
auto file_name = file_id == 0 ? stack_->read_c_string() : resolver::file_name(file_id);
|
||||
auto func_id = stack_->read<std::uint32_t>();
|
||||
auto func_name = func_id == 0 ? stack_->read_c_string() : resolver::token_name(func_id);
|
||||
|
||||
inst->data.push_back(file_name != "" ? file_name : utils::string::va("_ID%i", file_id));
|
||||
inst->data.push_back(func_name != "" ? func_name : utils::string::va("_ID%i", func_id));
|
||||
}
|
||||
|
||||
void disassembler::disassemble_jump(const gsc::instruction_ptr& inst, bool expr, bool back)
|
||||
{
|
||||
std::int32_t addr;
|
||||
std::string label;
|
||||
|
||||
if (expr)
|
||||
{
|
||||
addr = inst->index + 3 + script_->read<std::int16_t>();
|
||||
label = utils::string::va("loc_%X", addr);
|
||||
inst->data.push_back(label);
|
||||
}
|
||||
else if (back)
|
||||
{
|
||||
addr = inst->index + 3 - script_->read<std::uint16_t>();
|
||||
label = utils::string::va("loc_%X", addr);
|
||||
inst->data.push_back(label);
|
||||
}
|
||||
else
|
||||
{
|
||||
addr = inst->index + 5 + script_->read<std::int32_t>();
|
||||
label = utils::string::va("loc_%X", addr);
|
||||
inst->data.push_back(label);
|
||||
}
|
||||
|
||||
labels_.insert({addr, label});
|
||||
}
|
||||
|
||||
void disassembler::disassemble_field_variable(const gsc::instruction_ptr& inst)
|
||||
{
|
||||
std::uint32_t field_id = script_->read<std::uint32_t>();
|
||||
std::string field_name;
|
||||
|
||||
if(field_id > 0x1C000)
|
||||
{
|
||||
auto temp = stack_->read<std::uint32_t>();
|
||||
field_name = temp == 0 ? stack_->read_c_string() : std::to_string(temp);
|
||||
}
|
||||
else
|
||||
{
|
||||
field_name = resolver::token_name(field_id);
|
||||
}
|
||||
|
||||
inst->data.push_back(field_name != "" ? field_name : utils::string::va("_ID%i", field_id));
|
||||
}
|
||||
|
||||
void disassembler::disassemble_formal_params(const gsc::instruction_ptr& inst)
|
||||
{
|
||||
auto size = script_->read<std::uint8_t>();
|
||||
|
||||
inst->size += size;
|
||||
inst->data.push_back(utils::string::va("%i", size));
|
||||
|
||||
while(size > 0)
|
||||
{
|
||||
inst->data.push_back(utils::string::va("%d", script_->read<std::uint8_t>()));
|
||||
size--;
|
||||
}
|
||||
}
|
||||
|
||||
void disassembler::disassemble_switch(const gsc::instruction_ptr& inst)
|
||||
{
|
||||
std::int32_t addr = inst->index + 4 + script_->read<std::int32_t>();
|
||||
std::string label = utils::string::va("loc_%X", addr);
|
||||
|
||||
inst->data.push_back(label);
|
||||
labels_.insert({addr, label});
|
||||
}
|
||||
|
||||
void disassembler::disassemble_end_switch(const gsc::instruction_ptr& inst)
|
||||
{
|
||||
std::uint16_t case_num = script_->read<std::uint16_t>();
|
||||
inst->data.push_back(utils::string::va("%i", case_num));
|
||||
|
||||
std::uint32_t internal_index = inst->index + 3;
|
||||
|
||||
if (case_num)
|
||||
{
|
||||
for (auto i = case_num; i > 0; i--)
|
||||
{
|
||||
std::uint32_t case_label = script_->read<std::uint32_t>();
|
||||
|
||||
if (case_label < 0x80000 && case_label > 0)
|
||||
{
|
||||
inst->data.push_back("case");
|
||||
inst->data.push_back(utils::string::quote(stack_->read_c_string(), false));
|
||||
}
|
||||
else if (case_label == 0)
|
||||
{
|
||||
inst->data.push_back("default");
|
||||
stack_->read<std::uint16_t>();
|
||||
}
|
||||
else
|
||||
{
|
||||
inst->data.push_back("case");
|
||||
inst->data.push_back(utils::string::va("%i", (case_label - 0x800000) & 0xFFFFFF));
|
||||
}
|
||||
|
||||
inst->size += 4;
|
||||
internal_index += 4;
|
||||
|
||||
auto addr = this->disassemble_offset() + internal_index;
|
||||
std::string label = utils::string::va("loc_%X", addr);
|
||||
inst->data.push_back(label);
|
||||
|
||||
labels_.insert({addr, label});
|
||||
|
||||
inst->size += 3;
|
||||
internal_index += 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto disassembler::disassemble_offset() -> std::int32_t
|
||||
{
|
||||
std::array<std::uint8_t, 4> bytes = {};
|
||||
|
||||
for (auto i = 0; i < 3; i++)
|
||||
{
|
||||
bytes[i] = script_->read<std::uint8_t>();
|
||||
}
|
||||
|
||||
std::int32_t offset = *reinterpret_cast<std::int32_t*>(bytes.data());
|
||||
|
||||
offset = (offset << 8) >> 8;
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
void disassembler::resolve_local_functions()
|
||||
{
|
||||
for (auto& func : functions_)
|
||||
{
|
||||
for (auto& inst : func->instructions)
|
||||
{
|
||||
switch (opcode(inst->opcode))
|
||||
{
|
||||
case opcode::OP_GetLocalFunction:
|
||||
case opcode::OP_ScriptLocalFunctionCall:
|
||||
case opcode::OP_ScriptLocalFunctionCall2:
|
||||
case opcode::OP_ScriptLocalMethodCall:
|
||||
case opcode::OP_ScriptLocalThreadCall:
|
||||
case opcode::OP_ScriptLocalChildThreadCall:
|
||||
case opcode::OP_ScriptLocalMethodThreadCall:
|
||||
case opcode::OP_ScriptLocalMethodChildThreadCall:
|
||||
inst->data.at(0) = this->resolve_function(inst->data[0]);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto disassembler::resolve_function(const std::string& index) -> std::string
|
||||
{
|
||||
if (utils::string::is_hex_number(index))
|
||||
{
|
||||
std::uint32_t idx = std::stoul(index, nullptr, 16);
|
||||
|
||||
for (auto& func : functions_)
|
||||
{
|
||||
if (func->index == idx)
|
||||
{
|
||||
return func->name;
|
||||
}
|
||||
}
|
||||
|
||||
throw gsc::disasm_error(utils::string::va("Couldn't resolve function name at index '0x%04X'!", idx));
|
||||
}
|
||||
|
||||
throw gsc::disasm_error(utils::string::va("\"%s\" is not valid function address!", index.data()));
|
||||
}
|
||||
|
||||
void disassembler::print_function(const gsc::function_ptr& func)
|
||||
{
|
||||
output_->write_string("\n");
|
||||
output_->write_string(utils::string::va("%s\n", func->name.data()));
|
||||
|
||||
for (auto& inst : func->instructions)
|
||||
{
|
||||
const auto itr = func->labels.find(inst->index);
|
||||
|
||||
if (itr != func->labels.end())
|
||||
{
|
||||
output_->write_string(utils::string::va("\t%s\n", itr->second.data()));
|
||||
}
|
||||
|
||||
this->print_instruction(inst);
|
||||
}
|
||||
|
||||
output_->write_string("\n");
|
||||
output_->write_string(utils::string::va("end_%s\n", func->name.substr(4).data()));
|
||||
}
|
||||
|
||||
void disassembler::print_instruction(const gsc::instruction_ptr& inst)
|
||||
{
|
||||
switch (opcode(inst->opcode))
|
||||
{
|
||||
case opcode::OP_endswitch:
|
||||
output_->write_string(utils::string::va("\t\t%s", resolver::opcode_name(inst->opcode).data()));
|
||||
output_->write_string(utils::string::va(" %s\n", inst->data[0].data()));
|
||||
{
|
||||
std::uint32_t totalcase = std::stoul(inst->data[0]);
|
||||
auto index = 0;
|
||||
for (auto casenum = 0u; casenum < totalcase; casenum++)
|
||||
{
|
||||
if (inst->data[1 + index] == "case")
|
||||
{
|
||||
output_->write_string(utils::string::va("\t\t\t%s %s %s", inst->data[1 + index].data(), inst->data[1 + index + 1].data(), inst->data[1 + index + 2].data()));
|
||||
index += 3;
|
||||
}
|
||||
else if (inst->data[1 + index] == "default")
|
||||
{
|
||||
output_->write_string(utils::string::va("\t\t\t%s %s", inst->data[1 + index].data(), inst->data[1 + index + 1].data()));
|
||||
index += 2;
|
||||
}
|
||||
if (casenum != totalcase - 1)
|
||||
{
|
||||
output_->write_string("\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
output_->write_string(utils::string::va("\t\t%s", resolver::opcode_name(inst->opcode).data()));
|
||||
for (auto& d : inst->data)
|
||||
{
|
||||
output_->write_string(utils::string::va(" %s", d.data()));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
output_->write_string("\n");
|
||||
}
|
||||
|
||||
} // namespace xsk::gsc::s4
|
43
src/s4/xsk/disassembler.hpp
Normal file
43
src/s4/xsk/disassembler.hpp
Normal file
@ -0,0 +1,43 @@
|
||||
// Copyright 2021 xensik. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a GNU GPLv3 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace xsk::gsc::s4
|
||||
{
|
||||
|
||||
class disassembler : public gsc::disassembler
|
||||
{
|
||||
std::string filename_;
|
||||
utils::byte_buffer_ptr script_;
|
||||
utils::byte_buffer_ptr stack_;
|
||||
utils::byte_buffer_ptr output_;
|
||||
std::vector<gsc::function_ptr> functions_;
|
||||
std::unordered_map<std::uint32_t, std::string> labels_;
|
||||
|
||||
public:
|
||||
auto output() -> std::vector<gsc::function_ptr>;
|
||||
auto output_data() -> std::vector<std::uint8_t>;
|
||||
void disassemble(const std::string& file, std::vector<std::uint8_t>& script, std::vector<std::uint8_t>& stack);
|
||||
|
||||
private:
|
||||
void dissasemble_function(const gsc::function_ptr& func);
|
||||
void dissasemble_instruction(const gsc::instruction_ptr& inst);
|
||||
void disassemble_builtin_call(const gsc::instruction_ptr& inst, bool method, bool arg_num);
|
||||
void disassemble_local_call(const gsc::instruction_ptr& inst, bool thread);
|
||||
void disassemble_far_call(const gsc::instruction_ptr& inst, bool thread);
|
||||
void disassemble_jump(const gsc::instruction_ptr& inst, bool expr, bool back);
|
||||
void disassemble_field_variable(const gsc::instruction_ptr& inst);
|
||||
void disassemble_formal_params(const gsc::instruction_ptr& inst);
|
||||
void disassemble_switch(const gsc::instruction_ptr& inst);
|
||||
void disassemble_end_switch(const gsc::instruction_ptr& inst);
|
||||
auto disassemble_offset() -> std::int32_t;
|
||||
void resolve_local_functions();
|
||||
auto resolve_function(const std::string& index) -> std::string;
|
||||
void print_function(const gsc::function_ptr& func);
|
||||
void print_instruction(const gsc::instruction_ptr& inst);
|
||||
};
|
||||
|
||||
} // namespace xsk::gsc::s4
|
2882
src/s4/xsk/lexer.cpp
Normal file
2882
src/s4/xsk/lexer.cpp
Normal file
File diff suppressed because it is too large
Load Diff
708
src/s4/xsk/lexer.hpp
Normal file
708
src/s4/xsk/lexer.hpp
Normal file
@ -0,0 +1,708 @@
|
||||
#ifndef s4_HEADER_H
|
||||
#define s4_HEADER_H 1
|
||||
#define s4_IN_HEADER 1
|
||||
|
||||
#line 5 "lexer.hpp"
|
||||
#include "stdafx.hpp"
|
||||
#include "s4.hpp"
|
||||
#include "parser.hpp"
|
||||
using namespace xsk::gsc;
|
||||
|
||||
#line 11 "lexer.hpp"
|
||||
|
||||
#define YY_INT_ALIGNED short int
|
||||
|
||||
/* A lexical scanner generated by flex */
|
||||
|
||||
#define FLEX_SCANNER
|
||||
#define YY_FLEX_MAJOR_VERSION 2
|
||||
#define YY_FLEX_MINOR_VERSION 6
|
||||
#define YY_FLEX_SUBMINOR_VERSION 4
|
||||
#if YY_FLEX_SUBMINOR_VERSION > 0
|
||||
#define FLEX_BETA
|
||||
#endif
|
||||
|
||||
#ifdef yy_create_buffer
|
||||
#define s4__create_buffer_ALREADY_DEFINED
|
||||
#else
|
||||
#define yy_create_buffer s4__create_buffer
|
||||
#endif
|
||||
|
||||
#ifdef yy_delete_buffer
|
||||
#define s4__delete_buffer_ALREADY_DEFINED
|
||||
#else
|
||||
#define yy_delete_buffer s4__delete_buffer
|
||||
#endif
|
||||
|
||||
#ifdef yy_scan_buffer
|
||||
#define s4__scan_buffer_ALREADY_DEFINED
|
||||
#else
|
||||
#define yy_scan_buffer s4__scan_buffer
|
||||
#endif
|
||||
|
||||
#ifdef yy_scan_string
|
||||
#define s4__scan_string_ALREADY_DEFINED
|
||||
#else
|
||||
#define yy_scan_string s4__scan_string
|
||||
#endif
|
||||
|
||||
#ifdef yy_scan_bytes
|
||||
#define s4__scan_bytes_ALREADY_DEFINED
|
||||
#else
|
||||
#define yy_scan_bytes s4__scan_bytes
|
||||
#endif
|
||||
|
||||
#ifdef yy_init_buffer
|
||||
#define s4__init_buffer_ALREADY_DEFINED
|
||||
#else
|
||||
#define yy_init_buffer s4__init_buffer
|
||||
#endif
|
||||
|
||||
#ifdef yy_flush_buffer
|
||||
#define s4__flush_buffer_ALREADY_DEFINED
|
||||
#else
|
||||
#define yy_flush_buffer s4__flush_buffer
|
||||
#endif
|
||||
|
||||
#ifdef yy_load_buffer_state
|
||||
#define s4__load_buffer_state_ALREADY_DEFINED
|
||||
#else
|
||||
#define yy_load_buffer_state s4__load_buffer_state
|
||||
#endif
|
||||
|
||||
#ifdef yy_switch_to_buffer
|
||||
#define s4__switch_to_buffer_ALREADY_DEFINED
|
||||
#else
|
||||
#define yy_switch_to_buffer s4__switch_to_buffer
|
||||
#endif
|
||||
|
||||
#ifdef yypush_buffer_state
|
||||
#define s4_push_buffer_state_ALREADY_DEFINED
|
||||
#else
|
||||
#define yypush_buffer_state s4_push_buffer_state
|
||||
#endif
|
||||
|
||||
#ifdef yypop_buffer_state
|
||||
#define s4_pop_buffer_state_ALREADY_DEFINED
|
||||
#else
|
||||
#define yypop_buffer_state s4_pop_buffer_state
|
||||
#endif
|
||||
|
||||
#ifdef yyensure_buffer_stack
|
||||
#define s4_ensure_buffer_stack_ALREADY_DEFINED
|
||||
#else
|
||||
#define yyensure_buffer_stack s4_ensure_buffer_stack
|
||||
#endif
|
||||
|
||||
#ifdef yylex
|
||||
#define s4_lex_ALREADY_DEFINED
|
||||
#else
|
||||
#define yylex s4_lex
|
||||
#endif
|
||||
|
||||
#ifdef yyrestart
|
||||
#define s4_restart_ALREADY_DEFINED
|
||||
#else
|
||||
#define yyrestart s4_restart
|
||||
#endif
|
||||
|
||||
#ifdef yylex_init
|
||||
#define s4_lex_init_ALREADY_DEFINED
|
||||
#else
|
||||
#define yylex_init s4_lex_init
|
||||
#endif
|
||||
|
||||
#ifdef yylex_init_extra
|
||||
#define s4_lex_init_extra_ALREADY_DEFINED
|
||||
#else
|
||||
#define yylex_init_extra s4_lex_init_extra
|
||||
#endif
|
||||
|
||||
#ifdef yylex_destroy
|
||||
#define s4_lex_destroy_ALREADY_DEFINED
|
||||
#else
|
||||
#define yylex_destroy s4_lex_destroy
|
||||
#endif
|
||||
|
||||
#ifdef yyget_debug
|
||||
#define s4_get_debug_ALREADY_DEFINED
|
||||
#else
|
||||
#define yyget_debug s4_get_debug
|
||||
#endif
|
||||
|
||||
#ifdef yyset_debug
|
||||
#define s4_set_debug_ALREADY_DEFINED
|
||||
#else
|
||||
#define yyset_debug s4_set_debug
|
||||
#endif
|
||||
|
||||
#ifdef yyget_extra
|
||||
#define s4_get_extra_ALREADY_DEFINED
|
||||
#else
|
||||
#define yyget_extra s4_get_extra
|
||||
#endif
|
||||
|
||||
#ifdef yyset_extra
|
||||
#define s4_set_extra_ALREADY_DEFINED
|
||||
#else
|
||||
#define yyset_extra s4_set_extra
|
||||
#endif
|
||||
|
||||
#ifdef yyget_in
|
||||
#define s4_get_in_ALREADY_DEFINED
|
||||
#else
|
||||
#define yyget_in s4_get_in
|
||||
#endif
|
||||
|
||||
#ifdef yyset_in
|
||||
#define s4_set_in_ALREADY_DEFINED
|
||||
#else
|
||||
#define yyset_in s4_set_in
|
||||
#endif
|
||||
|
||||
#ifdef yyget_out
|
||||
#define s4_get_out_ALREADY_DEFINED
|
||||
#else
|
||||
#define yyget_out s4_get_out
|
||||
#endif
|
||||
|
||||
#ifdef yyset_out
|
||||
#define s4_set_out_ALREADY_DEFINED
|
||||
#else
|
||||
#define yyset_out s4_set_out
|
||||
#endif
|
||||
|
||||
#ifdef yyget_leng
|
||||
#define s4_get_leng_ALREADY_DEFINED
|
||||
#else
|
||||
#define yyget_leng s4_get_leng
|
||||
#endif
|
||||
|
||||
#ifdef yyget_text
|
||||
#define s4_get_text_ALREADY_DEFINED
|
||||
#else
|
||||
#define yyget_text s4_get_text
|
||||
#endif
|
||||
|
||||
#ifdef yyget_lineno
|
||||
#define s4_get_lineno_ALREADY_DEFINED
|
||||
#else
|
||||
#define yyget_lineno s4_get_lineno
|
||||
#endif
|
||||
|
||||
#ifdef yyset_lineno
|
||||
#define s4_set_lineno_ALREADY_DEFINED
|
||||
#else
|
||||
#define yyset_lineno s4_set_lineno
|
||||
#endif
|
||||
|
||||
#ifdef yyget_column
|
||||
#define s4_get_column_ALREADY_DEFINED
|
||||
#else
|
||||
#define yyget_column s4_get_column
|
||||
#endif
|
||||
|
||||
#ifdef yyset_column
|
||||
#define s4_set_column_ALREADY_DEFINED
|
||||
#else
|
||||
#define yyset_column s4_set_column
|
||||
#endif
|
||||
|
||||
#ifdef yywrap
|
||||
#define s4_wrap_ALREADY_DEFINED
|
||||
#else
|
||||
#define yywrap s4_wrap
|
||||
#endif
|
||||
|
||||
#ifdef yyalloc
|
||||
#define s4_alloc_ALREADY_DEFINED
|
||||
#else
|
||||
#define yyalloc s4_alloc
|
||||
#endif
|
||||
|
||||
#ifdef yyrealloc
|
||||
#define s4_realloc_ALREADY_DEFINED
|
||||
#else
|
||||
#define yyrealloc s4_realloc
|
||||
#endif
|
||||
|
||||
#ifdef yyfree
|
||||
#define s4_free_ALREADY_DEFINED
|
||||
#else
|
||||
#define yyfree s4_free
|
||||
#endif
|
||||
|
||||
/* First, we deal with platform-specific or compiler-specific issues. */
|
||||
|
||||
/* begin standard C headers. */
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
/* end standard C headers. */
|
||||
|
||||
/* flex integer type definitions */
|
||||
|
||||
#ifndef FLEXINT_H
|
||||
#define FLEXINT_H
|
||||
|
||||
/* C99 systems have <inttypes.h>. Non-C99 systems may or may not. */
|
||||
|
||||
#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
|
||||
|
||||
/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h,
|
||||
* if you want the limit (max/min) macros for int types.
|
||||
*/
|
||||
#ifndef __STDC_LIMIT_MACROS
|
||||
#define __STDC_LIMIT_MACROS 1
|
||||
#endif
|
||||
|
||||
#include <inttypes.h>
|
||||
typedef int8_t flex_int8_t;
|
||||
typedef uint8_t flex_uint8_t;
|
||||
typedef int16_t flex_int16_t;
|
||||
typedef uint16_t flex_uint16_t;
|
||||
typedef int32_t flex_int32_t;
|
||||
typedef uint32_t flex_uint32_t;
|
||||
#else
|
||||
typedef signed char flex_int8_t;
|
||||
typedef short int flex_int16_t;
|
||||
typedef int flex_int32_t;
|
||||
typedef unsigned char flex_uint8_t;
|
||||
typedef unsigned short int flex_uint16_t;
|
||||
typedef unsigned int flex_uint32_t;
|
||||
|
||||
/* Limits of integral types. */
|
||||
#ifndef INT8_MIN
|
||||
#define INT8_MIN (-128)
|
||||
#endif
|
||||
#ifndef INT16_MIN
|
||||
#define INT16_MIN (-32767-1)
|
||||
#endif
|
||||
#ifndef INT32_MIN
|
||||
#define INT32_MIN (-2147483647-1)
|
||||
#endif
|
||||
#ifndef INT8_MAX
|
||||
#define INT8_MAX (127)
|
||||
#endif
|
||||
#ifndef INT16_MAX
|
||||
#define INT16_MAX (32767)
|
||||
#endif
|
||||
#ifndef INT32_MAX
|
||||
#define INT32_MAX (2147483647)
|
||||
#endif
|
||||
#ifndef UINT8_MAX
|
||||
#define UINT8_MAX (255U)
|
||||
#endif
|
||||
#ifndef UINT16_MAX
|
||||
#define UINT16_MAX (65535U)
|
||||
#endif
|
||||
#ifndef UINT32_MAX
|
||||
#define UINT32_MAX (4294967295U)
|
||||
#endif
|
||||
|
||||
#ifndef SIZE_MAX
|
||||
#define SIZE_MAX (~(size_t)0)
|
||||
#endif
|
||||
|
||||
#endif /* ! C99 */
|
||||
|
||||
#endif /* ! FLEXINT_H */
|
||||
|
||||
/* begin standard C++ headers. */
|
||||
|
||||
/* TODO: this is always defined, so inline it */
|
||||
#define yyconst const
|
||||
|
||||
#if defined(__GNUC__) && __GNUC__ >= 3
|
||||
#define yynoreturn __attribute__((__noreturn__))
|
||||
#else
|
||||
#define yynoreturn
|
||||
#endif
|
||||
|
||||
/* An opaque pointer. */
|
||||
#ifndef YY_TYPEDEF_YY_SCANNER_T
|
||||
#define YY_TYPEDEF_YY_SCANNER_T
|
||||
typedef void* yyscan_t;
|
||||
#endif
|
||||
|
||||
/* For convenience, these vars (plus the bison vars far below)
|
||||
are macros in the reentrant scanner. */
|
||||
#define yyin yyg->yyin_r
|
||||
#define yyout yyg->yyout_r
|
||||
#define yyextra yyg->yyextra_r
|
||||
#define yyleng yyg->yyleng_r
|
||||
#define yytext yyg->yytext_r
|
||||
#define yylineno (YY_CURRENT_BUFFER_LVALUE->yy_bs_lineno)
|
||||
#define yycolumn (YY_CURRENT_BUFFER_LVALUE->yy_bs_column)
|
||||
#define yy_flex_debug yyg->yy_flex_debug_r
|
||||
|
||||
/* Size of default input buffer. */
|
||||
#ifndef YY_BUF_SIZE
|
||||
#ifdef __ia64__
|
||||
/* On IA-64, the buffer size is 16k, not 8k.
|
||||
* Moreover, YY_BUF_SIZE is 2*YY_READ_BUF_SIZE in the general case.
|
||||
* Ditto for the __ia64__ case accordingly.
|
||||
*/
|
||||
#define YY_BUF_SIZE 32768
|
||||
#else
|
||||
#define YY_BUF_SIZE 16384
|
||||
#endif /* __ia64__ */
|
||||
#endif
|
||||
|
||||
#ifndef YY_TYPEDEF_YY_BUFFER_STATE
|
||||
#define YY_TYPEDEF_YY_BUFFER_STATE
|
||||
typedef struct yy_buffer_state *YY_BUFFER_STATE;
|
||||
#endif
|
||||
|
||||
#ifndef YY_TYPEDEF_YY_SIZE_T
|
||||
#define YY_TYPEDEF_YY_SIZE_T
|
||||
typedef size_t yy_size_t;
|
||||
#endif
|
||||
|
||||
#ifndef YY_STRUCT_YY_BUFFER_STATE
|
||||
#define YY_STRUCT_YY_BUFFER_STATE
|
||||
struct yy_buffer_state
|
||||
{
|
||||
FILE *yy_input_file;
|
||||
|
||||
char *yy_ch_buf; /* input buffer */
|
||||
char *yy_buf_pos; /* current position in input buffer */
|
||||
|
||||
/* Size of input buffer in bytes, not including room for EOB
|
||||
* characters.
|
||||
*/
|
||||
int yy_buf_size;
|
||||
|
||||
/* Number of characters read into yy_ch_buf, not including EOB
|
||||
* characters.
|
||||
*/
|
||||
int yy_n_chars;
|
||||
|
||||
/* Whether we "own" the buffer - i.e., we know we created it,
|
||||
* and can realloc() it to grow it, and should free() it to
|
||||
* delete it.
|
||||
*/
|
||||
int yy_is_our_buffer;
|
||||
|
||||
/* Whether this is an "interactive" input source; if so, and
|
||||
* if we're using stdio for input, then we want to use getc()
|
||||
* instead of fread(), to make sure we stop fetching input after
|
||||
* each newline.
|
||||
*/
|
||||
int yy_is_interactive;
|
||||
|
||||
/* Whether we're considered to be at the beginning of a line.
|
||||
* If so, '^' rules will be active on the next match, otherwise
|
||||
* not.
|
||||
*/
|
||||
int yy_at_bol;
|
||||
|
||||
int yy_bs_lineno; /**< The line count. */
|
||||
int yy_bs_column; /**< The column count. */
|
||||
|
||||
/* Whether to try to fill the input buffer when we reach the
|
||||
* end of it.
|
||||
*/
|
||||
int yy_fill_buffer;
|
||||
|
||||
int yy_buffer_status;
|
||||
|
||||
};
|
||||
#endif /* !YY_STRUCT_YY_BUFFER_STATE */
|
||||
|
||||
void yyrestart ( FILE *input_file , yyscan_t yyscanner );
|
||||
void yy_switch_to_buffer ( YY_BUFFER_STATE new_buffer , yyscan_t yyscanner );
|
||||
YY_BUFFER_STATE yy_create_buffer ( FILE *file, int size , yyscan_t yyscanner );
|
||||
void yy_delete_buffer ( YY_BUFFER_STATE b , yyscan_t yyscanner );
|
||||
void yy_flush_buffer ( YY_BUFFER_STATE b , yyscan_t yyscanner );
|
||||
void yypush_buffer_state ( YY_BUFFER_STATE new_buffer , yyscan_t yyscanner );
|
||||
void yypop_buffer_state ( yyscan_t yyscanner );
|
||||
|
||||
YY_BUFFER_STATE yy_scan_buffer ( char *base, yy_size_t size , yyscan_t yyscanner );
|
||||
YY_BUFFER_STATE yy_scan_string ( const char *yy_str , yyscan_t yyscanner );
|
||||
YY_BUFFER_STATE yy_scan_bytes ( const char *bytes, int len , yyscan_t yyscanner );
|
||||
|
||||
void *yyalloc ( yy_size_t , yyscan_t yyscanner );
|
||||
void *yyrealloc ( void *, yy_size_t , yyscan_t yyscanner );
|
||||
void yyfree ( void * , yyscan_t yyscanner );
|
||||
|
||||
/* Begin user sect3 */
|
||||
|
||||
#define s4_wrap(yyscanner) (/*CONSTCOND*/1)
|
||||
#define YY_SKIP_YYWRAP
|
||||
|
||||
#define yytext_ptr yytext_r
|
||||
|
||||
#ifdef YY_HEADER_EXPORT_START_CONDITIONS
|
||||
#define INITIAL 0
|
||||
#define COMMENT_BLOCK_STATE 1
|
||||
#define DEVELOPER_BLOCK_STATE 2
|
||||
|
||||
#endif
|
||||
|
||||
#ifndef YY_NO_UNISTD_H
|
||||
/* Special case for "unistd.h", since it is non-ANSI. We include it way
|
||||
* down here because we want the user's section 1 to have been scanned first.
|
||||
* The user has a chance to override it with an option.
|
||||
*/
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#ifndef YY_EXTRA_TYPE
|
||||
#define YY_EXTRA_TYPE void *
|
||||
#endif
|
||||
|
||||
int yylex_init (yyscan_t* scanner);
|
||||
|
||||
int yylex_init_extra ( YY_EXTRA_TYPE user_defined, yyscan_t* scanner);
|
||||
|
||||
/* Accessor methods to globals.
|
||||
These are made visible to non-reentrant scanners for convenience. */
|
||||
|
||||
int yylex_destroy ( yyscan_t yyscanner );
|
||||
|
||||
int yyget_debug ( yyscan_t yyscanner );
|
||||
|
||||
void yyset_debug ( int debug_flag , yyscan_t yyscanner );
|
||||
|
||||
YY_EXTRA_TYPE yyget_extra ( yyscan_t yyscanner );
|
||||
|
||||
void yyset_extra ( YY_EXTRA_TYPE user_defined , yyscan_t yyscanner );
|
||||
|
||||
FILE *yyget_in ( yyscan_t yyscanner );
|
||||
|
||||
void yyset_in ( FILE * _in_str , yyscan_t yyscanner );
|
||||
|
||||
FILE *yyget_out ( yyscan_t yyscanner );
|
||||
|
||||
void yyset_out ( FILE * _out_str , yyscan_t yyscanner );
|
||||
|
||||
int yyget_leng ( yyscan_t yyscanner );
|
||||
|
||||
char *yyget_text ( yyscan_t yyscanner );
|
||||
|
||||
int yyget_lineno ( yyscan_t yyscanner );
|
||||
|
||||
void yyset_lineno ( int _line_number , yyscan_t yyscanner );
|
||||
|
||||
int yyget_column ( yyscan_t yyscanner );
|
||||
|
||||
void yyset_column ( int _column_no , yyscan_t yyscanner );
|
||||
|
||||
/* Macros after this point can all be overridden by user definitions in
|
||||
* section 1.
|
||||
*/
|
||||
|
||||
#ifndef YY_SKIP_YYWRAP
|
||||
#ifdef __cplusplus
|
||||
extern "C" int yywrap ( yyscan_t yyscanner );
|
||||
#else
|
||||
extern int yywrap ( yyscan_t yyscanner );
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef yytext_ptr
|
||||
static void yy_flex_strncpy ( char *, const char *, int , yyscan_t yyscanner);
|
||||
#endif
|
||||
|
||||
#ifdef YY_NEED_STRLEN
|
||||
static int yy_flex_strlen ( const char * , yyscan_t yyscanner);
|
||||
#endif
|
||||
|
||||
#ifndef YY_NO_INPUT
|
||||
|
||||
#endif
|
||||
|
||||
/* Amount of stuff to slurp up with each read. */
|
||||
#ifndef YY_READ_BUF_SIZE
|
||||
#ifdef __ia64__
|
||||
/* On IA-64, the buffer size is 16k, not 8k */
|
||||
#define YY_READ_BUF_SIZE 16384
|
||||
#else
|
||||
#define YY_READ_BUF_SIZE 8192
|
||||
#endif /* __ia64__ */
|
||||
#endif
|
||||
|
||||
/* Number of entries by which start-condition stack grows. */
|
||||
#ifndef YY_START_STACK_INCR
|
||||
#define YY_START_STACK_INCR 25
|
||||
#endif
|
||||
|
||||
/* Default declaration of generated scanner - a define so the user can
|
||||
* easily add parameters.
|
||||
*/
|
||||
#ifndef YY_DECL
|
||||
#define YY_DECL_IS_OURS 1
|
||||
|
||||
extern int yylex (yyscan_t yyscanner);
|
||||
|
||||
#define YY_DECL int yylex (yyscan_t yyscanner)
|
||||
#endif /* !YY_DECL */
|
||||
|
||||
/* yy_get_previous_state - get the state just before the EOB char was reached */
|
||||
|
||||
#undef YY_NEW_FILE
|
||||
#undef YY_FLUSH_BUFFER
|
||||
#undef yy_set_bol
|
||||
#undef yy_new_buffer
|
||||
#undef yy_set_interactive
|
||||
#undef YY_DO_BEFORE_ACTION
|
||||
|
||||
#ifdef YY_DECL_IS_OURS
|
||||
#undef YY_DECL_IS_OURS
|
||||
#undef YY_DECL
|
||||
#endif
|
||||
|
||||
#ifndef s4__create_buffer_ALREADY_DEFINED
|
||||
#undef yy_create_buffer
|
||||
#endif
|
||||
#ifndef s4__delete_buffer_ALREADY_DEFINED
|
||||
#undef yy_delete_buffer
|
||||
#endif
|
||||
#ifndef s4__scan_buffer_ALREADY_DEFINED
|
||||
#undef yy_scan_buffer
|
||||
#endif
|
||||
#ifndef s4__scan_string_ALREADY_DEFINED
|
||||
#undef yy_scan_string
|
||||
#endif
|
||||
#ifndef s4__scan_bytes_ALREADY_DEFINED
|
||||
#undef yy_scan_bytes
|
||||
#endif
|
||||
#ifndef s4__init_buffer_ALREADY_DEFINED
|
||||
#undef yy_init_buffer
|
||||
#endif
|
||||
#ifndef s4__flush_buffer_ALREADY_DEFINED
|
||||
#undef yy_flush_buffer
|
||||
#endif
|
||||
#ifndef s4__load_buffer_state_ALREADY_DEFINED
|
||||
#undef yy_load_buffer_state
|
||||
#endif
|
||||
#ifndef s4__switch_to_buffer_ALREADY_DEFINED
|
||||
#undef yy_switch_to_buffer
|
||||
#endif
|
||||
#ifndef s4_push_buffer_state_ALREADY_DEFINED
|
||||
#undef yypush_buffer_state
|
||||
#endif
|
||||
#ifndef s4_pop_buffer_state_ALREADY_DEFINED
|
||||
#undef yypop_buffer_state
|
||||
#endif
|
||||
#ifndef s4_ensure_buffer_stack_ALREADY_DEFINED
|
||||
#undef yyensure_buffer_stack
|
||||
#endif
|
||||
#ifndef s4_lex_ALREADY_DEFINED
|
||||
#undef yylex
|
||||
#endif
|
||||
#ifndef s4_restart_ALREADY_DEFINED
|
||||
#undef yyrestart
|
||||
#endif
|
||||
#ifndef s4_lex_init_ALREADY_DEFINED
|
||||
#undef yylex_init
|
||||
#endif
|
||||
#ifndef s4_lex_init_extra_ALREADY_DEFINED
|
||||
#undef yylex_init_extra
|
||||
#endif
|
||||
#ifndef s4_lex_destroy_ALREADY_DEFINED
|
||||
#undef yylex_destroy
|
||||
#endif
|
||||
#ifndef s4_get_debug_ALREADY_DEFINED
|
||||
#undef yyget_debug
|
||||
#endif
|
||||
#ifndef s4_set_debug_ALREADY_DEFINED
|
||||
#undef yyset_debug
|
||||
#endif
|
||||
#ifndef s4_get_extra_ALREADY_DEFINED
|
||||
#undef yyget_extra
|
||||
#endif
|
||||
#ifndef s4_set_extra_ALREADY_DEFINED
|
||||
#undef yyset_extra
|
||||
#endif
|
||||
#ifndef s4_get_in_ALREADY_DEFINED
|
||||
#undef yyget_in
|
||||
#endif
|
||||
#ifndef s4_set_in_ALREADY_DEFINED
|
||||
#undef yyset_in
|
||||
#endif
|
||||
#ifndef s4_get_out_ALREADY_DEFINED
|
||||
#undef yyget_out
|
||||
#endif
|
||||
#ifndef s4_set_out_ALREADY_DEFINED
|
||||
#undef yyset_out
|
||||
#endif
|
||||
#ifndef s4_get_leng_ALREADY_DEFINED
|
||||
#undef yyget_leng
|
||||
#endif
|
||||
#ifndef s4_get_text_ALREADY_DEFINED
|
||||
#undef yyget_text
|
||||
#endif
|
||||
#ifndef s4_get_lineno_ALREADY_DEFINED
|
||||
#undef yyget_lineno
|
||||
#endif
|
||||
#ifndef s4_set_lineno_ALREADY_DEFINED
|
||||
#undef yyset_lineno
|
||||
#endif
|
||||
#ifndef s4_get_column_ALREADY_DEFINED
|
||||
#undef yyget_column
|
||||
#endif
|
||||
#ifndef s4_set_column_ALREADY_DEFINED
|
||||
#undef yyset_column
|
||||
#endif
|
||||
#ifndef s4_wrap_ALREADY_DEFINED
|
||||
#undef yywrap
|
||||
#endif
|
||||
#ifndef s4_get_lval_ALREADY_DEFINED
|
||||
#undef yyget_lval
|
||||
#endif
|
||||
#ifndef s4_set_lval_ALREADY_DEFINED
|
||||
#undef yyset_lval
|
||||
#endif
|
||||
#ifndef s4_get_lloc_ALREADY_DEFINED
|
||||
#undef yyget_lloc
|
||||
#endif
|
||||
#ifndef s4_set_lloc_ALREADY_DEFINED
|
||||
#undef yyset_lloc
|
||||
#endif
|
||||
#ifndef s4_alloc_ALREADY_DEFINED
|
||||
#undef yyalloc
|
||||
#endif
|
||||
#ifndef s4_realloc_ALREADY_DEFINED
|
||||
#undef yyrealloc
|
||||
#endif
|
||||
#ifndef s4_free_ALREADY_DEFINED
|
||||
#undef yyfree
|
||||
#endif
|
||||
#ifndef s4_text_ALREADY_DEFINED
|
||||
#undef yytext
|
||||
#endif
|
||||
#ifndef s4_leng_ALREADY_DEFINED
|
||||
#undef yyleng
|
||||
#endif
|
||||
#ifndef s4_in_ALREADY_DEFINED
|
||||
#undef yyin
|
||||
#endif
|
||||
#ifndef s4_out_ALREADY_DEFINED
|
||||
#undef yyout
|
||||
#endif
|
||||
#ifndef s4__flex_debug_ALREADY_DEFINED
|
||||
#undef yy_flex_debug
|
||||
#endif
|
||||
#ifndef s4_lineno_ALREADY_DEFINED
|
||||
#undef yylineno
|
||||
#endif
|
||||
#ifndef s4_tables_fload_ALREADY_DEFINED
|
||||
#undef yytables_fload
|
||||
#endif
|
||||
#ifndef s4_tables_destroy_ALREADY_DEFINED
|
||||
#undef yytables_destroy
|
||||
#endif
|
||||
#ifndef s4_TABLES_NAME_ALREADY_DEFINED
|
||||
#undef yyTABLES_NAME
|
||||
#endif
|
||||
|
||||
#line 155 "lexer.lpp"
|
||||
|
||||
|
||||
#line 706 "lexer.hpp"
|
||||
#undef s4_IN_HEADER
|
||||
#endif /* s4_HEADER_H */
|
4116
src/s4/xsk/parser.cpp
Normal file
4116
src/s4/xsk/parser.cpp
Normal file
File diff suppressed because it is too large
Load Diff
4918
src/s4/xsk/parser.hpp
Normal file
4918
src/s4/xsk/parser.hpp
Normal file
File diff suppressed because it is too large
Load Diff
442
src/s4/xsk/resolver.cpp
Normal file
442
src/s4/xsk/resolver.cpp
Normal file
@ -0,0 +1,442 @@
|
||||
// Copyright 2021 xensik. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a GNU GPLv3 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
#include "stdafx.hpp"
|
||||
#include "s4.hpp"
|
||||
|
||||
namespace xsk::gsc::s4
|
||||
{
|
||||
|
||||
std::unordered_map<std::uint8_t, std::string> opcode_map;
|
||||
std::unordered_map<std::uint16_t, std::string> function_map;
|
||||
std::unordered_map<std::uint16_t, std::string> method_map;
|
||||
std::unordered_map<std::uint32_t, std::string> file_map;
|
||||
std::unordered_map<std::uint32_t, std::string> token_map;
|
||||
std::unordered_map<std::string, std::uint8_t> opcode_map_rev;
|
||||
std::unordered_map<std::string, std::uint16_t> function_map_rev;
|
||||
std::unordered_map<std::string, std::uint16_t> method_map_rev;
|
||||
std::unordered_map<std::string, std::uint32_t> file_map_rev;
|
||||
std::unordered_map<std::string, std::uint32_t> token_map_rev;
|
||||
|
||||
auto resolver::opcode_id(const std::string& name) -> std::uint8_t
|
||||
{
|
||||
const auto itr = opcode_map_rev.find(name);
|
||||
|
||||
if (itr != opcode_map_rev.end())
|
||||
{
|
||||
return itr->second;
|
||||
}
|
||||
|
||||
throw gsc::error(utils::string::va("Couldn't resolve opcode id for name '%s'!", name.data()));
|
||||
}
|
||||
|
||||
auto resolver::opcode_name(std::uint8_t id) -> std::string
|
||||
{
|
||||
const auto itr = opcode_map.find(id);
|
||||
|
||||
if (itr != opcode_map.end())
|
||||
{
|
||||
return itr->second;
|
||||
}
|
||||
|
||||
throw gsc::error(utils::string::va("Couldn't resolve opcode name for id '0x%hhX'!", id));
|
||||
}
|
||||
|
||||
auto resolver::function_id(const std::string& name) -> std::uint16_t
|
||||
{
|
||||
const auto itr = function_map_rev.find(name);
|
||||
|
||||
if (itr != function_map_rev.end())
|
||||
{
|
||||
return itr->second;
|
||||
}
|
||||
|
||||
throw gsc::error(utils::string::va("Couldn't resolve builtin function id for name '%s'!", name.data()));
|
||||
}
|
||||
|
||||
auto resolver::function_name(std::uint16_t id) -> std::string
|
||||
{
|
||||
const auto itr = function_map.find(id);
|
||||
|
||||
if (itr != function_map.end())
|
||||
{
|
||||
return itr->second;
|
||||
}
|
||||
|
||||
return utils::string::va("_func_%04X", id);
|
||||
// throw gsc::error(utils::string::va("Couldn't resolve builtin function name for id '%i'!", id));
|
||||
}
|
||||
|
||||
auto resolver::method_id(const std::string& name) -> std::uint16_t
|
||||
{
|
||||
const auto itr = method_map_rev.find(name);
|
||||
|
||||
if (itr != method_map_rev.end())
|
||||
{
|
||||
return itr->second;
|
||||
}
|
||||
|
||||
throw gsc::error(utils::string::va("Couldn't resolve builtin method id for name '%s'!", name.data()));
|
||||
}
|
||||
|
||||
auto resolver::method_name(std::uint16_t id) -> std::string
|
||||
{
|
||||
const auto itr = method_map.find(id);
|
||||
|
||||
if (itr != method_map.end())
|
||||
{
|
||||
return itr->second;
|
||||
}
|
||||
|
||||
return utils::string::va("_meth_%04X", id);
|
||||
// throw gsc::error(utils::string::va("Couldn't resolve builtin method name for id '%i'!", id));
|
||||
}
|
||||
|
||||
auto resolver::file_id(const std::string& name) -> std::uint32_t
|
||||
{
|
||||
const auto itr = file_map_rev.find(name);
|
||||
|
||||
if (itr != file_map_rev.end())
|
||||
{
|
||||
return itr->second;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto resolver::file_name(std::uint32_t id) -> std::string
|
||||
{
|
||||
const auto itr = file_map.find(id);
|
||||
|
||||
if (itr != file_map.end())
|
||||
{
|
||||
return itr->second;
|
||||
}
|
||||
|
||||
return utils::string::va("_ID%i", id);
|
||||
}
|
||||
|
||||
auto resolver::token_id(const std::string& name) -> std::uint32_t
|
||||
{
|
||||
const auto itr = token_map_rev.find(name);
|
||||
|
||||
if (itr != token_map_rev.end())
|
||||
{
|
||||
return itr->second;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto resolver::token_name(std::uint32_t id) -> std::string
|
||||
{
|
||||
const auto itr = token_map.find(id);
|
||||
|
||||
if (itr != token_map.end())
|
||||
{
|
||||
return itr->second;
|
||||
}
|
||||
|
||||
return utils::string::va("_ID%i", id);
|
||||
}
|
||||
|
||||
auto resolver::find_function(const std::string& name) -> bool
|
||||
{
|
||||
const auto itr = function_map_rev.find(name);
|
||||
|
||||
if (itr != function_map_rev.end())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
auto resolver::find_method(const std::string& name) -> bool
|
||||
{
|
||||
const auto itr = method_map_rev.find(name);
|
||||
|
||||
if (itr != method_map_rev.end())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
const std::array<gsc::pair_8C, 190> opcode_list
|
||||
{{
|
||||
{ std::uint8_t(opcode::OP_CastFieldObject), "CAST_FIELD_OBJECT" },
|
||||
{ std::uint8_t(opcode::OP_SetLocalVariableFieldCached), "SET_LOCAL_VARIABLE_FIELD_CACHED" },
|
||||
{ std::uint8_t(opcode::OP_plus), "PLUS" },
|
||||
{ std::uint8_t(opcode::OP_RemoveLocalVariables), "REMOVE_LOCAL_VARIABLES" },
|
||||
{ std::uint8_t(opcode::OP_EvalSelfFieldVariableRef), "EVAL_SELF_FIELD_VARIABLE_REF" },
|
||||
{ std::uint8_t(opcode::OP_ScriptFarMethodChildThreadCall), "SCRIPT_FAR_METHOD_CHILD_THREAD_CALL" },
|
||||
{ std::uint8_t(opcode::OP_GetGameRef), "GET_GAME_REF" },
|
||||
{ std::uint8_t(opcode::OP_EvalAnimFieldVariable), "EVAL_ANIM_FIELD_VARIABLE" },
|
||||
{ std::uint8_t(opcode::OP_EvalLevelFieldVariableRef), "EVAL_LEVEL_FIELD_VARIABLE_REF" },
|
||||
{ std::uint8_t(opcode::OP_GetThisthread), "GET_THISTHREAD" },
|
||||
{ std::uint8_t(opcode::OP_greater), "GREATER" },
|
||||
{ std::uint8_t(opcode::OP_waittillmatch), "WAITTILLMATCH" },
|
||||
{ std::uint8_t(opcode::OP_shift_right), "SHIFT_RIGHT" },
|
||||
{ std::uint8_t(opcode::OP_dec), "DECREMENT" },
|
||||
{ std::uint8_t(opcode::OP_JumpOnTrue), "JUMP_ON_TRUE" },
|
||||
{ std::uint8_t(opcode::OP_bit_or), "BIT_OR" },
|
||||
{ std::uint8_t(opcode::OP_equality), "EQUALITY" },
|
||||
{ std::uint8_t(opcode::OP_ClearLocalVariableFieldCached0), "CLEAR_LOCAL_VARIABLE_FIELD_CACHED_0" },
|
||||
{ std::uint8_t(opcode::OP_notify), "NOTIFY" },
|
||||
{ std::uint8_t(opcode::OP_GetVector), "GET_VECTOR" },
|
||||
{ std::uint8_t(opcode::OP_ScriptMethodChildThreadCallPointer), "SCRIPT_METHOD_CHILD_THREAD_CALL_POINTER" },
|
||||
{ std::uint8_t(opcode::OP_PreScriptCall), "PRE_SCRIPT_CALL" },
|
||||
{ std::uint8_t(opcode::OP_GetByte), "GET_BYTE" },
|
||||
{ std::uint8_t(opcode::OP_ScriptFarThreadCall), "SCRIPT_FAR_THREAD_CALL" },
|
||||
{ std::uint8_t(opcode::OP_SetSelfFieldVariableField), "SET_SELF_FIELD_VARIABLE_FIELD" },
|
||||
{ std::uint8_t(opcode::OP_JumpOnFalseExpr), "JUMP_ON_FALSE_EXPR" },
|
||||
{ std::uint8_t(opcode::OP_GetUndefined), "GET_UNDEFINED" },
|
||||
{ std::uint8_t(opcode::OP_jumpback), "JUMP_BACK" },
|
||||
{ std::uint8_t(opcode::OP_JumpOnTrueExpr), "JUMP_ON_TRUE_EXPR" },
|
||||
{ std::uint8_t(opcode::OP_CallBuiltin0),"CALL_BUILTIN_FUNC_0" },
|
||||
{ std::uint8_t(opcode::OP_CallBuiltin1),"CALL_BUILTIN_FUNC_1" },
|
||||
{ std::uint8_t(opcode::OP_CallBuiltin2),"CALL_BUILTIN_FUNC_2" },
|
||||
{ std::uint8_t(opcode::OP_CallBuiltin3),"CALL_BUILTIN_FUNC_3" },
|
||||
{ std::uint8_t(opcode::OP_CallBuiltin4),"CALL_BUILTIN_FUNC_4" },
|
||||
{ std::uint8_t(opcode::OP_CallBuiltin5),"CALL_BUILTIN_FUNC_5" },
|
||||
{ std::uint8_t(opcode::OP_CallBuiltin),"CALL_BUILTIN_FUNC" },
|
||||
{ std::uint8_t(opcode::OP_SetLocalVariableFieldCached0), "SET_LOCAL_VARIABLE_FIELD_CACHED_0" },
|
||||
{ std::uint8_t(opcode::OP_ClearFieldVariable), "CLEAR_FIELD_VARIABLE" },
|
||||
{ std::uint8_t(opcode::OP_GetLevel), "GET_LEVEL" },
|
||||
{ std::uint8_t(opcode::OP_size), "SIZE" },
|
||||
{ std::uint8_t(opcode::OP_SafeSetWaittillVariableFieldCached), "SAFE_SET_WAITTILL_VARIABLE_FIELD_CACHED" },
|
||||
{ std::uint8_t(opcode::OP_ScriptLocalMethodThreadCall), "SCRIPT_LOCAL_METHOD_THREAD_CALL" },
|
||||
{ std::uint8_t(opcode::OP_AddArray), "ADD_ARRAY" },
|
||||
{ std::uint8_t(opcode::OP_endon), "ENDON" },
|
||||
{ std::uint8_t(opcode::OP_EvalFieldVariable), "EVAL_FIELD_VARIABLE" },
|
||||
{ std::uint8_t(opcode::OP_shift_left), "SHIFT_LEFT" },
|
||||
{ std::uint8_t(opcode::OP_EvalLocalArrayRefCached0), "EVAL_LOCAL_ARRAY_REF_CACHED_0" },
|
||||
{ std::uint8_t(opcode::OP_Return), "RETURN" },
|
||||
{ std::uint8_t(opcode::OP_CreateLocalVariable), "CREATE_LOCAL_VARIABLE" },
|
||||
{ std::uint8_t(opcode::OP_SafeSetVariableFieldCached0), "SAFE_SET_VARIABLE_FIELD_CACHED_0" },
|
||||
{ std::uint8_t(opcode::OP_GetBuiltinFunction), "GET_BUILTIN_FUNCTION" },
|
||||
{ std::uint8_t(opcode::OP_ScriptLocalMethodCall), "SCRIPT_LOCAL_METHOD_CALL" },
|
||||
{ std::uint8_t(opcode::OP_CallBuiltinMethodPointer), "CALL_BUILTIN_METHOD_POINTER" },
|
||||
{ std::uint8_t(opcode::OP_ScriptLocalChildThreadCall), "SCRIPT_LOCAL_CHILD_THREAD_CALL" },
|
||||
{ std::uint8_t(opcode::OP_GetSelfObject), "GET_SELF_OBJECT" },
|
||||
{ std::uint8_t(opcode::OP_GetGame), "GET_GAME" },
|
||||
{ std::uint8_t(opcode::OP_SetLevelFieldVariableField), "SET_LEVEL_FIELD_VARIABLE_FIELD" },
|
||||
{ std::uint8_t(opcode::OP_EvalArray), "EVAL_ARRAY" },
|
||||
{ std::uint8_t(opcode::OP_GetSelf), "GET_SELF" },
|
||||
{ std::uint8_t(opcode::OP_End), "END" },
|
||||
{ std::uint8_t(opcode::OP_EvalSelfFieldVariable), "EVAL_SELF_FIELD_VARIABLE" },
|
||||
{ std::uint8_t(opcode::OP_less_equal), "LESS_EQUAL" },
|
||||
{ std::uint8_t(opcode::OP_EvalLocalVariableCached0), "EVAL_LOCAL_VARIABLE_CACHED_0" },
|
||||
{ std::uint8_t(opcode::OP_EvalLocalVariableCached1), "EVAL_LOCAL_VARIABLE_CACHED_1" },
|
||||
{ std::uint8_t(opcode::OP_EvalLocalVariableCached2), "EVAL_LOCAL_VARIABLE_CACHED_2" },
|
||||
{ std::uint8_t(opcode::OP_EvalLocalVariableCached3), "EVAL_LOCAL_VARIABLE_CACHED_3" },
|
||||
{ std::uint8_t(opcode::OP_EvalLocalVariableCached4), "EVAL_LOCAL_VARIABLE_CACHED_4" },
|
||||
{ std::uint8_t(opcode::OP_EvalLocalVariableCached5), "EVAL_LOCAL_VARIABLE_CACHED_5" },
|
||||
{ std::uint8_t(opcode::OP_EvalLocalVariableCached), "EVAL_LOCAL_VARIABLE_CACHED" },
|
||||
{ std::uint8_t(opcode::OP_EvalNewLocalArrayRefCached0), "EVAL_NEW_LOCAL_ARRAY_REF_CACHED_0" },
|
||||
{ std::uint8_t(opcode::OP_ScriptChildThreadCallPointer), "SCRIPT_CHILD_THREAD_CALL_POINTER" },
|
||||
{ std::uint8_t(opcode::OP_EvalLocalVariableObjectCached), "EVAL_LOCAL_VARIABLE_OBJECT_CACHED" },
|
||||
{ std::uint8_t(opcode::OP_ScriptLocalThreadCall), "SCRIPT_LOCAL_THREAD_CALL" },
|
||||
{ std::uint8_t(opcode::OP_GetInteger), "GET_INTEGER" },
|
||||
{ std::uint8_t(opcode::OP_ScriptMethodCallPointer), "SCRIPT_METHOD_CALL_POINTER" },
|
||||
{ std::uint8_t(opcode::OP_checkclearparams), "CHECK_CLEAR_PARAMS" },
|
||||
{ std::uint8_t(opcode::OP_SetAnimFieldVariableField), "SET_ANIM_FIELD_VARIABLE_FIELD" },
|
||||
{ std::uint8_t(opcode::OP_waittillmatch2), "WAITTILLMATCH2" },
|
||||
{ std::uint8_t(opcode::OP_minus), "MINUS" },
|
||||
{ std::uint8_t(opcode::OP_ScriptLocalFunctionCall2), "SCRIPT_LOCAL_FUNCTION_CALL2" },
|
||||
{ std::uint8_t(opcode::OP_GetNegUnsignedShort), "GET_NEG_USHORT" },
|
||||
{ std::uint8_t(opcode::OP_GetNegByte), "GET_NEG_BYTE" },
|
||||
{ std::uint8_t(opcode::OP_SafeCreateVariableFieldCached), "SAFE_CREATE_VARIABLE_FIELD_CACHED" },
|
||||
{ std::uint8_t(opcode::OP_greater_equal), "GREATER_EQUAL" },
|
||||
{ std::uint8_t(opcode::OP_vector), "VECTOR" },
|
||||
{ std::uint8_t(opcode::OP_GetBuiltinMethod), "GET_BUILTIN_METHOD" },
|
||||
{ std::uint8_t(opcode::OP_endswitch), "END_SWITCH" },
|
||||
{ std::uint8_t(opcode::OP_ClearArray), "CLEAR_ARRAY" },
|
||||
{ std::uint8_t(opcode::OP_DecTop), "DECREMENT_TOP" },
|
||||
{ std::uint8_t(opcode::OP_CastBool), "CAST_BOOL" },
|
||||
{ std::uint8_t(opcode::OP_EvalArrayRef), "EVAL_ARRAY_REF" },
|
||||
{ std::uint8_t(opcode::OP_SetNewLocalVariableFieldCached0), "SET_NEW_LOCAL_VARIABLE_FIELD_CACHED_0" },
|
||||
{ std::uint8_t(opcode::OP_GetZero), "GET_ZERO" },
|
||||
{ std::uint8_t(opcode::OP_wait), "WAIT" },
|
||||
{ std::uint8_t(opcode::OP_waittill), "WAITTILL" },
|
||||
{ std::uint8_t(opcode::OP_GetIString), "GET_ISTRING" },
|
||||
{ std::uint8_t(opcode::OP_ScriptFarFunctionCall), "SCRIPT_FAR_FUNCTION_CALL" },
|
||||
{ std::uint8_t(opcode::OP_GetAnimObject), "GET_ANIM_OBJECT" },
|
||||
{ std::uint8_t(opcode::OP_GetAnimTree), "GET_ANIMTREE" },
|
||||
{ std::uint8_t(opcode::OP_EvalLocalArrayCached), "EVAL_LOCAL_ARRAY_CACHED" },
|
||||
{ std::uint8_t(opcode::OP_mod), "MOD" },
|
||||
{ std::uint8_t(opcode::OP_ScriptFarMethodThreadCall), "SCRIPT_FAR_METHOD_THREAD_CALL" },
|
||||
{ std::uint8_t(opcode::OP_GetUnsignedShort), "GET_USHORT" },
|
||||
{ std::uint8_t(opcode::OP_clearparams), "CLEAR_PARAMS" },
|
||||
{ std::uint8_t(opcode::OP_ScriptMethodThreadCallPointer), "SCRIPT_METHOD_THREAD_CALL_POINTER" },
|
||||
{ std::uint8_t(opcode::OP_ScriptFunctionCallPointer), "SCRIPT_FUNCTION_CALL_POINTER" },
|
||||
{ std::uint8_t(opcode::OP_EmptyArray), "EMPTY_ARRAY" },
|
||||
{ std::uint8_t(opcode::OP_SafeSetVariableFieldCached), "SAFE_SET_VARIABLE_FIELD_CACHED" },
|
||||
{ std::uint8_t(opcode::OP_ClearVariableField), "CLEAR_VARIABLE_FIELD" },
|
||||
{ std::uint8_t(opcode::OP_EvalFieldVariableRef), "EVAL_FIELD_VARIABLE_REF" },
|
||||
{ std::uint8_t(opcode::OP_ScriptLocalMethodChildThreadCall), "SCRIPT_LOCAL_METHOD_CHILD_THREAD_CALL" },
|
||||
{ std::uint8_t(opcode::OP_EvalNewLocalVariableRefCached0), "EVAL_NEW_LOCAL_VARIABLE_REF_CACHED_0" },
|
||||
{ std::uint8_t(opcode::OP_GetFloat), "GET_FLOAT" },
|
||||
{ std::uint8_t(opcode::OP_EvalLocalVariableRefCached), "EVAL_LOCAL_VARIABLE_REF_CACHED" },
|
||||
{ std::uint8_t(opcode::OP_JumpOnFalse), "JUMP_ON_FALSE" },
|
||||
{ std::uint8_t(opcode::OP_BoolComplement), "BOOL_COMPLEMENT" },
|
||||
{ std::uint8_t(opcode::OP_ScriptThreadCallPointer), "SCRIPT_THREAD_CALL_POINTER" },
|
||||
{ std::uint8_t(opcode::OP_ScriptFarFunctionCall2), "SCRIPT_FAR_FUNCTION_CALL2" },
|
||||
{ std::uint8_t(opcode::OP_less), "LESS" },
|
||||
{ std::uint8_t(opcode::OP_BoolNot), "BOOL_NOT" },
|
||||
{ std::uint8_t(opcode::OP_waittillFrameEnd), "WAITTILLFRAMEEND" },
|
||||
{ std::uint8_t(opcode::OP_waitframe), "WAITFRAME" },
|
||||
{ std::uint8_t(opcode::OP_GetString), "GET_STRING" },
|
||||
{ std::uint8_t(opcode::OP_EvalLevelFieldVariable), "EVAL_LEVEL_FIELD_VARIABLE" },
|
||||
{ std::uint8_t(opcode::OP_GetLevelObject), "GET_LEVEL_OBJECT" },
|
||||
{ std::uint8_t(opcode::OP_inc), "INCREMENT" },
|
||||
{ std::uint8_t(opcode::OP_CallBuiltinMethod0),"CALL_BUILTIN_METHOD_0" },
|
||||
{ std::uint8_t(opcode::OP_CallBuiltinMethod1),"CALL_BUILTIN_METHOD_1" },
|
||||
{ std::uint8_t(opcode::OP_CallBuiltinMethod2),"CALL_BUILTIN_METHOD_2" },
|
||||
{ std::uint8_t(opcode::OP_CallBuiltinMethod3),"CALL_BUILTIN_METHOD_3" },
|
||||
{ std::uint8_t(opcode::OP_CallBuiltinMethod4),"CALL_BUILTIN_METHOD_4" },
|
||||
{ std::uint8_t(opcode::OP_CallBuiltinMethod5),"CALL_BUILTIN_METHOD_5" },
|
||||
{ std::uint8_t(opcode::OP_CallBuiltinMethod),"CALL_BUILTIN_METHOD" },
|
||||
{ std::uint8_t(opcode::OP_GetAnim), "GET_ANIM" },
|
||||
{ std::uint8_t(opcode::OP_switch), "SWITCH" },
|
||||
{ std::uint8_t(opcode::OP_SetVariableField), "SET_VARIABLE_FIELD" },
|
||||
{ std::uint8_t(opcode::OP_divide), "DIV" },
|
||||
{ std::uint8_t(opcode::OP_GetLocalFunction), "GET_LOCAL_FUNCTION" },
|
||||
{ std::uint8_t(opcode::OP_ScriptFarChildThreadCall), "SCRIPT_FAR_CHILD_THREAD_CALL" },
|
||||
{ std::uint8_t(opcode::OP_multiply), "MUL" },
|
||||
{ std::uint8_t(opcode::OP_ClearLocalVariableFieldCached), "CLEAR_LOCAL_VARIABLE_FIELD_CACHED" },
|
||||
{ std::uint8_t(opcode::OP_EvalAnimFieldVariableRef), "EVAL_ANIM_FIELD_VARIABLE_REF" },
|
||||
{ std::uint8_t(opcode::OP_EvalLocalArrayRefCached), "EVAL_LOCAL_ARRAY_REF_CACHED" },
|
||||
{ std::uint8_t(opcode::OP_EvalLocalVariableRefCached0), "EVAL_LOCAL_VARIABLE_REF_CACHED_0" },
|
||||
{ std::uint8_t(opcode::OP_bit_and), "BIT_AND" },
|
||||
{ std::uint8_t(opcode::OP_GetAnimation), "GET_ANIMATION" },
|
||||
{ std::uint8_t(opcode::OP_GetFarFunction), "GET_FAR_FUNCTION" },
|
||||
{ std::uint8_t(opcode::OP_CallBuiltinPointer), "CALL_BUILTIN_POINTER" },
|
||||
{ std::uint8_t(opcode::OP_jump), "JUMP" },
|
||||
{ std::uint8_t(opcode::OP_voidCodepos), "VOIDCODEPOS" },
|
||||
{ std::uint8_t(opcode::OP_ScriptFarMethodCall), "SCRIPT_FAR_METHOD_CALL" },
|
||||
{ std::uint8_t(opcode::OP_inequality), "INEQUALITY" },
|
||||
{ std::uint8_t(opcode::OP_ScriptLocalFunctionCall), "SCRIPT_LOCAL_FUNCTION_CALL" },
|
||||
{ std::uint8_t(opcode::OP_bit_ex_or), "BIT_EXOR" },
|
||||
{ std::uint8_t(opcode::OP_NOP), "NOP" },
|
||||
{ std::uint8_t(opcode::OP_abort), "ABORT" },
|
||||
{ std::uint8_t(opcode::OP_object), "OBJECT" },
|
||||
{ std::uint8_t(opcode::OP_thread_object), "THREAD_OBJECT" },
|
||||
{ std::uint8_t(opcode::OP_EvalLocalVariable), "EVAL_LOCAL_VARIABLE" },
|
||||
{ std::uint8_t(opcode::OP_EvalLocalVariableRef), "EVAL_LOCAL_VARIABLE_REF" },
|
||||
{ std::uint8_t(opcode::OP_prof_begin), "PROF_BEGIN" },
|
||||
{ std::uint8_t(opcode::OP_prof_end), "PROF_END" },
|
||||
{ std::uint8_t(opcode::OP_breakpoint), "BREAKPOINT" },
|
||||
{ std::uint8_t(opcode::OP_assignmentBreakpoint), "ASSIGN_BREAKPOINT" },
|
||||
{ std::uint8_t(opcode::OP_manualAndAssignmentBreakpoint), "MANUAL_AND_ASSIGN_BREAKPOINT" },
|
||||
{ std::uint8_t(opcode::OP_BoolNotAfterAnd), "BOOL_NOT_AFTER_AND" },
|
||||
{ std::uint8_t(opcode::OP_FormalParams), "FORMAL_PARAMS" },
|
||||
{ std::uint8_t(opcode::OP_IsDefined), "IS_DEFINED" },
|
||||
{ std::uint8_t(opcode::OP_IsTrue), "IS_TRUE" },
|
||||
{ std::uint8_t(opcode::OP_NativeGetLocalFunction), "NATIVE_GET_LOCAL_FUNCTION" },
|
||||
{ std::uint8_t(opcode::OP_NativeLocalFunctionCall), "NATIVE_LOCAL_FUNCTION_CALL" },
|
||||
{ std::uint8_t(opcode::OP_NativeLocalFunctionCall2), "NATIVE_LOCAL_FUNCTION_CALL2" },
|
||||
{ std::uint8_t(opcode::OP_NativeLocalMethodCall), "NATIVE_LOCAL_METHOD_CALL" },
|
||||
{ std::uint8_t(opcode::OP_NativeLocalFunctionThreadCall), "NATIVE_LOCAL_FUNCTION_THREAD_CALL" },
|
||||
{ std::uint8_t(opcode::OP_NativeLocalMethodThreadCall), "NATIVE_LOCAL_METHOD_THREAD_CALL" },
|
||||
{ std::uint8_t(opcode::OP_NativeLocalFunctionChildThreadCall), "NATIVE_LOCAL_FUNCTION_CHILD_THREAD_CALL" },
|
||||
{ std::uint8_t(opcode::OP_NativeLocalMethodChildThreadCall), "NATIVE_LOCAL_METHOD_CHILD_THREAD_CALL" },
|
||||
{ std::uint8_t(opcode::OP_NativeGetFarFunction), "NATIVE_GET_FAR_FUNCTION" },
|
||||
{ std::uint8_t(opcode::OP_NativeFarFunctionCall), "NATIVE_FAR_FUNCTION_CALL" },
|
||||
{ std::uint8_t(opcode::OP_NativeFarFunctionCall2), "NATIVE_FAR_FUNCTION_CALL2" },
|
||||
{ std::uint8_t(opcode::OP_NativeFarMethodCall), "NATIVE_FAR_METHOD_CALL" },
|
||||
{ std::uint8_t(opcode::OP_NativeFarFunctionThreadCall), "NATIVE_FAR_FUNCTION_THREAD_CALL" },
|
||||
{ std::uint8_t(opcode::OP_NativeFarMethodThreadCall), "NATIVE_FAR_METHOD_THREAD_CALL" },
|
||||
{ std::uint8_t(opcode::OP_NativeFarFunctionChildThreadCall), "NATIVE_FAR_FUNCTION_CHILD_THREAD_CALL" },
|
||||
{ std::uint8_t(opcode::OP_NativeFarMethodChildThreadCall), "NATIVE_FAR_METHOD_CHILD_THREAD_CALL" },
|
||||
{ std::uint8_t(opcode::OP_EvalNewLocalArrayRefCached0_Precompiled), "EVAL_NEW_LOCAL_ARRAY_REF_CACHED_0_PRECOMPILED" },
|
||||
{ std::uint8_t(opcode::OP_SetNewLocalVariableFieldCached0_Precompiled), "SET_NEW_LOCAL_VARIABLE_FIELD_CACHED_0_PRECOMPILED" },
|
||||
{ std::uint8_t(opcode::OP_CreateLocalVariable_Precompiled), "CREATE_LOCAL_VARIABLE_PRECOMPILED" },
|
||||
{ std::uint8_t(opcode::OP_SafeCreateVariableFieldCached_Precompiled), "SAFE_CREATE_VARIABLE_FIELD_CACHED_PRECOMPILED" },
|
||||
{ std::uint8_t(opcode::OP_FormalParams_Precompiled), "FORMAL_PARAMS_PRECOMPILED" },
|
||||
}};
|
||||
|
||||
const std::array<gsc::pair_16C, 4> function_list
|
||||
{{
|
||||
{ 0x08F, "getdvar" },
|
||||
{ 0x09B, "getfirstarraykey" },
|
||||
{ 0x0B1, "getnextarraykey" },
|
||||
{ 0x126, "isusingmatchrulesdata" },
|
||||
}};
|
||||
const std::array<gsc::pair_16C, 1> method_list
|
||||
{{
|
||||
{ 0x0, "null" },
|
||||
}};
|
||||
|
||||
const std::array<gsc::pair_32C, 1> file_list
|
||||
{{
|
||||
{ 0x0, "null" },
|
||||
}};
|
||||
|
||||
const std::array<gsc::pair_32C, 4> token_list
|
||||
{{
|
||||
{ 0x00, "" }, // VOID
|
||||
{ 0x01, "pl#" }, // PL
|
||||
{ 0x02, "-" }, // MINUS
|
||||
// { 0x03, "" }, // RADIUS_TYPO
|
||||
{ 0x04, ":" }, // NOTE_COLON
|
||||
}};
|
||||
|
||||
struct __init__
|
||||
{
|
||||
__init__()
|
||||
{
|
||||
static bool init = false;
|
||||
if(init) return;
|
||||
init = true;
|
||||
|
||||
opcode_map.reserve(opcode_list.size());
|
||||
opcode_map_rev.reserve(opcode_list.size());
|
||||
function_map.reserve(function_list.size());
|
||||
function_map_rev.reserve(function_list.size());
|
||||
method_map.reserve(method_list.size());
|
||||
method_map_rev.reserve(method_list.size());
|
||||
file_map.reserve(file_list.size());
|
||||
file_map_rev.reserve(file_list.size());
|
||||
token_map.reserve(token_list.size());
|
||||
token_map_rev.reserve(token_list.size());
|
||||
|
||||
for(const auto& entry : opcode_list)
|
||||
{
|
||||
opcode_map.insert({ entry.key, entry.value });
|
||||
opcode_map_rev.insert({ entry.value, entry.key });
|
||||
}
|
||||
|
||||
for(const auto& entry : function_list)
|
||||
{
|
||||
function_map.insert({ entry.key, entry.value });
|
||||
function_map_rev.insert({ entry.value, entry.key });
|
||||
}
|
||||
|
||||
for(const auto& entry : method_list)
|
||||
{
|
||||
method_map.insert({ entry.key, entry.value });
|
||||
method_map_rev.insert({ entry.value, entry.key });
|
||||
}
|
||||
|
||||
for(const auto& entry : file_list)
|
||||
{
|
||||
file_map.insert({ entry.key, entry.value });
|
||||
file_map_rev.insert({ entry.value, entry.key });
|
||||
}
|
||||
|
||||
for(const auto& entry : token_list)
|
||||
{
|
||||
token_map.insert({ entry.key, entry.value });
|
||||
token_map_rev.insert({ entry.value, entry.key });
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
__init__ _;
|
||||
|
||||
} // namespace xsk::gsc::s4
|
33
src/s4/xsk/resolver.hpp
Normal file
33
src/s4/xsk/resolver.hpp
Normal file
@ -0,0 +1,33 @@
|
||||
// Copyright 2021 xensik. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a GNU GPLv3 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace xsk::gsc::s4
|
||||
{
|
||||
|
||||
class resolver
|
||||
{
|
||||
public:
|
||||
static auto opcode_id(const std::string& name) -> std::uint8_t;
|
||||
static auto opcode_name(std::uint8_t id) -> std::string;
|
||||
|
||||
static auto function_id(const std::string& name) -> std::uint16_t;
|
||||
static auto function_name(std::uint16_t id) -> std::string;
|
||||
|
||||
static auto method_id(const std::string& name) -> std::uint16_t;
|
||||
static auto method_name(std::uint16_t id) -> std::string;
|
||||
|
||||
static auto file_id(const std::string& name) -> std::uint32_t;
|
||||
static auto file_name(std::uint32_t id) -> std::string;
|
||||
|
||||
static auto token_id(const std::string& name) -> std::uint32_t;
|
||||
static auto token_name(std::uint32_t id) -> std::string;
|
||||
|
||||
static auto find_function(const std::string& name) -> bool;
|
||||
static auto find_method(const std::string& name) -> bool;
|
||||
};
|
||||
|
||||
} // namespace xsk::gsc::s4
|
229
src/s4/xsk/s4.cpp
Normal file
229
src/s4/xsk/s4.cpp
Normal file
@ -0,0 +1,229 @@
|
||||
// Copyright 2021 xensik. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a GNU GPLv3 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
#include "stdafx.hpp"
|
||||
#include "s4.hpp"
|
||||
|
||||
namespace xsk::gsc::s4
|
||||
{
|
||||
|
||||
auto opcode_size(std::uint8_t id) -> std::uint32_t
|
||||
{
|
||||
switch (opcode(id))
|
||||
{
|
||||
case opcode::OP_CastFieldObject:
|
||||
case opcode::OP_plus:
|
||||
case opcode::OP_GetGameRef:
|
||||
case opcode::OP_GetThisthread:
|
||||
case opcode::OP_greater:
|
||||
case opcode::OP_shift_right:
|
||||
case opcode::OP_dec:
|
||||
case opcode::OP_bit_or:
|
||||
case opcode::OP_equality:
|
||||
case opcode::OP_ClearLocalVariableFieldCached0:
|
||||
case opcode::OP_notify:
|
||||
case opcode::OP_PreScriptCall:
|
||||
case opcode::OP_GetUndefined:
|
||||
case opcode::OP_SetLocalVariableFieldCached0:
|
||||
case opcode::OP_GetLevel:
|
||||
case opcode::OP_size:
|
||||
case opcode::OP_AddArray:
|
||||
case opcode::OP_endon:
|
||||
case opcode::OP_shift_left:
|
||||
case opcode::OP_EvalLocalArrayRefCached0:
|
||||
case opcode::OP_Return:
|
||||
case opcode::OP_SafeSetVariableFieldCached0:
|
||||
case opcode::OP_GetSelfObject:
|
||||
case opcode::OP_GetGame:
|
||||
case opcode::OP_EvalArray:
|
||||
case opcode::OP_GetSelf:
|
||||
case opcode::OP_End:
|
||||
case opcode::OP_less_equal:
|
||||
case opcode::OP_EvalLocalVariableCached0:
|
||||
case opcode::OP_EvalLocalVariableCached1:
|
||||
case opcode::OP_EvalLocalVariableCached2:
|
||||
case opcode::OP_EvalLocalVariableCached3:
|
||||
case opcode::OP_EvalLocalVariableCached4:
|
||||
case opcode::OP_EvalLocalVariableCached5:
|
||||
case opcode::OP_ScriptMethodCallPointer:
|
||||
case opcode::OP_checkclearparams:
|
||||
case opcode::OP_waittillmatch2:
|
||||
case opcode::OP_minus:
|
||||
case opcode::OP_greater_equal:
|
||||
case opcode::OP_vector:
|
||||
case opcode::OP_ClearArray:
|
||||
case opcode::OP_DecTop:
|
||||
case opcode::OP_CastBool:
|
||||
case opcode::OP_EvalArrayRef:
|
||||
case opcode::OP_GetZero:
|
||||
case opcode::OP_wait:
|
||||
case opcode::OP_waittill:
|
||||
case opcode::OP_GetAnimObject:
|
||||
case opcode::OP_mod:
|
||||
case opcode::OP_clearparams:
|
||||
case opcode::OP_ScriptFunctionCallPointer:
|
||||
case opcode::OP_EmptyArray:
|
||||
case opcode::OP_ClearVariableField:
|
||||
case opcode::OP_EvalNewLocalVariableRefCached0:
|
||||
case opcode::OP_BoolComplement:
|
||||
case opcode::OP_less:
|
||||
case opcode::OP_BoolNot:
|
||||
case opcode::OP_waittillFrameEnd:
|
||||
case opcode::OP_waitframe:
|
||||
case opcode::OP_GetLevelObject:
|
||||
case opcode::OP_inc:
|
||||
case opcode::OP_GetAnim:
|
||||
case opcode::OP_SetVariableField:
|
||||
case opcode::OP_divide:
|
||||
case opcode::OP_multiply:
|
||||
case opcode::OP_EvalLocalVariableRefCached0:
|
||||
case opcode::OP_bit_and:
|
||||
case opcode::OP_voidCodepos:
|
||||
case opcode::OP_inequality:
|
||||
case opcode::OP_bit_ex_or:
|
||||
/*
|
||||
case opcode::OP_NOP:
|
||||
case opcode::OP_abort:
|
||||
case opcode::OP_object:
|
||||
case opcode::OP_thread_object:
|
||||
case opcode::OP_EvalLocalVariable:
|
||||
case opcode::OP_EvalLocalVariableRef:
|
||||
case opcode::OP_breakpoint:
|
||||
case opcode::OP_assignmentBreakpoint:
|
||||
case opcode::OP_manualAndAssignmentBreakpoint:
|
||||
*/
|
||||
case opcode::OP_BoolNotAfterAnd:
|
||||
case opcode::OP_IsDefined:
|
||||
case opcode::OP_IsTrue:
|
||||
return 1;
|
||||
case opcode::OP_SetLocalVariableFieldCached:
|
||||
case opcode::OP_RemoveLocalVariables:
|
||||
case opcode::OP_ScriptMethodChildThreadCallPointer:
|
||||
case opcode::OP_GetByte:
|
||||
case opcode::OP_SafeSetWaittillVariableFieldCached:
|
||||
case opcode::OP_CreateLocalVariable:
|
||||
case opcode::OP_CallBuiltinMethodPointer:
|
||||
case opcode::OP_EvalLocalVariableCached:
|
||||
case opcode::OP_EvalNewLocalArrayRefCached0:
|
||||
case opcode::OP_ScriptChildThreadCallPointer:
|
||||
case opcode::OP_EvalLocalVariableObjectCached:
|
||||
case opcode::OP_GetNegByte:
|
||||
case opcode::OP_SafeCreateVariableFieldCached:
|
||||
case opcode::OP_SetNewLocalVariableFieldCached0:
|
||||
case opcode::OP_GetAnimTree:
|
||||
case opcode::OP_EvalLocalArrayCached:
|
||||
case opcode::OP_ScriptMethodThreadCallPointer:
|
||||
case opcode::OP_SafeSetVariableFieldCached:
|
||||
case opcode::OP_EvalLocalVariableRefCached:
|
||||
case opcode::OP_ScriptThreadCallPointer:
|
||||
case opcode::OP_ClearLocalVariableFieldCached:
|
||||
case opcode::OP_EvalLocalArrayRefCached:
|
||||
case opcode::OP_CallBuiltinPointer:
|
||||
// case opcode::OP_prof_end:
|
||||
case opcode::OP_FormalParams:
|
||||
/*
|
||||
case opcode::OP_EvalNewLocalArrayRefCached0_Precompiled:
|
||||
case opcode::OP_SetNewLocalVariableFieldCached0_Precompiled:
|
||||
case opcode::OP_CreateLocalVariable_Precompiled:
|
||||
case opcode::OP_SafeCreateVariableFieldCached_Precompiled:
|
||||
case opcode::OP_FormalParams_Precompiled:
|
||||
*/
|
||||
return 2;
|
||||
case opcode::OP_waittillmatch:
|
||||
case opcode::OP_JumpOnTrue:
|
||||
case opcode::OP_JumpOnFalseExpr:
|
||||
case opcode::OP_jumpback:
|
||||
case opcode::OP_JumpOnTrueExpr:
|
||||
case opcode::OP_CallBuiltin0:
|
||||
case opcode::OP_CallBuiltin1:
|
||||
case opcode::OP_CallBuiltin2:
|
||||
case opcode::OP_CallBuiltin3:
|
||||
case opcode::OP_CallBuiltin4:
|
||||
case opcode::OP_CallBuiltin5:
|
||||
case opcode::OP_GetBuiltinFunction:
|
||||
case opcode::OP_GetNegUnsignedShort:
|
||||
case opcode::OP_GetBuiltinMethod:
|
||||
case opcode::OP_endswitch:
|
||||
case opcode::OP_GetUnsignedShort:
|
||||
case opcode::OP_JumpOnFalse:
|
||||
case opcode::OP_CallBuiltinMethod0:
|
||||
case opcode::OP_CallBuiltinMethod1:
|
||||
case opcode::OP_CallBuiltinMethod2:
|
||||
case opcode::OP_CallBuiltinMethod3:
|
||||
case opcode::OP_CallBuiltinMethod4:
|
||||
case opcode::OP_CallBuiltinMethod5:
|
||||
return 3;
|
||||
case opcode::OP_CallBuiltin:
|
||||
case opcode::OP_ScriptLocalMethodCall:
|
||||
case opcode::OP_ScriptLocalFunctionCall2:
|
||||
case opcode::OP_ScriptFarFunctionCall:
|
||||
case opcode::OP_ScriptFarFunctionCall2:
|
||||
case opcode::OP_CallBuiltinMethod:
|
||||
case opcode::OP_GetLocalFunction:
|
||||
case opcode::OP_GetFarFunction:
|
||||
case opcode::OP_ScriptFarMethodCall:
|
||||
case opcode::OP_ScriptLocalFunctionCall:
|
||||
/*
|
||||
case opcode::OP_NativeGetLocalFunction:
|
||||
case opcode::OP_NativeLocalFunctionCall:
|
||||
case opcode::OP_NativeLocalFunctionCall2:
|
||||
case opcode::OP_NativeLocalMethodCall:
|
||||
case opcode::OP_NativeGetFarFunction:
|
||||
case opcode::OP_NativeFarFunctionCall:
|
||||
case opcode::OP_NativeFarFunctionCall2:
|
||||
case opcode::OP_NativeFarMethodCall:
|
||||
*/
|
||||
return 4;
|
||||
case opcode::OP_EvalSelfFieldVariableRef:
|
||||
case opcode::OP_ScriptFarMethodChildThreadCall:
|
||||
case opcode::OP_EvalAnimFieldVariable:
|
||||
case opcode::OP_EvalLevelFieldVariableRef:
|
||||
case opcode::OP_ScriptFarThreadCall:
|
||||
case opcode::OP_SetSelfFieldVariableField:
|
||||
case opcode::OP_ClearFieldVariable:
|
||||
case opcode::OP_ScriptLocalMethodThreadCall:
|
||||
case opcode::OP_EvalFieldVariable:
|
||||
case opcode::OP_ScriptLocalChildThreadCall:
|
||||
case opcode::OP_SetLevelFieldVariableField:
|
||||
case opcode::OP_EvalSelfFieldVariable:
|
||||
case opcode::OP_ScriptLocalThreadCall:
|
||||
case opcode::OP_GetInteger:
|
||||
case opcode::OP_SetAnimFieldVariableField:
|
||||
case opcode::OP_GetIString:
|
||||
case opcode::OP_ScriptFarMethodThreadCall:
|
||||
case opcode::OP_EvalFieldVariableRef:
|
||||
case opcode::OP_ScriptLocalMethodChildThreadCall:
|
||||
case opcode::OP_GetFloat:
|
||||
case opcode::OP_GetString:
|
||||
case opcode::OP_EvalLevelFieldVariable:
|
||||
case opcode::OP_switch:
|
||||
case opcode::OP_ScriptFarChildThreadCall:
|
||||
case opcode::OP_EvalAnimFieldVariableRef:
|
||||
case opcode::OP_jump:
|
||||
/*
|
||||
case opcode::OP_NativeLocalFunctionThreadCall:
|
||||
case opcode::OP_NativeLocalMethodThreadCall:
|
||||
case opcode::OP_NativeLocalFunctionChildThreadCall:
|
||||
case opcode::OP_NativeLocalMethodChildThreadCall:
|
||||
case opcode::OP_NativeFarFunctionThreadCall:
|
||||
case opcode::OP_NativeFarMethodThreadCall:
|
||||
case opcode::OP_NativeFarFunctionChildThreadCall:
|
||||
case opcode::OP_NativeFarMethodChildThreadCall:
|
||||
*/
|
||||
return 5;
|
||||
/*
|
||||
case opcode::OP_prof_begin:
|
||||
return 6;
|
||||
*/
|
||||
case opcode::OP_GetAnimation:
|
||||
return 9;
|
||||
case opcode::OP_GetVector:
|
||||
return 13;
|
||||
default:
|
||||
throw std::runtime_error("Couldn't resolve instruction size for " + std::to_string(id));
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace xsk::gsc::s4
|
216
src/s4/xsk/s4.hpp
Normal file
216
src/s4/xsk/s4.hpp
Normal file
@ -0,0 +1,216 @@
|
||||
// Copyright 2021 xensik. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by a GNU GPLv3 license
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "utils/xsk/utils.hpp"
|
||||
|
||||
#include "assembler.hpp"
|
||||
#include "disassembler.hpp"
|
||||
#include "compiler.hpp"
|
||||
#include "decompiler.hpp"
|
||||
#include "resolver.hpp"
|
||||
|
||||
namespace xsk::gsc::s4
|
||||
{
|
||||
|
||||
enum class opcode : std::uint8_t
|
||||
{
|
||||
OP_CastFieldObject = 0x0,
|
||||
OP_SetLocalVariableFieldCached = 0x1,
|
||||
OP_plus = 0x2,
|
||||
OP_RemoveLocalVariables = 0x3,
|
||||
OP_EvalSelfFieldVariableRef = 0x4,
|
||||
OP_ScriptFarMethodChildThreadCall = 0x5,
|
||||
OP_GetGameRef = 0x6,
|
||||
OP_EvalAnimFieldVariable = 0x7,
|
||||
OP_EvalLevelFieldVariableRef = 0x8,
|
||||
OP_GetThisthread = 0x9,
|
||||
OP_greater = 0xA,
|
||||
OP_waittillmatch = 0xB,
|
||||
OP_shift_right = 0xC,
|
||||
OP_dec = 0xD,
|
||||
OP_JumpOnTrue = 0xE,
|
||||
OP_bit_or = 0xF,
|
||||
OP_equality = 0x10,
|
||||
OP_ClearLocalVariableFieldCached0 = 0x11,
|
||||
OP_notify = 0x12,
|
||||
OP_GetVector = 0x13,
|
||||
OP_ScriptMethodChildThreadCallPointer = 0x14,
|
||||
OP_PreScriptCall = 0x15,
|
||||
OP_GetByte = 0x16,
|
||||
OP_ScriptFarThreadCall = 0x17,
|
||||
OP_SetSelfFieldVariableField = 0x18,
|
||||
OP_JumpOnFalseExpr = 0x19,
|
||||
OP_GetUndefined = 0x1A,
|
||||
OP_jumpback = 0x1B,
|
||||
OP_JumpOnTrueExpr = 0x1C,
|
||||
OP_CallBuiltin0 = 0x1D,
|
||||
OP_CallBuiltin1 = 0x1E,
|
||||
OP_CallBuiltin2 = 0x1F,
|
||||
OP_CallBuiltin3 = 0x20,
|
||||
OP_CallBuiltin4 = 0x21,
|
||||
OP_CallBuiltin5 = 0x22,
|
||||
OP_CallBuiltin = 0x23,
|
||||
OP_SetLocalVariableFieldCached0 = 0x24,
|
||||
OP_ClearFieldVariable = 0x25,
|
||||
OP_GetLevel = 0x26,
|
||||
OP_size = 0x27,
|
||||
OP_SafeSetWaittillVariableFieldCached = 0x28,
|
||||
OP_ScriptLocalMethodThreadCall = 0x29,
|
||||
OP_AddArray = 0x2A,
|
||||
OP_endon = 0x2B,
|
||||
OP_EvalFieldVariable = 0x2C,
|
||||
OP_shift_left = 0x2D,
|
||||
OP_EvalLocalArrayRefCached0 = 0x2E,
|
||||
OP_Return = 0x2F,
|
||||
OP_CreateLocalVariable = 0x30,
|
||||
OP_SafeSetVariableFieldCached0 = 0x31,
|
||||
OP_GetBuiltinFunction = 0x32,
|
||||
OP_ScriptLocalMethodCall = 0x33,
|
||||
OP_CallBuiltinMethodPointer = 0x34,
|
||||
OP_ScriptLocalChildThreadCall = 0x35,
|
||||
OP_GetSelfObject = 0x36,
|
||||
OP_GetGame = 0x37,
|
||||
OP_SetLevelFieldVariableField = 0x38,
|
||||
OP_EvalArray = 0x39,
|
||||
OP_GetSelf = 0x3A,
|
||||
OP_End = 0x3B,
|
||||
OP_EvalSelfFieldVariable = 0x3C,
|
||||
OP_less_equal = 0x3D,
|
||||
OP_EvalLocalVariableCached0 = 0x3E,
|
||||
OP_EvalLocalVariableCached1 = 0x3F,
|
||||
OP_EvalLocalVariableCached2 = 0x40,
|
||||
OP_EvalLocalVariableCached3 = 0x41,
|
||||
OP_EvalLocalVariableCached4 = 0x42,
|
||||
OP_EvalLocalVariableCached5 = 0x43,
|
||||
OP_EvalLocalVariableCached = 0x44,
|
||||
OP_EvalNewLocalArrayRefCached0 = 0x45,
|
||||
OP_ScriptChildThreadCallPointer = 0x46,
|
||||
OP_EvalLocalVariableObjectCached = 0x47,
|
||||
OP_ScriptLocalThreadCall = 0x48,
|
||||
OP_GetInteger = 0x49,
|
||||
OP_ScriptMethodCallPointer = 0x4A,
|
||||
OP_checkclearparams = 0x4B,
|
||||
OP_SetAnimFieldVariableField = 0x4C,
|
||||
OP_waittillmatch2 = 0x4D,
|
||||
OP_minus = 0x4E,
|
||||
OP_ScriptLocalFunctionCall2 = 0x4F,
|
||||
OP_GetNegUnsignedShort = 0x50,
|
||||
OP_GetNegByte = 0x51,
|
||||
OP_SafeCreateVariableFieldCached = 0x52,
|
||||
OP_greater_equal = 0x53,
|
||||
OP_vector = 0x54,
|
||||
OP_GetBuiltinMethod = 0x55,
|
||||
OP_endswitch = 0x56,
|
||||
OP_ClearArray = 0x57,
|
||||
OP_DecTop = 0x58,
|
||||
OP_CastBool = 0x59,
|
||||
OP_EvalArrayRef = 0x5A,
|
||||
OP_SetNewLocalVariableFieldCached0 = 0x5B,
|
||||
OP_GetZero = 0x5C,
|
||||
OP_wait = 0x5D,
|
||||
OP_waittill = 0x5E,
|
||||
OP_GetIString = 0x5F,
|
||||
OP_ScriptFarFunctionCall = 0x60,
|
||||
OP_GetAnimObject = 0x61,
|
||||
OP_GetAnimTree = 0x62,
|
||||
OP_EvalLocalArrayCached = 0x63,
|
||||
OP_mod = 0x64,
|
||||
OP_ScriptFarMethodThreadCall = 0x65,
|
||||
OP_GetUnsignedShort = 0x66,
|
||||
OP_clearparams = 0x67,
|
||||
OP_ScriptMethodThreadCallPointer = 0x68,
|
||||
OP_ScriptFunctionCallPointer = 0x69,
|
||||
OP_EmptyArray = 0x6A,
|
||||
OP_SafeSetVariableFieldCached = 0x6B,
|
||||
OP_ClearVariableField = 0x6C,
|
||||
OP_EvalFieldVariableRef = 0x6D,
|
||||
OP_ScriptLocalMethodChildThreadCall = 0x6E,
|
||||
OP_EvalNewLocalVariableRefCached0 = 0x6F,
|
||||
OP_GetFloat = 0x70,
|
||||
OP_EvalLocalVariableRefCached = 0x71,
|
||||
OP_JumpOnFalse = 0x72,
|
||||
OP_BoolComplement = 0x73,
|
||||
OP_ScriptThreadCallPointer = 0x74,
|
||||
OP_ScriptFarFunctionCall2 = 0x75,
|
||||
OP_less = 0x76,
|
||||
OP_BoolNot = 0x77,
|
||||
OP_waittillFrameEnd = 0x78,
|
||||
OP_waitframe = 0x79,
|
||||
OP_GetString = 0x7A,
|
||||
OP_EvalLevelFieldVariable = 0x7B,
|
||||
OP_GetLevelObject = 0x7C,
|
||||
OP_inc = 0x7D,
|
||||
OP_CallBuiltinMethod0 = 0x7E,
|
||||
OP_CallBuiltinMethod1 = 0x7F,
|
||||
OP_CallBuiltinMethod2 = 0x80,
|
||||
OP_CallBuiltinMethod3 = 0x81,
|
||||
OP_CallBuiltinMethod4 = 0x82,
|
||||
OP_CallBuiltinMethod5 = 0x83,
|
||||
OP_CallBuiltinMethod = 0x84,
|
||||
OP_GetAnim = 0x85,
|
||||
OP_switch = 0x86,
|
||||
OP_SetVariableField = 0x87,
|
||||
OP_divide = 0x88,
|
||||
OP_GetLocalFunction = 0x89,
|
||||
OP_ScriptFarChildThreadCall = 0x8A,
|
||||
OP_multiply = 0x8B,
|
||||
OP_ClearLocalVariableFieldCached = 0x8C,
|
||||
OP_EvalAnimFieldVariableRef = 0x8D,
|
||||
OP_EvalLocalArrayRefCached = 0x8E,
|
||||
OP_EvalLocalVariableRefCached0 = 0x8F,
|
||||
OP_bit_and = 0x90,
|
||||
OP_GetAnimation = 0x91,
|
||||
OP_GetFarFunction = 0x92,
|
||||
OP_CallBuiltinPointer = 0x93,
|
||||
OP_jump = 0x94,
|
||||
OP_voidCodepos = 0x95,
|
||||
OP_ScriptFarMethodCall = 0x96,
|
||||
OP_inequality = 0x97,
|
||||
OP_ScriptLocalFunctionCall = 0x98,
|
||||
OP_bit_ex_or = 0x99,
|
||||
OP_NOP = 0x9A,
|
||||
OP_abort = 0x9B,
|
||||
OP_object = 0x9C,
|
||||
OP_thread_object = 0x9D,
|
||||
OP_EvalLocalVariable = 0x9E,
|
||||
OP_EvalLocalVariableRef = 0x9F,
|
||||
OP_prof_begin = 0xA0,
|
||||
OP_prof_end = 0xA1,
|
||||
OP_breakpoint = 0xA2,
|
||||
OP_assignmentBreakpoint = 0xA3,
|
||||
OP_manualAndAssignmentBreakpoint = 0xA4,
|
||||
OP_BoolNotAfterAnd = 0xA5,
|
||||
OP_FormalParams = 0xA6,
|
||||
OP_IsDefined = 0xA7,
|
||||
OP_IsTrue = 0xA8,
|
||||
OP_NativeGetLocalFunction = 0xA9,
|
||||
OP_NativeLocalFunctionCall = 0xAA,
|
||||
OP_NativeLocalFunctionCall2 = 0xAB,
|
||||
OP_NativeLocalMethodCall = 0xAC,
|
||||
OP_NativeLocalFunctionThreadCall = 0xAD,
|
||||
OP_NativeLocalMethodThreadCall = 0xAE,
|
||||
OP_NativeLocalFunctionChildThreadCall = 0xAF,
|
||||
OP_NativeLocalMethodChildThreadCall = 0xB0,
|
||||
OP_NativeGetFarFunction = 0xB1,
|
||||
OP_NativeFarFunctionCall = 0xB2,
|
||||
OP_NativeFarFunctionCall2 = 0xB3,
|
||||
OP_NativeFarMethodCall = 0xB4,
|
||||
OP_NativeFarFunctionThreadCall = 0xB5,
|
||||
OP_NativeFarMethodThreadCall = 0xB6,
|
||||
OP_NativeFarFunctionChildThreadCall = 0xB7,
|
||||
OP_NativeFarMethodChildThreadCall = 0xB8,
|
||||
OP_EvalNewLocalArrayRefCached0_Precompiled = 0xB9,
|
||||
OP_SetNewLocalVariableFieldCached0_Precompiled = 0xBA,
|
||||
OP_CreateLocalVariable_Precompiled = 0xBB,
|
||||
OP_SafeCreateVariableFieldCached_Precompiled = 0xBC,
|
||||
OP_FormalParams_Precompiled = 0xBD,
|
||||
OP_count = 0xBE,
|
||||
};
|
||||
|
||||
auto opcode_size(std::uint8_t op) -> std::uint32_t;
|
||||
|
||||
} // namespace xsk::gsc::s4
|
@ -11,6 +11,7 @@
|
||||
#include "iw8/xsk/iw8.hpp"
|
||||
#include "s1/xsk/s1.hpp"
|
||||
#include "s2/xsk/s2.hpp"
|
||||
#include "s4/xsk/s4.hpp"
|
||||
#include "h1/xsk/h1.hpp"
|
||||
#include "h2/xsk/h2.hpp"
|
||||
|
||||
@ -18,7 +19,7 @@ namespace xsk::gsc
|
||||
{
|
||||
|
||||
enum class mode { __, ASM, DISASM, COMP, DECOMP };
|
||||
enum class game { __, IW5, IW6, IW7, IW8, S1, S2, H1, H2 };
|
||||
enum class game { __, IW5, IW6, IW7, IW8, S1, S2, S4, H1, H2 };
|
||||
|
||||
std::map<std::string, mode> modes =
|
||||
{
|
||||
@ -36,6 +37,7 @@ std::map<std::string, game> games =
|
||||
{ "-iw8", game::IW8 },
|
||||
{ "-s1", game::S1 },
|
||||
{ "-s2", game::S2 },
|
||||
{ "-s4", game::S4 },
|
||||
{ "-h1", game::H1 },
|
||||
{ "-h2", game::H2 },
|
||||
};
|
||||
@ -76,6 +78,7 @@ auto choose_resolver_file_name(uint32_t id, game& game) -> std::string
|
||||
case game::IW8: return iw8::resolver::file_name(id);
|
||||
case game::S1: return s1::resolver::file_name(static_cast<std::uint16_t>(id));
|
||||
case game::S2: return s2::resolver::file_name(static_cast<std::uint16_t>(id));
|
||||
case game::S4: return s4::resolver::file_name(id);
|
||||
case game::H1: return h1::resolver::file_name(static_cast<std::uint16_t>(id));
|
||||
case game::H2: return h2::resolver::file_name(static_cast<std::uint16_t>(id));
|
||||
default: return "";
|
||||
@ -386,7 +389,7 @@ int parse_flags(int argc, char** argv, game& game, mode& mode, bool& zonetool)
|
||||
void print_usage()
|
||||
{
|
||||
std::cout << "usage: gsc-tool.exe <game> <mode> <file>\n";
|
||||
std::cout << " * games: -iw5, -iw6, -iw7, -s1, -s2, -h1, -h2\n";
|
||||
std::cout << " * games: -iw5, -iw6, -iw7, -iw8, -s1, -s2, -s4, -h1, -h2\n";
|
||||
std::cout << " * modes: -asm, -disasm, -comp, -decomp\n";
|
||||
}
|
||||
|
||||
@ -435,6 +438,11 @@ std::uint32_t main(std::uint32_t argc, char** argv)
|
||||
s2::assembler assembler;
|
||||
assemble_file(assembler, file, zonetool);
|
||||
}
|
||||
else if (game == game::S4)
|
||||
{
|
||||
s4::assembler assembler;
|
||||
assemble_file(assembler, file, zonetool);
|
||||
}
|
||||
else if (game == game::H1)
|
||||
{
|
||||
h1::assembler assembler;
|
||||
@ -478,6 +486,11 @@ std::uint32_t main(std::uint32_t argc, char** argv)
|
||||
s2::disassembler disassembler;
|
||||
disassemble_file(disassembler, file, game, zonetool);
|
||||
}
|
||||
else if (game == game::S4)
|
||||
{
|
||||
s4::disassembler disassembler;
|
||||
disassemble_file(disassembler, file, game, zonetool);
|
||||
}
|
||||
else if (game == game::H1)
|
||||
{
|
||||
h1::disassembler disassembler;
|
||||
@ -527,6 +540,12 @@ std::uint32_t main(std::uint32_t argc, char** argv)
|
||||
s2::compiler compiler;
|
||||
compile_file(assembler, compiler, file ,zonetool);
|
||||
}
|
||||
else if (game == game::S4)
|
||||
{
|
||||
s4::assembler assembler;
|
||||
s4::compiler compiler;
|
||||
compile_file(assembler, compiler, file ,zonetool);
|
||||
}
|
||||
else if (game == game::H1)
|
||||
{
|
||||
h1::assembler assembler;
|
||||
@ -578,6 +597,12 @@ std::uint32_t main(std::uint32_t argc, char** argv)
|
||||
s2::decompiler decompiler;
|
||||
decompile_file(disassembler, decompiler, file, game, zonetool);
|
||||
}
|
||||
else if (game == game::S4)
|
||||
{
|
||||
s4::disassembler disassembler;
|
||||
s4::decompiler decompiler;
|
||||
decompile_file(disassembler, decompiler, file, game, zonetool);
|
||||
}
|
||||
else if (game == game::H1)
|
||||
{
|
||||
h1::disassembler disassembler;
|
||||
|
Loading…
Reference in New Issue
Block a user